Docker 使用共享 X11 套接字:为什么它可以 "start" Firefox 在容器之外?

Docker with shared X11 socket: Why can it "start" Firefox outside of the container?

我有以下场景:

  1. 我设置了一个可以访问 X11 套接字的 Docker 容器,实际上我是这样做的:
  2. 然后我在容器中安装了 Firefox,并使用 bash 中的 "firefox" 命令启动了它。

我注意到:如果当我在容器中启动 Firefox 时它已经 运行 在我的主机上,它本质上是 "escaped" 容器,因为它刚刚打开一个新的 window Firefox 的主机实例。因此它可以访问主机上的所有内容并且容器变得无用。

反之亦然:如果 Firefox 不在主机上 运行 而我在容器中启动了一个实例,那么它确实在容器中 运行。如果我随后在主机上启动 Firefox,新实例也会 运行 在容器内。

但是,我无法使用 gvim 而不是 Firefox 重现此行为。

我很清楚 X11 套接字共享固有的安全问题,但我无法解释我上面描述的场景。为什么容器可以在其受限环境之外启动 "process"--- 或者 window---?我的主机系统怎么可能仅仅因为同一个程序已经 运行 在容器中就在容器中启动了一个进程?

(请注意,除了 "process",我不知道如何调用这样的程序图形实例,尽管在这种情况下它可能不是真正的进程...)

系统:Ubuntu GNOME 14.10,Docker 1.5,ubuntu:latest Docker 图片。

更新:如果我使用 -new-instance 标志启动 Firefox,则不会发生这种情况,因此它似乎更像是 Firefox 问题而不是 X11 套接字问题。

更新 2:似乎在其他情况下也会发生这种情况,例如将 ssh 与 X 转发一起使用:
https://unix.stackexchange.com/questions/104476/why-starting-firefox-from-command-line-in-vm-starts-the-firefox-in-the-host-ma

https://superuser.com/questions/462055/launching-firefox-on-remote-server-causes-local-firefox-to-open-the-page-instead

现在的问题是,Firefox 到底是怎么做到的?他们使用什么样的 X11 魔法来确定 Firefox 是否已经 运行?

因为您将 x11 套接字转发到容器中,所以任何图形程序,无论是在容器内还是在容器外,都将与同一个 Xorg 服务器通信。这与使用带有 X 转发的 ssh 时相同。

现在假设一个 firefox 实例已经启动并与该 xserver 通信。如果我们是第二个启动的 firefox 进程,我们可能会发现第一个进程 navigating the window tree from the root. We might be able to identify a window belonging to firefox through some properties that it sets on it's windows. Once we found a window belonging to firefox, we might send a message 到拥有 window 的进程,要求它添加一个新选项卡。

也许如果我们找到这样的进程并要求它打开一个新选项卡,我们就会在工作完成时消失。

当然,我们总是可以 look at the source 并发现 firefox 确实基本上做到了这一点。特别是他们:

但他们不会通过客户端消息通知它。他们通过改变 window 属性 来做到这一点。据推测,创建 window 的进程也订阅了 属性 更改通知。如果您好奇代码的完整路径是:

  • 从解析命令行,StartRemoteClient
  • which creats a client(注意他们也在 d-bus/wayland 上这样做)然后调用 SendCommandLine()
  • 这是一个虚函数,所以找到它被覆盖XRemoteClient
  • 在那里你可以看到它在哪里调用链接到 FindBestWindow()DoSendCommandLine() 的前两个函数。