42.6 Filesystem Hardening: noexec, nosuid, nodev Mount Options
Right, let’s talk about making your filesystem a less hospitable place for miscreants. You’ve got your server up, it’s serving what it needs to serve, and you’re feeling pretty good. But if you’re just using the default mount options, you’re leaving the front door unlocked and a big “FREE LAPTOP” sign on the lawn. The noexec, nosuid, and nodev mount options are like deadbolts, a security system, and taking that stupid sign down.
Think of any directory that you let the world write to, like /tmp or /var/tmp. Now, imagine an attacker finds a way to drop a malicious binary in there. If they can trick a user or a service into running it, game over. The noexec option is our first line of defense here. It does exactly what it sounds like: it prevents the execution of any binaries directly from that filesystem. The file can be written, read, even set as executable with chmod +x (which is a cruel joke at that point), but the kernel will flat-out refuse to run it. It’s like having a recipe for a bomb but no kitchen to build it in.
When to use noexec (and when not to)
You should slap noexec on any filesystem that has no legitimate reason to run executables. This is almost always the right choice for:
/tmp/var/tmp- User-owned directories used for file uploads (e.g.,
/var/www/uploads)
Here’s how you make it permanent in your /etc/fstab. Find the line for your partition and add the option.
# /etc/fstab
# Before (a vulnerable default)
UUID=12345-abcde /tmp ext4 defaults 0 0
# After (a much smarter setup)
UUID=12345-abcde /tmp ext4 defaults,noexec 0 0
After editing, remount it without a reboot:
sudo mount -o remount /tmp
Now, test it. Try to compile a simple binary and run it from /tmp.
cd /tmp
echo 'int main() { return 0; }' > test.c
gcc test.c -o test
./test
You’ll be greeted with a beautiful -bash: ./test: Permission denied, even though ls -l shows it has the execute bit set. That’s noexec doing its job perfectly.
The Big Pitfall: Do not put noexec on /usr or /var (the whole thing). /usr contains, you know, all your programs. /var might contain things like CGI scripts or other legitimate executables. You’ll break your system in spectacular and confusing ways. Be surgical.
The weird world of nosuid and nodev
While noexec deals with binaries, nosuid and nodev deal with special files.
nosuid is crucial. It prevents the Set User ID (SUID) and Set Group ID (SGID) bits on files from having any effect. An SUID binary runs as the owner of the file (usually root), not the user who executed it. passwd is a classic example—it needs to run as root to write to /etc/shadow. If an attacker can plant a malicious SUID binary in a world-writable directory like /tmp, they can get a root shell instantly. nosuid neuters this entire attack vector. There is almost never a good reason for an SUID binary to exist in /tmp or /var/tmp, so nosuid is a must.
nodev prevents device files from being created on the filesystem. In Unix, everything is a file, even hardware devices like /dev/sda1. If an attacker can create a device file in a writable directory, they can potentially read directly from memory or write to disk blocks, leading to all sorts of mayhem. This is a more esoteric attack, but it costs you nothing to enable nodev on these non-root filesystems.
Your /etc/fstab line should ideally use all three for maximum hardening:
UUID=12345-abcde /tmp ext4 defaults,noexec,nosuid,nodev 0 0
The One Annoying Exception (Because Of Course)
So you’ve hardened /tmp with noexec and now some poorly-written legacy application or shitty install script is failing because it tries to execute something from /tmp. It’s frustrating, but it happens. You have three choices:
Fix the Application: Tell the vendor their app is bad and they should feel bad. The correct place for this is
/var/tmp(which should also benoexec!) or a dedicated directory under/optor/var.Use a Bind Mount (The “Fine, You Win” Solution): Create a dedicated directory for this one annoying app that does need executable space, and mount it with
exec.sudo mkdir /var/tmp-exec sudo mount -o bind /var/tmp-exec /tmp/special-app-dirThen add a more specific line to your
fstab:/var/tmp-exec /tmp/special-app-dir none bind,exec 0 0This contains the risk to a single directory.
The Nuclear Option: Remove
noexecfrom/tmp. Please don’t do this. It’s admitting defeat and making your system less secure for everyone. Exhaust options 1 and 2 first.
Using these options isn’t just checklist security; it’s about fundamentally reducing your attack surface. It forces the system to behave the way it should behave in those locations, closing off whole classes of exploits before they can even be attempted. It’s one of the easiest, most effective wins you’ll get.