Filesystem Security

Mount Options

noexec, nosuid, nodev, and ro: reducing what a filesystem allows.

Not every filesystem needs every capability. A scratch directory does not need to run programs; a data volume does not need device nodes; a config partition might not need to be writable at all. By default the kernel grants all of these everywhere, which means a writable area like /tmp becomes a convenient landing pad: an attacker drops a binary, marks it executable, and runs it. Mount options let you remove those capabilities per mount point, so the kernel itself refuses the abuse. The change is cheap, enforced by the kernel rather than by policy, and easy to reverse. This page complements Disk Encryption (which protects the bytes at rest) and Integrity Monitoring (which detects tampering).

What each option prevents

OptionEffectAttack it blunts
noexecThe kernel refuses to execute any file on the mountRunning a dropped payload or shell script directly from /tmp
nosuidsetuid and setgid bits are ignoredA planted setuid-root binary granting privilege escalation
nodevDevice nodes on the filesystem are ignoredA crafted device node (for example a copy of /dev/mem or a disk) used to bypass permissions
roMount is read-onlyAny modification, including persistence and log tampering

These options are independent and can be combined. noexec alone is not a complete barrier (an attacker can sometimes invoke the interpreter directly, as in bash script.sh), which is why you combine it with nosuid and nodev and treat it as one layer among several.

Sensible options per mount point

Mount pointSuggested optionsReasoning
/tmpnodev,nosuid,noexecPurely scratch space; nothing legitimate runs from here
/var/tmpnodev,nosuid,noexecPersistent scratch; same reasoning as /tmp
/homenodev,nosuidUsers store data, not devices or setuid binaries. Omit noexec if users legitimately run scripts from their home directory
/varnodev,nosuidLogs and spool data, not devices
Removable media (USB)nodev,nosuid,noexecUntrusted media should never introduce devices or executables

Be cautious with noexec on /home and /tmp: some package managers and language toolchains build in temporary directories. Test before enforcing on a system with real workloads.

Applying options via /etc/fstab

On a stock Ubuntu system /tmp often lives on the root filesystem, so first give it a dedicated entry (here backed by tmpfs, an in-memory filesystem).

# Inspect current mounts and their options
findmnt /tmp

Expected output:

TARGET SOURCE FSTYPE OPTIONS
/tmp   /dev/sda1[/tmp] ext4 rw,relatime

Add or edit a line in /etc/fstab, then remount. A tmpfs /tmp line looks like this:

# Append a hardened tmpfs mount for /tmp
echo 'tmpfs /tmp tmpfs defaults,nodev,nosuid,noexec,size=1G 0 0' | sudo tee -a /etc/fstab

# Validate fstab syntax WITHOUT rebooting (critical: a bad line can break boot)
sudo findmnt --verify

# Apply the new options
sudo mount -o remount /tmp

Expected output:

Success, no errors or warnings detected

TARGET SOURCE FSTYPE OPTIONS
/tmp   tmpfs  tmpfs  rw,nosuid,nodev,noexec,size=1048576k

Confirm the options took effect and that execution is now blocked.

# Prove noexec is enforced
cp /bin/true /tmp/probe && chmod +x /tmp/probe && /tmp/probe; echo "exit=$?"

Expected output:

bash: /tmp/probe: Permission denied
exit=126

systemd mount units

systemd can manage mounts too, and on Ubuntu a tmp.mount unit is the modern way to harden /tmp. The unit name must match the mount path (/tmp becomes tmp.mount).

# Use the shipped example unit and enable it
sudo cp /usr/share/systemd/tmp.mount /etc/systemd/system/tmp.mount
sudo systemctl daemon-reload
sudo systemctl enable --now tmp.mount
systemctl show tmp.mount -p Options

Expected output:

Options=mode=1777,strictatime,nosuid,nodev,noexec,size=50%%

Prefer fstab for simple static mounts and systemd units when you need ordering dependencies or want the mount tied to other units. Do not configure the same mount in both places.

Practical Guidance

  1. Give /tmp and /var/tmp their own mounts with nodev,nosuid,noexec; a shared scratch area is the classic payload drop zone.
  2. Always run sudo findmnt --verify after editing /etc/fstab, and test on a snapshot: a malformed line can leave the host unbootable.
  3. Apply nodev,nosuid broadly (/home, /var) but introduce noexec cautiously, since some toolchains build in temporary directories.
  4. Force removable media to mount nodev,nosuid,noexec so untrusted USB drives cannot introduce devices or executables.
  5. Verify enforcement rather than trusting the config: copy a binary in and confirm it is denied, as shown above.
  6. Remember mount options are one layer only; pair them with encryption and integrity monitoring for data at rest.