Warum Strace in Docker nicht funktioniert

Als ich die Seite mit den Containerfunktionen für das Magazin How Containers Work bearbeitete , musste ich erklären, warum Docker nicht funktioniert strace. Folgendes ist passiert, als straceich in einem Docker-Container auf meinem Laptop ausgeführt wurde:



$ docker run  -it ubuntu:18.04 /bin/bash
$ # ... install strace ...
root@e27f594da870:/# strace ls
strace: ptrace(PTRACE_TRACEME, ...): Operation not permitted


stracefunktioniert über einen Systemaufruf ptrace, daher ptracefunktioniert es nicht ohne Erlaubnis ! Aber es ist einfach zu reparieren und auf meinem Laptop habe ich es so gemacht:



docker run --cap-add=SYS_PTRACE  -it ubuntu:18.04 /bin/bash


Aber ich war nicht daran interessiert, das Problem zu lösen, sondern herauszufinden, warum diese Situation überhaupt auftritt. Warum funktioniert es stracenicht und --cap-add=SYS_PTRACErepariert alles?



Hypothese 1: Containerprozesse haben kein eigenes Privileg CAP_SYS_PTRACE



Da das Problem konsequent gelöst wird --cap-add=SYS_PTRACE, schien es mir immer, dass Docker-Container-Prozesse per Definition keine eigenen Berechtigungen haben CAP_SYS_PTRACE, aber aus zwei Gründen passt hier etwas nicht zusammen.



Grund 1: Als Experiment, das als normaler Benutzer angemeldet war, konnte ich problemlos straceeinen beliebigen Prozess starten. Bei der Überprüfung, ob mein aktueller Prozess über Berechtigungen verfügt, wurde CAP_SYS_PTRACEjedoch nichts gefunden:



