Provided by: manpages-de_4.26.0-1_all bug

BEZEICHNUNG

       user_namespaces - Überblick über Benutzernamensräume in Linux

BESCHREIBUNG

       Für einen Überblick über Namensräume, siehe namespaces(7).

       Benutzernamensräume isolieren sicherheitsrelevante Kennzeichner und Attribute, insbesondere Benutzer- und
       Gruppenkennungen  (siehe  credentials(7)),  das  Wurzelverzeichnis,  Schlüssel  (siehe  keyrings(7))  und
       Capabilitys (siehe capabilities(7)). Die Benutzer- und Gruppenkennung eines Prozesses kann innerhalb  und
       außerhalb  eines  Benutzernamensraums verschieden sein. Insbesondere kann ein Prozess eine normale, nicht
       privilegierte Benutzerkennung außerhalb eines Benutzernamensraums haben,  während  er  gleichzeitig  eine
       Benutzerkennung  0  innerhalb  des Namensraums hat; mit anderen Worten, der Prozess hat volle Privilegien
       für Aktionen innerhalb des Benutzernamensraums, ist aber für Aktionen  außerhalb  des  Namensraums  nicht
       privilegiert.

   Verschachtelte Namensräume, Namensraum-Mitgliedschaft
       Benutzernamensräume  können  verschachtelt  werden, das bedeutet, dass jeder Benutzernamensraum–außer dem
       anfänglichen  (»Wurzel-«)Namensraum–über  einen  Vorgängernamensraum  verfügt  und  keinen  oder  mehrere
       Nachfolgernamensräume  haben  kann. Der Vorgängernamensraum ist der Benutzernamensraum des Prozesses, der
       den Benutzernamensraum mittels eines Aufrufs von unshare(2) oder clone(2) mit dem Schalter  CLONE_NEWUSER
       erstellte.

       (Seit   Linux   3.11)   erzwingt   der   Kernel   eine   Begrenzung  von  32  verschachtelten  Stufen  an
       Benutzernamensräumen. Aufrufe an unshare(2) oder clone(2), die zum Überschreiten dieser Begrenzung führen
       würden, schlagen mit dem Fehler EUSERS fehl.

       Jeder Prozess ist Mitglied in genau einem Benutzernamensraum. Ein mit  fork(2)  oder  clone(2)  ohne  den
       Schalter  CLONE_NEWUSER  erstellter  Prozess  ist  ein  Mitglied  im gleichen Benutzernamensraum wie sein
       Elternprozess. Ein Prozess mit nur einem  Thread  kann  einem  anderen  Benutzernamensraum  mit  setns(2)
       beitreten,  falls er über CAP_SYS_ADMIN in diesem Namensraum verfügt; wenn er dies durchführt, erlangt er
       den vollständigen Satz an Capabilitys in diesem Namensraum.

       Ein Aufruf von clone(2) oder unshare(2) mit dem Schalter CLONE_NEWUSER führt dazu, dass  der  Kindprozess
       (für  clone(2))  oder der Aufrufende (für unshare(2)) ein Mitglied des neuen, durch den Aufruf erstellten
       Benutzernamensraums wird.

       Die  Aktion  NS_GET_PARENT  ioctl(2)  kann   zum   Erkennen   der   Vorgänger-/Nachfolger-Beziehung   von
       Benutzernamensräumen verwandt werden; siehe ioctl_nfs(2).

       Ein   Task,   der   eine  seiner  effektiven  Kennungen  ändert,  bekommt  sein  »dumpable«  auf  den  in
       /proc/sys/fs/suid_dumpable  angegebenen  Wert  zurückgesetzt.  Dies   kann   die   Eigentümerschaft   von
       Proc-Dateien   von   Kindprozessen   betreffen  und  kann  daher  dazu  führen,  dass  dem  Elternprozess
       Berechtigungen fehlen, um  in  Mapping-Dateien  des  Kindprozesses,  die  in  neuen  Benutzernamensräumen
       ausgeführt  werden,  zu  schreiben.  Das  Problem  kann  korrigiert  werden,  indem  in diesen Fällen der
       Elternprozess mittels PR_SET_DUMPABLE in einem Aufruf von prctl(2) vor der Erstellung  des  Kindprozesses
       in  einem neuen Benutzernamensraum »dumpable« gemacht wird. Siehe prctl(2) und proc(5) zu Details wie die
       Eigentümerschaft betroffen ist.

   Capabilitys
       Der durch clone(2) mit dem Schalter CLONE_NEWUSER erstellte Kindprozess beginnt mit  einem  vollständigen
       Satz  an  Capabilitys  in dem neuen Benutzernamensraum. Entsprechend erlangt ein Prozess, der einen neuen
       Benutzernamensraum mittels unshare(2) erstellt oder ihm mittels setns(2)  beitritt,  einen  vollständigen
       Satz  an  Capabilitys  in  diesem  Namensraum.  Anderserseits hat dieser Prozess keine Capabilitys in dem
       Vorgänger-  (im  Falle  von  clone(2))  oder  vorhergehenden  (im  Falle  von  unshare(2)  und  setns(2))
       Benutzernamensraum,  selbst  falls  der  neue  Namensraum vom Benutzer root erstellt wird oder dieser ihm
       beitritt (d.h. einem Prozess mit der Benutzerkennung 0 im Wurzel-Namensraum).

       Beachten Sie, dass ein Aufruf von execve(2) dazu führt, dass die  Capabilitys  eines  Prozesses  auf  die
       normale  Art  und  Weise  erneut berechnet werden (siehe capabilities(7)). Folglich wird der Prozess alle
       Capabilitys verlieren, außer er hat eine  Benutzerkennung  von  0  innerhalb  des  Namensraums  oder  die
       ausführbare  Datei  hat  eine  vererbbare  Capability-Maske,  die  nicht leer ist. Siehe die nachfolgende
       Diskussion von Benutzer- und Gruppenkennungabbildung.

       Ein Aufruf von clone(2) oder unshare(2) mit dem Schalter CLONE_NEWUSER oder ein Aufruf von setns(2),  der
       den  Aufrufenden  in  einen anderen Benutzernamensraum verschiebt, setzt die Schalter »securebits« (siehe
       capabilities(7)) im Kind (für clone(2)) oder dem Aufrufenden (für  unshare(2)  oder  setns(2))  auf  ihre
       Vorgabewerte  (alle  Schalter  deaktiviert).  Beachten  Sie,  dass  der  Aufrufende nach einem Aufruf von
       setns(2) keine Capabilitys in seinem ursprünglichen Benutzernamensraum mehr hat und es  daher  für  einen
       Prozess   nicht   möglich   ist,  seine  Schalter  »securebits«  zurückzusetzen  und  gleichzeitig  seine
       Mitgliedschaft im Benutzernamensraum zu erhalten, indem ein Paar von setns(2)-Aufrufen verwandt wird,  um
       sich  in  einen  anderen  Benutzernamensraum  zu verschieben und dann zu seinem ursprünglichen Namensraum
       zurückzukehren.

       Die Regeln zur Bestimmung, ob ein Prozess eine Capability in  einem  bestimmten  Benutzernamensraum  hat,
       sind wie folgt:

       •  Ein  Prozess  hat  eine  Capability  innerhalb eines Benutzernamensraums, falls er ein Mitglied dieses
          Namensraums ist und er die Capability in seiner effektiven  Capability-Menge  hat.  Ein  Prozess  kann
          Capabilitys  in  seiner  effektiven  Capability-Menge  auf verschiedene Arten erlangen. Beispielsweise
          könnte er ein set-user-ID-Programm oder eine  ausführbare  Datei  mit  zugeordneten  Datei-Capabilitys
          ausführen.  Zusätzlich  könnte  ein Prozess Capabilitys mittels der bereits beschriebenen Auswirkungen
          von clone(2), unshare(2) oder setns(2) erlangen.

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

       •  Wenn  ein  Benutzernamensraum  erstellt  wird,  zeichnet  der Kernel die effektive Benutzerkennung des
          erstellenden Prozesses als »Eigentümer« des Namensraums auf. Ein Prozess, der sich  im  Vorgänger  des
          Benutzernamensraums  befindet  und  dessen  effektive  Benutzerkennung  auf  die  des  Eigentümers des
          Namensraums passt, hat alle Capabilitys in diesem Namensraum. Dank der vorherigen Regel bedeutet dies,
          dass der Prozess auch über alle Capabilitys in allen weiteren entfernten nachfolgenden  Benutzerräumen
          verfügt.  Die  Aktion NS_GET_OWNER_UID ioctl(2) kann zum Ermitteln der Benutzerkennung des Eigentümers
          des Namensraums verwandt werden; siehe ioctl_nfs(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_nfs(2).

   Benutzer- und Gruppenkennungabbildungen: uid_map und gid_map
       Wenn ein  Benutzernamensraum  erstellt  wird,  beginnt  er  mit  einer  Abbildung  der  Benutzerkennungen
       (Gruppenkennungen) auf die des Vorgängernamensraumes. Die Dateien /proc/PID/uid_map und /proc/PID/gid_map
       (verfügbar  seit  Linux 3.5) legen diese Abbildungen für die Benutzer- und Gruppenkennungen innerhalb des
       Benutzernamensraumes für  den  Prozess  PID  offen.  Diese  Dateien  können  ausgelesen  werden,  um  die
       Abbildungen  innerhalb  eines  Benutzernamensraums  zu  betrachten und (einmal) beschrieben zu werden, um
       diese Abbildungen zu definieren.

       Die Beschreibung in den folgenden Absätzen erklärt die  Details  für  uid_map;  gid_map  ist  vollständig
       identisch, sofern jedes Vorkommen von »Benutzerkennung« durch »Gruppenkennung« ersetzt wird.

       Die  Datei uid_map legt die Abbildung der Benutzerkennung von dem Benutzernamensraum des Prozesses PID in
       den Benutzernamensraum des Prozesses offen,  der  uid_map  öffnete  (siehe  aber  auch  die  nachfolgende
       Qualifizierung   dieses   Punktes).   Mit   anderen   Worten,   Prozesse,   die   sich  in  verschiedenen
       Benutzernamensräumen befinden, werden möglicherweise andere Werte sehen, wenn sie  aus  einer  bestimmten
       Datei  uid_map  lesen, abhängig von der Benutzerkennungsabbildung für den Benutzernamensraum des lesenden
       Prozesses.

       Jede Zeile der Datei uid_map legt eine  1-zu-1-Abbildung  des  Bereichs  fortlaufender  Benutzerkennungen
       zwischen  zwei Benutzernamensräumen fest. (Wenn ein Benutzernamensraum erstmalig erstellt wird, ist diese
       Datei leer.) Die Festlegung in jeder Zeile hat die Form von drei durch Leerraum  getrennten  Zahlen.  Die
       ersten  zwei Zahlen geben die am Anfang befindliche Benutzerkennung in jedem der zwei Benutzernamensräume
       an. Die dritte Zahl gibt die Länge des abgebildeten Bereichs an. Im Detail werden die  Felder  wie  folgt
       interpretiert:

       (1)  Der Anfang des Bereichs von Benutzerkennungen in dem Benutzernamensraum des Prozesses PID.

       (2)  Der  Anfang  des  Bereichs  von  Benutzerkennungen,  auf  die  die  Benutzerkennungen  aus Feld eins
            abgebildet werden. Wie Feld zwei interpretiert wird, hängt davon ab, ob  der  Prozess,  der  uid_map
            öffnete und der Prozess PID sich in dem gleichen Benutzernamensraum befinden, wie folgt:

            (a)  Falls  sich die zwei Prozesse in verschiedenen Benutzernamensräumen befinden: Feld zwei ist der
                 Anfang des Bereichs von Benutzerkennungen in dem Benutzernamensraum des Prozesses, der  uid_map
                 öffnete.

            (b)  Falls  die  zwei  Prozesse  im  gleichen  Benutzernamensraum sind: Feld zwei ist der Anfang des
                 Bereichs von Benutzerkennungen in dem Vorgängerbenutzernamensraum  des  Prozesses  PID.  Dieser
                 Fall  ermöglicht  es  dem  Öffnenden  von  uid_map  (der  typische Fall hier ist das Öffnen von
                 /proc/self/uid_map)  die  Abbildung  der  Benutzerkennungen  in  den   Benutzernamensraum   des
                 Prozesses, der diesen Benutzernamensraum erstellte, zu sehen.

       (3)  Die  Länge des Bereichs von Benutzerkennungen, die zwischen den zwei Benutzernamensräumen abgebildet
            wird.

       Systemaufrufe, die Benutzerkennungen (Gruppenkennungen) zurückliefern–beispielsweise getuid(2), getgid(2)
       und  die  Berechtigungsdatenfelder  in  der  durch   stat(2)   zurückgelieferten   Struktur–liefern   die
       Benutzerkennung (Gruppenkennung) abgebildet auf den Benutzernamensraum des Aufrufenden zurück.

       Wenn  ein  Prozess  auf  eine  Datei zugreift, werden seine Benutzer- und Gruppenkennungen zum Zwecke der
       Zugriffsprüfung und der Zuweisungen von Kennungen beim Erstellen von Dateien  auf  die  des  anfänglichen
       Benutzernamensraumens  abgebildet. Wenn ein Prozess die Dateibenutzer- und -gruppenkennungen über stat(2)
       ermittelt,  werden  die  Kennungen  in  die  andere  Richtung  abgebildet,  um  Werte  relativ   zu   den
       Prozessbenutzer- und -gruppenkennungsabildungen zu erstellen.

       Der  anfängliche  Benutzernamensraum  hat  keinen  Vorgängernamensraum.  Aus Konsistenzgründen stellt der
       Kernel Pseudo-Benutzer- und -Gruppenkennungsabbildungsdateien für  diesen  Namensraum  bereit.  Wird  vom
       anfänglichen Namensraum aus auf die Datei uid_map (gid_map ist identisch) geschaut, ergibt sich:

           $ cat /proc/$$/uid_map
                    0          0 4294967295

       Diese  Abbildung  teilt  uns mit, dass der Bereich bei der Benutzerkennung 0 in diesem Namensraum auf den
       Bereich beginnend bei 0 in dem (nicht existierenden) Vorgängernamensraum abgebildet ist und die Länge des
       Bereichs die größte vorzeichenlose 32-bit-Ganzzahl ist. Dies lässt  4294967295  (der  vorzeichenbehaftete
       32-bit-Wert)  nicht  abgebildet. Dies ist absichtlich: (uid_t) -1 wird von einer Reihe von Schnittstellen
       (z.B. setreuid(2)) dazu verwandt, »keine Benutzerkennung« festzulegen. Da (uid_t) -1 nicht abgebildet und
       unbenutzbar ist, wird sichergestellt, dass es keine Verwirrung bei der Verwendung  dieser  Schnittstellen
       gibt.

   Definieren von Benutzer- und Gruppenkennungsabbildungen; Schreiben in uid_map und gid_map
       Nach der Erstellung eines neuen Benutzernamensraumes kann die Datei uid_map von einem der Prozesse in dem
       Namensraum   einmalig   geschrieben   werden,  um  die  Abbildung  der  Benutzerkennungen  in  dem  neuen
       Benutzernamensraum zu definieren. Jeder  Versuch,  mehr  als  einmal  in  eine  Datei  uid_map  in  einem
       Benutzernamensraum  zu  schreiben,  schlägt mit dem Fehler EPERM fehl. Ähnliche Regeln gelten für Dateien
       gid_map.

       Die in uid_map (gid_map) geschriebenen Zeilen müssen die folgenden Gültigkeitsregeln erfüllen:

       •  Die drei Felder müssen gültige Zahlen sein und das letzte Feld muss größer als 0 sein.

       •  Zeilen werden durch einen Zeilenumbruch beendet.

       •  Es gibt eine Beschränkung bezüglich der Anzahl der Zeilen in der Datei. In Linux 4.14  und  älter  war
          diese  Beschränkung  (willkürlich)  auf  5  Zeilen gesetzt. Seit Linux 4.15 ist diese Beschränkung 340
          Zeilen. Zusätzlich muss die Anzahl an in diese Datei geschriebenen Bytes kleiner als  die  Seitengröße
          des  Systems  sein  und  das  Schreiben muss am Anfang der Datei beginnen (d.h. lseek(2) und pwrite(2)
          können nicht zum Schreiben an einen von Null verschiedenen Versatz in der Datei verwandt werden).

       •  Die Bereiche der Benutzerkennungen (Gruppenkennungen), die in den  einzelnen  Zeilen  angegeben  sind,
          dürfen  sich nicht gegenseitig überlappen. In der anfänglichen Implementierung (Linux 3.8) wurde diese
          Anforderung durch eine simplistische Implementierung erfüllt, die weitere Einschränkungen  auferlegte,
          dass  die  Werte  sowohl  in  Feld  1 als auch Feld 2 von aufeinanderfolgenden Zeilen in aufsteigender
          numerischer Reihenfolge sein mussten, womit andernfalls  gültige  Abbildungen  nicht  erstellt  werden
          konnten.  Linux  3.9  und  neuer  korrigierte  diese  Beschränkung  und  erlaubte jede Kombination von
          nichtüberlappenden Abbildungen.

       •  Mindestens eine Zeile muss in die Datei geschrieben werden.

       Schreibvorgänge, die die obigen Regeln verletzen, schlagen mit dem Fehler EINVAL fehl.

       Damit ein Prozess in die Datei /proc/PID/uid_map (/proc/PID/gid_map)  schreiben  kann,  müssen  alle  der
       folgenden Berechtigungsanforderungen erfüllt sein:

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

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

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

       •  Falls die Aktualisierung von  /proc/PID/uid_map  eine  Abbildung  erstellt,  die  die  UID  0  in  dem
          Vorgängernamensraum abbildet, dann muss eine der folgenden Bedingungen wahr sein:

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

          (b)  falls der schreibende Prozess in  dem  nachfolgenden  Benutzernamensraum  liegt,  dann  muss  der
               Prozess,  der den Benutzernamensraum erstellte, über die Capability CAP_SETFCAP verfügen, als der
               Benutzernamensraum erstellt wurde.

          Diese Regel gibt es seit Linux 5.12. Sie beseitigt einen  älteren  Sicherheitsfehler,  durch  den  ein
          UID-0-Prozess ohne die Capability CAP_SETFCAP (die zum Erstellen eines Programms mit Datei-Capabilitys
          im  Namensraum  benötigt  wird,  wie  das  in  capabilities(7)  beschrieben ist), trotzdem ein solches
          Programm erstellen konnte, indem es Folgendes durchführte:

          (1)  Erstellung eines neuen Benutzernamensraums mit der Identitätsabbildung (d.h. UID 0 in  dem  neuen
               Benutzernamensraum  wird  auf  UID  0 im Vorgängernamensraum abgebildet), so dass UID 0 in beiden
               Namensräumen äquivalent zu der gleichen Root-Benutzerkennung ist.

          (2)  Da der Nachfolgerprozess über die Capability CAP_SETFCAP verfügt, könnte er ein Programm mit  den
               Datei-Capabilitys  im Namensraum erstellen, die auch im Vorgängernamensraum wirksam wären (da die
               Root-Benutzerkennungen in beiden Namensräumen identisch sind).

       •  Einer der folgenden zwei Fälle trifft zu:

          (a)  Entweder verfügt der schreibende Prozess über  die  Capability  CAP_SETUID  (CAP_SETGID)  in  dem
               Vorgängernamensraum.

               •  Es  gelten  keine  weiteren  Einschränkungen;  der  Prozess  kann  Abbildungen  auf  beliebige
                  Benutzerkennungen (Gruppenkennungen) im Vorgängernamensraum durchführen.

          (b)  Oder es gelten alle der folgenden Beschränkungen:

               •  Die in uid_map (gid_map) geschriebenen Daten müssen aus einer einzelnen  Zeile  bestehen,  die
                  die   effektive   Benutzerkennung   (Gruppenkennung)   des   schreibenden   Prozesses  in  dem
                  Vorgängernamensraum  auf  eine  Benutzerkennung  (Gruppenkennung)  in  den  Benutzernamensraum
                  abbildet.

               •  Der  schreibende Prozess muss die gleiche effektive Benutzerkennung wie der Prozess haben, der
                  den Benutzernamensraum erstellte.

               •  Im Falle von gid_map muss  zuerst  die  Verwendung  des  Systemaufrufs  setgroups(2)  verboten
                  werden, indem »deny« in die Datei /proc/PID/setgroups geschrieben wird (siehe unten), bevor in
                  gid_map geschrieben wird.

       Schreibaktionen, die die obigen Regeln verletzen, werden mit EPERM fehlschlagen.

   Projektkennungsabbildung: projid_map
       Ähnlich  zu  Benutzer-  und  Gruppenkennungsabbildungen ist es möglich, eine Projektkennungsabbildung für
       einen Benutzernamensraum zu erstellen. (Projektkennungen werden für  Plattenkontingente  verwandt,  siehe
       setquota(8) und quotactl(2).)

       Projektkennungsabbildungen  werden durch Schreiben in die Datei /proc/PID/projid_map definiert (vorhanden
       seit Linux 3.7).

       Die Gültigkeitsregeln für das Schreiben in die Datei /proc/PID/projid_map sind wie beim Schreiben in  die
       Datei uid_map; Verletzung dieser Regeln führt beim write(2) zum Fehlschlag EINVAL.

       Die Erlaubnisregeln für das Schreiben in die Datei /proc/PID/projid_map sind wie folgt:

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

       •  Die abgebildeten Projektkennungen müssen wiederum eine Abbildung im Vorgängernamensraum haben.

       Verletzung dieser Regeln führt dazu, dass write(2) mit EPERM fehlschlägt.

   Wechselwirkung mit Systemaufrufen, die Prozessbenutzerkennungen oder -gruppenkennungen ändern
       In einem Benutzernamensraum,  in  dem  die  Datei  uid_map  noch  nicht  geschrieben  wurde,  werden  die
       Systemaufrufe,  die  die  Benutzerkennung ändern, fehlschlagen. Ähnlich werden die Systemaufrufe, die die
       Gruppenkennungen ändern, fehlschlagen, falls die Datei gid_map noch nicht geschrieben wurde. Nachdem  die
       Dateien  uid_map  und  gid_map  geschrieben  wurden,  können nur die abgebildeten Werte in Systemaufrufen
       verwandt werden, die die Benutzer- und Gruppenkennungen ändern.

       Für Benutzerkennungen sind die relevanten Systemaufrufe unter anderem setuid(2), setfsuid(2), setreuid(2)
       und setresuid(2). Für  Gruppenkennungen  sind  die  relevanten  Systemaufrufe  unter  anderem  setgid(2),
       setfsgid(2), setregid(2), setresgid(2) und setgroups(2).

       Durch  Schreiben von »deny« in die Datei /proc/PID/setgroups vor dem Schreiben von /proc/PID/gid_map wird
       setgroups(2)  in   einem   Benutzernamensraum   dauerhaft   deaktiviert   und   erlaubt   Schreiben   von
       /proc/PID/gid_map, ohne über die Capability CAP_SETGID im Vorgängernamensraum zu verfügen.

   Die Datei /proc/PID/setgroups
       Die  Datei  /proc/PID/setgroups zeigt die Zeichenkette »allow«, falls Prozesse in dem Benutzernamensraum,
       der den Prozess PID enthält, die Erlaubnis haben, den Systemaufruf setgroups(2)  einzusetzen.  Sie  zeigt
       »deny«  an, falls setgroups(2) in diesem Benutzernamensraum nicht erlaubt ist. Beachten Sie, dass Aufrufe
       von setgroups(2) auch nicht erlaubt sind, falls /proc/PID/gid_map noch nicht  gesetzt  wurde,  unabhängig
       von dem Wert der Datei /proc/PID/setgroups (und unabhängig von den Capabilitys des Prozesses).

       Ein  privilegierter  Prozess  (einer  mit  der  Capability CAP_SYS_ADMIN in dem Namensraum) darf eine der
       Zeichenketten »allow« oder »deny« in diese  Datei  schreiben,  bevor  eine  Gruppenkennungsabbildung  für
       diesen   Benutzernamensraum  in  die  Datei  /proc/PID/gid_map  geschrieben  wird.  Durch  Schreiben  der
       Zeichenkette »deny« wird  jedem  Prozess  in  diesem  Benutzernamensraum  der  Einsatz  von  setgroups(2)
       verboten.

       Die  Essenz  der  in  den vorhergehenden Absätzen beschriebenen Beschränkungen ist, dass das Schreiben in
       /proc/PID/setgroups nur so lange erlaubt ist, wie setgroups(2) nicht erlaubt  ist,  da  /proc/PID/gid_map
       noch  nicht  gesetzt  wurde. Damit wird sichergestellt, dass ein Prozess nicht von einem Zustand, bei dem
       setgroups(2) erlaubt ist, zu einem Zustand, bei  dem  setgroups(2)  verboten  ist,  übergehen  kann;  ein
       Prozess kann nur von setgroups(2) nicht erlaubt zu setgroups(2) erlaubt übergehen.

       Der Vorgabewert für diese Datei in dem anfänglichen Namensraum ist »allow«.

       Sobald  /proc/PID/gid_map  geschrieben  wurde  (wodurch  setgroups(2) in dem Benutzernamensraum aktiviert
       wird), ist es nicht mehr möglich, setgroups(2) durch  Schreiben  von  »deny«  in  /proc/PID/setgroups  zu
       verbieten (das Schreiben schlägt mit EPERM fehl).

       Ein Nachfolgernamensraum erbt die Einstellungen /proc/PID/setgroups von seinem Vorgänger.

       Falls  die  Datei  setgroups  den  Wert »deny« enthält, dann kann der Systemaufruf setgroups(2) in diesem
       Namensraum nachfolgend nicht mehr aktiviert werden (durch Schreiben von »allow« in die Datei). (Versuche,
       dies   durchzuführen,   schlagen   mit   EPERM   fehl.)   Diese   Beschränkung   wird   auch   an    alle
       Nachfolgerbenutzernamensräume dieses Benutzernamensraums weitergeleitet.

       Die  Datei  /proc/PID/setgroups  wurde  in  Linux  3.19  hinzugefügt; allerdings wurde sie auch auf viele
       frühere stabile Kernel rückportiert, da sie ein Sicherheitsproblem adressiert. Das Problem betraf Dateien
       mit Berechtigungen wie »rwx---rwx«. Diese Dateien geben  der  »Gruppe«  weniger  Berechtigungen  als  sie
       »anderen«  geben.  Das  bedeutet,  dass  die  Abgabe  von  Gruppen  mittels  setgroups(2)  einem  Prozess
       Dateizugriff erlauben könnte, den er vorher nicht hatte. Vor der Existenz von Benutzernamensräumen führte
       dies zu  keine  Sorgen,  da  nur  ein  privilegierter  Prozess  (einer  mit  der  Capability  CAP_SETGID)
       setgroups(2)  aufrufen  konnte.  Mit  der  Einführung  von  Benutzernamensräumen wurde es für einen nicht
       privilegierten Prozess allerdings möglich, einen neuen Namensraum zu erstellen, in dem der Benutzer  alle
       Privilegien  hatte.  Dies ermöglichte es dann vorher nicht privilegierten Benutzern Gruppen abzugeben und
       damit Dateizugriff zu erlangen,  den  sie  vorher  nicht  hatten.  Die  Datei  /proc/PID/setgroups  wurde
       hinzugefügt, um dieses Sicherheitsproblem zu adressieren, indem jeder Pfad für einen nicht privilegierten
       Prozess, Gruppen mit setgroups(2) abzugeben, verboten wurde.

   Nicht abgebildete Benutzer- und Gruppenkennungen
       Es  gibt  verschiedene  Stellen,  an  denen  nicht  abgebildete  Benutzerkennungen  (Gruppenkennungen) im
       Anwendungsraum offengelegt werden  können.  Beispielsweise  könnte  der  erste  Prozess  in  einem  neuen
       Benutzernamensraum  getuid(2) aufrufen, bevor eine Benutzerkennungsabbildung für den Namensraum definiert
       wurde.  In  den  meisten  solcher  Fälle   wird   eine   nicht   abgebildete   Benutzerkennung   in   die
       Überlauf-Benutzerkennung  (Gruppenkennung)  konvertiert; der Vorgabewert für die Überlauf-Benutzerkennung
       (Gruppenkennung)   ist   65534.   Siehe   die   Beschreibung   von    /proc/sys/kernel/overflowuid    und
       /proc/sys/kernel/overflowgid in proc(5).

       Zu  den  Fällen,  in  denen  nicht abgebildete Benutzerkennungen auf diese Art abgebildet werden, gehören
       Systemaufrufe,   die   Benutzerkennungen   zurückliefern    (getuid(2),    getgid(2)    und    ähnliche),
       Benutzerberechtigungen, die über ein UNIX-Domain-Socket übergeben werden, Benutzerberechtigungen, die von
       stat(2),    waitid(2)    und    den    System-V-IPC-»ctl«-IPC_STAT-Aktionen    zurückgeliefert    werden,
       Benutzerberechtigungen, die mittels /proc/PID/status  und  den  Dateien  in  /proc/sysvipc/*  offengelegt
       werden,  Benutzerberechtigungen,  die  über das Feld si_uid in dem mit einem Signal siginfo_t empfangenen
       Feld   zurückgeliefert   werden   (siehe    sigaction(2)),    Benutzerberechtigungen,    die    in    die
       Prozessbuchhaltungsdatei   geschrieben   werden  (siehe  acct(5))  und  Benutzerberechtigungen,  die  mit
       POSIX-Nachrichtenwarteschlangen-Benachrichtigungen zurückgeliefert werden (siehe mq_notify(3)).

       Es gibt einen erwähnenswerten Fall, bei dem nicht abgebildete Benutzer- und Gruppenkennungen nicht in die
       entsprechende Überlaufkennung konvertiert werden. Beim Betrachten einer Datei uid_map oder  gid_map,  bei
       der es keine Abbildung für das zweite Feld gibt, wird das Feld als 4294967295 (-1 als eine vorzeichenlose
       Ganzzahl) dargestellt.

   Dateizugriff
       Um Berechtigungen zu bestimmen, wenn ein nicht privilegierter Prozess auf eine Datei zugreift, werden die
       Prozessberechtigungen  (UID,  GID) und die Dateiberechtigungen letztendlich auf die zurückabgebildet, die
       sie im anfänglichen Benutzernamensraum wären und dann verglichen, um die Berechtigungen zu bestimmen, die
       der Prozess auf die Datei hat. Das gleiche trifft auch für andere Objekte zu, die das Zugriffsmodell  mit
       Benutzerberechtigungen sowie Berechtigungsmasken einsetzen, wie System-V-IPC-Objekte.

   Aktionen mit Datei-bezogenen Capabilitys
       Bestimmte   Capabilitys   erlauben  es  einem  Prozess,  verschiedene,  durch  den  Kernel  durchgesetzte
       Beschränkungen zu umgehen, wenn Aktionen auf Dateien durchgeführt  werden,  die  anderen  Benutzern  oder
       Gruppen  gehören. Diese Capabilitys sind CAP_CHOWN, CAP_DAC_OVERRIDE, CAP_DAC_READ_SEARCH, CAP_FOWNER und
       CAP_FSETID.

       Innerhalb eines Benutzernamensraumes erlauben diese Capabilitys einem Prozess,  die  Regeln  zu  umgehen,
       falls der Prozess über die relevante Capability über die Datei verfügt. Das bedeutet:

       •  Der Prozess hat die relevante effektive Capability in seinem eigenen Benutzernamensraum; und

       •  die Benutzer- und Gruppenkennung der Datei habe beide gültige Abbildungen in dem Benutzernamensraum.

       Die  Capability  CAP_FOWNER wird etwas besonders behandelt: sie erlaubt einem Prozess, die entsprechenden
       Regeln zu  umgehen,  solange  zumindest  die  Benutzerkennung  der  Datei  über  eine  Abbildung  in  dem
       Benutzernamensraum verfügt (d.h. die Gruppenkennung der Datei benötigt keine gültige Abbildung).

   Set-user-ID- und set-group-ID-Programme
       Wenn  ein  Prozess innerhalb eines Benutzernamensraums ein set-user-ID- (set-group-ID)-Programm ausführt,
       wird die effektive Benutzer- (Gruppen-)Kennung des Prozesses innerhalb  des  Namensraums  auf  denjenigen
       Wert geändert, der für die Benutzer- (Gruppen)kennung der Datei abgebildet ist. Falls allerdings entweder
       die  Benutzer-  oder die Gruppenkennung der Datei über keine Abbildung innerhalb des Namensraums verfügt,
       wird das set-user-ID- (set-group-ID-)Bit ohne Rückmeldung ignoriert: das neue Programm  wird  ausgeführt,
       aber  die  effektive  Benutzer-  (Gruppen-)Kennung  des  Prozesses bleibt unverändert. (Dies spiegelt die
       Semantik bei der Ausführung eines set-user-ID- oder set-group-ID-Programmes wider,  das  sich  auf  einem
       Dateisystem  befindet,  das mit dem Schalter MS_NOSUID eingehängt wurde, wie dies in mount(2) beschrieben
       ist.)

   Verschiedenes
       Wenn die Benutzer- und Gruppenkennungen eines Prozesses über ein UNIX-Domain-Socket an einen  Prozess  in
       einem  anderen  Benutzernamensraum  übergeben  werden  (siehe  die  Beschreibung  von  SCM_CREDENTIALS in
       unix(7)), werden sie in  die  entsprechenden  Werte  der  Benutzer-  und  Gruppenkennungsabbildungen  des
       empfangenen Prozesses übersetzt.

STANDARDS

       Linux.

ANMERKUNGEN

       Über  die  Jahre  wurden  eine  Reihe  von  Funktionalitäten  zu  dem  Linux-Kernel  hinzugefügt, die nur
       privilegierten Benutzern verfügbar gemacht wurden,  da  sie  möglicherweise  set-user-ID-root-Anwendungen
       durcheinander   bringen   könnten.   Im   Allgemeinen  wird  es  sicher,  einem  Root-Benutzer  in  einem
       Benutzernamensraum die Verwendung  dieser  Funktionalitäten  zu  erlauben,  da  es  unmöglich  ist,  mehr
       Privilegien  zu  erlangen,  als  der  Root-Benutzer innerhalb eines Benutzernamensraumes hat, während der
       Prozess im Benutzernamensraum ist.

   Globaler Root
       Der Ausdruck »Globaler Root« wird manchmal als  Abkürzung  für  die  Benutzerkennung  0  im  anfänglichen
       Benutzernamensraum verwandt.

   Verfügbarkeit
       Die  Verwendung  von  Benutzernamensräumen  benötigt  einen  Kernel,  der  mit  der Option CONFIG_USER_NS
       konfiguriert ist. Benutzernamensräume benötigen die Unterstützung in einer ganzen Reihe  von  Subsystemen
       im  Kernel. Wird ein nicht unterstütztes Subsystem in den Kernel konfiguriert, dann ist es nicht möglich,
       die Unterstützung von Benutzernamensräumen zu konfigurieren.

       Seit Linux  3.8  unterstützen  die  wichtigsten  Subsysteme  Benutzernamensräume,  aber  eine  Reihe  von
       Dateisystemen  hatten  noch nicht die benötigte Infrastruktur, um Benutzer- und Gruppenkennungen zwischen
       Benutzernamensräumen abzubilden. Linux 3.9 fügte die benötigte Infrastruktur für viele der  verbliebenen,
       nicht unterstützten Dateisysteme (Plan 9 (9P), Andrew File System (AFS), Ceph, CIFS, CODA, NFS und OCFS2)
       hinzu. Linux 3.12 fügte Unterstützung für das letzte große verbliebene und nicht unterstützte Dateisystem
       hinzu: XFS.

BEISPIELE

       Das  nachfolgende  Programm  ist  zum  Experimentieren  mit  Benutzernamensräumen sowie anderen Arten von
       Namensräumen gedacht. Es erstellt einen Namensraum, wie er über die Befehlszeilenoptionen angegeben  ist,
       und  führt  dann  innerhalb  dieser Namensräume einen Befehl aus. Die Kommentare und die Funktion usage()
       innerhalb des Programmes bieten eine vollständige Erklärung des Programms. Die nachfolgende Shell-Sitzung
       zeigt seine Verwendung.

       Zuerst schauen wir auf die Laufzeitumgebung:

           $ uname -rs     # Benötigt Linux 3.8 oder neuer
           Linux 3.8.0
           $ id -u         # Ausführung als nicht privilegierter Benutzer
           1000
           $ id -g
           1000

       Jetzt wird eine neue Shell in neuen Benutzer- (-U), Einhänge- (-m) und PID- (-p) Namensräumen  gestartet,
       wobei  innerhalb  des  Benutzernamensraums  die  Benutzerkennung  (-M) und Gruppenkennung (-G) 1000 auf 0
       abgebildet wird:

           $ ./userns_child_exec -p -m -U -M '0 1000 1' -G '0 1000 1' bash

       Diese Shell hat PID 1, da sie der erste Prozess in dem neuen PID-Namensraum ist:

           bash$ echo $$
           1

       Wird ein neues Dateisystem /proc eingehängt und alle in  dem  neuen  PID-Namensraum  sichtbaren  Prozesse
       aufgelistet,  kann gesehen werden, dass die Shell keinerlei Prozesse außerhalb des PID-Namensraumes sehen
       kann:

           bash$ mount -t proc proc /proc
           bash$ ps ax
             PID TTY      STAT   TIME COMMAND
               1 pts/3    S      0:00 bash
              22 pts/3    R+     0:00 ps ax

       Innerhalb des Benutzernamensraumes hat die Shell die Benutzer- und Gruppenkennung 0 und eine vollständige
       Menge an erlaubten und effektiven Capabilitys:

           bash$ cat /proc/$$/status | egrep '^[UG]id'
           Uid: 0    0    0    0
           Gid: 0    0    0    0
           bash$ cat /proc/$$/status | egrep '^Cap(Prm|Inh|Eff)'
           CapInh:   0000000000000000
           CapPrm:   0000001fffffffff
           CapEff:   0000001fffffffff

   Programmquelltext

       /* userns_child_exec.c

          Lizenziert unter der GNU General Public License v2 oder neuer

          Erzeugt einen Kindprozess, der einen Shell-Befehl in einem oder mehreren
          neuen Namensräumen ausführt; erlaubt UID- und GID-Abbildungen anzugeben,
          wenn ein Benutzernamensraum erstellt wird
       */
       #define _GNU_SOURCE
       #include <err.h>
       #include <sched.h>
       #include <unistd.h>
       #include <stdint.h>
       #include <stdlib.h>
       #include <sys/wait.h>
       #include <signal.h>
       #include <fcntl.h>
       #include <stdio.h>
       #include <string.h>
       #include <limits.h>
       #include <errno.h>

       struct child_args {
           char **argv;        /* Vom Kind auszuführender Befehl, mit Argumenten */
           int    pipe_fd[2];  /* Zur Sychronisation Eltern/Kind verwandte Pipe */
       };

       static int verbose;

       static void
       usage(char *pname)
       {
           fprintf(stderr, "Aufruf: %s [Optionen] Bef [Arg…]\n\n", pname);
           fprintf(stderr, "Erstellt einen Kindprozess, der einen Shellbefehl "
                   "in einem neuen Benutzernamensraum ausführt\n"
                   "und möglicherweise auch anderen neuen Namensräumen.\n\n");
           fprintf(stderr, "Optionen können sein:\n\n");
       #define fpe(str) fprintf(stderr, "    %s", str);
           fpe("-i          Neuer IPC-Namensraum\n");
           fpe("-m          Neuer Einhänge-Namensraum\n");
           fpe("-n          Neuer Netzwerk-Namensraum\n");
           fpe("-p          Neuer PID-Namensraum\n");
           fpe("-u          Neuer UTS-Namensraum\n");
           fpe("-U          Neuer Benutzernamensraum\n");
           fpe("-M uid_map  Angabe einer UID-Abbildung für Benutzernamensraum\n");
           fpe("-G gid_map  Angabe einer GID-Abbildung für Benutzernamensraum\n");
           fpe("-z          Benutzer-UID und -GID auf 0 im Benutzernamensraum abbilden\n");
           fpe("            (äquivalent zu: -M '0 <uid> 1' -G '0 <gid> 1')\n");
           fpe("-v          Anzeige ausführlicher Meldungen\n");
           fpe("\n");
           fpe("Falls -z, -M oder -G angegeben wird, ist -U verpflichtend.\n");
           fpe("Es ist nicht erlaubt, sowohl -z als auch entweder -M oder -G anzugeben.\n");
           fpe("\n");
           fpe("Abbildungszeichenketten für -M und -G bestehen aus Datensätzen der folgenden Form:\n");
           fpe("\n");
           fpe("    Namensrauminterne-Kennung   Namensraumexterne-Kennung   Länge\n");
           fpe("\n");
           fpe("Eine Abbildungszeichenkette kann mehrere Datensätze enthalten,"
               " getrennt durch Kommata;\n");
           fpe("die Kommata werden vor dem Schreiben in die Abbildungsdateien durch"
               " Zeilenumbrüche ersetzt.\n");

           exit(EXIT_FAILURE);
       }

       /* Aktualisiert die Abbildungsdatei »map_file« mit dem in »mapping«
          bereitgestellten Wert, einer Zeichenkette, die eine UID- oder GID-
          Abbildung definiert. Eine UID- oder GID-Abbildung besteht aus einem oder
          mehreren, durch Zeilenumbrüche getrennten Datensätzen der folgenden Form:

              Namensrauminterne-Kennung   Namensraumexterne-Kennung   Länge

          Für die Befehlszeile zu verlangen, dass Zeichenketten mit Zeilenumbrüchen
          bereitgestellt werden, ist natürlich unbequem. Daher erlauben wir die
          Verwendung von Kommata zur Begrenzung von Datensätzen in dieser
          Zeichenkette und ersetzen sie vor dem Schreiben in die Datei durch
          Zeilenumbrüche. */

       static void
       update_map(char *mapping, char *map_file)
       {
           int fd;
           size_t map_len;     /* Länge der »mapping« */

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

           map_len = strlen(mapping);
           for (size_t j = 0; j < map_len; j++)
               if (mapping[j] == ',')
                   mapping[j] = '\n';

           fd = open(map_file, O_RDWR);
           if (fd == -1) {
               fprintf(stderr, "FEHLER: open %s: %s\n", map_file,
                       strerror(errno));
               exit(EXIT_FAILURE);
           }

           if (write(fd, mapping, map_len) != map_len) {
               fprintf(stderr, "FEHLER: write %s: %s\n", map_file,
                       strerror(errno));
               exit(EXIT_FAILURE);
           }

           close(fd);
       }

       /* Linux 3.19 änderte die Handhabung von setgroups(2) und die Datei
          »gid_map«, um ein Sicherheitsproblem zu adressieren. Das Problem erlaubte
          *nicht privilegierten* Benutzern einen Benutzernamensraum einzusetzen, um
          Gruppen abzugeben. Das Fazit der 3.19er Änderung ist, dass die Verwendung
          des Systemaufrufs setgroups() in diesem Benutzernamensraum zuerst durch
          Schreiben von »deny« in eine der Dateien /proc/PID/setgroups für diesen
          Namensraum erfolgen muss, damit die Datei »gid_maps« aktualisert wird.
          Das ist der Zweck der folgenden Funktion. */

       static void
       proc_setgroups_write(pid_t child_pid, char *str)
       {
           char setgroups_path[PATH_MAX];
           int fd;

           snprintf(setgroups_path, PATH_MAX, "/proc/%jd/setgroups",
                   (intmax_t) child_pid);

           fd = open(setgroups_path, O_RDWR);
           if (fd == -1) {

               /* Vielleicht sind wir auf einem System, das /proc/PID/setgroups
                  nicht unterstützt. Dann wird diese Datei nicht existieren und das
                  System wird nicht die Beschränkungen erzwingen, die Linux 3.19
                  hinzugefügt hat. Das ist OK, wir brauchen nichts zu machen, damit
                  »gid_map« aktualisiert wird.

                  Falls allerdings der Fehler von open() sich von ENOENT
                  unterscheidet (der in diesem Fall zu erwarten ist), informieren
                  wir den Benutzer. */

               if (errno != ENOENT)
                   fprintf(stderr, "FEHLER: open %s: %s\n", setgroups_path,
                       strerror(errno));
               return;
           }

           if (write(fd, str, strlen(str)) == -1)
               fprintf(stderr, "FEHLER: write %s: %s\n", setgroups_path,
                   strerror(errno));

           close(fd);
       }

       static int              /* Funktion für geklontes Kind starten */
       childFunc(void *arg)
       {
           struct child_args *args = arg;
           char ch;

           /* Warten, bis der Elternprozess seine UID- und GID-Abbildungen
              aktualisiert hat. Siehe den Kommentar in main(). Wir warten, bis
              auf einer Pipe das Dateiende kommt, die vom Elternprozess geschlossen
              wird, sobald er seine Abbildungen aktualisiert hat. */

           close(args->pipe_fd[1]);    /* Unseren Deskriptor für das Ende des
                                              Schreibens schließen, so dass wir EOF
                                              sehen, wenn der Elternprozess seinen
                                              Deskriptor schließt. */
           if (read(args->pipe_fd[0], &ch, 1) != 0) {
               fprintf(stderr,
                       "Fehler im Kind: Lesen von der Pipe lieferte != 0\n");
               exit(EXIT_FAILURE);
           }

           close(args->pipe_fd[0]);

           /* Einen Shell-Befehl ausführen. */

           printf("Gleich wird exec %s ausgeführt\n", args->argv[0]);
           execvp(args->argv[0], args->argv);
           err(EXIT_FAILURE, "execvp");
       }

       #define STACK_SIZE (1024 * 1024)

       static char child_stack[STACK_SIZE];    /* Platz für den Stack des Kindes */

       int
       main(int argc, char *argv[])
       {
           int flags, opt, map_zero;
           pid_t child_pid;
           struct child_args args;
           char *uid_map, *gid_map;
           const int MAP_BUF_SIZE = 100;
           char map_buf[MAP_BUF_SIZE];
           char map_path[PATH_MAX];

           /* Befehlszeilenoptionen auswerten. Das anfängliche »+«-Zeichen in dem
              abschließenden getopt()-Argument verhindert GNU-artige Vertauschungen
              der Befehlszeilenoptionen. Das ist nützlich, da manchmal der von
              diesem Programm selbst ausgeführte »Befehl« über Befehlszeilenoptionen
              verfügt. Wir wollen nicht, dass getopt() solche als Optionen für
              dieses Programm behandelt. */

           flags = 0;
           verbose = 0;
           gid_map = NULL;
           uid_map = NULL;
           map_zero = 0;
           while ((opt = getopt(argc, argv, "+imnpuUM:G:zv")) != -1) {
               switch (opt) {
               case 'i': flags |= CLONE_NEWIPC;        break;
               case 'm': flags |= CLONE_NEWNS;         break;
               case 'n': flags |= CLONE_NEWNET;        break;
               case 'p': flags |= CLONE_NEWPID;        break;
               case 'u': flags |= CLONE_NEWUTS;        break;
               case 'v': verbose = 1;                  break;
               case 'z': map_zero = 1;                 break;
               case 'M': uid_map = optarg;             break;
               case 'G': gid_map = optarg;             break;
               case 'U': flags |= CLONE_NEWUSER;       break;
               default:  usage(argv[0]);
               }
           }

           /* -M oder -G ohne -U ist sinnlos */

           if (((uid_map != NULL || gid_map != NULL || map_zero) &&
                       !(flags & CLONE_NEWUSER)) ||
                   (map_zero && (uid_map != NULL || gid_map != NULL)))
               usage(argv[0]);

           args.argv = &argv[optind];

           /* Wir verwenden eine Pipe, um den Eltern- und Kindprozess zu
              synchronisieren, damit sichergestellt wird, dass der Elternprozess
              die UID- und GID-Abbildungen einrichtet, bevor der Kindprozess
              execve() aufruft. Dies stellt sicher, dass das Kind seine Capabilitys
              während des execve() erhält, wenn der typische Fall vorliegt, dass
              wir möchten, dass die effektive Benutzerkennung des Kindprozesses auf
              0 in dem neuen Benutzernamensraum abgebildet wird. Ohne diese
              Synchronisation würde der Kindprozess seine Capabilitys verlieren,
              falls es ein execve() mit einer von Null verschiedenen Benutzerkennung
              durchführen würde (siehe die Handbuchseite capabilities(7) für Details
              des Übergangs der Capabilitys eines Prozesses während execve()). */

           if (pipe(args.pipe_fd) == -1)
               err(EXIT_FAILURE, "pipe");

           /* Den Kindprozess in dem oder den neuen Namensraum/-räumen erstellen. */

           child_pid = clone(childFunc, child_stack + STACK_SIZE,
                             flags | SIGCHLD, &args);
           if (child_pid == -1)
               err(EXIT_FAILURE, "clone");

           /* Elternprozess fällt bis hierher durch. */

           if (verbose)
               printf("%s: PID des durch clone() erstellten Kindprozesses lautet %jd\n",
                       argv[0], (intmax_t) child_pid);

           /* Die UID- und GID-Abbildungen in dem Kindprozess aktualisieren. */

           if (uid_map != NULL || map_zero) {
               snprintf(map_path, PATH_MAX, "/proc/%jd/uid_map",
                       (intmax_t) child_pid);
               if (map_zero) {
                   snprintf(map_buf, MAP_BUF_SIZE, "0 %jd 1",
                           (intmax_t) getuid());
                   uid_map = map_buf;
               }
               update_map(uid_map, map_path);
           }

           if (gid_map != NULL || map_zero) {
               proc_setgroups_write(child_pid, "deny");

               snprintf(map_path, PATH_MAX, "/proc/%jd/gid_map",
                       (intmax_t) child_pid);
               if (map_zero) {
                   snprintf(map_buf, MAP_BUF_SIZE, "0 %ld 1",
                           (intmax_t) getgid());
                   gid_map = map_buf;
               }
               update_map(gid_map, map_path);
           }

           /* Das Schreibe-Ende der Pipe schließen, um dem Kindprozess zu
              signalisieren, dass wir die UID- und GID-Abbildungen aktualisiert
              haben. */

           close(args.pipe_fd[1]);

           if (waitpid(child_pid, NULL, 0) == -1)      /* Warten auf Kindprozess */
               err(EXIT_FAILURE, "waitpid");

           if (verbose)
               printf("%s: beende\n", argv[0]);

           exit(EXIT_SUCCESS);
       }

SIEHE AUCH

       newgidmap(1), newuidmap(1), clone(2), ptrace(2), setns(2),  unshare(2),  proc(5),  subgid(5),  subuid(5),
       capabilities(7), cgroup_namespaces(7), credentials(7), namespaces(7), pid_namespaces(7)

       Die Kernelquelldatei Documentation/admin-guide/namespaces/resource-control.rst.

ÜBERSETZUNG

       Die deutsche Übersetzung dieser Handbuchseite wurde von Helge Kreutzmann <debian@helgefjell.de> erstellt.

       Diese  Übersetzung ist Freie Dokumentation; lesen Sie die GNU General Public License Version 3 oder neuer
       bezüglich der Copyright-Bedingungen. Es wird KEINE HAFTUNG übernommen.

       Wenn Sie Fehler in der Übersetzung dieser Handbuchseite finden, schicken Sie bitte  eine  E-Mail  an  die
       Mailingliste der Übersetzer.

Linux man-pages 6.9.1                             15. Juni 2024                               user_namespaces(7)