/tmp ist der weltweit schreibbare Sammelpfad für kurzlebige Dateien — Zwischen-Output von Kompilierungen, entpackte Archive, Editor-Swap-Files, IPC-Sockets. Auf modernen Distributionen liegt /tmp häufig als tmpfs im RAM, ist also nach jedem Reboot leer und blitzschnell. Das Sticky-Bit (Mode 1777) verhindert, dass Nutzer fremde Dateien dort löschen — der wichtigste Schutz auf einem Multi-User-System.

Was ist /tmp?

Der FHS-Standard (3.0, Kapitel 3.18) beschreibt /tmp als Pfad für temporäre Daten, auf den jeder User schreibend zugreifen darf. Drei Eigenschaften definieren das Verzeichnis:

  1. World-writable: jeder User kann Dateien anlegen, also Mode 1777 (drwxrwxrwt).
  2. Sticky-Bit gesetzt: trotz des rwx für alle dürfen User nur ihre eigenen Dateien löschen oder umbenennen.
  3. Vergänglich: Programme dürfen nicht erwarten, dass Dateien einen Reboot überleben oder länger als nötig erhalten bleiben.
Bash Berechtigungen von /tmp prüfen
ls -ld /tmp
# drwxrwxrwt 22 root root 4096 ... /tmp

# Das 't' am Ende ist das Sticky-Bit
# Numerisch: 1777
stat -c '%a %n' /tmp
# 1777 /tmp

Was typisch in /tmp landet:

  • IPC-Sockets und Lock-Files von Daemons und User-Sessions (.X11-unix/, .ICE-unix/)
  • Build-Artefakte von gcc, pip, npm (während eines Compile-Laufs)
  • Editor-Swap- und Backup-Files von vim, emacs
  • Entpackte Archive und Download-Caches
  • Temp-Outputs von Shell-Skripten (mktemp legt hier an)
  • Browser-Caches in manchen Konfigurationen

Sticky-Bit: world-writable, aber nicht world-deletable

Ohne Sticky-Bit könnte jeder User in einem 0777-Verzeichnis nicht nur eigene Dateien anlegen, sondern auch fremde Dateien löschen oder umbenennen — denn nur die Verzeichnis-Berechtigung zählt für unlink(). Das ist auf einem Multi-User-System natürlich gefährlich.

Das Sticky-Bit (Bit 9 der Unix-Permissions, dargestellt als t an der letzten Stelle) ändert genau diese Regel:

In einem Verzeichnis mit Sticky-Bit darf eine Datei nur vom Owner der Datei oder vom Owner des Verzeichnisses (typischerweise root) gelöscht werden — auch wenn andere User Schreibrechte auf das Verzeichnis haben.

Bash Sticky-Bit selbst setzen und sehen
# Sticky-Bit setzen
chmod +t /pfad/zum/dir
chmod 1777 /pfad/zum/dir   # alternativ numerisch

# Sichtbar als 't' am Ende
ls -ld /pfad/zum/dir
# drwxrwxrwt 2 root root 4096 ... /pfad/zum/dir

# Großes T: rwx fehlt für andere, Sticky trotzdem gesetzt
ls -ld /pfad/restricted
# drwxrwx--T

# Sticky-Bit entfernen
chmod -t /pfad

Außer /tmp haben auch /var/tmp und manche IPC-Verzeichnisse (/dev/shm, /run/lock) das Sticky-Bit. Außerhalb dieser Standard-Pfade ist es selten nötig.

tmpfs: /tmp im RAM

Auf den meisten modernen Distributionen ist /tmp als tmpfs gemountet — ein Filesystem, das vollständig im RAM lebt. Das hat mehrere Vorteile:

  • Geschwindigkeit: Dateioperationen passieren auf RAM-Speed, kein Disk-I/O.
  • Automatisch leer nach Reboot: RAM verliert seinen Inhalt beim Strom-Aus, kein Cleanup-Skript nötig.
  • Schreibbar: anders als /usr oder /etc ist tmpfs immer rw.
  • Größenlimit: tmpfs kann mit size=-Option begrenzt werden — voller /tmp füllt nicht die Disk.
Bash Ist /tmp ein tmpfs?
mount | grep ' /tmp '
# tmpfs on /tmp type tmpfs (rw,nosuid,nodev,size=8011656k,nr_inodes=...)

# Wieviel RAM ist /tmp aktuell zugewiesen?
df -h /tmp
# tmpfs   7.6G   12K  7.6G   1% /tmp

