Kurz gesagt über Linux-Berechtigungen (Funktionen)

Eine Übersetzung des Artikels wurde speziell für Studenten des Linux Administrator- Kurses erstellt.


Dank SystemD, Docker und Orchestratoren wie Kubernetes werden Funktionen immer häufiger genutzt. Wie mir scheint, ist die Dokumentation jedoch etwas schwer zu verstehen, und einige Teile der Implementierung von Berechtigungen erwiesen sich für mich als etwas verwirrend. Deshalb habe ich beschlossen, mein aktuelles Wissen in diesem kurzen Artikel zu teilen.



Der wichtigste Berechtigungslink ist die Manpage zu Funktionen (7) . Für eine erste Bekanntschaft ist sie jedoch nicht sehr geeignet.

Prozessfähigkeiten


Die Rechte gewöhnlicher Benutzer sind sehr begrenzt, während die Rechte des "Root" -Nutzers sehr umfangreich sind. Obwohl Prozesse, die als "root" ausgeführt werden, häufig nicht alle Root-Berechtigungen erfordern.

Um die Root-Benutzerrechte zu verringern, bieten POSIX-Berechtigungen (POSIX-Funktionen) eine Möglichkeit, die Gruppen privilegierter Systemvorgänge einzuschränken, die ein Prozess und seine Nachkommen ausführen dürfen. Im Wesentlichen teilen sie alle "Root" -Rechte in eine Reihe separater Berechtigungen auf. Die Idee der Fähigkeiten wurde 1997 in einem Entwurf von POSIX 1003.1e beschrieben.

Unter Linux hat jeder Prozess (Aufgabe) fünf 64-Bit-Nummern (Sätze), die Berechtigungsbits enthalten (vor Linux 2.6.25 waren sie 32-Bit), die in angezeigt werden können
  / proc / <pid> / status 
.

CapInh: 00000000000004c0 CapPrm: 00000000000004c0 CapEff: 00000000000004c0 CapBnd: 00000000000004c0 CapAmb: 0000000000000000 

Diese Zahlen (hier in hexadezimaler Schreibweise dargestellt) sind Bitmaps, in denen Berechtigungssätze dargestellt werden. Hier sind ihre vollständigen Namen:

  • Vererbbar - Berechtigungen, die Nachkommen erben können
  • Zulässig - Berechtigungen, die von der Aufgabe verwendet werden können.
  • Effektiv - Aktuelle effektive Berechtigungen
  • Bounding - Vor Linux 2.6.25 war der Bounding-Satz ein systemweites Attribut, das allen Threads gemeinsam war und einen Satz beschreibt, über den hinaus die Berechtigungen nicht erweitert werden konnten. Dies ist derzeit ein Satz für jede Aufgabe und nur ein Teil der Ausführungslogik (Details unten).
  • Ambient (extern seit Linux 4.3) - hinzugefügt, um es einfacher zu machen, dem Benutzer Nicht-Root-Berechtigungen bereitzustellen, ohne Setuid- oder Dateiberechtigungen zu verwenden (dazu später mehr).

Wenn eine Task eine privilegierte Operation anfordert (z. B. Bindung an Ports <1024), überprüft der Kernel den aktuellen Begrenzungssatz für CAP_NET_BIND_SERVICE . Wenn es installiert ist, wird der Vorgang fortgesetzt. Andernfalls wird die Operation mit EPERM abgelehnt (Operation nicht zulässig). Diese CAP_ im Kernel-Quellcode definiert und fortlaufend nummeriert, sodass CAP_NET_BIND_SERVICE gleich 10 Bit 1 << 10 = 0x400 bedeutet (dies ist die hexadezimale Ziffer „4“ in meinem vorherigen Beispiel).

Eine vollständige, für Menschen lesbare Liste der derzeit definierten Berechtigungen finden Sie in der Manpage zu den aktuellen Funktionen (7) (die Liste hier dient nur als Referenz).

Darüber hinaus gibt es eine libcap-Bibliothek, um die Verwaltung und Autorisierungsprüfungen zu vereinfachen. Neben der Bibliotheks-API enthält das Paket das Dienstprogramm capsh , mit dem Sie unter anderem Ihre Anmeldeinformationen anzeigen können.

 # capsh --print Current: = cap_setgid,cap_setuid,cap_net_bind_service+eip Bounding set = cap_setgid,cap_setuid,cap_net_bind_service Ambient set = Securebits: 00/0x0/1'b0 secure-noroot: no (unlocked) secure-no-suid-fixup: no (unlocked) secure-keep-caps: no (unlocked) secure-no-ambient-raise: no (unlocked) uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video) 

