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
، ولكن لسببين ، لا يوجد شيء هنا.
السبب الأول: كتجربة ، عند تسجيل الدخول كمستخدم عادي ، يمكنني التشغيل بسهولة
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
هي أننا ، عن طريق القياس مع الجذر ، يمكننا السيطرة على عملية تعسفية لأي مستخدم. بالنسبة إلى ptrace
المستخدم ، لا يحتاج هذا الامتياز إلى عملية تقليدية.
بالإضافة إلى ذلك ، أجريت فحصًا آخر: لقد أطلقت حاوية Docker من خلال
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
وببساطة لا تدخل فيها ، لكن النتيجة لا تتغير.)
الآن من الواضح لماذا لا تعمل الحاوية في حاوية Docker
strace
، لأنه من الواضح أن ptrace
المكالمة المحظورة تمامًا لن تعمل.
دعونا نختبر هذه الفرضية ونرى ما إذا كان بإمكاننا استخدام
strace
حاوية Docker إذا قمنا بتعطيل جميع قواعد 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 ...
غرامة! كل شيء يعمل ويكشف السر! هذا فقط ...
لماذا --cap-add=SYS_PTRACE
تحل المشكلة؟
ما زلنا لم نوضح سبب
--cap-add=SYS_PTRACE
حل المشكلة الناشئة مع المكالمات. docker run
تشرح الصفحة الرئيسية عمل الحجة على النحو التالي --cap-add
:
--cap-add=[]
Add Linux capabilities
لا شيء من هذا له علاقة بقواعد seccomp! ما المشكلة؟
دعونا نلقي نظرة على شفرة المصدر لـ Docker.
إذا لم تساعد الوثائق بالفعل ، فكل ما تبقى لنا هو الانغماس في المصدر.
شيء واحد لطيف في Go هو أنه من خلال بيع التبعيات في مستودع 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 وللمحات / seccomp / seccomp.go ، وللحساب seccomp ، بحكم التعريف ، يؤدي عمليات مماثلة ، لذلك ربما وجدنا إجابتنا!
--cap-add
يمكن أن يفعل Docker أكثر مما قال
في النهاية ، يبدو
--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
بالنسبة لإصدارات kernel 4.8 والإصدارات الأحدث ، وبفضل هذا الالتزام ، سمح Docker 19.03 أخيرًا باستدعاءات النظام
ptrace
. هذا فقط على جهاز الكمبيوتر المحمول Docker لا يزال هناك إصدار 18.09.7 ، ومن الواضح أن هذا الالتزام مفقود.
هذا كل شئ!
وتبين أنه من المثير للاهتمام التعامل مع هذه المشكلة ، وأعتقد أن هذا مثال جيد على "تعبئة" الحاويات غير المتفاعلة بشكل بسيط.
إذا أعجبك هذا المنشور ، فقد تعجبك أيضًا مجلتي كيف تعمل الحاويات ، والتي تشرح ميزات معالجة الحاويات المكونة من 24 صفحة في Linux kernel. يمكنك أيضًا مشاهدة الامتيازات و seccomp-bpf هناك .