# Kein tmpfs? /tmp liegt auf der normalen Disk
df -h / /tmp
# /dev/sda1   500G   80G  395G  17% /
# ...                                /tmp ← keine eigene Zeile

Auf systemd-Distributionen aktiviert das Unit tmp.mount (in /usr/lib/systemd/system/tmp.mount) den tmpfs-Mount. Standardmäßig ist die Größe 50 % des RAMs — auf Systemen mit wenig RAM und großen Build-Jobs kann das zu wenig sein.

Bash tmp.mount aktivieren oder ändern
# tmpfs für /tmp aktivieren (falls noch normales Disk-Verzeichnis)
sudo systemctl enable --now tmp.mount

# Größe anpassen via Drop-In
sudo systemctl edit tmp.mount
# [Mount]
# Options=mode=1777,strictatime,nosuid,nodev,size=4G
sudo systemctl daemon-reload
sudo systemctl restart tmp.mount

Nicht alle Distributionen aktivieren tmpfs für /tmp standardmäßig — Debian und Ubuntu lassen es als Disk-Verzeichnis, Fedora und Arch nutzen tmpfs.

Aufräumen: systemd-tmpfiles

Selbst wenn /tmp ein tmpfs ist und beim Reboot geleert wird — auf Servern, die Wochen oder Monate ohne Neustart laufen, sammelt sich dort Müll an. Hier kommt systemd-tmpfiles ins Spiel: ein Service, der nach Regeln in /usr/lib/tmpfiles.d/ und /etc/tmpfiles.d/ aufräumt.

Standard-Regel auf den meisten Distributionen: Dateien in /tmp, die älter als 10 Tage sind, werden gelöscht (und in /var/tmp älter als 30 Tage).

Bash systemd-tmpfiles in der Praxis
# Konfigurationsdateien anschauen
cat /usr/lib/tmpfiles.d/tmp.conf
# # See tmpfiles.d(5) for details
# q /tmp 1777 root root 10d
# q /var/tmp 1777 root root 30d
# ...

# Was wäre zu tun? Trockenlauf
sudo systemd-tmpfiles --clean --dry-run

# Tatsächlich aufräumen (passiert sonst täglich automatisch)
sudo systemd-tmpfiles --clean

# Status des Cleanup-Timers
systemctl status systemd-tmpfiles-clean.timer

Die Felder in einer tmpfiles-Regel: Type (q = quotaable, d = directory, f = file, …), Path, Mode, User, Group, Age. Mit eigenen Drop-Ins in /etc/tmpfiles.d/ lassen sich beliebige Aufräum-Regeln definieren.

/tmp vs /var/tmp vs $XDG_RUNTIME_DIR

Mehrere Pfade konkurrieren um „temporäre Daten" — sie haben aber jeweils eine spezifische Rolle:

PfadLebenszeitOwnerZweck
/tmpBis Reboot oder ~10 TageWorld-writable, StickyKurzlebig, schnelle IPC, Build-Output
/var/tmpÜber Reboots hinweg, ~30 TageWorld-writable, StickyPersistente Temp-Daten (Editor-Recovery, Pakete)
$XDG_RUNTIME_DIR (/run/user/<uid>/)Bis LogoutPro User exklusiv (0700)User-Session-Daten, Sockets, PID-Files
/dev/shmBis RebootWorld-writable, StickyShared-Memory zwischen Prozessen (POSIX shm)

Die Faustregeln:

  • Für Skripte und Build-Tools: mktemp ohne Argumente legt unter /tmp an. Wenn die Datei einen Reboot überstehen muss: mktemp --tmpdir=/var/tmp oder via TMPDIR=/var/tmp mktemp.
  • Für User-Sessions: $XDG_RUNTIME_DIR ist die richtige Wahl. Sockets, PID-Files, kurzfristige Caches gehören dort hin.
  • Für Shared Memory zwischen Prozessen: /dev/shm ist die POSIX-Standard-Schnittstelle für shm_open().
Bash Temporäre Dateien sicher anlegen
# Sichere Temp-Datei (eindeutig, nur für aktuellen User lesbar)
TMPFILE=$(mktemp)
trap "rm -f $TMPFILE" EXIT
echo "data" > "$TMPFILE"

# Mit Prefix für Lesbarkeit
TMPFILE=$(mktemp -t myapp-XXXXXX)

# Verzeichnis statt Datei
TMPDIR=$(mktemp -d)
trap "rm -rf $TMPDIR" EXIT

# In /var/tmp statt /tmp
TMPFILE=$(mktemp --tmpdir=/var/tmp)

