Friday, January 20, 2012

Given that there is a copious amount of misinformation being spread, here is a summary of CVE-2012-0064, straight from a horse's mouth.

Outline of the issue

The bug allows users to work around screen locking (e.g. gnome-screensaver) by hitting Control+Alt+keypad multiply or Control+Alt+keypad divide. This terminates the input grab the screensaver has and thus allows a user to interact with the desktop, skipping the password entry.

Affected versions

Affected is anyone running X server 1.11 or later (or release candidates thereof). So if "Xorg -version" shows something else on your box, stop worrying. I doubt any distribution would have back-ported the patches.

In Fedora/Red Hat land - the only distributions affected are Fedora 16 and current Fedora Rawhide. Both have been fixed, the F16 update is avaialble here. Note that the update is to xkeyboard-config, not to the server itself.

Fedora 15 is not affected. RHEL 4, 5, 6 and thus CentOS 4, 5, 6 and other derivatives are not affected. I believe that most other distributions have now pushed out updates as well, if you want to link to the respective updates, please do so in the comments.

History of the feature

The X protocol does not allow the server to break grabs. Once a client has a grab, the server must wait for that client to release the grab, terminate, or the grab window to become unviewable. This is an issue when debugging applications - if your client has a keyboard grab, you cannot use the debugger since all key events will go to the client being debugged. To avoid this issue, the X server has had two combinations to break grabs: Control+Alt+Keypad multiply and Control+Alt+Keypad divide. They forced grab termination inside the X server and although against the protocol it made debugging possible. The option required explicit enabling in the xorg.conf.

These options were removed in server 1.4 and disabled since. Which made debugging hard, so last year we merged a patch to bring them back, together with some other features. They are triggered by XKB actions (as they used to be). The plan was to remove the XKB actions from the default keymap so that the action is available on request but not enabled by default. This is where a miscommunication happened, the removal from the default keymap never happened. So server 1.11 and vanilla xkeyboard-config ship with both the actions available and present in the current keymap. As a result, any user can break a grab from any application and thus get around screen locking.

Outline of the fix

To shoot yourself in the foot, you need two items: a gun and a trigger. We have removed the trigger. The fix we've now pushed into xkeyboard-config removes the actions from the default keymap and into an XKB option instead. So the fix does not remove the gun, but it requires the user to screw the trigger in themselves before trying to hurt themselves. In a default configuration, it is thus no longer possible to break the grab of your screensaver.

In this post, I'll outline how grabs on touch events work. This post assumes basic knowledge of the XI2 Xlib interfaces.

Passive grabs

The libXi
interface has one new passive grab call: XIGrabTouchBegin, which
works pretty much like the existing passive grab APIs. As with event selection, you must
set all three event masks XI_TouchBegin, XI_TouchUpdate and XI_TouchEnd or a
BadValue error occurs. Once a passive grab activates in response to a touch,
the client must choose to either accept or reject a touch.
Details on that below.

Grabs activate on a TouchBegin event and due to the nature of multitouch,
multiple touch grabs may be active at any time - some of them for different
clients.

Active grabs

Active grabs do not have a new call, they are handled through the event masks of the existing XIGrabDevice(3) call. If a client has an active touch grab on the device, it is automatically the owner of the touch sequence (ownership is described below). If a client has an active pointer or keyboard grab on the device, it is the owner of the touch sequence for pointer emulated touch events only. Other touch events are unaffected by the grab and are processed normally.

Acceptance and rejection

Pointer grabs provide exclusive access to the device, but to some degree a
client can opt to replay the event it received on the next client. We expect
that touch sequences will often trigger gesture recognition, and a client may realise after a few events that it doesn't actually want that touch sequence. So we expanded
the replay semantics. clients with a touch
grab must choose to either accept or reject a touch.

Accepting a touch signals to the server that the touch sequence is meant for
this client and no-one else. The server then exclusively delivers to that
client until the terminating TouchEnd.

Rejecting a touch sequence signals that the touch sequence is not meant for
this client. Once a client rejects a touch sequence, the server sends the
TouchEnd event to that client (if the touch is still active) and replays
the full touch sequence[1] on the next grab
or window. We use the term owner of a touch sequence to talk about
the current recipient.

The order of events for two clients Cg and Cw, with Cg having a
grab and Cw having a regular touch event selection on a window, is thus:

Events with + mark an event created by the server, * mark events replayed by the server

For nested grabs, this sequence simply repeats for each client until either
a grabbing client accepts the touch or the client with the event selection
becomes the owner.

In the above case, the touch ended after Cg rejected the touch. If the touch
ends before the current owner accepted or rejected it, the owner gets the
TouchEnd event and the touch is left handing until the owner accepts or
rejects it. If accepted, that's it. If rejected, the new owner gets the
full sequence in one go, including the TouchEnd event. The sequence is thus:

Touch ownership handling

One additional event type that XI 2.2 introduces is the
XI_TouchOwnership event. Clients selecting for this event signal that
they need to receive touch events before they're the owner of the
touch sequence. This event type can be selected on both grabs and event
selections.

First up: there are specific use-cases where you need this. If you don't
fall into them, you're better off just skipping on ownership events, they
make everything more complicated. And whether you need ownership events
depends not only on you, but also the stack you're running under.
On normal touch event selection, touch events are only delivered to the
current owner of the touch. With multiple grabs, the delivery is sequential
and delivery of touch events may be delayed.

Clients selecting for touch ownership events get the events as they occur,
even if they are not the current owner. The XI_TouchOwnership event is
delivered if and when they become the current owner. The last part is
important: if you select for ownership events, you may receive touch events
but you may not become the owner of that sequence. So while you can start
reacting to that sequence, anything your app does must be undo-able in case
the e.g. window manager claims the touch sequence.

If we look at the same sequence as above with two clients selecting for
ownership, the sequence looks like this:

Note: TouchOwnership events do not correspond to any physical event, they are always generated by the server

If a touch ends before the owner accepts, the current owner gets the
TouchEnd, all others get a TouchUpdate event instead. That TouchUpdate has a
flag XITouchPendingEnd set, signalling that no more actual events
will arrive from this touch but the touch is still waiting for owner
acceptance.

In the case of multiple grabs, the same strategy applies in order of grab
activation. Ownership events may be selected by some clients but not others.
In that case, each client is treated as requested, so the event sequence the
server deals with may actually look like this: