Provided by: manpages-de_4.21.0-2_all bug

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)