Mounting /tmp
with noexec
has been a longstanding security recommendation in Unix-like systems. The principle is straightforward: by preventing direct execution of binaries in the world-writable temporary directory, you create an additional barrier against privilege escalation attacks. This is particularly relevant in:
- Shared hosting environments
- Multi-user systems
- Services that process untrusted uploads
While noexec
provides a security boundary, determined attackers can bypass it through several methods:
# Method 1: Using the dynamic loader directly
/lib64/ld-linux-x86-64.so.2 /tmp/malicious-binary
# Method 2: Script execution via interpreters
python3 /tmp/exploit.py
perl /tmp/exploit.pl
These techniques effectively nullify the protection for many attack scenarios while introducing management overhead.
Several common applications expect executable /tmp
space:
# Debian's debconf example
DEBIAN_FRONTEND=noninteractive apt-get install -y some-package
# May fail with:
# Error: Could not create temporary directory for execution
Workarounds often involve creating dedicated executable spaces:
# Alternative tmp directory solution
mkdir -p /var/tmp-exec
mount -o bind,exec /var/tmp-exec /tmp/.exec
chmod 1777 /tmp/.exec
The security value of /tmp
hardening varies by use case:
Scenario | noexec Benefit | Bypass Difficulty |
---|---|---|
Automated mass exploitation | High - blocks many ready-to-run exploits | Medium |
Targeted attacks by skilled adversaries | Low - easily bypassed | Low |
Misconfigured services | Medium - prevents some RCE vectors | High |
For systems where noexec
causes compatibility issues, consider:
# Namespace isolation with PrivateTmp in systemd
[Service]
PrivateTmp=true
# Mounting tmpfs with restricted permissions
mount -t tmpfs -o size=1G,nosuid,nodev,noexec,mode=1777 tmpfs /tmp
For containerized environments, combine with:
# Docker example
docker run --read-only --tmpfs /tmp:noexec,nosuid,size=1g
Historically, mounting /tmp
with noexec
was considered a security best practice to prevent execution of malicious binaries in world-writable directories. The Debian Security Manual explicitly recommends:
# /etc/fstab example
tmpfs /tmp tmpfs nosuid,nodev,noexec 0 0
Colin Watson and other security researchers have demonstrated practical bypass methods:
# Method 1: Using ld-linux directly
/lib64/ld-linux-x86-64.so.2 ./malicious-binary
# Method 2: Script execution via interpreters
#!/bin/bash
echo "Malicious payload" > /tmp/script.sh
/bin/bash /tmp/script.sh
In containerized environments, the effectiveness diminishes further. Consider this Docker scenario:
FROM alpine
RUN mkdir -p /tmp/exploit && \
echo -e '#!/bin/sh\nid > /tmp/output' > /tmp/exploit/poc && \
chmod +x /tmp/exploit/poc && \
/bin/sh /tmp/exploit/poc
More effective approaches include:
- Implementing filesystem namespaces
- Using SELinux/AppArmor policies
- Applying mount point restrictions
Example AppArmor profile snippet:
# /etc/apparmor.d/deny-tmp-exec
/tmp/** ix,
Despite limitations, noexec
remains valuable for:
- Blocking naive exploit attempts
- Compliance requirements
- Defense-in-depth strategies
For systems using debconf
, configure exceptions:
# /etc/debconf.conf
TmpFileMode: 0755
Modern tmpfs implementations show negligible overhead from noexec:
$ time dd if=/dev/zero of=/tmp/test bs=1M count=1000
# Compare with and without noexec