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

Issue 613964 link

Starred by 1 user

Issue metadata

Status: WontFix
Owner:
Closed: Jun 2016
Cc:
Components:
EstimatedDays: ----
NextAction: ----
OS: Linux
Pri: 2
Type: Bug-Security



Sign in to add a comment

renderer processes are not protected from outside access by Yama

Project Member Reported by jannh@google.com, May 23 2016

Issue description

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

Steps to reproduce the problem:
1. Switch Yama to YAMA_SCOPE_RELATIONAL or YAMA_SCOPE_CAPABILITY mode.
2. Run Chrome.
3. Look up the PID of a renderer and attach to it using strace (from the same UID under which Chrome was executed).

What is the expected behavior?
According to jln, the expected behavior is that strace can't attach to the renderer because it is not a parent of the renderer.

What went wrong?
Yama, except in YAMA_SCOPE_NO_ATTACH mode, always grants access if the caller is capable *relative to the target process*. Because Chrome unshares the user namespace for renderers in order to be able to sandbox them without using real root privileges, renderers are executed in a child namespace of the one in which the rest of the user's processes run (usually the init namespace), with the namespace owner UID being the EUID of the browser process. This means that any process in the outer namespace with the user's UID as EUID is considered to be privileged relative to the renderer processes (see cap_capable() in security/commoncap.c in the kernel).

IIRC someone complained about this on https://bugzilla.kernel.org/ before, but I can't find the issue atm.

As far as I know, on Linux, it currently isn't possible to unshare the user namespace without granting every process with the same EUID in the old namespace full privileges over yourself. It might be a good idea to write a kernel patch that permits the creation of user namespaces without an owner UID, only granting capabilities in the namespace to processes that are also privileged in the outer namespace.

Did this work before? N/A 

Chrome version: 50.0.2661.102  Channel: stable
OS Version: 
Flash Version: 

Please Cc jln, keescook and rickyz on this issue.
Since this is just a quirk that allows a relatively privileged process to access a renderer, I think this is low severity at most.
 

Comment 1 by jln@chromium.org, May 23 2016

Cc: kerrnel@chromium.org jln@chromium.org keescook@chromium.org
Labels: -Restrict-View-SecurityTeam Security_Severity-Low
Owner: rickyz@chromium.org
Status: Available (was: Unconfirmed)
I'm making the bug public since the security impact is very low.

- I would think that this is a bit of a concern and could warrant a kernel patch/workaround. Kees, what do you think?

- In Chromium, we could make renderers non dumpable again, but I'm not sure this warrants the complexity.
Moreover, non dumpability is very fragile since one could signal a process with SIGSEGV to make it dumpable; protections against this have regressed several times (c.f. http://www.openwall.com/lists/oss-security/2011/03/22/13).

Any other idea?

Comment 2 by jannh@google.com, May 23 2016

Nondumpability wouldn't have any effect here - relative capability overrides nondumpability:

	if (task->mm)
		dumpable = get_dumpable(task->mm);
	rcu_read_lock();
	if (dumpable != SUID_DUMP_USER &&
	    !ptrace_has_cap(__task_cred(task)->user_ns, mode)) {
		rcu_read_unlock();
		return -EPERM;
	}
	rcu_read_unlock();

Comment 3 by jln@chromium.org, May 23 2016

Ohh right. This seems quite ugly in the kernel then, no?

For instance it looks like this could be used to bypass the non-dumpability of setuid binaries.
If there is a r-x--x--x setuid binary, this becomes a way to read the binary image, which would normally not be allowed.

Comment 4 by jannh@google.com, May 23 2016

Meh, the kernel doesn't really make a big effort to enforce the unreadability of such setuid executables anyway.

IIRC you can e.g. cause the execution to be marked as unsafe ((bprm->unsafe&~LSM_UNSAFE_PTRACE_CAP)!=0, by setting NO_NEW_PRIVS, sharing the fs struct or ptracing) and then execute such a binary, and then the execution will be "downgraded" to a normal one (in cap_bprm_set_creds()). While the kernel should still mark the process as nondumpable via BINPRM_FLAGS_ENFORCE_NONDUMP, the AT_SECURE flag (whose value is separate from nondumpability and determined by cap_bprm_secureexec(bprm) and LSMs, invoked via security_bprm_secureexec() in binfmt_elf.c) will still be zero because no capabilities were actually gained, so if the binary isn't linked statically, the new process will load any library you specify in LD_PRELOAD, and then that library can dump the memory. Another thing you can IIRC do is to just stay attached over the setuid execution - you won't be able to reattach after the setuid execution, but if you attach before, it should work.

And if you have namespaces, if the binary isn't statically linked, another way is to just chroot into a directory with a fake ld.so that dumps the program for you.

But yes, there are bigger problems with this approach, one of them being that it's basically impossible for an unprivileged user to safely enter a user namespace whose root user is not the same one as the owner (because to enter a user namespace, you need to either have a capability in the outer namespace - which the unprivileged user doesn't have - or have the owner's UID as EUID - but if you do that, then the namespace root can ptrace you as soon as you enter and steal your access to the owner uid). I actually wrote a patch that works around this (https://lkml.org/lkml/2015/12/25/71) that IIRC at least one distro treated as a security patch while upstream hasn't taken it yet and views it as a feature patch. (If you want to have unprivileged containers at the moment, you have to either be really sure that no credentials can leak out of the container and ensure that you enter the user namespace before entering the pid namespace, or you can use a more robust solution involving an intermediate user namespace (owned by the container owner) between the init namespace and the container's namespace in which the container owner is mapped as root and the rest of the container, including its root user, is mapped to other uids, and then, when entering the container, first enter the intermediate namespace, then drop to the container root uid and enter the container's user namespace. But obviously nobody does that.)
Project Member

Comment 5 by ClusterFuzz, May 23 2016

Status: Assigned (was: Available)

Comment 6 by mea...@chromium.org, May 25 2016

Components: Internals
Labels: Security_Impact-Stable
Project Member

Comment 7 by sheriffbot@chromium.org, Jun 2 2016

Labels: Hotlist-Google
Status: WontFix (was: Assigned)
WontFix based on previous comments and "Since this is just a quirk that allows a relatively privileged process to access a renderer, I think this is low severity at most."
Project Member

Comment 9 by sheriffbot@chromium.org, Oct 1 2016

This bug has been closed for more than 14 weeks. Removing security view restrictions.

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

Comment 10 by sheriffbot@chromium.org, Oct 2 2016

This bug has been closed for more than 14 weeks. Removing security view restrictions.

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

Sign in to add a comment