strace
. Inilah yang terjadi ketika berjalan strace
di wadah Docker di laptop saya:
$ docker run -it ubuntu:18.04 /bin/bash
$ # ... install strace ...
root@e27f594da870:/# strace ls
strace: ptrace(PTRACE_TRACEME, ...): Operation not permitted
strace
berfungsi melalui panggilan sistem ptrace
, sehingga ptrace
tidak akan berfungsi tanpa izin ! Tapi itu mudah diperbaiki, dan di laptop saya melakukannya seperti ini:
docker run --cap-add=SYS_PTRACE -it ubuntu:18.04 /bin/bash
Tetapi menarik bagi saya untuk tidak menyelesaikan masalah, tetapi untuk mencari tahu mengapa situasi ini umumnya muncul. Jadi mengapa tidak
strace
berhasil, tetapi --cap-add=SYS_PTRACE
memperbaiki semuanya?
Hipotesis 1: Proses wadah tidak memiliki hak istimewa mereka sendiri CAP_SYS_PTRACE
Karena masalah ini diselesaikan secara konsisten
--cap-add=SYS_PTRACE
, bagi saya selalu tampak bahwa proses kontainer Docker, menurut definisi, tidak memiliki hak istimewa sendiri CAP_SYS_PTRACE
, tetapi karena dua alasan ada sesuatu yang tidak ditambahkan di sini.
Alasan 1: Sebagai percobaan, saya, yang masuk sebagai pengguna biasa, dapat dengan mudah memulai
strace
proses apa pun, namun, saya CAP_SYS_PTRACE
tidak menemukan apa pun dalam keistimewaan proses saya saat ini :
$ getpcaps $$
Capabilities for `11589': =
Alasan 2: dalam
man capabilities
hak istimewa CAP_SYS_PTRACE
berbunyi sebagai berikut:
CAP_SYS_PTRACE
* Trace arbitrary processes using ptrace(2);
Intinya
CAP_SYS_PTRACE
adalah bahwa, dengan analogi dengan root, kita dapat mengendalikan proses sembarang pengguna. Untuk ptrace
pengguna Anda, hak istimewa ini tidak memerlukan proses konvensional.
Selain itu, saya melakukan satu pemeriksaan lagi: Saya meluncurkan wadah Docker melalui
docker run --cap-add=SYS_PTRACE -it ubuntu:18.04 /bin/bash
, kemudian mencabut hak istimewa CAP_SYS_PTRACE
- dan strace
terus bekerja dengan benar bahkan tanpa hak istimewa. Mengapa?!
Hipotesis 2: Apakah ini namespace khusus?
Hipotesis saya berikutnya (dan jauh lebih tidak beralasan) terdengar seperti "hmm, mungkin prosesnya dalam ruang nama pengguna yang berbeda dan
strace
tidak berfungsi ... hanya karena?" Sepertinya seperangkat pernyataan yang tidak terlalu koheren, tapi saya masih mencoba melihat masalah dari sudut pandang ini.
Jadi, apakah proses dalam ruang nama yang ditentukan pengguna berbeda? Ini adalah tampilannya di wadah:
root@e27f594da870:/# ls /proc/$$/ns/user -l
... /proc/1/ns/user -> 'user:[4026531837]'
Dan begini tampilannya pada host:
bork@kiwi:~$ ls /proc/$$/ns/user -l
... /proc/12177/ns/user -> 'user:[4026531837]'
root dalam wadah adalah pengguna yang sama dengan root pada host, karena mereka memiliki pengidentifikasi usernamespace yang umum (4026531837), jadi seharusnya tidak ada
strace
alasan yang mengganggu di sisi itu . Seperti yang Anda lihat, hipotesisnya ternyata begitu-begitu, tetapi kemudian saya belum menyadari bahwa pengguna dalam wadah dan pada host adalah sama, dan pendekatan ini tampak menarik bagi saya.
Hipotesis 3: Panggilan sistem ptrace
diblokir oleh suatu aturanseccomp-bpf
Saya sudah tahu bahwa ada aturan di Docker untuk membatasi sejumlah besar panggilan sistem untuk dijalankan oleh pemroses kontainer di Docker
seccomp-bpf
, dan ternyata ada dan dalam daftar panggilannya diblokir menurut definisi ptrace
! (Faktanya, daftar doa adalah daftar pengecualian dan ptrace
tidak masuk ke dalamnya, tetapi hasilnya tidak berubah.)
Sekarang jelas mengapa itu tidak bekerja dalam wadah Docker
strace
, karena jelas bahwa ptrace
panggilan yang diblokir sepenuhnya tidak akan berfungsi.
Mari kita uji hipotesis ini dan lihat apakah kita dapat menggunakan
strace
wadah Docker jika kita menonaktifkan semua aturan seccomp:
$ 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 ...
Baik! Semuanya berfungsi, dan rahasianya terungkap! Itu hanya ...
Mengapa --cap-add=SYS_PTRACE
itu memecahkan masalah?
Kami masih belum menjelaskan mengapa ini
--cap-add=SYS_PTRACE
memecahkan masalah tantangan yang muncul. Halaman utama docker run
menjelaskan cara kerja argumen sebagai berikut --cap-add
:
--cap-add=[]
Add Linux capabilities
Semua ini tidak ada hubungannya dengan aturan seccomp! Apa masalahnya?
Mari kita lihat kode sumber Docker.
Jika dokumentasi tidak membantu, yang harus kita lakukan adalah menyelami sumbernya.
Satu hal yang menyenangkan tentang Go adalah dengan membatalkan dependensi dalam repositori Go, Anda
grep
dapat menelusuri seluruh repositori dan menemukan kode yang Anda minati. Jadi saya github.com/moby/moby
mengkloning dan menjelajahinya untuk ekspresi semacam itu rg CAP_SYS_PTRACE
.
Menurut pendapat saya, inilah yang terjadi: dalam pelaksanaan seccomp di dalam wadah, di bagian contrib / seccomp / seccomp_default.go ada banyak kode yang, melalui aturan seccomp, memeriksa apakah proses dengan hak istimewa memiliki izin untuk menggunakan panggilan sistem sesuai dengan hak istimewa ini.
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{},
})
Ada juga kode di sana, yang di moby dan untuk profil / seccomp / seccomp.go , dan untuk seccomp profil, menurut definisi, melakukan operasi yang sama, jadi kami mungkin menemukan jawaban kami!
Docker --cap-add
mampu melakukan lebih dari apa yang dikatakan
Pada akhirnya, tampaknya
--cap-add
tidak persis seperti yang dikatakan di halaman utama, dan lebih baik terlihat seperti --cap-add-and-also-whitelist-some-extra-system-calls-if-required
. Dan tampaknya benar: jika Anda memiliki hak istimewa roh CAP_SYS_PTRACE
, yang memungkinkan Anda untuk menggunakan panggilan sistem process_vm_readv
, tetapi panggilan tersebut diblokir profil Seccomp, Anda tidak banyak membantu, sehingga otorisasi untuk menggunakan panggilan sistem process_vm_readv
dan ptrace
melalui CAP_SYS_PTRACE
terlihat masuk akal.
Ternyata strace
berfungsi di versi terbaru Docker
Untuk versi kernel 4.8 dan lebih tinggi, berkat komit ini , Docker 19.03 akhirnya mengizinkan panggilan sistem
ptrace
. Kecuali, di laptop saya, Docker masih versi 18.09.7 dan komit ini jelas hilang.
Itu saja!
Ternyata menarik untuk menangani masalah ini, dan saya pikir ini adalah contoh yang baik dari interaksi "pengisian" kontainer secara nontrivial.
Jika Anda menyukai posting ini, Anda mungkin juga menyukai majalah saya How Containers Work , yang menjelaskan fitur penanganan kontainer 24-halaman kernel Linux. Anda juga dapat melihat hak istimewa dan seccomp-bpf di sana .