Support the unprivileged namespace sandbox

Bug #1447345 reported by Chris Coulson
40
This bug affects 6 people
Affects Status Importance Assigned to Milestone
Oxide
Triaged
High
Chris Coulson
chromium-browser (Ubuntu)
Confirmed
Undecided
Unassigned
evince (Ubuntu)
Confirmed
Undecided
Unassigned

Bug Description

Chromium has a new layer 1 sandbox which replaces the suid sandbox on systems with CLONE_NEWUSER. However, it's currently incompatible with application confinement.

To summarize, the sandbox mechanism does something like this:

1) Browser launches zygote process:
  - clones with CLONE_NEWUSER | CLONE_NEWPID | CLONE_NEWNET and then exec()

2) Zygote initializes sandbox:
  - unshare(CLONE_NEWUSER)
  - clones a new process with CLONE_FS and then does waitpid(). The child chroots to /proc/self/fdinfo
  - Enables CAP_SYS_ADMIN (see below)

3) Zygote forks
  - Parent becomes init
  - Child continues as zygote

4) Zygote waits for requests from the browser to create render processes

5) On each request:
  - Zygote clones a new process with CLONE_NEWPID (this is why it needs CAP_SYS_ADMIN)
  - New process drops all privileges and becomes a renderer

This produces the following denial on the device:

type=1400 audit(1429733985.487:153): apparmor="DENIED" operation="capable" profile="com.zeptolab.cuttherope.full_cuttherope_0.5.2" pid=7195 comm="qmlscene" capability=21 capname="sys_admin"

The oxide_helper profile already allows sys_admin, but this is coming from the browser process, just here:

7229 clone(child_stack=0, flags=CLONE_NEWUSER|SIGCHLD) = 7246 <-- Test that the new sandbox can be used
7246 exit_group(0) = ?
7229 wait4(7246, <unfinished ...>
7246 +++ exited with 0 +++
7229 <... wait4 resumed> [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0, NULL) = 7246
7229 --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=7246, si_status=0, si_utime=0, si_stime=0} ---
7229 write(13, "\0", 1) = 1
7229 rt_sigreturn() = 7246
7229 access("/proc/self/ns/user", F_OK) = 0
7229 access("/proc/self/ns/user", F_OK) = 0
7229 access("/proc/self/ns/pid", F_OK) = 0
7229 access("/proc/self/ns/user", F_OK) = 0
7229 access("/proc/self/ns/net", F_OK) = 0
7229 getuid32() = 32011
7229 getgid32() = 32011
7229 access("/proc/self/setgroups", F_OK) = -1 ENOENT (No such file or directory)
7229 rt_sigprocmask(SIG_SETMASK, ~[RTMIN RT_1], [], 8) = 0
7229 clone(child_stack=0xbe8518d4, flags=CLONE_NEWUSER|CLONE_NEWPID|CLONE_NEWNET|SIGCHLD) = -1 EPERM (Operation not permitted)

It fails in step 1) above, because it needs CAP_SYS_ADMIN before it's able to transition to the oxide_helper profile (which allows it)

Revision history for this message
Tyler Hicks (tyhicks) wrote :

I've done some testing with a little test program and basic AppArmor confinement. When an unconfined and unprivileged process enters a new user and pid namespace, it picks up all capabilities. When a confined and unprivileged process enters a new user and pid namespace, it only picks up the capabilities that are listed in the AppArmor profile.

Revision history for this message
Tyler Hicks (tyhicks) wrote :

Here's the test program that I used. It emulates the second clone(2) that Chris mentioned and then prints out the list of capabilities that it has after entering new user, pid, and net namespaces.

# Build it
$ gcc demo_ns.c -Wall -pedantic -lcap -o demo-ns
# Run it unconfined
$ ./demo-ns
eUID = 65534; eGID = 65534; capabilities: = cap_chown,cap_dac_override,cap_dac_read_search,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_linux_immutable,cap_net_bind_service,cap_net_broadcast,cap_net_admin,cap_net_raw,cap_ipc_lock,cap_ipc_owner,cap_sys_module,cap_sys_rawio,cap_sys_chroot,cap_sys_ptrace,cap_sys_pacct,cap_sys_admin,cap_sys_boot,cap_sys_nice,cap_sys_resource,cap_sys_time,cap_sys_tty_config,cap_mknod,cap_lease,cap_audit_write,cap_audit_control,cap_setfcap,cap_mac_override,cap_mac_admin,cap_syslog,cap_wake_alarm,cap_block_suspend,37+ep
# Create an AppArmor profile that only grants file access
$ echo "profile demo-ns { file, }" | sudo apparmor_parser -qr
# Rerun the demo program under confinement
$ aa-exec -p demo-ns -- ./demo-ns
clone: Operation not permitted
$ sudo tail /var/log/audit/audit.log | grep DENIED
type=AVC msg=audit(1429741255.712:2723): apparmor="DENIED" operation="capable" profile="demo-ns" pid=12921 comm="demo-ns" capability=21 capname="sys_admin"
# Add a CAP_SYS_ADMIN and CAP_NET_BIND_SERVICE
$ echo "profile demo-ns { file, capability sys_admin, capability net_bind_service, }" | sudo apparmor_parser -qr
# Rerun it
$ aa-exec -p demo-ns -- ./demo-ns
eUID = 65534; eGID = 65534; capabilities: = cap_net_bind_service,cap_sys_admin+ep

