strace
。これstrace
は私のラップトップのDockerコンテナーで実行したときに何が起こったかです:
$ docker run -it ubuntu:18.04 /bin/bash
$ # ... install strace ...
root@e27f594da870:/# strace ls
strace: ptrace(PTRACE_TRACEME, ...): Operation not permitted
strace
システムコールを介して機能するptrace
ため、許可なく機能しptrace
ません。しかし、修正は簡単で、私のラップトップでは次のようにしました。
docker run --cap-add=SYS_PTRACE -it ubuntu:18.04 /bin/bash
しかし、問題を解決するのではなく、なぜこの状況が一般的に発生するのかを理解することは私にとって興味深いことでした。では、なぜそれが機能せ
strace
ず、--cap-add=SYS_PTRACE
すべてを修正しないのですか?
仮説1:コンテナープロセスには独自の特権がない CAP_SYS_PTRACE
問題はを通じて一貫して解決されているため、
--cap-add=SYS_PTRACE
Dockerコンテナープロセスには本来、独自の特権がないように見えますCAP_SYS_PTRACE
が、2つの理由により、ここでは何かが追加されません。
理由1:実験として、通常のユーザーとしてログインしている
strace
ため、任意のプロセスを簡単に起動できましたが、現在のプロセスに特権があるかどうかを確認してCAP_SYS_PTRACE
も何も見つかりませんでした。
$ getpcaps $$
Capabilities for `11589': =
理由2:に
man capabilities
特権CAP_SYS_PTRACE
次のように読み取ります。
CAP_SYS_PTRACE
* Trace arbitrary processes using ptrace(2);
要点
CAP_SYS_PTRACE
は、rootと同様に、ユーザーの任意のプロセスを制御できるということです。以下のためにptrace
、ユーザーの通常のプロセス、この権限は必要ありません。
また、私は1つの以上のチェックを行わ:私はを通じてドッカーコンテナを開始しました
docker run --cap-add=SYS_PTRACE -it ubuntu:18.04 /bin/bash
権限を取り消した後、CAP_SYS_PTRACE
-とstrace
さえ特権なしで正常に動作し続けました。なぜ?!
仮説2:カスタム名前空間ですか?
私の次の(そして十分に根拠のない)仮説は、「うーん、おそらくプロセスは別のユーザー名前空間にあり、
strace
機能しない...という理由で?」それはあまり一貫性のない一連のステートメントのように見えますが、私はまだ問題をこちら側から見てみました。
それで、プロセスは別のカスタム名前空間にありますか?これはコンテナ内でどのように見えるかです:
root@e27f594da870:/# ls /proc/$$/ns/user -l
... /proc/1/ns/user -> 'user:[4026531837]'
そして、これはホスト上での外観です。
bork@kiwi:~$ ls /proc/$$/ns/user -l
... /proc/12177/ns/user -> 'user:[4026531837]'
コンテナー内のルートは、ホストのルートと同じユーザーです。これは、共通のユーザー名空間識別子(4026531837)を持っているため、その側で干渉する
strace
理由があるはずがないためです。ご覧のとおり、仮説はまあまあであることが判明しましたが、コンテナー内のユーザーとホスト上のユーザーが同じであることにまだ気づいておらず、このアプローチは興味深いものに思えました。
仮説3:システムコールがptrace
ルールによってブロックされているseccomp-bpf
Dockerには、コンテナプロセッサによる多数のシステムコールの起動を制限するルールがあることはすでに知っていました。また
seccomp-bpf
、定義によってブロックされているコールのリストに、そのルールがあることがわかりましたptrace
。(実際、呼び出しリストは例外シートであり、ptrace
単に
その中に含まれませんが、結果は変わりません。)これで、
strace
完全にブロックされたptrace
ものを呼び出すことが機能しないことが明らかであるため、Docker でコンテナーが機能しない理由が明らかになりました。
この仮説をテストして、
strace
すべてのseccompルールを無効にした場合にDockerコンテナーを使用できるかどうかを確認してみましょう。
$ docker run --security-opt seccomp=unconfined -it ubuntu:18.04 /bin/bash
$ strace ls
execve("/bin/ls", ["ls"], 0x7ffc69a65580 /* 8 vars */) = 0
... it works fine ...
いいね!すべてが機能し、その秘密が明らかになります!それだけです...
なぜ--cap-add=SYS_PTRACE
問題が解決するのですか?
なぜそれ
--cap-add=SYS_PTRACE
が通話で発生する問題を解決するのかについてはまだ説明していません。メインページでdocker run
は、引数が次のように機能する方法が説明されています--cap-add
。
--cap-add=[]
Add Linux capabilities
これは、seccompルールとは何の関係もありません!どうしたの?
Dockerのソースコードを見てみましょう。
ドキュメントがまだ役に立たない場合は、ソースに突入するだけで残ります。
Goには1つの優れた機能があります。Goリポジトリでの依存関係の自動販売のおかげで、リポジトリ
grep
全体を調べて、興味のあるコードを見つけることができます。それで、私はそれをgithub.com/moby/moby
複製して、フォームの表現を探すためにスキャンしましたrg CAP_SYS_PTRACE
。
私の意見では、これはここで起こることです:コンテナー内のseccompの実装のcontrib / seccomp / seccomp_default.goセクションには、seccompルールを通じて、特権を持つプロセスがこの特権に従ってシステムコールを使用する権限を持っているかどうかをチェックする多くのコードがあります。
case "CAP_SYS_PTRACE":
s.Syscalls = append(s.Syscalls, specs.LinuxSyscall{
Names: []string{
"kcmp",
"process_vm_readv",
"process_vm_writev",
"ptrace",
},
Action: specs.ActAllow,
Args: []specs.LinuxSeccompArg{},
})
mobyにはまだコードがあり、profiles / seccomp / seccomp.goとseccompプロファイルでは、定義により、同様の操作を実行するため、おそらく答えが見つかりました!
Docker --cap-add
は言われている以上の能力があります
結局のところ、それ
--cap-add
はメインページに表示されているとおりではなく、のように見えるはず--cap-add-and-also-whitelist-some-extra-system-calls-if-required
です。そして、本当のようです:あなたは精神の権限がある場合CAP_SYS_PTRACE
は、システムコールを使用することができます、process_vm_readv
しかし、コールがSeccompプロファイルをブロックされているが、あなたは認証がシステムコールを使用するようにすることを、多くの助けではないprocess_vm_readv
とptrace
を通じてCAP_SYS_PTRACE
合理的なルックス。
strace
Dockerの最新バージョンで動作することが判明
カーネルバージョン4.8以降では、このコミットのおかげで、Docker 19.03はついにシステムコールを許可しました
ptrace
。それはちょうど私のDockerラップトップでまだバージョン18.09.7があり、このコミットが明らかに欠落しています。
それで全部です!
この問題に対処することは興味深いことがわかりました。これは、コンテナーの移動する「充填」の重要な相互作用の良い例だと思います。
この投稿が気に入った場合は、私の雑誌How Containers Workも気に入っていただけると思います。これは、Linuxカーネルの24ページのコンテナー処理機能について説明しています。そこには、特権とseccomp-bpfが表示されます。