Provided by: manpages-de_4.21.0-2_all 

BEZEICHNUNG
user_namespaces - Überblick über Benutzernamensräume in Linux
BESCHREIBUNG
Für einen Überblick über Namensräume, siehe namespaces(7).
Benutzernamensräume isolieren sicherheitsrelevante Kennzeichner und Attribute, insbesondere Benutzer- und
Gruppenkennungen (siehe credentials(7)), das Wurzelverzeichnis, Schlüssel (siehe keyrings(7)) und
Capabilitys (siehe capabilities(7)). Die Benutzer- und Gruppenkennung eines Prozesses kann innerhalb und
außerhalb eines Benutzernamensraums verschieden sein. Insbesondere kann ein Prozess eine normale, nicht
privilegierte Benutzerkennung außerhalb eines Benutzernamensraums haben, während er gleichzeitig eine
Benutzerkennung 0 innerhalb des Namensraums hat; mit anderen Worten, der Prozess hat volle Privilegien
für Aktionen innerhalb des Benutzernamensraums, ist aber für Aktionen außerhalb des Namensraums nicht
privilegiert.
Verschachtelte Namensräume, Namensraum-Mitgliedschaft
Benutzernamensräume können verschachtelt werden, das bedeutet, dass jeder Benutzernamensraum–außer dem
anfänglichen (»Wurzel-«)Namensraum–über einen Vorgängernamensraum verfügt und keinen oder mehrere
Nachfolgernamensräume haben kann. Der Vorgängernamensraum ist der Benutzernamensraum des Prozesses, der
den Benutzernamensraum mittels eines Aufrufs von unshare(2) oder clone(2) mit dem Schalter CLONE_NEWUSER
erstellte.
(Seit Linux 3.11) erzwingt der Kernel eine Begrenzung von 32 verschachtelten Stufen an
Benutzernamensräumen. Aufrufe an unshare(2) oder clone(2), die zum Überschreiten dieser Begrenzung führen
würden, schlagen mit dem Fehler EUSERS fehl.
Jeder Prozess ist Mitglied in genau einem Benutzernamensraum. Ein mit fork(2) oder clone(2) ohne den
Schalter CLONE_NEWUSER erstellter Prozess ist ein Mitglied im gleichen Benutzernamensraum wie sein
Elternprozess. Ein Prozess mit nur einem Thread kann einem anderen Benutzernamensraum mit setns(2)
beitreten, falls er über CAP_SYS_ADMIN in diesem Namensraum verfügt; wenn er dies durchführt, erlangt er
den vollständigen Satz an Capabilitys in diesem Namensraum.
Ein Aufruf von clone(2) oder unshare(2) mit dem Schalter CLONE_NEWUSER führt dazu, dass der Kindprozess
(für clone(2)) oder der Aufrufende (für unshare(2)) ein Mitglied des neuen, durch den Aufruf erstellten
Benutzernamensraums wird.
Die Aktion NS_GET_PARENT ioctl(2) kann zum Erkennen der Vorgänger-/Nachfolger-Beziehung von
Benutzernamensräumen verwandt werden; siehe ioctl_ns(2).
Capabilitys
Der durch clone(2) mit dem Schalter CLONE_NEWUSER erstellte Kindprozess beginnt mit einem vollständigen
Satz an Capabilitys in dem neuen Benutzernamensraum. Entsprechend erlangt ein Prozess, der einen neuen
Benutzernamensraum mittels unshare(2) erstellt oder ihm mittels setns(2) beitritt, einen vollständigen
Satz an Capabilitys in diesem Namensraum. Anderserseits hat dieser Prozess keine Capabilitys in dem
Vorgänger- (im Falle von clone(2)) oder vorhergehenden (im Falle von unshare(2) und setns(2))
Benutzernamensraum, selbst falls der neue Namensraum vom Benutzer root erstellt wird oder dieser ihm
beitritt (d.h. einem Prozess mit der Benutzerkennung 0 im Wurzel-Namensraum).
Beachten Sie, dass ein Aufruf von execve(2) dazu führt, dass die Capabilitys eines Prozesses auf die
normale Art und Weise erneut berechnet werden (siehe capabilities(7)). Folglich wird der Prozess alle
Capabilitys verlieren, außer er hat eine Benutzerkennung von 0 innerhalb des Namensraums oder die
ausführbare Datei hat eine vererbbare Capability-Maske, die nicht leer ist. Siehe die nachfolgende
Diskussion von Benutzer- und Gruppenkennungabbildung.
Ein Aufruf von clone(2) oder unshare(2) mit dem Schalter CLONE_NEWUSER oder ein Aufruf von setns(2), der
den Aufrufenden in einen anderen Benutzernamensraum verschiebt, setzt die Schalter »securebits« (siehe
capabilities(7)) im Kind (für clone(2)) oder dem Aufrufenden (für unshare(2) oder setns(2)) auf ihre
Vorgabewerte (alle Schalter deaktiviert). Beachten Sie, dass der Aufrufende nach einem Aufruf von
setns(2) keine Capabilitys in seinem ursprünglichen Benutzernamensraum mehr hat und es daher für einen
Prozess nicht möglich ist, seine Schalter »securebits« zurückzusetzen und gleichzeitig seine
Mitgliedschaft im Benutzernamensraum zu erhalten, indem ein Paar von setns(2)-Aufrufen verwandt wird, um
sich in einen anderen Benutzernamensraum zu verschieben und dann zu seinem ursprünglichen Namensraum
zurückzukehren.
Die Regeln zur Bestimmung, ob ein Prozess eine Capability in einem bestimmten Benutzernamensraum hat,
sind wie folgt:
• Ein Prozess hat eine Capability innerhalb eines Benutzernamensraums, falls er ein Mitglied dieses
Namensraums ist und er die Capability in seiner effektiven Capability-Menge hat. Ein Prozess kann
Capabilitys in seiner effektiven Capability-Menge auf verschiedene Arten erlangen. Beispielsweise
könnte er ein set-user-ID-Programm oder eine ausführbare Datei mit zugeordneten Datei-Capabilitys
ausführen. Zusätzlich könnte ein Prozess Capabilitys mittels der bereits beschriebenen Auswirkungen
von clone(2), unshare(2) oder setns(2) erlangen.
• Falls ein Prozess eine Capability in einem Benutzernamensraum hat, dann hat es diese Capability in
allen nachfolgenden (und weiter entfernten Nachfolge-) Namensräumen ebenfalls.
• Wenn ein Benutzernamensraum erstellt wird, zeichnet der Kernel die effektive Benutzerkennung des
erstellenden Prozesses als »Eigentümer« des Namensraums auf. Ein Prozess, der sich im Vorgänger des
Benutzernamensraums befindet und dessen effektive Benutzerkennung auf die des Eigentümers des
Namensraums passt, hat alle Capabilitys in diesem Namensraum. Dank der vorherigen Regel bedeutet dies,
dass der Prozess auch über alle Capabilitys in allen weiteren entfernten nachfolgenden Benutzerräumen
verfügt. Die Aktion NS_GET_OWNER_UID ioctl(2) kann zum Ermitteln der Benutzerkennung des Eigentümers
des Namensraums verwandt werden; siehe ioctl_ns(2).
Auswirkungen von Capabilitys innerhalb eines Benutzernamensraums
Hat ein Prozess eine Capability innerhalb eines Benutzernamensraums, dann darf er Aktionen nur auf
Ressourcen anwenden (die Privilegien benötigen), die durch diesen Namensraum reguliert werden. Mit
anderen Worten erlaubt eine Capability in einem Benutzernamensraum einem Prozess, privilegierte Aktionen
auf Ressourcen durchzuführen, die durch (Nichtbenutzer-)Namensräume gelenkt werden, die den
Benutzernamensräumen gehören bzw. diesen zugeordnet sind (siehe den nächsten Unterabschnitt).
Auf der anderen Seite gibt es viele privilegierte Aktionen, die Ressourcen betreffen, die keinem
Namensraumtyp zugeordnet sind, beispielsweise dem Ändern der Systemzeit (z.B. Kalender) (wird durch
CAP_SYS_TIME reguliert), dem Laden eines Kernelmoduls (wird durch CAP_SYS_MODULE reguliert) und dem
Erstellen eines Gerätes (wird durch CAP_MKNOD reguliert). Nur Prozesse, die über Privilegien in dem
ursprünglichen Benutzernamensraum verfügen, können solche Aktionen durchführen.
Wenn ein Prozess CAP_SYS_ADMIN innerhalb eines Namensraums hält, der den Einhängenamensraum des Prozesses
besitzt, dann kann er Bind-Einhängungen erstellen und die folgenden Arten an Dateisystemen einhängen:
• /proc (seit Linux 3.8)
• /sys (seit Linux 3.8)
• devpts (seit Linux 3.9)
• tmpfs(5) (seit Linux 3.9)
• ramfs (seit Linux 3.9)
• mqueue (seit Linux 3.9)
• bpf (seit Linux 4.4)
• overlayfs (seit Linux 5.11)
Wenn ein Prozess CAP_SYS_ADMIN innerhalb eines Namensraums hält, der den Cgroup-Namensraum des Prozesses
besitzt, dann kann er (seit Linux 4.6) das Cgroup-Version-2-Dateisystem und die benannten
Cgroup-Version-1-Hierarchien (d.h. Cgroup-Dateisysteme, die mit der Option "none,name=" eingehängt sind)
einhängen.
Wenn ein Prozess CAP_SYS_ADMIN innerhalb eines Namensraums hält, der den PID-Namensraum des Prozesses
besitzt, dann kann er (seit Linux 3.8) /proc-Dateisysteme einhängen.
Beachten Sie, dass das Einhängen blockbasierter Dateisysteme nur von Prozessen erfolgen kann, die
CAP_SYS_ADMIN in dem anfänglichen Benutzernamensraum enthalten.
Wechselwirkung von Benutzernamensräumen und anderen Arten von Namensräumen
Seit Linux 3.8 können nicht privilegierte Prozesse Benutzernamensräume erstellen und andere Arten von
Namensräumen können nur mit der Capability CAP_SYS_ADMIN im Benutzernamensraum des Aufrufenden erstellt
werden.
Wenn ein Nichtbenutzer-Namensraum erstellt wird, gehört er dem Benutzernamensraum, in dem der erstellende
Prozess zum Erstellungszeitraum des Namensraums Mitglied war. Privilegierte Aktionen auf Ressourcen, die
von einem Nichtbenutzer-Namensraum reguliert werden, benötigen, dass der Prozess über die notwendigen
Capabilitys in dem Benutzernamensraum verfügt, der den Nichtbenutzer-Namensraum besitzt.
Falls CLONE_NEWUSER zusammen mit anderen Schaltern CLONE_NEW* in einem einzelnen Aufruf von clone(2) oder
unshare(2) angegeben wird, wird garantiert, dass der Namensraum zuerst erstellt wird, und damit dem
Kindprozess (clone(2)) oder dem aufrufenden Prozess (unshare(2)) Privilegien über den durch den Aufruf
erstellten Namensraum gegeben wird. Daher ist es für einen nicht privilegierten Aufrufenden möglich,
diese Schalterkombination festzulegen.
Wenn ein neuer Namensraum (der kein Benutzernamensraum ist) mittels clone(2) oder unshare(2) erstellt
wird, zeichnet der Kernel den Benutzernamensraum des erstellenden Prozesses als Eigentümer des neuen
Namensraums auf. (Diese Zuordnung kann nicht geändert werden). Wenn nachfolgend ein Prozess in dem neuen
Namensraum eine privilegierte Aktion durchführt, die auf globalen Ressourcen agiert, die durch den
Namensraum isoliert werden, dann erfolgen die Berechtigungsprüfungen gemäß der Capabilitys des Prozesses
in dem Benutzernamensraum, den der Kernel dem neuen Namensraum zuordnet. Wird beispielsweise angenommen,
dass ein Prozess versucht, den Rechnernamen, eine durch UTS-Namensräume regulierte Ressource, zu ändern
(sethostname(2)), dann wird der Kernel bestimmen, welchem Benutzernamensraum der UTS-Namensraum des
Prozesses gehört und prüfen, ob der Prozess über die benötigte Capability (CAP_SYS_ADMIN) in diesem
Benutzernamensraum verfügt.
Die Aktion NS_GET_USERNS ioctl(2) kann zum Erkennen des Benutzernamensraums verwandt werden, dem der
Nichtbenutzer-Namensraum gehört; siehe ioctl_ns(2).
Benutzer- und Gruppenkennungabbildungen: uid_map und gid_map
Wenn ein Benutzernamensraum erstellt wird, beginnt er mit einer Abbildung der Benutzerkennungen
(Gruppenkennungen) auf die des Vorgängernamensraumes. Die Dateien /proc/PID/uid_map und /proc/PID/gid_map
(verfügbar seit Linux 3.5) legen diese Abbildungen für die Benutzer- und Gruppenkennungen innerhalb des
Benutzernamensraumes für den Prozess PID offen. Diese Dateien können ausgelesen werden, um die
Abbildungen innerhalb eines Benutzernamensraums zu betrachten und (einmal) beschrieben zu werden, um
diese Abbildungen zu definieren.
Die Beschreibung in den folgenden Absätzen erklärt die Details für uid_map; gid_map ist vollständig
identisch, sofern jedes Vorkommen von »Benutzerkennung« durch »Gruppenkennung« ersetzt wird.
Die Datei uid_map legt die Abbildung der Benutzerkennung von dem Benutzernamensraum des Prozesses PID in
den Benutzernamensraum des Prozesses offen, der uid_map öffnete (siehe aber auch die nachfolgende
Qualifizierung dieses Punktes). Mit anderen Worten, Prozesse, die sich in verschiedenen
Benutzernamensräumen befinden, werden möglicherweise andere Werte sehen, wenn sie aus einer bestimmten
Datei uid_map lesen, abhängig von der Benutzerkennungsabbildung für den Benutzernamensraum des lesenden
Prozesses.
Jede Zeile der Datei uid_map legt eine 1-zu-1-Abbildung des Bereichs fortlaufender Benutzerkennungen
zwischen zwei Benutzernamensräumen fest. (Wenn ein Benutzernamensraum erstmalig erstellt wird, ist diese
Datei leer.) Die Festlegung in jeder Zeile hat die Form von drei durch Leerraum getrennten Zahlen. Die
ersten zwei Zahlen geben die am Anfang befindliche Benutzerkennung in jedem der zwei Benutzernamensräume
an. Die dritte Zahl gibt die Länge des abgebildeten Bereichs an. Im Detail werden die Felder wie folgt
interpretiert:
(1) Der Anfang des Bereichs von Benutzerkennungen in dem Benutzernamensraum des Prozesses PID.
(2) Der Anfang des Bereichs von Benutzerkennungen, auf die die Benutzerkennungen aus Feld eins
abgebildet werden. Wie Feld zwei interpretiert wird, hängt davon ab, ob der Prozess, der uid_map
öffnete und der Prozess PID sich in dem gleichen Benutzernamensraum befinden, wie folgt:
(a) Falls sich die zwei Prozesse in verschiedenen Benutzernamensräumen befinden: Feld zwei ist der
Anfang des Bereichs von Benutzerkennungen in dem Benutzernamensraum des Prozesses, der uid_map
öffnete.
(b) Falls die zwei Prozesse im gleichen Benutzernamensraum sind: Feld zwei ist der Anfang des
Bereichs von Benutzerkennungen in dem Vorgängerbenutzernamensraum des Prozesses PID. Dieser
Fall ermöglicht es dem Öffnenden von uid_map (der typische Fall hier ist das Öffnen von
/proc/self/uid_map) die Abbildung der Benutzerkennungen in den Benutzernamensraum des
Prozesses, der diesen Benutzernamensraum erstellte, zu sehen.
(3) Die Länge des Bereichs von Benutzerkennungen, die zwischen den zwei Benutzernamensräumen abgebildet
wird.
Systemaufrufe, die Benutzerkennungen (Gruppenkennungen) zurückliefern–beispielsweise getuid(2), getgid(2)
und die Berechtigungsdatenfelder in der durch stat(2) zurückgelieferten Struktur–liefern die
Benutzerkennung (Gruppenkennung) abgebildet auf den Benutzernamensraum des Aufrufenden zurück.
Wenn ein Prozess auf eine Datei zugreift, werden seine Benutzer- und Gruppenkennungen zum Zwecke der
Zugriffsprüfung und der Zuweisungen von Kennungen beim Erstellen von Dateien auf die des anfänglichen
Benutzernamensraumens abgebildet. Wenn ein Prozess die Dateibenutzer- und -gruppenkennungen über stat(2)
ermittelt, werden die Kennungen in die andere Richtung abgebildet, um Werte relativ zu den
Prozessbenutzer- und -gruppenkennungsabildungen zu erstellen.
Der anfängliche Benutzernamensraum hat keinen Vorgängernamensraum. Aus Konsistenzgründen stellt der
Kernel Pseudo-Benutzer- und -Gruppenkennungsabbildungsdateien für diesen Namensraum bereit. Wird vom
anfänglichen Namensraum aus auf die Datei uid_map (gid_map ist identisch) geschaut, ergibt sich:
$ cat /proc/$$/uid_map
0 0 4294967295
Diese Abbildung teilt uns mit, dass der Bereich bei der Benutzerkennung 0 in diesem Namensraum auf den
Bereich beginnend bei 0 in dem (nicht existierenden) Vorgängernamensraum abgebildet ist und die Länge des
Bereichs die größte vorzeichenlose 32-bit-Ganzzahl ist. Dies lässt 4294967295 (der vorzeichenbehaftete
32-bit-Wert) nicht abgebildet. Dies ist absichtlich: (uid_t) -1 wird von einer Reihe von Schnittstellen
(z.B. setreuid(2)) dazu verwandt, »keine Benutzerkennung« festzulegen. Da (uid_t) -1 nicht abgebildet und
unbenutzbar ist, wird sichergestellt, dass es keine Verwirrung bei der Verwendung dieser Schnittstellen
gibt.
Definieren von Benutzer- und Gruppenkennungsabbildungen; Schreiben in uid_map und gid_map
Nach der Erstellung eines neuen Benutzernamensraumes kann die Datei uid_map von einem der Prozesse in dem
Namensraum einmalig geschrieben werden, um die Abbildung der Benutzerkennungen in dem neuen
Benutzernamensraum zu definieren. Jeder Versuch, mehr als einmal in eine Datei uid_map in einem
Benutzernamensraum zu schreiben, schlägt mit dem Fehler EPERM fehl. Ähnliche Regeln gelten für Dateien
gid_map.
Die in uid_map (gid_map) geschriebenen Zeilen müssen die folgenden Gültigkeitsregeln erfüllen:
• Die drei Felder müssen gültige Zahlen sein und das letzte Feld muss größer als 0 sein.
• Zeilen werden durch einen Zeilenumbruch beendet.
• Es gibt eine Beschränkung bezüglich der Anzahl der Zeilen in der Datei. In Linux 4.14 und älter war
diese Beschränkung (willkürlich) auf 5 Zeilen gesetzt. Seit Linux 4.15 ist diese Beschränkung 340
Zeilen. Zusätzlich muss die Anzahl an in diese Datei geschriebenen Bytes kleiner als die Seitengröße
des Systems sein und das Schreiben muss am Anfang der Datei beginnen (d.h. lseek(2) und pwrite(2)
können nicht zum Schreiben an einen von Null verschiedenen Versatz in der Datei verwandt werden).
• Die Bereiche der Benutzerkennungen (Gruppenkennungen), die in den einzelnen Zeilen angegeben sind,
dürfen sich nicht gegenseitig überlappen. In der anfänglichen Implementierung (Linux 3.8) wurde diese
Anforderung durch eine simplistische Implementierung erfüllt, die weitere Einschränkungen auferlegte,
dass die Werte sowohl in Feld 1 als auch Feld 2 von aufeinanderfolgenden Zeilen in aufsteigender
numerischer Reihenfolge sein mussten, womit andernfalls gültige Abbildungen nicht erstellt werden
konnten. Linux 3.9 und neuer korrigierte diese Beschränkung und erlaubte jede Kombination von
nichtüberlappenden Abbildungen.
• Mindestens eine Zeile muss in die Datei geschrieben werden.
Schreibvorgänge, die die obigen Regeln verletzen, schlagen mit dem Fehler EINVAL fehl.
Damit ein Prozess in die Datei /proc/PID/uid_map (/proc/PID/gid_map) schreiben kann, müssen alle der
folgenden Berechtigungsanforderungen erfüllt sein:
• Der schreibende Prozess muss über die Capability CAP_SETUID (CAP_SETGID) des Benutzernamensraums des
Prozeses PID verfügen.
• Der schreibende Prozess muss entweder in dem Benutzernamensraum des Prozesses PID oder in dem
Vorgängernamensraum des Prozesses PID sein.
• Die abgebildeten Benutzerkennungen (Gruppenkennungen) müssen wiederum eine Abbildung in dem
Vorgänger-Benutzernamensraum haben.
• Falls die Aktualisierung von /proc/PID/uid_map eine Abbildung erstellt, die die UID 0 in dem
Vorgängernamensraum abbildet, dann muss eine der folgenden Bedingungen wahr sein:
(a) Falls der schreibende Prozess im Vorgänger-Benutzernamensraum liegt, dann muss er über die
Capability CAP_SETFCAP in diesem Benutzernamensraum verfügen; oder
(b) falls der schreibende Prozess in dem nachfolgenden Benutzernamensraum liegt, dann muss der
Prozess, der den Benutzernamensraum erstellte, über die Capability CAP_SETFCAP verfügen, als der
Benutzernamensraum erstellt wurde.
Diese Regel gibt es seit Linux 5.12. Sie beseitigt einen älteren Sicherheitsfehler, durch den ein
UID-0-Prozess ohne die Capability CAP_SETFCAP (die zum Erstellen eines Programms mit Datei-Capabilitys
im Namensraum benötigt wird, wie das in capabilities(7) beschrieben ist), trotzdem ein solches
Programm erstellen konnte, indem es Folgendes durchführte:
(1) Erstellung eines neuen Benutzernamensraums mit der Identitätsabbildung (d.h. UID 0 in dem neuen
Benutzernamensraum wird auf UID 0 im Vorgängernamensraum abgebildet), so dass UID 0 in beiden
Namensräumen äquivalent zu der gleichen Root-Benutzerkennung ist.
(2) Da der Nachfolgerprozess über die Capability CAP_SETFCAP verfügt, könnte er ein Programm mit den
Datei-Capabilitys im Namensraum erstellen, die auch im Vorgängernamensraum wirksam wären (da die
Root-Benutzerkennungen in beiden Namensräumen identisch sind).
• Einer der folgenden zwei Fälle trifft zu:
(a) Entweder verfügt der schreibende Prozess über die Capability CAP_SETUID (CAP_SETGID) in dem
Vorgängernamensraum.
• Es gelten keine weiteren Einschränkungen; der Prozess kann Abbildungen auf beliebige
Benutzerkennungen (Gruppenkennungen) im Vorgängernamensraum durchführen.
(b) Oder es gelten alle der folgenden Beschränkungen:
• Die in uid_map (gid_map) geschriebenen Daten müssen aus einer einzelnen Zeile bestehen, die
die effektive Benutzerkennung (Gruppenkennung) des schreibenden Prozesses in dem
Vorgängernamensraum auf eine Benutzerkennung (Gruppenkennung) in den Benutzernamensraum
abbildet.
• Der schreibende Prozess muss die gleiche effektive Benutzerkennung wie der Prozess haben, der
den Benutzernamensraum erstellte.
• Im Falle von gid_map muss zuerst die Verwendung des Systemaufrufs setgroups(2) verboten
werden, indem »deny« in die Datei /proc/PID/setgroups geschrieben wird (siehe unten), bevor in
gid_map geschrieben wird.
Schreibaktionen, die die obigen Regeln verletzen, werden mit EPERM fehlschlagen.
Projektkennungsabbildung: projid_map
Ähnlich zu Benutzer- und Gruppenkennungsabbildungen ist es möglich, eine Projektkennungsabbildung für
einen Benutzernamensraum zu erstellen. (Projektkennungen werden für Plattenkontingente verwandt, siehe
setquota(8) und quotactl(2).)
Projektkennungsabbildungen werden durch Schreiben in die Datei /proc/PID/projid_map definiert (vorhanden
seit Linux 3.7).
Die Gültigkeitsregeln für das Schreiben in die Datei /proc/PID/projid_map sind wie beim Schreiben in die
Datei uid_map; Verletzung dieser Regeln führt beim write(2) zum Fehlschlag EINVAL.
Die Erlaubnisregeln für das Schreiben in die Datei /proc/PID/projid_map sind wie folgt:
• Der schreibende Prozess muss entweder in dem Benutzernamensraum des Prozesses PID oder in dem
Vorgängernamensraum des Prozesses PID sein.
• Die abgebildeten Projektkennungen müssen wiederum eine Abbildung im Vorgängernamensraum haben.
Verletzung dieser Regeln führt dazu, dass write(2) mit EPERM fehlschlägt.
Wechselwirkung mit Systemaufrufen, die Prozessbenutzerkennungen oder -gruppenkennungen ändern
In einem Benutzernamensraum, in dem die Datei uid_map noch nicht geschrieben wurde, werden die
Systemaufrufe, die die Benutzerkennung ändern, fehlschlagen. Ähnlich werden die Systemaufrufe, die die
Gruppenkennungen ändern, fehlschlagen, falls die Datei gid_map noch nicht geschrieben wurde. Nachdem die
Dateien uid_map und gid_map geschrieben wurden, können nur die abgebildeten Werte in Systemaufrufen
verwandt werden, die die Benutzer- und Gruppenkennungen ändern.
Für Benutzerkennungen sind die relevanten Systemaufrufe unter anderem setuid(2), setfsuid(2), setreuid(2)
und setresuid(2). Für Gruppenkennungen sind die relevanten Systemaufrufe unter anderem setgid(2),
setfsgid(2), setregid(2), setresgid(2) und setgroups(2).
Durch Schreiben von »deny« in die Datei /proc/PID/setgroups vor dem Schreiben von /proc/PID/gid_map wird
setgroups(2) in einem Benutzernamensraum dauerhaft deaktiviert und erlaubt Schreiben von
/proc/PID/gid_map, ohne über die Capability CAP_SETGID im Vorgängernamensraum zu verfügen.
Die Datei /proc/PID/setgroups
Die Datei /proc/PID/setgroups zeigt die Zeichenkette »allow«, falls Prozesse in dem Benutzernamensraum,
der den Prozess PID enthält, die Erlaubnis haben, den Systemaufruf setgroups(2) einzusetzen. Sie zeigt
»deny« an, falls setgroups(2) in diesem Benutzernamensraum nicht erlaubt ist. Beachten Sie, dass Aufrufe
von setgroups(2) auch nicht erlaubt sind, falls /proc/PID/gid_map noch nicht gesetzt wurde, unabhängig
von dem Wert der Datei /proc/PID/setgroups (und unabhängig von den Capabilitys des Prozesses).
Ein privilegierter Prozess (einer mit der Capability CAP_SYS_ADMIN in dem Namensraum) darf eine der
Zeichenketten »allow« oder »deny« in diese Datei schreiben, bevor eine Gruppenkennungsabbildung für
diesen Benutzernamensraum in die Datei /proc/PID/gid_map geschrieben wird. Durch Schreiben der
Zeichenkette »deny« wird jedem Prozess in diesem Benutzernamensraum der Einsatz von setgroups(2)
verboten.
Die Essenz der in den vorhergehenden Absätzen beschriebenen Beschränkungen ist, dass das Schreiben in
/proc/PID/setgroups nur so lange erlaubt ist, wie setgroups(2) nicht erlaubt ist, da /proc/PID/gid_map
noch nicht gesetzt wurde. Damit wird sichergestellt, dass ein Prozess nicht von einem Zustand, bei dem
setgroups(2) erlaubt ist, zu einem Zustand, bei dem setgroups(2) verboten ist, übergehen kann; ein
Prozess kann nur von setgroups(2) nicht erlaubt zu setgroups(2) erlaubt übergehen.
Der Vorgabewert für diese Datei in dem anfänglichen Namensraum ist »allow«.
Sobald /proc/PID/gid_map geschrieben wurde (wodurch setgroups(2) in dem Benutzernamensraum aktiviert
wird), ist es nicht mehr möglich, setgroups(2) durch Schreiben von »deny« in /proc/PID/setgroups zu
verbieten (das Schreiben schlägt mit EPERM fehl).
Ein Nachfolgernamensraum erbt die Einstellungen /proc/PID/setgroups von seinem Vorgänger.
Falls die Datei setgroups den Wert »deny« enthält, dann kann der Systemaufruf setgroups(2) in diesem
Namensraum nachfolgend nicht mehr aktiviert werden (durch Schreiben von »allow« in die Datei). (Versuche,
dies durchzuführen, schlagen mit EPERM fehl.) Diese Beschränkung wird auch an alle
Nachfolgerbenutzernamensräume dieses Benutzernamensraums weitergeleitet.
Die Datei /proc/PID/setgroups wurde in Linux 3.19 hinzugefügt; allerdings wurde sie auch auf viele
frühere stabile Kernel rückportiert, da sie ein Sicherheitsproblem adressiert. Das Problem betraf Dateien
mit Berechtigungen wie »rwx---rwx«. Diese Dateien geben der »Gruppe« weniger Berechtigungen als sie
»anderen« geben. Das bedeutet, dass die Abgabe von Gruppen mittels setgroups(2) einem Prozess
Dateizugriff erlauben könnte, den er vorher nicht hatte. Vor der Existenz von Benutzernamensräumen führte
dies zu keine Sorgen, da nur ein privilegierter Prozess (einer mit der Capability CAP_SETGID)
setgroups(2) aufrufen konnte. Mit der Einführung von Benutzernamensräumen wurde es für einen nicht
privilegierten Prozess allerdings möglich, einen neuen Namensraum zu erstellen, in dem der Benutzer alle
Privilegien hatte. Dies ermöglichte es dann vorher nicht privilegierten Benutzern Gruppen abzugeben und
damit Dateizugriff zu erlangen, den sie vorher nicht hatten. Die Datei /proc/PID/setgroups wurde
hinzugefügt, um dieses Sicherheitsproblem zu adressieren, indem jeder Pfad für einen nicht privilegierten
Prozess, Gruppen mit setgroups(2) abzugeben, verboten wurde.
Nicht abgebildete Benutzer- und Gruppenkennungen
Es gibt verschiedene Stellen, an denen nicht abgebildete Benutzerkennungen (Gruppenkennungen) im
Anwendungsraum offengelegt werden können. Beispielsweise könnte der erste Prozess in einem neuen
Benutzernamensraum getuid(2) aufrufen, bevor eine Benutzerkennungsabbildung für den Namensraum definiert
wurde. In den meisten solcher Fälle wird eine nicht abgebildete Benutzerkennung in die
Überlauf-Benutzerkennung (Gruppenkennung) konvertiert; der Vorgabewert für die Überlauf-Benutzerkennung
(Gruppenkennung) ist 65534. Siehe die Beschreibung von /proc/sys/kernel/overflowuid und
/proc/sys/kernel/overflowgid in proc(5).
Zu den Fällen, in denen nicht abgebildete Benutzerkennungen auf diese Art abgebildet werden, gehören
Systemaufrufe, die Benutzerkennungen zurückliefern (getuid(2), getgid(2) und ähnliche),
Benutzerberechtigungen, die über ein UNIX-Domain-Socket übergeben werden, Benutzerberechtigungen, die von
stat(2), waitid(2) und den System-V-IPC-»ctl«-IPC_STAT-Aktionen zurückgeliefert werden,
Benutzerberechtigungen, die mittels /proc/PID/status und den Dateien in /proc/sysvipc/* offengelegt
werden, Benutzerberechtigungen, die über das Feld si_uid in dem mit einem Signal siginfo_t empfangenen
Feld zurückgeliefert werden (siehe sigaction(2)), Benutzerberechtigungen, die in die
Prozessbuchhaltungsdatei geschrieben werden (siehe acct(5)) und Benutzerberechtigungen, die mit
POSIX-Nachrichtenwarteschlangen-Benachrichtigungen zurückgeliefert werden (siehe mq_notify(3)).
Es gibt einen erwähnenswerten Fall, bei dem nicht abgebildete Benutzer- und Gruppenkennungen nicht in die
entsprechende Überlaufkennung konvertiert werden. Beim Betrachten einer Datei uid_map oder gid_map, bei
der es keine Abbildung für das zweite Feld gibt, wird das Feld als 4294967295 (-1 als eine vorzeichenlose
Ganzzahl) dargestellt.
Dateizugriff
Um Berechtigungen zu bestimmen, wenn ein nicht privilegierter Prozess auf eine Datei zugreift, werden die
Prozessberechtigungen (UID, GID) und die Dateiberechtigungen letztendlich auf die zurückabgebildet, die
sie im anfänglichen Benutzernamensraum wären und dann verglichen, um die Berechtigungen zu bestimmen, die
der Prozess auf die Datei hat. Das gleiche trifft auch für andere Objekte zu, die das Zugriffsmodell mit
Benutzerberechtigungen sowie Berechtigungsmasken einsetzen, wie System-V-IPC-Objekte.
Aktionen mit Datei-bezogenen Capabilitys
Bestimmte Capabilitys erlauben es einem Prozess, verschiedene, durch den Kernel durchgesetzte
Beschränkungen zu umgehen, wenn Aktionen auf Dateien durchgeführt werden, die anderen Benutzern oder
Gruppen gehören. Diese Capabilitys sind CAP_CHOWN, CAP_DAC_OVERRIDE, CAP_DAC_READ_SEARCH, CAP_FOWNER und
CAP_FSETID.
Innerhalb eines Benutzernamensraumes erlauben diese Capabilitys einem Prozess, die Regeln zu umgehen,
falls der Prozess über die relevante Capability über die Datei verfügt. Das bedeutet:
• Der Prozess hat die relevante effektive Capability in seinem eigenen Benutzernamensraum; und
• die Benutzer- und Gruppenkennung der Datei habe beide gültige Abbildungen in dem Benutzernamensraum.
Die Capability CAP_FOWNER wird etwas besonders behandelt: sie erlaubt einem Prozess, die entsprechenden
Regeln zu umgehen, solange zumindest die Benutzerkennung der Datei über eine Abbildung in dem
Benutzernamensraum verfügt (d.h. die Gruppenkennung der Datei benötigt keine gültige Abbildung).
Set-user-ID- und set-group-ID-Programme
Wenn ein Prozess innerhalb eines Benutzernamensraums ein set-user-ID- (set-group-ID)-Programm ausführt,
wird die effektive Benutzer- (Gruppen-)Kennung des Prozesses innerhalb des Namensraums auf denjenigen
Wert geändert, der für die Benutzer- (Gruppen)kennung der Datei abgebildet ist. Falls allerdings entweder
die Benutzer- oder die Gruppenkennung der Datei über keine Abbildung innerhalb des Namensraums verfügt,
wird das set-user-ID- (set-group-ID-)Bit ohne Rückmeldung ignoriert: das neue Programm wird ausgeführt,
aber die effektive Benutzer- (Gruppen-)Kennung des Prozesses bleibt unverändert. (Dies spiegelt die
Semantik bei der Ausführung eines set-user-ID- oder set-group-ID-Programmes wider, das sich auf einem
Dateisystem befindet, das mit dem Schalter MS_NOSUID eingehängt wurde, wie dies in mount(2) beschrieben
ist.)
Verschiedenes
Wenn die Benutzer- und Gruppenkennungen eines Prozesses über ein UNIX-Domain-Socket an einen Prozess in
einem anderen Benutzernamensraum übergeben werden (siehe die Beschreibung von SCM_CREDENTIALS in
unix(7)), werden sie in die entsprechenden Werte der Benutzer- und Gruppenkennungsabbildungen des
empfangenen Prozesses übersetzt.
STANDARDS
Namensräume sind eine Linux-spezifische Funktionalität.
ANMERKUNGEN
Über die Jahre wurden eine Reihe von Funktionalitäten zu dem Linux-Kernel hinzugefügt, die nur
privilegierten Benutzern verfügbar gemacht wurden, da sie möglicherweise set-user-ID-root-Anwendungen
durcheinander bringen könnten. Im Allgemeinen wird es sicher, einem Root-Benutzer in einem
Benutzernamensraum die Verwendung dieser Funktionalitäten zu erlauben, da es unmöglich ist, mehr
Privilegien zu erlangen, als der Root-Benutzer innerhalb eines Benutzernamensraumes hat, während der
Prozess im Benutzernamensraum ist.
Globaler Root
Der Ausdruck »Globaler Root« wird manchmal als Abkürzung für die Benutzerkennung 0 im anfänglichen
Benutzernamensraum verwandt.
Verfügbarkeit
Die Verwendung von Benutzernamensräumen benötigt einen Kernel, der mit der Option CONFIG_USER_NS
konfiguriert ist. Benutzernamensräume benötigen die Unterstützung in einer ganzen Reihe von Subsystemen
im Kernel. Wird ein nicht unterstütztes Subsystem in den Kernel konfiguriert, dann ist es nicht möglich,
die Unterstützung von Benutzernamensräumen zu konfigurieren.
Seit Linux 3.8 unterstützen die wichtigsten Subsysteme Benutzernamensräume, aber eine Reihe von
Dateisystemen hatten noch nicht die benötigte Infrastruktur, um Benutzer- und Gruppenkennungen zwischen
Benutzernamensräumen abzubilden. Linux 3.9 fügte die benötigte Infrastruktur für viele der verbliebenen,
nicht unterstützten Dateisysteme (Plan 9 (9P), Andrew File System (AFS), Ceph, CIFS, CODA, NFS und OCFS2)
hinzu. Linux 3.12 fügte Unterstützung für das letzte große verbliebene und nicht unterstützte Dateisystem
hinzu: XFS.
BEISPIELE
Das nachfolgende Programm ist zum Experimentieren mit Benutzernamensräumen sowie anderen Arten von
Namensräumen gedacht. Es erstellt einen Namensraum, wie er über die Befehlszeilenoptionen angegeben ist,
und führt dann innerhalb dieser Namensräume einen Befehl aus. Die Kommentare und die Funktion usage()
innerhalb des Programmes bieten eine vollständige Erklärung des Programms. Die nachfolgende Shell-Sitzung
zeigt seine Verwendung.
Zuerst schauen wir auf die Laufzeitumgebung:
$ uname -rs # Benötigt Linux 3.8 oder neuer
Linux 3.8.0
$ id -u # Ausführung als nicht privilegierter Benutzer
1000
$ id -g
1000
Jetzt wird eine neue Shell in neuen Benutzer- (-U), Einhänge- (-m) und PID- (-p) Namensräumen gestartet,
wobei innerhalb des Benutzernamensraums die Benutzerkennung (-M) und Gruppenkennung (-G) 1000 auf 0
abgebildet wird:
$ ./userns_child_exec -p -m -U -M '0 1000 1' -G '0 1000 1' bash
Diese Shell hat PID 1, da sie der erste Prozess in dem neuen PID-Namensraum ist:
bash$ echo $$
1
Wird ein neues Dateisystem /proc eingehängt und alle in dem neuen PID-Namensraum sichtbaren Prozesse
aufgelistet, kann gesehen werden, dass die Shell keinerlei Prozesse außerhalb des PID-Namensraumes sehen
kann:
bash$ mount -t proc proc /proc
bash$ ps ax
PID TTY STAT TIME COMMAND
1 pts/3 S 0:00 bash
22 pts/3 R+ 0:00 ps ax
Innerhalb des Benutzernamensraumes hat die Shell die Benutzer- und Gruppenkennung 0 und eine vollständige
Menge an erlaubten und effektiven Capabilitys:
bash$ cat /proc/$$/status | egrep '^[UG]id'
Uid: 0 0 0 0
Gid: 0 0 0 0
bash$ cat /proc/$$/status | egrep '^Cap(Prm|Inh|Eff)'
CapInh: 0000000000000000
CapPrm: 0000001fffffffff
CapEff: 0000001fffffffff
Programmquelltext
/* userns_child_exec.c
Lizenziert unter der GNU General Public License v2 oder neuer
Erzeugt einen Kindprozess, der einen Shell-Befehl in einem oder mehreren
neuen Namensräumen ausführt; erlaubt UID- und GID-Abbildungen anzugeben,
wenn ein Benutzernamensraum erstellt wird
*/
#define _GNU_SOURCE
#include <err.h>
#include <sched.h>
#include <unistd.h>
#include <stdint.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <signal.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <limits.h>
#include <errno.h>
struct child_args {
char **argv; /* Vom Kind auszuführender Befehl, mit Argumenten */
int pipe_fd[2]; /* Zur Sychronisation Eltern/Kind verwandte Pipe */
};
static int verbose;
static void
usage(char *pname)
{
fprintf(stderr, "Aufruf: %s [Optionen] Bef [Arg…]\n\n", pname);
fprintf(stderr, "Erstellt einen Kindprozess, der einen Shellbefehl "
"in einem neuen Benutzernamensraum ausführt\n"
"und möglicherweise auch anderen neuen Namensräumen.\n\n");
fprintf(stderr, "Optionen können sein:\n\n");
#define fpe(str) fprintf(stderr, " %s", str);
fpe("-i Neuer IPC-Namensraum\n");
fpe("-m Neuer Einhänge-Namensraum\n");
fpe("-n Neuer Netzwerk-Namensraum\n");
fpe("-p Neuer PID-Namensraum\n");
fpe("-u Neuer UTS-Namensraum\n");
fpe("-U Neuer Benutzernamensraum\n");
fpe("-M uid_map Angabe einer UID-Abbildung für Benutzernamensraum\n");
fpe("-G gid_map Angabe einer GID-Abbildung für Benutzernamensraum\n");
fpe("-z Benutzer-UID und -GID auf 0 im Benutzernamensraum abbilden\n");
fpe(" (äquivalent zu: -M '0 <uid> 1' -G '0 <gid> 1')\n");
fpe("-v Anzeige ausführlicher Meldungen\n");
fpe("\n");
fpe("Falls -z, -M oder -G angegeben wird, ist -U verpflichtend.\n");
fpe("Es ist nicht erlaubt, sowohl -z als auch entweder -M oder -G anzugeben.\n");
fpe("\n");
fpe("Abbildungszeichenketten für -M und -G bestehen aus Datensätzen der folgenden Form:\n");
fpe("\n");
fpe(" Namensrauminterne-Kennung Namensraumexterne-Kennung Länge\n");
fpe("\n");
fpe("Eine Abbildungszeichenkette kann mehrere Datensätze enthalten,"
" getrennt durch Kommata;\n");
fpe("die Kommata werden vor dem Schreiben in die Abbildungsdateien durch"
" Zeilenumbrüche ersetzt.\n");
exit(EXIT_FAILURE);
}
/* Aktualisiert die Abbildungsdatei »map_file« mit dem in »mapping«
bereitgestellten Wert, einer Zeichenkette, die eine UID- oder GID-
Abbildung definiert. Eine UID- oder GID-Abbildung besteht aus einem oder
mehreren, durch Zeilenumbrüche getrennten Datensätzen der folgenden Form:
Namensrauminterne-Kennung Namensraumexterne-Kennung Länge
Für die Befehlszeile zu verlangen, dass Zeichenketten mit Zeilenumbrüchen
bereitgestellt werden, ist natürlich unbequem. Daher erlauben wir die
Verwendung von Kommata zur Begrenzung von Datensätzen in dieser
Zeichenkette und ersetzen sie vor dem Schreiben in die Datei durch
Zeilenumbrüche. */
static void
update_map(char *mapping, char *map_file)
{
int fd;
size_t map_len; /* Länge der »mapping« */
/* Kommata durch Zeilenumbrüche in Abbildungszeichenkette ersetzen. */
map_len = strlen(mapping);
for (size_t j = 0; j < map_len; j++)
if (mapping[j] == ',')
mapping[j] = '\n';
fd = open(map_file, O_RDWR);
if (fd == -1) {
fprintf(stderr, "FEHLER: open %s: %s\n", map_file,
strerror(errno));
exit(EXIT_FAILURE);
}
if (write(fd, mapping, map_len) != map_len) {
fprintf(stderr, "FEHLER: write %s: %s\n", map_file,
strerror(errno));
exit(EXIT_FAILURE);
}
close(fd);
}
/* Linux 3.19 änderte die Handhabung von setgroups(2) und die Datei
»gid_map«, um ein Sicherheitsproblem zu adressieren. Das Problem erlaubte
*nicht privilegierten* Benutzern einen Benutzernamensraum einzusetzen, um
Gruppen abzugeben. Das Fazit der 3.19er Änderung ist, dass die Verwendung
des Systemaufrufs setgroups() in diesem Benutzernamensraum zuerst durch
Schreiben von »deny« in eine der Dateien /proc/PID/setgroups für diesen
Namensraum erfolgen muss, damit die Datei »gid_maps« aktualisert wird.
Das ist der Zweck der folgenden Funktion. */
static void
proc_setgroups_write(pid_t child_pid, char *str)
{
char setgroups_path[PATH_MAX];
int fd;
snprintf(setgroups_path, PATH_MAX, "/proc/%jd/setgroups",
(intmax_t) child_pid);
fd = open(setgroups_path, O_RDWR);
if (fd == -1) {
/* Vielleicht sind wir auf einem System, das /proc/PID/setgroups
nicht unterstützt. Dann wird diese Datei nicht existieren und das
System wird nicht die Beschränkungen erzwingen, die Linux 3.19
hinzugefügt hat. Das ist OK, wir brauchen nichts zu machen, damit
»gid_map« aktualisiert wird.
Falls allerdings der Fehler von open() sich von ENOENT
unterscheidet (der in diesem Fall zu erwarten ist), informieren
wir den Benutzer. */
if (errno != ENOENT)
fprintf(stderr, "FEHLER: open %s: %s\n", setgroups_path,
strerror(errno));
return;
}
if (write(fd, str, strlen(str)) == -1)
fprintf(stderr, "FEHLER: write %s: %s\n", setgroups_path,
strerror(errno));
close(fd);
}
static int /* Funktion für geklontes Kind starten */
childFunc(void *arg)
{
struct child_args *args = arg;
char ch;
/* Warten, bis der Elternprozess seine UID- und GID-Abbildungen
aktualisiert hat. Siehe den Kommentar in main(). Wir warten, bis
auf einer Pipe das Dateiende kommt, die vom Elternprozess geschlossen
wird, sobald er seine Abbildungen aktualisiert hat. */
close(args->pipe_fd[1]); /* Unseren Deskriptor für das Ende des
Schreibens schließen, so dass wir EOF
sehen, wenn der Elternprozess seinen
Deskriptor schließt. */
if (read(args->pipe_fd[0], &ch, 1) != 0) {
fprintf(stderr,
"Fehler im Kind: Lesen von der Pipe lieferte != 0\n");
exit(EXIT_FAILURE);
}
close(args->pipe_fd[0]);
/* Einen Shell-Befehl ausführen. */
printf("Gleich wird exec %s ausgeführt\n", args->argv[0]);
execvp(args->argv[0], args->argv);
err(EXIT_FAILURE, "execvp");
}
#define STACK_SIZE (1024 * 1024)
static char child_stack[STACK_SIZE]; /* Platz für den Stack des Kindes */
int
main(int argc, char *argv[])
{
int flags, opt, map_zero;
pid_t child_pid;
struct child_args args;
char *uid_map, *gid_map;
const int MAP_BUF_SIZE = 100;
char map_buf[MAP_BUF_SIZE];
char map_path[PATH_MAX];
/* Befehlszeilenoptionen auswerten. Das anfängliche »+«-Zeichen in dem
abschließenden getopt()-Argument verhindert GNU-artige Vertauschungen
der Befehlszeilenoptionen. Das ist nützlich, da manchmal der von
diesem Programm selbst ausgeführte »Befehl« über Befehlszeilenoptionen
verfügt. Wir wollen nicht, dass getopt() solche als Optionen für
dieses Programm behandelt. */
flags = 0;
verbose = 0;
gid_map = NULL;
uid_map = NULL;
map_zero = 0;
while ((opt = getopt(argc, argv, "+imnpuUM:G:zv")) != -1) {
switch (opt) {
case 'i': flags |= CLONE_NEWIPC; break;
case 'm': flags |= CLONE_NEWNS; break;
case 'n': flags |= CLONE_NEWNET; break;
case 'p': flags |= CLONE_NEWPID; break;
case 'u': flags |= CLONE_NEWUTS; break;
case 'v': verbose = 1; break;
case 'z': map_zero = 1; break;
case 'M': uid_map = optarg; break;
case 'G': gid_map = optarg; break;
case 'U': flags |= CLONE_NEWUSER; break;
default: usage(argv[0]);
}
}
/* -M oder -G ohne -U ist sinnlos */
if (((uid_map != NULL || gid_map != NULL || map_zero) &&
!(flags & CLONE_NEWUSER)) ||
(map_zero && (uid_map != NULL || gid_map != NULL)))
usage(argv[0]);
args.argv = &argv[optind];
/* Wir verwenden eine Pipe, um den Eltern- und Kindprozess zu
synchronisieren, damit sichergestellt wird, dass der Elternprozess
die UID- und GID-Abbildungen einrichtet, bevor der Kindprozess
execve() aufruft. Dies stellt sicher, dass das Kind seine Capabilitys
während des execve() erhält, wenn der typische Fall vorliegt, dass
wir möchten, dass die effektive Benutzerkennung des Kindprozesses auf
0 in dem neuen Benutzernamensraum abgebildet wird. Ohne diese
Synchronisation würde der Kindprozess seine Capabilitys verlieren,
falls es ein execve() mit einer von Null verschiedenen Benutzerkennung
durchführen würde (siehe die Handbuchseite capabilities(7) für Details
des Übergangs der Capabilitys eines Prozesses während execve()). */
if (pipe(args.pipe_fd) == -1)
err(EXIT_FAILURE, "pipe");
/* Den Kindprozess in dem oder den neuen Namensraum/-räumen erstellen. */
child_pid = clone(childFunc, child_stack + STACK_SIZE,
flags | SIGCHLD, &args);
if (child_pid == -1)
err(EXIT_FAILURE, "clone");
/* Elternprozess fällt bis hierher durch. */
if (verbose)
printf("%s: PID des durch clone() erstellten Kindprozesses lautet %jd\n",
argv[0], (intmax_t) child_pid);
/* Die UID- und GID-Abbildungen in dem Kindprozess aktualisieren. */
if (uid_map != NULL || map_zero) {
snprintf(map_path, PATH_MAX, "/proc/%jd/uid_map",
(intmax_t) child_pid);
if (map_zero) {
snprintf(map_buf, MAP_BUF_SIZE, "0 %jd 1",
(intmax_t) getuid());
uid_map = map_buf;
}
update_map(uid_map, map_path);
}
if (gid_map != NULL || map_zero) {
proc_setgroups_write(child_pid, "deny");
snprintf(map_path, PATH_MAX, "/proc/%jd/gid_map",
(intmax_t) child_pid);
if (map_zero) {
snprintf(map_buf, MAP_BUF_SIZE, "0 %ld 1",
(intmax_t) getgid());
gid_map = map_buf;
}
update_map(gid_map, map_path);
}
/* Das Schreibe-Ende der Pipe schließen, um dem Kindprozess zu
signalisieren, dass wir die UID- und GID-Abbildungen aktualisiert
haben. */
close(args.pipe_fd[1]);
if (waitpid(child_pid, NULL, 0) == -1) /* Warten auf Kindprozess */
err(EXIT_FAILURE, "waitpid");
if (verbose)
printf("%s: beende\n", argv[0]);
exit(EXIT_SUCCESS);
}
SIEHE AUCH
newgidmap(1), newuidmap(1), clone(2), ptrace(2), setns(2), unshare(2), proc(5), subgid(5), subuid(5),
capabilities(7), cgroup_namespaces(7), credentials(7), namespaces(7), pid_namespaces(7)
Die Kernelquelldatei Documentation/admin-guide/namespaces/resource-control.rst.
ÜBERSETZUNG
Die deutsche Übersetzung dieser Handbuchseite wurde von Helge Kreutzmann <debian@helgefjell.de> erstellt.
Diese Übersetzung ist Freie Dokumentation; lesen Sie die GNU General Public License Version 3 oder neuer
bezüglich der Copyright-Bedingungen. Es wird KEINE HAFTUNG übernommen.
Wenn Sie Fehler in der Übersetzung dieser Handbuchseite finden, schicken Sie bitte eine E-Mail an die
Mailingliste der Übersetzer.
Linux man-pages 6.03 5. Februar 2023 user_namespaces(7)