Debian GNU/Linux · Filesystem & permissions

Mount /tmp as a separate filesystem with nodev, nosuid and noexec

When it fails: Programs can be run, or device files and setuid programs used, from /tmp. Every user can write to /tmp, so it is the usual place to drop and run attack tools, and filling it can fill the root filesystem.

CB-DEB-FS-003mediumactiveautomatedautomated fixprofile core

As released in v0.1.1 beta · pre-release. Current state.

Description

/tmp is a separate filesystem mounted with:

  • nodev: device files on it are not usable;
  • nosuid: setuid and setgid bits on it are ignored;
  • noexec: programs on it cannot be executed directly.

On Debian the simplest way is the tmp.mount unit of systemd, which mounts a tmpfs (in memory, emptied at each boot). Debian 13 enables it by default with nodev and nosuid; Debian 12 keeps /tmp on the root filesystem and ships the unit as an example in /usr/share/systemd/.

The fix uses tmp.mount and a drop-in that adds noexec. On Debian 12, /tmp becomes a tmpfs at the next reboot only: mounting it on a running system would hide files that programs are using. Files left in the old on-disk /tmp are then hidden under the mount. When /tmp is a partition declared in /etc/fstab, the fix stops and the options must be added by hand.

Rationale

/tmp is writable by every user and every service. Attackers drop their tools there and run them, and a setuid file or device node placed there by a compromised account can be abused. noexec, nosuid and nodev stop these uses. A separate filesystem also keeps a user or a runaway process that fills /tmp from filling the root filesystem.

Impact

Scripts and binaries in /tmp cannot be run directly (./script); sh /tmp/script still works, so noexec is a hurdle, not a barrier. A few installers and build tools that run helpers from /tmp fail: point their TMPDIR elsewhere. A tmpfs /tmp uses memory (up to half of the RAM) and loses its content at reboot.

Setting

Location/etc/systemd/system/tmp.mount.d/60-cirsec.conf, or /etc/fstab
DefaultDebian 12: directory of the root filesystem. Debian 13: tmpfs with nodev,nosuid
RecommendedSeparate filesystem (tmpfs) with nodev,nosuid,noexec

Audit

Run findmnt -kn /tmp. It must print a line (separate filesystem) whose options contain nodev, nosuid and noexec.

Automated: every check must pass. Scanners report each check by its id.

mount

/tmp is a mount point and its options include nodev, nosuid and noexec.

script: |
  o=$(findmnt -kn -o SOURCE,FSTYPE,OPTIONS --mountpoint /tmp | tail -n 1)
  [ -n "$o" ] || { echo "/tmp is not a separate filesystem"; exit 1; }
  echo "/tmp $o"
  rc=0
  for opt in nodev nosuid noexec; do
    case ,${o##* }, in *,$opt,*) ;; *) echo "missing $opt"; rc=1 ;; esac
  done
  exit $rc

Remediation

With a tmpfs (recommended):

  1. On Debian 12 only: cp /usr/share/systemd/tmp.mount /etc/systemd/system/ then systemctl enable tmp.mount.
  2. Create /etc/systemd/system/tmp.mount.d/60-cirsec.conf:
    [Mount]
    Options=mode=1777,strictatime,nosuid,nodev,noexec,size=50%%,nr_inodes=1m
    
  3. Run systemctl daemon-reload. If /tmp is already a tmpfs, run mount -o remount,nodev,nosuid,noexec /tmp; otherwise reboot.

With a partition declared in /etc/fstab: add nodev,nosuid,noexec to the options of the /tmp line, then run mount -o remount /tmp.

Restartsystem reboot
Disruptionlow

Rollback

Delete /etc/systemd/system/tmp.mount.d/60-cirsec.conf (and, on Debian 12, run systemctl disable tmp.mount and delete /etc/systemd/system/tmp.mount), run systemctl daemon-reload and reboot.

tmp-mount

# CB-DEB-FS-003: mount /tmp as a tmpfs with nodev, nosuid and noexec through systemd's tmp.mount.
if awk '$1 !~ /^#/ && $2 == "/tmp"' /etc/fstab | grep -q .; then
  echo "/tmp is defined in /etc/fstab: add nodev,nosuid,noexec to its options by hand" >&2
  exit 1
fi
if [ -L /tmp ]; then
  echo "/tmp is a symbolic link, tmp.mount does not apply" >&2
  exit 1
fi

# Debian 12 ships tmp.mount as an example in /usr/share/systemd, Debian 13 as an active unit.
if ! systemctl cat tmp.mount >/dev/null 2>&1; then
  [ -f /usr/share/systemd/tmp.mount ] || { echo "no tmp.mount unit available" >&2; exit 1; }
  cb_backup /etc/systemd/system/tmp.mount
  cp /usr/share/systemd/tmp.mount /etc/systemd/system/tmp.mount
fi

f=/etc/systemd/system/tmp.mount.d/60-cirsec.conf
cb_backup "$f"
mkdir -p /etc/systemd/system/tmp.mount.d
printf '%s\n' '# Written by CIRSEC Baselines CB-DEB-FS-003' '[Mount]' \
  'Options=mode=1777,strictatime,nosuid,nodev,noexec,size=50%%,nr_inodes=1m' >"$f"
chmod 644 "$f"
systemctl daemon-reload
[ "$(systemctl is-enabled tmp.mount 2>/dev/null)" = disabled ] && systemctl enable tmp.mount

# Mounting a new tmpfs over a live /tmp would hide files in use: only remount an existing tmpfs.
if [ "$(findmnt -kn -o FSTYPE --mountpoint /tmp | tail -n 1)" = tmpfs ]; then
  mount -o remount,nodev,nosuid,noexec /tmp
else
  echo "/tmp becomes a tmpfs at the next reboot"
fi

Handwritten code reads parameters from CB_<NAME> environment variables. Each release turns these fixes into remediate.sh and an Ansible role per profile: dry run by default, a fix runs only when its check fails.

References

Mappings

FrameworkIDRelationNote
ANSSI-BP-028 - Recommandations de configuration d'un système GNU/Linux2.0R28partialR28 covers the whole partitioning; this control covers /tmp.
NIST SP 800-53 Rev. 55.1.1CM-7related

How this control relates to the other framework's: equivalent, stricter, looser, partial or related.

Threats mitigated

  • related CB-DEB-FS-004 Mount /dev/shm with nodev, nosuid and noexec
  • related CB-DEB-FS-006 Mount separate filesystems with nodev, nosuid and noexec where they are not needed

People and lifecycle

Authors
Verified2026-10-18 by Sn0wAlice on 12, Proxmox VM 922, Debian 12 genericcloud image, kernel 6.1.0-54-cloud-amd64. Fails on fresh install (/tmp on the root filesystem); fix copies tmp.mount, /tmp becomes a tmpfs at reboot; fix adds noexec through a tmp.mount drop-in; tmpfs with nodev,nosuid,noexec after reboot; apt-get still installs packages; running a script from /tmp is refused.
Verified2026-10-18 by Sn0wAlice on 13, Proxmox VM 932, Debian 13 genericcloud image, kernel 6.12.113+deb13-cloud-amd64. Fails on fresh install (tmp.mount without noexec); fix remounts at once; fix adds noexec through a tmp.mount drop-in; tmpfs with nodev,nosuid,noexec after reboot; apt-get still installs packages; running a script from /tmp is refused.
Introduced inv0.1.0
Created, updated2026-10-18, 2026-10-18
Translationsfr