seccompプロファイルを使ってdockerのシステムコールを制御

Dockerコンテナでアプリケーションのプロセスをdebugするためにstraceをすると
Operation not permittedで怒られた。

1
2
strace -f -p 1
strace: attach: ptrace(PTRACE_ATTACH, ...): Operation not permitted

エラー内容から調べてみると、どうやらセキュリティ的にコンテナ内のシステムコールへのアクセスが制限されていると思われる。
dockerのリポジトリのdocumentを見るとSeccomp security profiles for Dockerという項目がある。
どうやらこのPR(#17989)で追加されてるようだ。

seccompを設定しているprofileがあるようで、これを変更することでシステムコールを制御できるようす。

seccomp

そもそもseccomp(secure computing mode)はプロセスのexit, sigreturn, read, writeを行うシステムコールを制御する。
また、seccomp-bpf(seccomp mode filter)は、システムコールのフィルタにBPFを実装しており、
システムコールの番号と引数をフィルタリングすることでより柔軟に扱うことができる。

というもの。

docker seccomp profile

dockerではseccompの設定はこのようなdefault.jsonで定義されている。
適当なシステムコールプロファイルをjsonで作成し、–security-optオプションで実行してみる。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
docker version
Client:
Version: 1.11.0
API version: 1.23
Go version: go1.5.4
Git commit: 4dc5990
Built: Wed Apr 13 18:13:28 2016
OS/Arch: darwin/amd64

Server:
Version: 1.11.0
API version: 1.23
Go version: go1.5.4
Git commit: 4dc5990
Built: Wed Apr 13 19:36:04 2016
OS/Arch: linux/amd64

cat seccomp.json | jq .
{
"defaultAction": "SCMP_ACT_ALLOW",
"syscalls": [
{
"name": "mkdir",
"action": "SCMP_ACT_ERRNO",
"args": []
}
]
}

docker run -it --security-opt seccomp:seccomp.json alpine sh
/ # mkdir -p tmp/test
mkdir: can't create directory 'tmp/': Operation not permitted
/ # apk update
fetch http://dl-cdn.alpinelinux.org/alpine/v3.4/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.4/community/x86_64/APKINDEX.tar.gz
v3.4.0-84-g5967d51 [http://dl-cdn.alpinelinux.org/alpine/v3.4/main]
v3.4.0-75-g8d1dc52 [http://dl-cdn.alpinelinux.org/alpine/v3.4/community]
OK: 5958 distinct packages available
/ # apk add strace
(1/1) Installing strace (4.11-r2)
Executing busybox-1.24.2-r9.trigger
OK: 6 MiB in 12 packages
/ # ls
bin dev etc home lib linuxrc media mnt proc root run sbin srv sys tmp usr var
/ # strace ls home
execve("/bin/ls", ["ls", "home"], [/* 6 vars */]) = 0
arch_prctl(ARCH_SET_FS, 0x7f2a390e3c28) = 0
set_tid_address(0x7f2a390e3c60) = 14
mprotect(0x7f2a390e0000, 4096, PROT_READ) = 0
mprotect(0x55ab364b6000, 16384, PROT_READ) = 0
getuid() = 0
ioctl(0, TIOCGWINSZ, {ws_row=45, ws_col=181, ws_xpixel=0, ws_ypixel=0}) = 0
ioctl(1, TIOCGWINSZ, {ws_row=45, ws_col=181, ws_xpixel=0, ws_ypixel=0}) = 0
ioctl(1, TIOCGWINSZ, {ws_row=45, ws_col=181, ws_xpixel=0, ws_ypixel=0}) = 0
stat("home", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
open("home", O_RDONLY|O_DIRECTORY|O_CLOEXEC) = 3
fcntl(3, F_SETFD, FD_CLOEXEC) = 0
getdents64(3, /* 2 entries */, 2048) = 48
getdents64(3, /* 0 entries */, 2048) = 0
close(3) = 0
exit_group(0) = ?
+++ exited with 0 +++

SCMP_ACT_ALLOW は許可。SCMP_ACT_ERRNOは拒否となるので、
SCMP_ACT_ALLOW でフィルターに一致しない場合は許可。
mkdirを呼び出すとSCMP_ACT_ERRNOでエラーが返る。

mkdir以外は許可されているのでstraceも問題ない。

また、デフォルトのseccomp profileなしで使うなら–security-optオプションにunconfinedを渡してあげると良い。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
docker run -it --security-opt seccomp=unconfined alpine sh
/ # apk update
fetch http://dl-cdn.alpinelinux.org/alpine/v3.4/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.4/community/x86_64/APKINDEX.tar.gz
v3.4.0-84-g5967d51 [http://dl-cdn.alpinelinux.org/alpine/v3.4/main]
v3.4.0-75-g8d1dc52 [http://dl-cdn.alpinelinux.org/alpine/v3.4/community]
OK: 5958 distinct packages available
/ # apk add strace
(1/1) Installing strace (4.11-r2)
Executing busybox-1.24.2-r9.trigger
OK: 6 MiB in 12 packages
/ # ls
bin dev etc home lib linuxrc media mnt proc root run sbin srv sys tmp usr var
/ # strace ls home
execve("/bin/ls", ["ls", "home"], [/* 6 vars */]) = 0
arch_prctl(ARCH_SET_FS, 0x7feb31d3ec28) = 0
set_tid_address(0x7feb31d3ec60) = 14
mprotect(0x7feb31d3b000, 4096, PROT_READ) = 0
mprotect(0x559a8af6c000, 16384, PROT_READ) = 0
getuid() = 0
ioctl(0, TIOCGWINSZ, {ws_row=45, ws_col=181, ws_xpixel=0, ws_ypixel=0}) = 0
ioctl(1, TIOCGWINSZ, {ws_row=45, ws_col=181, ws_xpixel=0, ws_ypixel=0}) = 0
ioctl(1, TIOCGWINSZ, {ws_row=45, ws_col=181, ws_xpixel=0, ws_ypixel=0}) = 0
stat("home", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
open("home", O_RDONLY|O_DIRECTORY|O_CLOEXEC) = 3
fcntl(3, F_SETFD, FD_CLOEXEC) = 0
getdents64(3, /* 2 entries */, 2048) = 48
getdents64(3, /* 0 entries */, 2048) = 0
close(3) = 0
exit_group(0) = ?
+++ exited with 0 +++

ちなみに v1.11だとLinux kernel が 4.3の場合、–pids-limitオプションでリソース制限もできるようになってるみたい。

参考にしたページ

Seccomp security profiles for Docker
DOCKER ENGINE 1.10 SECURITY IMPROVEMENTS
Phase 1: Initial seccomp support

Comments