Ich arbeite derzeit an einem Projekt, in dem ich einen übergeordneten Prozess habe, der ein Socketpair einrichtet, gabelt und dann dieses Socketpair zur Kommunikation verwendet. Das Kind sollte, wenn es eine Datei (oder eine andere auf Dateideskriptoren basierende Ressource) öffnen möchte, immer zum übergeordneten fd
Element gehen, die Ressource anfordern und die über das Socketpair gesendete Datei erhalten. Außerdem möchte ich verhindern, dass das Kind einen Dateideskriptor selbst öffnet.
Ich bin darüber gestolpert, setrlimit
was das Kind erfolgreich daran hindert, neue Dateideskriptoren zu öffnen, aber es scheint auch alle Dateideskriptoren ungültig zu machen, die über die anfängliche Socket-Verbindung gesendet wurden. Gibt es unter Linux eine Methode, mit der ein einzelner Prozess eine Datei öffnen, seinen Dateideskriptor an andere Prozesse senden und diese verwenden kann, ohne dass diese anderen Prozesse einen Dateideskriptor selbst öffnen können?
Für meinen Anwendungsfall kann dies eine beliebige Kernelkonfiguration, ein Systemaufruf usw. sein, solange sie nach dem Fork angewendet werden kann und solange sie für alle Dateideskriptoren gilt (nicht nur für Dateien, sondern auch für Sockets, Socketpairs usw.).
quelle
Antworten:
Was Sie hier haben, ist genau der Anwendungsfall von seccomp .
Mit seccomp können Sie Systemaufrufe auf verschiedene Arten filtern. Was Sie in dieser Situation tun mögen , ist, direkt nach
fork()
, eine installierenseccomp
Filter, der die Verwendung von nicht zulässtopen(2)
,openat(2)
,socket(2)
(und mehr). Um dies zu erreichen, können Sie Folgendes tun:seccomp_init(3)
mit dem Standardverhalten vonSCMP_ACT_ALLOW
.seccomp_rule_add(3)
Fügen Sie dann dem Kontext eine Regel hinzu, indem Sie für jeden Systemaufruf, den Sie ablehnen möchten, eine Regel verwenden . Sie könnenSCMP_ACT_KILL
den Vorgang beenden, wenn der Syscall versucht wirdSCMP_ACT_ERRNO(val)
, damit der Syscall den angegebenenerrno
Wert oder einen anderenaction
auf der Handbuchseite definierten Wert nicht zurückgibt.seccomp_load(3)
, um ihn effektiv zu machen.Bevor Sie fortfahren, beachten Sie, dass ein Blacklist-Ansatz wie dieser im Allgemeinen schwächer ist als ein Whitelist-Ansatz. Es erlaubt jeden Systemaufruf, der nicht explizit verboten ist, und kann zu einer Umgehung des Filters führen . Wenn Sie der Meinung sind, dass der untergeordnete Prozess, den Sie ausführen möchten, in böswilliger Absicht versucht, den Filter zu umgehen, oder wenn Sie bereits wissen, welche Systemaufrufe von den untergeordneten Prozessen benötigt werden, ist ein Whitelist-Ansatz besser, und Sie sollten das Gegenteil der oben genannten Schritte ausführen: Erstellen Sie einen Filter mit der Standardaktion
SCMP_ACT_KILL
und lassen Sie die erforderlichen Systemaufrufe mit zuSCMP_ACT_ALLOW
. In Bezug auf den Code ist der Unterschied minimal (die Whitelist ist wahrscheinlich länger, aber die Schritte sind gleich).Hier ist ein Beispiel für das oben Genannte (ich mache es
exit(-1)
im Fehlerfall nur der Einfachheit halber):Jetzt können Sie in Ihrem Programm die obige Funktion aufrufen, um den Seccomp-Filter direkt nach dem folgenden anzuwenden
fork()
:Einige wichtige Hinweise zu seccomp:
fork(2)
oderclone(2)
zulässt, werden alle untergeordneten Prozesse durch denselben Filter eingeschränkt.execve(2)
zulässig ist, bleibt der vorhandene Filter während eines Aufrufs von erhaltenexecve(2)
.prctl(2)
Systemaufruf zulässig ist, kann der Prozess weitere Filter anwenden.quelle
socket(2)
auch ein erstellen kannfd
, so dass auch das blockiert werden sollte. Wenn Sie den untergeordneten Prozess kennen, ist ein Whitelist-Ansatz besser.creat()
,dup()
, unddup2()
sind alle Linux - Systemaufrufe , dass return Dateideskriptoren. Es gibt viele Möglichkeiten, eine schwarze Liste zu umgehen ...