Hier gibt es einige verwirrende Punkte:

  • Aktuell - Zeigt die effektiven, geerbten und verfügbaren Berechtigungen des Capsh-Prozesses im Format cap_to_text (3) an . In diesem Format werden Rechte als Berechtigungsgruppen “capability[,capability…]+(e|i|p)” , wobei “e” effektiv, “i” geerbt und “p” verfügbar bedeutet. Die Liste wird nicht durch das Symbol “,” , wie Sie vielleicht vermutet haben (cap_setgid+eip, cap_setuid+eip) . Ein Komma teilt die Berechtigungen in eine Aktionsgruppe auf. Die tatsächliche Liste der Aktionsgruppen wird dann durch Leerzeichen getrennt. Ein weiteres Beispiel mit zwei Aktionsgruppen wäre “= cap_sys_chroot+ep cap_net_bind_service+eip” . Außerdem codieren die folgenden zwei Gruppen von Aktionen “= cap_net_bind_service+e cap_net_bind_service+ip” denselben Wert wie ein “cap_net_bind_service+eip” .
  • Begrenzungssatz / Umgebungssatz . Zur weiteren Verwirrung enthalten diese beiden Zeilen nur eine Liste von Berechtigungen, die in diesen Gruppen definiert sind und durch Leerzeichen getrennt sind. Das Format cap_to_text wird hier nicht verwendet, da es keine Sätze verfügbarer, effektiver und geerbter Berechtigungen enthält, sondern nur einen Satz (Bounding / Ambient).
  • Securebits : Zeigt die Securebits- Flags der Aufgabe im Dezimal- / Hexadezimal- / Verilog-Format an (ja, jeder erwartet dies hier, und dies ist völlig klar , wenn jeder Systemadministrator sein eigenes FPGA und ASIC programmiert). Das Folgende ist der Status von Securebits. Tatsächliche Flags werden in Securebits.h als SECBIT_* definiert und auch in den Funktionen (7) beschrieben .
  • Diesem Dienstprogramm fehlt die Anzeige der "NoNewPrivs" -Informationen , die in angezeigt werden können
      / proc / <pid> / status 
    . Es wird nur in prctl (2) erwähnt, obwohl es die Rechte direkt beeinflusst, wenn es zusammen mit Dateiberechtigungen verwendet wird (ausführlicher unten). NoNewPrivs wird wie folgt beschrieben: no_new_privs auf 1 gesetzt ist, verspricht execve (2), keine Berechtigungen für das zu erteilen, was ohne den Aufruf von execve (2) nicht möglich gewesen wäre (z. B. Verarbeitung der set-user-ID , set-group-ID Bits) set-group-ID und Deaktivieren der Dateiberechtigungsverarbeitung) . Nach der Installation kann das Attribut no_new_privs nicht zurückgesetzt werden. Der Wert dieses Attributs wird von Nachkommen geerbt, die mit fork (2) und clone (2) erstellt und über execve (2) gespeichert wurden. “ Kubernetes setzt dieses Flag auf 1, wenn allowPrivilegeEscalation im pod securityContext false ist.


Wenn Sie einen neuen Prozess über execve (2) starten, werden die Berechtigungen für den untergeordneten Prozess mithilfe der in Funktionen (7) angegebenen Formel konvertiert:

 P'(ambient) = (file is privileged) ? 0 : P(ambient) P'(permitted) = (P(inheritable) & F(inheritable)) | (F(permitted) & P(bounding)) | P'(ambient) P'(effective) = F(effective) ? P'(permitted) : P'(ambient) P'(inheritable) = P(inheritable) [ie, unchanged] P'(bounding) = P(bounding) [ie, unchanged] where: P() denotes the value of a thread capability set before the execve(2) -      execve(2) P'() denotes the value of a thread capability set after the execve(2) -      execve(2) F() denotes a file capability set -   


