mirror of
https://github.com/QubesOS/qubes-doc.git
synced 2024-10-01 01:25:40 -04:00
GUIdocs changed
This commit is contained in:
parent
19984fbc9b
commit
f82777dec4
89
GUIdocs.md
89
GUIdocs.md
@ -7,10 +7,89 @@ permalink: /wiki/GUIdocs/
|
|||||||
Qubes GUI protocol
|
Qubes GUI protocol
|
||||||
==================
|
==================
|
||||||
|
|
||||||
|
qubes\_gui and qubes\_guid processes
|
||||||
|
------------------------------------
|
||||||
|
|
||||||
|
All AppVM X applications connect to local (running in AppVM) Xorg server, that uses the following "hardware" drivers:
|
||||||
|
|
||||||
|
- *dummy\_drv* - video driver, that paints onto a framebuffer located in RAM, not connected to real hardware
|
||||||
|
- *qubes\_drv* - it provides a virtual keyboard and mouse (in fact, more, see below)
|
||||||
|
|
||||||
|
For each AppVM, there is a pair of *qubes\_gui* (running in AppVM) and *qubes\_guid* (running in dom0) processes, connected over vchan. Main responsibilities of *qubes\_gui* are:
|
||||||
|
|
||||||
|
- call XCompositeRedirectSubwindows on the root window, so that each window has its own composition buffer
|
||||||
|
- instruct the local Xorg server to notify it about window creation, configuration and damage events; pass information on these events to dom0
|
||||||
|
- receive information about keyboard and mouse events from dom0, tell *qubes\_drv* to fake appropriate events
|
||||||
|
- receive information about window size/position change, apply them to the local window
|
||||||
|
|
||||||
|
Main responsibilities of *qubes\_guid* are:
|
||||||
|
|
||||||
|
- create a window in dom0 whenever an information on window creation in AppVM is received from *qubes\_gui*
|
||||||
|
- whenever the local window receives XEvent, pass information on it to AppVM (particularly, mouse and keyboard data)
|
||||||
|
- whenever AppVM signals damage event, tell local Xorg server to repaint a given window fragment
|
||||||
|
- receive information about window size/position change, apply them to the local window
|
||||||
|
|
||||||
|
Note that keyboard and mouse events are passed to AppVM only if a window belonging to this AppVM has focus. AppVM has no way to get information on keystrokes fed to other AppVMs (e.g. XTEST extension will report the status of local AppVM keyboard only), nor synthetize and pass events to other AppVMs.
|
||||||
|
|
||||||
|
Window content updates implementation
|
||||||
|
-------------------------------------
|
||||||
|
|
||||||
|
Typical remote desktop applications, like *vnc*, pass the information on all changed window content in-band (say, over tcp). As the channel has limited throughput, this impacts video performance. In case of Qubes, *qubes\_gui* does not transfer all changed pixels via vchan. Instead, for each window, upon its creation or size change, *qubes\_gui*
|
||||||
|
|
||||||
|
- asks *qubes\_drv* driver for the list of physical memory frames that hold the composition buffer of a window
|
||||||
|
- pass this information via {{{MFNDUMP}} message to *qubes\_guid* in dom0
|
||||||
|
|
||||||
|
Now, *qubes\_guid* has to tell dom0 Xorg server about the location of the buffer. There is no supported way (e.g. Xorg extension) to do this zero-copy style. The following method is used in Qubes:
|
||||||
|
|
||||||
|
- in dom0, the Xorg server is started with *LD\_PRELOAD*-ed library named *shmoverride.so*. This library hooks all function calls related to shared memory.
|
||||||
|
- *qubes\_guid* creates a shared memory segment, and then tells Xorg to attach it via *MIT-SHM* extension
|
||||||
|
- when Xorg tries to attach the segment (via glibc *shmat*) *shmoverride.so* intercepts this call and instead maps AppVM memory via *xc\_map\_foreign\_range*
|
||||||
|
- since then, we can use MIT-SHM functions, e.g. *XShmPutImage* to draw onto a dom0 window. *XShmPutImage* will paint with DRAM speed; actually, many drivers use DMA for this.
|
||||||
|
|
||||||
|
To sum up, this solution has the following benefits:
|
||||||
|
|
||||||
|
- window updates at DRAM speed
|
||||||
|
- no changes to Xorg code
|
||||||
|
- minimal size of the supporting code
|
||||||
|
|
||||||
|
[![gui.png](/chrome/site/../../../site/gui.png "gui.png")](/chrome/site/../../../site/gui.png)
|
||||||
|
|
||||||
|
Security markers on dom0 windows
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
It is important that user knows which AppVM a given window belongs to. This prevents an attack when a rogue AppVM paints a window pretending to belong to other AppVM or dom0, and tries to steal e.g. passwords.
|
||||||
|
|
||||||
|
In Qubes, the custom window decorator is used, that paints a colourful frame (the colour is determined during AppVM creation) around decorated windows. Additionally, window title always starts with **[name of the AppVM]**. If a window has a *override\_redirect* attribute, meaning that it should not be treated by a window manager (typical case is menu windows), *qubes\_guid* draws a two-pixel colourful frame around it manually.
|
||||||
|
|
||||||
|
Clipboard sharing implementation
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
Certainly, it would be insecure to allow AppVM to read/write clipboard of other AppVMs unconditionally. Therefore, the following mechanism is used:
|
||||||
|
|
||||||
|
- there is a "qubes clipboard" in dom0 - its contents is stored in a regular file in dom0.
|
||||||
|
- if user wants to copy local AppVM clipboard to qubes clipboard, she must focus on any window belonging to this AppVM, and press **Ctrl-Shift-C**. This combination is trapped by *qubes-guid*, and `CLIPBOARD_REQ` message is sent to AppVM. *qubes-gui* responds with *CLIPBOARD\_DATA* message followed by clipboard contents.
|
||||||
|
- user focuses on other AppVM window, presses **Ctrl-Shift-V**. This combination is trapped by *qubes-guid*, and `CLIPBOARD_DATA` message followed by qubes clipboard contents is sent to AppVM; *qubes\_gui* copies data to the the local clipboard, and then user can paste its contents to local applications normally.
|
||||||
|
|
||||||
|
This way, user can quickly copy clipboards between AppVMs. This action is fully controlled by the user, it cannot be triggered/forced by any AppVM.
|
||||||
|
|
||||||
|
*qubes\_gui* and *qubes\_guid* code notes
|
||||||
|
-----------------------------------------
|
||||||
|
|
||||||
|
Both applications are structures similarly. They use *select* function to wait for any of the two event sources
|
||||||
|
|
||||||
|
- messages from the local X server
|
||||||
|
- messages from the vchan connecting to the remote party
|
||||||
|
|
||||||
|
The XEvents are handled by *handle\_xevent\_eventname* function, messages are handled by *handle\_messagename* function. One should be very careful when altering the actual *select* loop - e.g. both XEvents and vchan messages are buffered, meaning that *select* will not wake for each message.
|
||||||
|
|
||||||
|
If one changes the number/order/signature of messages, one should increase the *QUBES\_GUID\_PROTOCOL\_VERSION* constant in *messages.h* include file.
|
||||||
|
|
||||||
|
*qubes\_guid* writes debugging information to */var/log/qubes/qubes.domain\_id.log* file; *qubes\_gui* writes debugging information to */var/log/qubes/gui\_agent.log*. Include these files when reporting a bug.
|
||||||
|
|
||||||
AppVM -\> dom0 messages
|
AppVM -\> dom0 messages
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
||||||
Proper handling of the below messages is security-critical. Observe that beside two messages (`CLIPBOARD` and `MFNDUMP`) the rest have fixed size, so there is no need for error-prone parsing.
|
Proper handling of the below messages is security-critical. Observe that beside two messages (`CLIPBOARD` and `MFNDUMP`) the rest have fixed size, so the parsing code can be small.
|
||||||
|
|
||||||
Each message starts with the following header
|
Each message starts with the following header
|
||||||
|
|
||||||
@ -84,7 +163,7 @@ struct msghdr {
|
|||||||
```
|
```
|
||||||
|
|
||||||
The header is followed by message-specific data.
|
The header is followed by message-specific data.
|
||||||
` KEYPRESS, BUTTON, MOTION ` messages pass information extracted from dom0 XEvent; see appropriate event documentation.
|
` KEYPRESS, BUTTON, MOTION, FOCUS ` messages pass information extracted from dom0 XEvent; see appropriate event documentation.
|
||||||
|
|
||||||
|Message name|Structure after header|Action|
|
|Message name|Structure after header|Action|
|
||||||
|:-----------|:---------------------|:-----|
|
|:-----------|:---------------------|:-----|
|
||||||
@ -94,20 +173,20 @@ The header is followed by message-specific data.
|
|||||||
` uint32_t y; `
|
` uint32_t y; `
|
||||||
` uint32_t state; `
|
` uint32_t state; `
|
||||||
` uint32_t keycode; `
|
` uint32_t keycode; `
|
||||||
` }; `|Tell qubes driver to generate a keypress|
|
` }; `|Tell *qubes\_drv* driver to generate a keypress|
|
||||||
|MSG\_BUTTON|` struct msg_button { `
|
|MSG\_BUTTON|` struct msg_button { `
|
||||||
` uint32_t type; `
|
` uint32_t type; `
|
||||||
` uint32_t x; `
|
` uint32_t x; `
|
||||||
` uint32_t y; `
|
` uint32_t y; `
|
||||||
` uint32_t state; `
|
` uint32_t state; `
|
||||||
` uint32_t button; `
|
` uint32_t button; `
|
||||||
` }; `|Tell qubes driver to generate mouseclick|
|
` }; `|Tell *qubes\_drv* driver to generate mouseclick|
|
||||||
|MSG\_MOTION|` struct msg_motion { `
|
|MSG\_MOTION|` struct msg_motion { `
|
||||||
` uint32_t x; `
|
` uint32_t x; `
|
||||||
` uint32_t y; `
|
` uint32_t y; `
|
||||||
` uint32_t state; `
|
` uint32_t state; `
|
||||||
` uint32_t is_hint; `
|
` uint32_t is_hint; `
|
||||||
` }; `|Tell qubes driver to generate motion|
|
` }; `|Tell *qubes\_drv* driver to generate motion event|
|
||||||
|MSG\_CONFIGURE|` struct msg_configure { `
|
|MSG\_CONFIGURE|` struct msg_configure { `
|
||||||
` uint32_t x; `
|
` uint32_t x; `
|
||||||
` uint32_t y; `
|
` uint32_t y; `
|
||||||
|
Loading…
Reference in New Issue
Block a user