Revision history for this message
Tyler Hicks (tyhicks) wrote :

After talking with other members of upstream AppArmor, there's nothing that exists today to trigger an AppArmor profile transition upon the call to clone(2). So, the best option would be if we could introduce a patch to call aa_change_profile(2) just before the call to clone(2). That would allow us to place the 'capability sys_admin,' AppArmor rule into the profile that is changed to.

Revision history for this message
Chris Coulson (chrisccoulson) wrote :

Calling aa_change_profile before the call to clone would change the profile for the browser process, wouldn't it?

Revision history for this message
Tyler Hicks (tyhicks) wrote :

It would cause the browser process to change profile just before it becomes the zygote process. That would allow for the creation of a zygote profile that allows 'capability sys_admin,'. The browser profile would not need 'capability sys_admin,', which Jamie previously stated was important.

Revision history for this message
Tyler Hicks (tyhicks) wrote :

Bah, just as I hit 'send' I understood what you were saying. The parent process would also change AA profiles and wouldn't be able to switch back to the original profile. I'll need to think about this some more.

Changed in oxide:
status: New → Triaged
importance: Undecided → High
Changed in oxide:
milestone: none → branch-1.9
Changed in oxide:
milestone: branch-1.9 → branch-1.11
Changed in oxide:
milestone: branch-1.11 → branch-1.12
Changed in oxide:
assignee: nobody → Chris Coulson (chrisccoulson)
Revision history for this message
Jamie Strandboge (jdstrand) wrote :

There have been reports that chromium-browser in Ubuntu now doesn't start under its apparmor profile because of:
apparmor="ALLOWED" operation="capable" profile="/usr/lib/chromium-browser/chromium-browser" pid=2129 comm="chromium-browse" capability=21 capname="sys_admin"

Chad Miller (cmiller)
Changed in chromium-browser (Ubuntu):
assignee: nobody → Chad Miller (cmiller)
Changed in oxide:
milestone: branch-1.12 → branch-1.13
Changed in oxide:
milestone: branch-1.13 → branch-1.15
Revision history for this message
Launchpad Janitor (janitor) wrote :

Status changed to 'Confirmed' because the bug affects multiple users.

Changed in chromium-browser (Ubuntu):
status: New → Confirmed
Revision history for this message
hda_launchpad (hda-me) wrote :

Anyway to fix this?
>apparmor="ALLOWED" operation="capable" profile="/usr/lib/chromium-browser/chromium-browser" pid=2129 comm="chromium-browse" capability=21 capname="sys_admin"

Changed in oxide:
milestone: branch-1.15 → branch-1.16
Changed in oxide:
milestone: branch-1.16 → branch-1.17
Changed in oxide:
milestone: branch-1.17 → branch-1.18
Revision history for this message
Craig (craig-st) wrote :

I can confirm that chromium-browser does not start, syslog shows:

apparmor="DENIED" operation="capable" profile="/usr/lib/chromium-browser/chromium-browser" pid=27954 comm="chromium-browse" capability=21 capname="sys_admin"

Apparmor profile enforce mode.
Trusty 14.04.5
chromium-browser 51.0.2704.79
apparmor-profiles 2.8.95-2430

Changed in oxide:
milestone: branch-1.18 → branch-1.19
Revision history for this message
Jean Christophe André (progfou) wrote :

Same here with Evince not being able to lauch the browser when you clic on a link inside a PDF:

apparmor="DENIED" operation="capable" profile="/usr/bin/evince//sanitized_helper" pid=16137 comm="chromium-browse" capability=21 capname="sys_admin"

Changed in oxide:
milestone: branch-1.19 → branch-1.20
Changed in oxide:
milestone: branch-1.20 → branch-1.21
Revision history for this message
Launchpad Janitor (janitor) wrote :

Status changed to 'Confirmed' because the bug affects multiple users.

Changed in evince (Ubuntu):
status: New → Confirmed
Changed in oxide:
milestone: branch-1.21 → branch-1.22
Changed in oxide:
milestone: branch-1.22 → branch-1.23
Olivier Tilloy (osomon)
Changed in chromium-browser (Ubuntu):
assignee: Chad Miller (cmiller) → nobody
To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Bug attachments

Remote bug watches

Bug watches keep track of this bug in other bug trackers.