Diese Regeln beschreiben die Aktionen, die für jedes Bit in allen Berechtigungssätzen ausgeführt werden (Umgebung / zulässig / effektiv / vererbbar / Begrenzung). Die Standard-C-Syntax wird verwendet (& - für logisches UND, | - für logisches ODER). P 'ist ein untergeordneter Prozess. P ist der aktuelle Prozess, der execve (2) aufruft. F sind die sogenannten "Dateiberechtigungen" einer durch execve gestarteten Datei.

Darüber hinaus kann ein Prozess seine geerbten, zugänglichen und effizienten Mengen mit libcap jederzeit programmgesteuert gemäß den folgenden Regeln ändern:

  • Wenn der Aufrufer nicht über CAP_SETPCAP , muss die neue geerbte Menge eine Teilmenge von P (geerbt) & P (verfügbar) sein.
  • (mit Linux 2.6.25) Die neue geerbte Menge sollte eine Teilmenge von P (geerbt) & P (einschränkend) sein.
  • Die neue verfügbare Menge sollte eine Teilmenge von P sein (verfügbar)
  • Die neue effiziente Menge sollte eine Teilmenge von P sein (effektiv)


Dateiberechtigungen


Manchmal muss ein Benutzer mit eingeschränkten Rechten eine Datei ausführen, für die mehr Berechtigungen erforderlich sind. Früher wurde dies erreicht, indem das setuid-Bit ( chmod + s ./executable ) in einer Binärdatei gesetzt wurde. Wenn eine solche Datei zu root gehört, hat sie die vollen Root-Rechte, wenn sie von einem Benutzer ausgeführt wird.

Dieser Mechanismus verleiht einer Datei jedoch zu viele Berechtigungen, sodass POSIX-Berechtigungen ein Konzept namens "Dateiberechtigungen" implementiert haben. Sie werden als erweitertes Dateiattribut mit dem Namen "security.capability" gespeichert. Sie benötigen daher ein Dateisystem mit Unterstützung für erweiterte Attribute (ext *, XFS, Raiserfs, Brtfs, overlay2, ...). Um dieses Attribut zu ändern, ist CAP_SETFCAP Berechtigung CAP_SETFCAP (in den verfügbaren Prozessberechtigungen).

 $ getfattr -m - -d `which ping` # file: usr/bin/ping security.capability=0sAQAAAgAgAAAAAAAAAAAAAAAAAAA= $ getcap `which ping` /usr/bin/ping = cap_net_raw+ep 


Sonderfälle und Kommentare