$ getpcaps $$
Capabilities for `11589': =


Grund 2: in man capabilitiesdem Privileg CAP_SYS_PTRACElautet wie folgt:



CAP_SYS_PTRACE
       * Trace arbitrary processes using ptrace(2);


Der springende Punkt CAP_SYS_PTRACEist, dass wir in Analogie zu root die Kontrolle über den beliebigen Prozess eines jeden Benutzers übernehmen können. Für ptraceIhren Benutzer erfordert dieses Privileg keinen herkömmlichen Prozess.



Außerdem habe ich noch eine Überprüfung durchgeführt: Ich habe den Docker-Container durch gestartet docker run --cap-add=SYS_PTRACE -it ubuntu:18.04 /bin/bash, dann die Berechtigung widerrufen CAP_SYS_PTRACE- und straceauch ohne diese Berechtigung weiterhin ordnungsgemäß funktioniert. Warum?!



Hypothese 2: Fall im Benutzernamensraum?



Meine nächste (und viel schlimmere) Hypothese klang wie "hmm, vielleicht befindet sich der Prozess in einem anderen Benutzernamensraum und stracefunktioniert nicht ... nur weil?" Es sieht aus wie eine Reihe nicht sehr kohärenter Aussagen, aber ich habe trotzdem versucht, das Problem von dieser Seite aus zu betrachten.



Befindet sich der Prozess in einem anderen benutzerdefinierten Namespace? So sieht es im Container aus:



root@e27f594da870:/# ls /proc/$$/ns/user -l
... /proc/1/ns/user -> 'user:[4026531837]'


Und so sieht es auf dem Host aus:



bork@kiwi:~$ ls /proc/$$/ns/user -l
... /proc/12177/ns/user -> 'user:[4026531837]'


root im Container ist derselbe Benutzer wie root auf dem Host, da sie eine gemeinsame ID im Benutzernamensraum (4026531837) haben, sodass es von dieser Seite keine störenden straceGründe geben sollte . Wie Sie sehen, stellte sich die Hypothese als mittelmäßig heraus, aber dann wurde mir noch nicht klar, dass die Benutzer im Container und auf dem Host gleich sind, und dieser Ansatz schien mir interessant.



Hypothese 3: Der Systemaufruf wird ptracedurch eine Regel blockiertseccomp-bpf



Ich wusste bereits, dass es in Docker eine Regel gibt, die eine große Anzahl von Systemaufrufen einschränkt, die von Containerprozessoren in Docker ausgeführt werden sollen seccomp-bpf, und es stellte sich heraus, dass und in der Liste der Aufrufe per Definition blockiert sind ptrace! (Tatsächlich ist die Anrufliste ein Ausnahmeblatt und wird ptraceeinfach nicht aufgerufen , aber das Ergebnis ändert sich nicht.)



Jetzt ist klar, warum der Container im Docker nicht funktioniert strace, da es offensichtlich ptracenicht funktioniert, einen vollständig blockierten aufzurufen.



Lassen Sie uns diese Hypothese testen und sehen, ob wir den straceContainer im Docker verwenden können, wenn wir alle Seccomp-Regeln deaktivieren:



$ 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 ...


Fein! Alles funktioniert und das Geheimnis wird gelüftet! Das ist einfach ...



Warum --cap-add=SYS_PTRACElöst es das Problem?



Wir haben immer noch nicht erklärt, warum es --cap-add=SYS_PTRACEdas aufkommende Herausforderungsproblem löst. Auf der Hauptseite wird docker rundie Funktionsweise des Arguments wie folgt erläutert --cap-add:



--cap-add=[]
   Add Linux capabilities


All dies hat nichts mit den Regeln von seccomp zu tun! Was ist los?



Werfen wir einen Blick auf den Docker-Quellcode.



Wenn die Dokumentation nicht hilft, müssen wir nur in die Quellen eintauchen.

Go hat eine nette Funktion: Dank des Abhängigkeitsverkaufs im Go-Repository können Sie grepdurch das gesamte Repository gehen und den Code finden, an dem Sie interessiert sind. Also habe ich ihn github.com/moby/mobygeklont und nach solchen Ausdrücken abgesucht rg CAP_SYS_PTRACE.



Meiner Meinung nach passiert Folgendes: Bei der Implementierung von seccomp im Container gibt es im Abschnitt contrib / seccomp / seccomp_default.go viel Code, der anhand der seccomp-Regel prüft, ob der Prozess mit Berechtigungen die Berechtigung hat, Systemaufrufe gemäß diesem Privileg zu verwenden.



		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{},
			})




Es gibt immer noch Code in moby, der für Profile / seccomp / seccomp.go und für Seccomp-Profile per Definition ähnliche Operationen ausführt, also haben wir wahrscheinlich unsere Antwort gefunden!



Docker --cap-addkann mehr als gesagt



Am Ende scheint es, dass --cap-addes nicht genau das tut, was es auf der Hauptseite sagt, und eher so aussehen sollte --cap-add-and-also-whitelist-some-extra-system-calls-if-required. Und es scheint wahr zu sein: Wenn Sie das Privileg des Geistes haben CAP_SYS_PTRACE, das es Ihnen ermöglicht, einen Systemaufruf zu verwenden process_vm_readv, der Anruf jedoch blockiert ist, ist Seccomp-Profil keine große Hilfe, so dass die Berechtigung zur Verwendung der Systemaufrufe process_vm_readvund ptracedurch CAP_SYS_PTRACEvernünftig aussieht.



Es stellt sich heraus, dass es stracein den neuesten Versionen von Docker funktioniert



Für Kernel-Versionen 4.8 und höher erlaubte Docker 19.03 dank dieses Commits endlich Systemaufrufe ptrace. Das ist nur auf meinem Docker-Laptop, es gibt noch Version 18.09.7, und dieses Commit fehlt offensichtlich.



Das ist alles!



Es stellte sich als interessant heraus, sich mit diesem Problem zu befassen, und ich denke, dies ist ein gutes Beispiel für eine nicht trivial interagierende, sich bewegende „Befüllung“ von Behältern.



Wenn Ihnen dieser Beitrag gefallen hat, könnte Ihnen auch mein Magazin How Containers Work gefallen , in dem die 24-seitigen Containerhandhabungsfunktionen des Linux-Kernels erläutert werden. Dort können Sie auch Berechtigungen und seccomp-bpf sehen .



All Articles