# In XDG_RUNTIME_DIR (User-Session-Scope)
TMPFILE=$(mktemp -p "$XDG_RUNTIME_DIR")

Wichtig: niemals einen Pfad wie /tmp/myfile.tmp hartkodieren. Das ist ein klassisches Race-Condition-Risiko (zwei Skripte schreiben gleichzeitig in dieselbe Datei) und ein Sicherheits-Problem (Angreifer kann via Symlink-Attack steuern, wo gelandet wird). mktemp löst beides.

Mount-Optionen für /tmp: nosuid, nodev, noexec

Sicherheits-Praxis: /tmp sollte mit nosuid,nodev,noexec gemountet sein. Das verhindert klassische Privilege-Escalation-Vektoren:

OptionWirkung
nosuidSUID-Bit auf Dateien wird ignoriert — kein Root-Hack via dort abgelegtes Binary
nodevDevice-Nodes werden nicht respektiert — Schutz gegen /tmp/sda als Disk-Zugriff
noexecDateien sind nicht ausführbar — Angreifer kann kein Binary einschleusen und starten

Beim systemd-tmpfs sind die ersten beiden Optionen Default, noexec aber nicht — viele Build-Tools und Skripte erwarten, dass /tmp ausführbare Skripte halten kann (apt-get extrahiert .deb-Pakete dorthin, npm baut native Module).

Wer die Sicherheit aufdreht, riskiert, dass Tools brechen. Für besonders gehärtete Setups: noexec setzen, im Zweifel mit TMPDIR=/var/tmp oder ~/.local/tmp arbeiten.

Bash Mount-Optionen für /tmp prüfen
mount | grep ' /tmp '
# tmpfs on /tmp type tmpfs (rw,nosuid,nodev,size=4G,nr_inodes=...)

# Aktive Sicherheits-Hardening-Tests
sudo lynis audit system | grep -i tmp

Interessantes

/tmp ist nicht der Ort für wichtige Daten

Klassischer Anfänger-Fehler: ein Backup nach /tmp legen und sich wundern, warum es nach dem Reboot weg ist. Auch beim Editieren mit vim: das Original-File ist nicht in /tmp, aber das Recovery-File .swp schon — bei einem Crash ist es weg, wenn /tmp ein tmpfs ist. Für persistente Temp-Daten gehört es nach /var/tmp oder ~/.cache/.

Volle /tmp ist auf Build-Servern eine Standard-Plage

apt-get, dnf, npm, cargo, große Compiler — alle entpacken oder bauen in /tmp. Wer Container baut oder npm-Module kompiliert, kann mit 1 GB tmpfs schnell aus dem Speicher fallen. Lösung: tmpfs-Größe in tmp.mount auf 4 GB oder mehr setzen, oder TMPDIR=/var/tmp für ein konkretes Tool exportieren.

Sticky-Bit funktioniert auch ohne world-writable

+t lässt sich auch auf 0750-Verzeichnissen setzen — dann gilt: nur die Gruppen-Mitglieder dürfen schreiben, und auch sie können nur ihre eigenen Dateien löschen. Für Group-Drop-Boxes ist das ein praktisches Pattern.

systemd-tmpfiles räumt mehr als nur /tmp auf

Die Regeln in /usr/lib/tmpfiles.d/ decken auch /var/cache/, /run/, App-State unter /var/lib/<service> und vieles mehr ab. Ein eigener Service kann seine eigenen Aufräum-Regeln definieren (z. B. „Logs älter als 7 Tage in /var/log/myapp/ löschen") — das ist meist sauberer als ein Cron-Job.

Auf Containern ist /tmp oft tiny

Standard-Container-Images haben /tmp als ein normales Verzeichnis im Image-Layer — kein tmpfs, keine Größenlimits, aber auch geschrieben in den Container-Layer (was beim Commit oder Backup mitwandert). Wer im Container temporäre Dateien anlegt, sollte /tmp als Volume-Mount einrichten oder das Programm via TMPDIR=/dev/shm umlenken.

$XDG_RUNTIME_DIR ist die richtige Wahl für User-Sockets

PulseAudio, dbus, GnuPG-Agent legen ihre Sockets unter /run/user/<uid>/ ab — automatisch beim Login angelegt, automatisch beim Logout entlassen. Das ist eleganter als /tmp/<uid>/, weil keine Cleanup-Logik nötig ist und der Pfad nur dem aktuellen User gehört (mode=0700).

Weiterführende Ressourcen

Externe Quellen

/ Weiter

Zurück zu Verzeichnisstruktur

Zur Übersicht