In der Realität ist natürlich nicht alles so einfach, und in der Manpage zu Funktionen (7) werden einige Sonderfälle beschrieben. Die wahrscheinlich wichtigsten von ihnen sind:

  • Das Setuid-Bit und die Dateiberechtigungen werden ignoriert, wenn NoNewPrivs installiert ist oder das Dateisystem mit nosuid gemountet ist oder der Prozessaufruf execve von ptrace verfolgt wird. Dateiberechtigungen werden auch ignoriert, wenn der Kernel mit der Option no_file_caps .
  • Eine "dumme" Datei (Capability-dumm) ist eine Binärdatei, die von einer Setuid-Datei in eine Datei mit Dateiberechtigungen konvertiert wird, ohne jedoch den Quellcode zu ändern. Solche Dateien werden häufig durch Festlegen von + ep-Berechtigungen für sie erhalten, z. B. “setcap cap_net_bind_service+ep ./binary” . Der wichtige Teil ist "e" - effektiv. Nach dem Ausführen werden diese Berechtigungen sowohl zu verfügbaren als auch zu vorhandenen Berechtigungen hinzugefügt, sodass die ausführbare Datei für die Verwendung des privilegierten Vorgangs bereit ist. Im Gegensatz dazu kann eine "Capability-Smart" -Datei , die libcap oder eine ähnliche Funktionalität verwendet, cap_set_proc (3) (oder capset ) verwenden, um die "effektiven" oder "geerbten" Bits jederzeit zu setzen, wenn diese Berechtigung bereits vorhanden ist. " erschwingliches ”Kit. Daher reicht " setcap cap_net_bind_service+p ./binary” für eine "intelligente" Datei aus, da die erforderlichen Berechtigungen in einem effektiven Satz selbst festgelegt werden können, bevor eine privilegierte Operation setcap cap_net_bind_service+p ./binary” wird. Siehe Beispielcode .
  • Dateien mit setuid-root funktionieren weiterhin und gewähren alle Root-Rechte, wenn der Benutzer als Nicht-Root startet. Wenn für sie jedoch Dateiberechtigungen festgelegt sind, werden nur diese erteilt. Sie können auch eine Setuid-Datei mit einem leeren Satz von Berechtigungen erstellen, wodurch sie als Benutzer mit UID 0 ohne Berechtigungen ausgeführt wird. Es gibt spezielle Fälle für den Root-Benutzer, wenn eine Datei mit setuid-root ausgeführt und verschiedene Securebits-Flags gesetzt werden (siehe man).
  • Ein Begrenzungssatz maskiert verfügbare Berechtigungen, jedoch keine geerbten. Denken Sie daran, P '(verfügbar) = F (verfügbar) & P (limitierend). Wenn ein Stream eine Berechtigung in seiner geerbten Menge hat , die nicht in seiner Begrenzungsmenge enthalten ist, kann er diese Berechtigung dennoch in seiner zugänglichen Menge erhalten, indem er eine Datei ausführt, die eine Berechtigung in seiner geerbten Menge hat - P '(verfügbar) = P ( geerbt) & F (geerbt).
  • Durch Ausführen eines Programms, das die UID oder GID über die Bits set-user-ID, set-group-ID ändert, oder durch Ausführen eines Programms, für das Dateiberechtigungen festgelegt sind , wird der Umgebungssatz gelöscht . Berechtigungen werden mit PR_CAP_AMBIENT prctl zum umgebenden Satz hinzugefügt . Diese Berechtigungen sollten bereits in zugänglichen und geerbten Prozessgruppen vorhanden sein.
  • Wenn ein Prozess mit einer anderen UID als 0 execve (2) ausführt , werden alle Rechte an seinen verfügbaren und aktiven Sätzen gelöscht.
  • Wenn SECBIT_KEEP_CAPS (oder das umfassendere SECBIT_NO_SETUID_FIXUP ) nicht festgelegt ist und durch Ändern der UID von 0 auf ungleich Null alle Berechtigungen aus den geerbten, zugänglichen und effektiven SECBIT_NO_SETUID_FIXUP entfernt werden .


Also ...


Wenn der offizielle Nginx-Container, ingress-nginx oder Ihr eigener mit einem Fehler gestoppt oder neu gestartet wird:

bind() to 0.0.0.0:80 failed (13: Permission denied)

... dies bedeutet, dass versucht wurde, Port 80 als nicht CAP_NET_BIND_SERVICE (nicht 0) Benutzer CAP_NET_BIND_SERVICE , und dass der aktuelle Berechtigungssatz kein CAP_NET_BIND_SERVICE . Um diese Rechte zu erhalten, müssen Sie xattr und set (mit setcap ) für die Berechtigung der cap_net_bind_service+ie Datei mindestens cap_net_bind_service+ie . Diese Dateiberechtigung wird mit dem Legacy-Satz kombiniert (angegeben mit dem Begrenzungssatz aus pod SecurityContext / Capability / Add / NET_BIND_SERVICE) und wird auch in den Satz der verfügbaren Berechtigungen aufgenommen. Das Ergebnis ist cap_net_bind_service+pie .

Dies alles funktioniert, solange securityContext / allowPrivilegeEscalation auf true gesetzt ist und der Docker / rkt-Speichertreiber (siehe Docker-Dokumentation) xattrs unterstützt.

Wenn nginx in Bezug auf Berechtigungen cap_net_bind_service+i wäre, würde cap_net_bind_service+i ausreichen. Dann könnte er libcap verwenden, um die Rechte vom verfügbaren Satz auf effektiv zu erweitern. Als Ergebnis erhalten cap_net_bind_service+pie .

Neben der Verwendung von xattr besteht die einzige Möglichkeit, cap_net_bind_service in einem Nicht-Root-Container abzurufen, darin, Docker seine externen Funktionen (Umgebungsfunktionen) festlegen zu lassen. Bis April 2019 wurde dies jedoch noch nicht umgesetzt .

Codebeispiele


Hier ist ein Beispielcode , der libcap verwendet, um CAP_NET_BIND_SERVICE zu einem effizienten Berechtigungssatz hinzuzufügen. Für die Binärdatei ist die Berechtigung CAP_BIND_SERVICE+p erforderlich.

Referenzen (dt.):

Source: https://habr.com/ru/post/de471802/


All Articles