Alan Coopersmith
虽然X客户端库和服务器封装了X协议编码、解码、传输的大部分细节,但是对此传输模型的基本理解对X客户端、服务器的开发和驱动程序的开发是必要的。
X客户端和服务器之间的通信是“全双工”的:任意一端都能随时向对方发送信息。这个特性是TCP/IP套接字接口提供的典型功能,但是X也常常使用许多其他的通信方式,如Unix Domain Sockets、命名管道和共享内存。通信方式必须提供可靠的、有序的字节流——因为X协议不提供记录或重发包的机制。如使用TCP/IP连接时,我们使用TCP协议而不是UDP协议。
X通信时传输的信息是由X11协议定义的。此协议于1987年发布。在过去的25年间,X11被大大的扩展了,但其核心协议仍旧和原版的定义相兼容。协议的细节详见:http://www.x.org/releases/current/doc/ 。
X协议的扩展机制是其一大关键特性。在核心协议为了向后兼容而很少改变的同时,大多数的改进都是通过协议上的可选扩展实现的。核心协议提供机制以列举和查询X服务器所支持的扩展,并能把这些扩展的产生消息加入到服务器和客户端交流的信息中。服务器的构建者可以选择所要支持的扩展,开发者能随着用途的扩展增加或者移除扩展而不必担心会打破核心协议的兼容性。客户端需要检查服务器是否支持它们所以来的扩展。如果一个扩展不可用(在某个适当的版本号上),客户端可以转而提供更精简功能的界面,或是直接报错退出:扩展不存在。
当X客户端刚连接到X服务器时,会有一个握手操作来确立连接的建立,并验证客户端是否有有连接的认证,设定一些通信参量如byte-endinanness(字节序)。早期,X认为服务器应该是一台高性能的机器,而客户端不是。有趣的是,客户端能让服务器提供它所需要的字节序,服务器将根据需要对请求和回复进行字节序交换(byte-swap)。
然后,客户端将向服务器发送请求,好让服务器向客户端提供一些信息。一般来说,客户端将请求堆积在缓存中,然后成批地发送它们,这使得通信和上下文切换更有效率。这样的缓存功能通常由Xlib和XCB提供给客户端;客户端需要时常刷新请求缓存来保证操作能被及时处理。
X服务器按照从客户端收到请求的顺序来处理他们。但是X服务器也随时对不同客户端发来的信息进行分类,所以并不能保证请求在不同客户端间保持一定顺序,除非有特殊的请求。服务器和客户端都记录当前的请求号,并将其作为每次请求的序号。
服务器将响应发给客户端。客户端发送的许多请求被X服务器直接处理掉,如果没有错误就没有任何返回。如果是要返回信息的请求,服务器就给客户端发送一个称为回复(reply)的响应。回复的序列号标明了它属于哪一个请求。客户端可能一次发送多条请求给X服务器,并异步地等待服务器的响应。回复会按顺序返回,但客户端需要记录自己发送请求的序号来将服务器的回复对应到相应请求上。
如果处理请求时发生问题,X服务器将返回一个错误响应给客户端。错误响应包含了有问题的包的序号、一个错误码和一些有关错误的额外细节。对一个问题进行除虫,通常需要找出错误请求的源头。由于协议的异步性,错误响应常常会在客户端继续进行其他操作后收到,所以序列号在这里是非常有价值的信息。
客户端还可以在X服务器注册各种时间通知。事件发生时客户端将收到X服务器的特定响应。事件可能被如下原因或事物触发:
工具包和X协议库有功能能检查是否有从X服务器上收到的事件。大多数X应用由一个能捕捉事件响应并能正确处理它们的主“事件循环”驱动。
在X11协议中,每一个请求和响应的类型都有一个8位的识别码(identifier code)来标明它表示的的操作、事件或错误。这些识别码在通信的不同方向上是不同的。比如,每条从客户端发往服务器以3开始的消息都是GetWindowAtrributes请求。错误和事件的识别码是分开的,为3的错误码标识着一个BadWindow错误而为3的事件标识着一个KeyRelease事件。
X11通信协议的许多特性都是在很多年前就被支持了。如,客户端并不传送请求序号:服务器和客户端都按照假设来计数。回复序号只是部分的被传送,通过智能的协议来对剩下的部分保持追踪。类似地,协议规定服务器上的资源在请求时用成为XID的小整数来标识。XID其实是客户端按X服务器所给的那段XID来分配的。这两者和刚才提到的8位请求/响应ID空间都是为了能在网络上传输最小的包而设计的优化。因此,在屏幕上画一条线这样的操作只需要单向传递很少的几个比特就能做到。
扩展能按要求在核心协议的基础上增加请求、时间和错误。X服务器在启动时动态地给扩展消息分配识别码。因此,同样的扩展在不同配置的服务器上可能会得到不同的值。当前X服务器使用的值可以通过“xdpyinfo -queryExtensions”命令来显示。由于8位二进制数只有256个,所以扩展一般会尽量节省这个区域:扩展会增加单个请求或事件然后用第二个字节作为附加的识别码来标识该事件的子消息。
X核心协议的安全协议十分简单。建立连接时通过检查客户端的地址来确定是否允许其连接到服务器,如果为否,连接被拒绝。如果客户端被允许连接,那么客户端将具备所有访问服务器的权限。包括能向所有客户端发送信息,监视所有设备的状态(包括获取所有键盘事件、鼠标移动等)。客户端甚至可以请求X服务器杀掉其它客户端的连接。
许多扩展都提供了粒度可控的安全模型。“SECURITY”扩展提供简单的“Trusted”和“Untrusted”(“可信”和“不可信”)客户端识别。SELinux和Solaris的Xtsol则提供了更为复杂的多层安全模型。
客户端连接至服务器时的认证机制在不断发展。现在大多数的服务器支持种类繁多的认证机制。
最初的连接安全机制是基于主机地址的认证,这种方式下来自特定主机的任何用户或程序都被授予访问权限。默认状态下只有本地主机能够访问,但“xhost +hostname”能用于添加运行连接的主机。这种机制在某种程度上显得比较天真:它假设每台机器只有一个用户或那些机器上的每个用户都是可信的。
xhost机制在以后的版本中被扩展以增加更多的同样原理的访问控制机制。这些方式包含一个“服务器解释”(server interpreted)框架,这个框架中直接向服务器传送一个字符串并允许X服务器按需定义新的连接控制类型。“localuser”最普通的服务器解释框架,通过使用现代操作系统提供的接口来获取连接程序的user id来进行认证。xhost和Xsecurity的man page提供了更详细的信息。
现在最常用的认证方法是服务器和客户端间共享密码。这是X11协议后来加进去的功能,解决了了xhost认证的许多问题。共享密码有许多格式。最基础的是MIT-MAGIC-COOKIE-1。程序启动X服务器和会话(如xinit、gdm、xdm等等)并简单地选取个随机的128位数字并将其记录在一个文件中,通过“-auth”命令选项传送给X服务器,通过Xauthority文件传递给客户端(可能是“$HOME/.Xauthority”,也可能由“$XAUTHORITY”环境变量指定(译者的机器上该环境变量指向了家目录下的.Xauthority))。若客户端能读取这个文件且将正确的值传递给服务器,那么它就可以连接。在使用SECURITY扩展时,cookie也可能将客户端确定为Trusted和Untrusted并给予其适当的权限。详情参见xauth和Xsecurity的man page。
Martin Peres (mupuf)
应用曾经被限制得在复杂度和尺寸上都非常小且授权都一样。但现在不能再这样了,由于用户们需要使用专有软件或者大型的软件如Web浏览器,这样的软件有潜在的安全风险(如缓冲区溢出)。不幸的是,一旦X客户端被授权访问X服务器,基本上它就能自由地以多种方式和其他X客户端交互了:
因此,许多X应用都无法被信任且应被认为存在潜在的可信和完整性威胁。
X被连接到SELinux以通过扩展SELinux模型来为图形服务器减轻这种问题。核心思想在于通过一种合理的授权访问控制来加强对孤立的GUI的安全策略。为达成这一目的,SELinux模型要求:
X服务器的hook由X Access Control Extension(XACE)扩展提供,由xauth、xhost和“XSELinux”使用。每个资源的标签在资源分配时设定或在之后的访问控制操作时设定。做决定的引擎由libselinux提供,大多数时候在内核空间运行。
明显地,XSELinux能够控制如下的访问:
XSELinux提供一个合理授权的访问控制,可以有效地将X服务器上X客户端互相隔离开来。
更多信息见: http://selinuxproject.org/page/NBXWIN 和 https://www.nsa.gov/research/files/selinux/papers/xorg07-paper.pdf.
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。