Provided by: manpages-de_4.13-4_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 Version 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:

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

       2. Falls ein Prozess eine Capability in einem Benutzernamensraum hat, dann  hat  es  diese
          Capability  in  allen  nachfolgenden  (und  weiter  entfernten Nachfolge-) Namensräumen
          ebenfalls.

       3. 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)

       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 Regeln 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 Anforderungen erfüllt sein:

       1. Der  schreibende  Prozess  muss  über  die  Capability  CAP_SETUID   (CAP_SETGID)   des
          Benutzernamensraums des Prozeses PID verfügen.

       2. Der  schreibende Prozess muss entweder in dem Benutzernamensraum des Prozesses PID oder
          in dem Vorgängernamensraum des Prozesses PID sein.

       3. Die abgebildeten Benutzerkennungen (Gruppenkennungen) müssen wiederum eine Abbildung in
          dem Vorgänger-Benutzernamensraum haben.

       4. Einer der folgenden zwei Fälle trifft zu:

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

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

   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.

KONFORM ZU

       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.

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

       /* Eine einfache Fehlerbehandlungsfunktion; gibt basierend auf dem Wert in
          »errno« eine Fehlermeldung aus und beendet den aufrufenden Prozess*/

       #define errExit(Nachricht)    do { perror(Nachricht); exit(EXIT_FAILURE); \
                               } while (0)

       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 »Datei« mit dem in »Abbildung«
          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 »Abbildung« */

           /* Kommata durch Zeilenumbrüche in Abbildungszeichenkette ersetzen. */

           map_len = strlen(mapping);
           for (int 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
          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);
           errExit("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)
               errExit("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)
               errExit("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 */
               errExit("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/namespaces/resource-control.txt.

KOLOPHON

       Diese  Seite  ist  Teil  der  Veröffentlichung  5.10  des  Projekts  Linux-man-pages. Eine
       Beschreibung des Projekts, Informationen, wie Fehler  gemeldet  werden  können  sowie  die
       aktuelle Version dieser Seite finden sich unter https://www.kernel.org/doc/man-pages/.

Ü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 ⟨https://www.gnu.org/licenses/gpl-3.0.html⟩ 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 ⟨debian-l10n-german@lists.debian.org⟩.