Provided by: manpages-de_4.15.0-9_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)
           * 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:

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

          *  Falls der schreibende Prozess im Vorgänger-Benutzernamensraum liegt,  dann  muss  er
             über die Capability CAP_SETFCAP in diesem Benutzernamensraum verfügen; oder

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

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

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

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

   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:

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

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

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.

   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 <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/admin-guide/namespaces/resource-control.rst.

KOLOPHON

       Diese  Seite  ist  Teil  der  Veröffentlichung  5.13  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⟩.