لماذا لا تعمل Strace في Docker

عندما كنت أقوم بتحرير صفحة إمكانات الحاوية لمجلة How Containers Work ، كنت بحاجة إلى شرح سبب عدم عمل Docker 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 هناك .



All Articles