Wer einen neuen IT-Job an Land ziehen möchte, sollte sich darauf einstellen, dass er im Einstellungsgespräch womöglich die beliebte Frage nach dem Sticky-Bit bei Unix-Betriebssystemen gestellt bekommt. Zumindest hier zahlt es sich aus, Bescheid zu wissen.
Eine gängige Frage bei Einstellungsgesprächen ist die nach dem so genannten Sticky-Bit. Ich persönlich stelle diese Frage nie, wenn ich einen Kandidaten durchleuchte, denn ich denke, wer die Antwort weiß, zeichnet sich höchstens durch gute Gesprächsvorbereitung aus. Ein Beweis für Fachkompetenz lässt sich daraus nicht ableiten. Aber viele große Firmen im Silicon Valley haben die Frage im Katalog, und als Spieler in der A-Klasse der Software-Industrie muss man selbstverständlich auch auf unnütze Fragen eine Antwort wissen.
Deshalb nimmt sich diesmal der Perl-Snapshot das Thema vor: Wozu ist das Sticky-Bit da? Wie immer, wenn es um knifflige Unix-Fragen geht, hilft das Buch von Michael Kerrisk [2] weiter. Der Wälzer mit mehr als 1500 Seiten ist als Papierbuch nur von praktizierenden Bodybuildern handhabbar, aber als E-Book leicht überallhin mitzunehmen.
Wer denkt, er wüsste schon alles über die Feinheiten der Programmierung unter Unix, kippt bei der Lektüre dieses Jahrhundertwerks aus den Schuhen: Selbst graubärtige Unix-Gurus fördern aus den Tiefen dieses Schinkens immer wieder verblüffende Tatsachen hervor.
Wer hätte zum Beispiel gewusst, dass ein User auf einem Unix-System eine Datei aus einem Verzeichnis löschen kann, obwohl er keine Schreibrechte an dieser Datei hat? Richtig: Erforderlich sind nur Schreib- und Ausführungsrechte für das Verzeichnis, in dem die Datei liegt. Listing 1 legt zu Demonstrationszwecken ein neues Verzeichnis »test« im aktuellen Verzeichnis an und gibt ihm mit dem oktalen Wert »0333« die Rechte »-wx-wx-wx« .
Listing 1
file-rm
01 #!/usr/local/bin/perl -w 02 use strict; 03 use Sysadm::Install qw( blurt ); 04 use File::Path qw( rmtree ); 05 06 mkdir "test"; 07 blurt "data", "test/abc"; 08 chmod 0333, "test"; 09 chmod 0444, "test/abc"; 10 11 # d-wx-wx-wx test 12 # -r--r--r-- test/abc 13 14 unlink "test/abc" 15 or die "unlink failed: $!"; 16 17 rmtree "test";
Löschen ohne Rechte
Der anschließend mit »blurt()« aus dem CPAN-Modul Sysadm::Install erzeugten Datei »abc« weist die »chmod« -Anweisung in Zeile 9 mit »0444« die Rechte »-r–r–r–« zu. Alle User dürfen sie also lesen, aber nicht beschreiben. Dennoch läuft die »unlink« -Anweisung in Zeile 14 ohne Meckern durch, auch ein »rm -f test/abc« auf der Kommandozeile löscht die Datei ohne Rückfrage oder Fehler. Genau so ist es auch tatsächlich gemeint: Schreibrechte an einer Datei unter Unix erlauben das Modifizieren des Inhalts der Datei, Löschrechte hingegen regelt das Verzeichnis, in dem die Datei liegt, nicht die Datei selber.
Als weitere interessante Feinheit der Unix-Programmierung fällt im Listing 1 auf, dass das Verzeichnis »test« allen Usern mit »-wx-wx-wx« zwar Schreib- und Ausführungsrechte gewährt, aber keine Leserechte. Nach diesen Vorschriften kann das Skript das Verzeichnis also durchqueren und dabei schreibend darauf zugreifen, die in ihm enthaltenen Dateien jedoch nicht auflisten.
Da das Skript aber weiß, dass die Datei »test/abc« darin liegt, darf es sie auch löschen. Gehört die Datei einem anderen User, ändert sich nichts daran, dass Unix sie rücksichtslos löscht, wenn das Verzeichnis, in dem sie liegt, seine Zustimmung gegeben hat. Das führt naturgemäß zu Problemen, zu deren Behebung die Unix-Väter in grauer Vorzeit eine recht zusammengeschusterte Lösung fanden, aber davon später.
Wegerecht
Was bedeutet das »x« , wenn ein Verzeichnis die Rechte »-wx-wx-wx« anzeigt? Es regelt das Wegerecht zum Durchqueren des Verzeichnisses. Egal ob ein Kommando auf den Inhalt einer Datei »sub/file« schreibend oder lesend zugreift oder mit »sub/sub1« in ein im Verzeichnis »sub« liegendes Unterverzeichnis »sub1« hinabsteigt – es benötigt Ausführungsrechte am Verzeichnis »sub« .
Wie Listing 2 zeigt, heißt das aber nicht, dass ein Kommando, das auf das Verzeichnis »top/sub/sub1« zugreift, Ausführungsrechte an allen Pfadkomponenten »top« , »sub« und »sub1« benötigt. Hat ein Skript etwa sein aktuelles Verzeichnis vor dem Einrichten der Zugangssperre mit »chdir()« auf »top/sub/sub2« gesetzt, kann es mit der relativen Pfadangabe »../sub1« sehr wohl auch dann auf »sub1« zugreifen, wenn später »top« die »x« -Rechte wie in Zeile 21 in Listing 2 entzogen bekommt (Abbildung 1).
Listing 2
dir-traverse
01 #!/usr/local/bin/perl -w
02 use strict;
03 use Test::More;
04 use Test::Exception;
05 use File::Temp qw( tempdir );
06 use Sysadm::Install qw( blurt slurp
07 cd cdback );
08
09 my $ROOT_DIR = tempdir( CLEANUP => 1 );
10
11 # Read via a relative path while the abso-
12 # lute path doesn't have traversal rights.
13 dirmk( "top", 0700 );
14 dirmk( "top/sub", 0700 );
15 dirmk( "top/sub/sub1", 0700 );
16 dirmk( "top/sub/sub2", 0700 );
17
18 blurt "content",
19 "$ROOT_DIR/top/sub/sub1/file";
20 cd "$ROOT_DIR/top/sub/sub2";
21 chmod 0600, "$ROOT_DIR/top";
22
23 throws_ok
24 { slurp( "$ROOT_DIR/top/sub/sub1/file" ) }
25 qr/Permission denied/, "abs path fails";
26
27 is slurp( "../sub1/file" ),
28 "content", "rel path ok";
29
30 cdback;
31 done_testing();
32
33 ###########################################
34 sub dirmk {
35 ###########################################
36 my( $dir, $perm ) = @_;
37
38 my $path = "$ROOT_DIR/$dir";
39 mkdir $path or die "$!";
40 chmod $perm, $path or die "$!";
41 }
Listing 2 zeigt eine mit Test::More implementierte Testsuite zum Verifizieren dieser Tatsache. Die Funktion »throws_ok()« in Zeile 23 stammt aus dem CPAN-Modul Test::Exception. Sie fängt auftretende Fehler ab und erlaubt es, sie mittels regulärer Ausdrücke mit Fehlern zu vergleichen, die die Testsuite erwartet. So tritt beim Zugriff über den absoluten Pfad vorhersehbar ein “Permission denied”-Fehler auf, während eine relative Pfadangabe wie in Zeile 27 zum Erfolg führt:
$ ./dir-traverse ok 1 - abs path fails ok 2 - rel path ok 1..2
Wer übrigens denkt, dass der Trick mit dem relativen Pfad auch funktioniert, falls nicht »top« , sondern »top/sub« das Wegerecht storniert, irrt: Wenn ein Skript sich in »top/sub/sub2« befindet und mittels »../sub1« auf »top/sub/sub1« zugreift, durchschreitet es »top/sub« und benötigt deshalb dort das Wegerecht.
Klebriges Zeug
Das eingangs erwähnte Kuriosum, dass ein User eine Datei löschen darf, auch wenn ihm die Datei selbst keine Schreibrechte gewährt, führt zu Problemen, falls sich mehrere User ein Verzeichnis teilen. Legen zum Beispiel die User A und B die Dateien »file-a« und »file-b« in »/tmp« ab, sollte es A verwehrt bleiben, »file-b« zu löschen. Doch wie soll das gehen, wenn nicht die Datei selbst, sondern das enthaltende Verzeichnis den Löschzugriff regelt?
Damit jeder User auf »/tmp« zugreifen darf, sind dessen Rechte auf »rwxrwxrwx« eingestellt. Dies eröffnet allerdings auch beliebigen Usern Löschrechte an allen dort eingestellten Dateien, und deshalb behalfen sich die Unix-Väter mit einem Trick: Sie erfanden ein spezielles Sticky-Bit, das
chmod +t /tmp
setzt und daran zu erkennen ist, dass das »ls« -Kommando die Verzeichnisrechte folgendermaßen anzeigt:
$ ls -ld /tmp drwxrwxrwt 7 root root 4096 Apr 13 00:17 /tmp
Statt eines abschließenden »rwx« steht nun ein »rwt« in der Zugriffskennung, und Unix stellt deswegen die Zugriffsregeln in diesem Verzeichnis auf den Kopf. Auf einmal darf nun nicht mehr jeder beliebige User Einträge löschen, sondern nur noch der Eigentümer des jeweiligen Eintrags.
Genau deshalb setzt jedes Unix-System im Verzeichnis »/tmp« das Sticky-Bit. Es verhindert, dass User sich gegenseitig ihre temporären Dateien weglöschen. Schreib- und Leserechte am Verzeichnis sind nach wie vor für alle vorhanden.
Bonuspunkte
Bonuspunkte erhält der Kandidat beim Einstellungsgespräch übrigens, falls er erklären kann, wann Unix das Sticky-Bit eines Verzeichnisses mit »t« und wann mit »T« anzeigt. Mit dem abschließenden »t« in »rwt« verdeckt der Hack mit dem Sticky-Bit nämlich jenes Bit, das eigentlich Ausführungsrechte der Allgemeinheit am Verzeichnis anzeigt. Es lässt sich nicht mehr sagen, ob vor dem Setzen des Sticky-Bits »rw-« oder »rwx« eingestellt war. Deshalb zeigt Unix »rwt« an, falls »rwx« vorlag, und »rwT« , falls die Ausführungsrechte fehlen, also vorher »rw-« dort stand.
Wer auch noch weiß, dass nicht nur Verzeichnisse, sondern auch Dateien ein Sticky-Bit führen können, das aber etwas völlig anderes regelt, beweist, dass er die Vorbereitung ernst genommen und Kerrisks Standardwerk studiert hat. Der Kandidat erhält 100 Punkte und kommt sicher in die nächste Runde!
Online PLUS
Im Screencast demonstriert Michael Schilli das Beispiel: https://www.linux-magazin.de/Ausgaben/2015/06/plus
Infos
- Listings zu diesem Artikel: ftp://www.linux-magazin.de/pub/listings/magazin/2015/06/Perl
- Michael Kerrisk, “The Linux Programming Interface: A Linux and UNIX System Programming Handbook”: No Starch Press, 2010







