A vendor package installs a set-user-ID root helper binary under `/opt` on a Linux server. What risk does that single mode bit introduce, and what changes if the filesystem holding it is mounted with the `nosuid` option?
answer
- every local user may cross that boundary
- what does the caller control while it is root
- the bit is a property of the file, the flag a property of the mount
- user-writable filesystems and privileged binaries
- the bits stay, the kernel stops caring
basics
~20 sA set-user-ID root binary runs with root's effective identity for every user on the box, so any flaw in it becomes a local root exploit. Mounting its filesystem with nosuid makes the kernel ignore the bit, so the program runs unprivileged instead.
solid answer
~50 sThe bit turns that binary into a privilege boundary that every local user may cross on demand. Whatever the program does — follow a path you supply, run a subcommand, read or write a file you name, honour an environment variable — it does as root, so a bug that would be a nuisance in an ordinary tool becomes a local root escalation. Reviewing it means asking what inputs cross the boundary and whether the program restricts itself to the caller's real UID. `nosuid` is the blunt structural control: the kernel ignores set-user-ID and set-group-ID bits (and file capabilities) for anything executed from a mount carrying that flag, so the helper still runs, just as you. That is why `/tmp`, `/home` and removable media are commonly mounted `nosuid,nodev` — a user who can write files there must not be able to manufacture a privileged one.
code
bash · 1 linefind / -xdev -type f -perm -4000 -printf '%M %u %p\n' 2>/dev/nullgo deeper
Know that a set-user-ID root binary runs as root for anyone who executes it, and that a filesystem can be mounted so the kernel ignores those bits.
Explain that nosuid is a per-mount flag applied on the exec path — the bits remain on disk but stop taking effect — and know why user-writable filesystems are mounted nosuid,nodev.
Reason about the boundary concretely: enumerate what a caller controls (arguments, environment, descriptors, races), inventory privileged binaries per filesystem, and reconcile that inventory against the packaging system.
Set the fleet policy — a reviewed allowlist of privileged binaries, nosuid by default on everything users or vendors can write, and an explicit exception process for the workloads that genuinely need a privileged helper.
## What the bit actually costs you A set-user-ID root file is not "a program with a permission". It is a **gateway that any local user may walk through**, and the kernel offers no way to narrow it: the process gets the file owner's whole identity, for every caller, on every invocation. The interesting question is therefore never "is the binary trusted?" but "**what can a caller control about what it does while it is root?**" The attack surface of such a helper is everything that crosses from the caller into the privileged process: - **Arguments** — any path the program opens, creates or removes as root. If it writes to a filename you supply, you own the machine. - **The environment** — anything the program reads from the environment and acts on, classically `PATH` when it launches a helper by bare name, and `IFS` or `TMPDIR` in older code. glibc puts set-user-ID processes into *secure-execution mode*, which sanitises the loader-related variables such as `LD_PRELOAD` and `LD_LIBRARY_PATH`, but it cannot sanitise variables the application itself trusts. - **Anything that spawns a shell.** A privileged binary that can be persuaded to run an arbitrary command, open an editor, or drop into a pager is a root shell with extra steps. This is why so many ordinary utilities become escalation primitives the moment somebody sets the bit on them. - **File descriptors, resource limits, signals, the working directory** — all inherited from the attacker's process. - **Race windows.** Check-then-open sequences on a path in a world-writable directory let an attacker swap a symlink in between. A well-written helper narrows this by dropping privilege immediately (`seteuid()` around only the operation that needs root, or a permanent `setuid()` once the privileged work is done) and by validating that the operation is legitimate **for the real UID** rather than for root. ## Inventory You cannot reason about what you have not listed: ``` find / -xdev -type f -perm -4000 -printf '%M %u %p\n' 2>/dev/null ``` `-perm -4000` matches "at least these bits"; `-perm /6000` catches set-user-ID **or** set-group-ID; `-xdev` keeps the walk on one filesystem so you can run it per-mount. On a stock server the answer is a short, recognisable list — mount helpers, the password tool, a couple of network utilities. Anything outside that list deserves a justification. Compare the list against what the packaging system says should be there, and treat an unexplained entry as an incident, not as untidiness. Removing a bit is `chmod u-s`, and note two kernel behaviours that help: **changing an executable's owner clears set-user-ID and set-group-ID**, and so does writing to the file. An unprivileged user therefore cannot construct a privileged binary out of content they control — the bits can only be applied by somebody who is already privileged. ## What nosuid does `nosuid` is a **per-mount** flag. When a filesystem is mounted with it, the kernel does not honour set-user-ID or set-group-ID bits — and does not honour file capabilities — for programs executed from it. The bits stay on disk; they simply have no effect. The binary still runs, with the caller's identity. That makes it the right control for two distinct situations: 1. **Filesystems users can write.** `/tmp`, `/var/tmp`, `/home`, `/dev/shm`, removable media and network mounts are commonly mounted `nosuid,nodev` (often `noexec` too). If a user can place a file there, they must not be able to place a *privileged* file there — otherwise any way to get root to write a file becomes full escalation. 2. **Filesystems you do not control the contents of**, such as a vendor tree under `/opt` or a mounted image. Mounting it `nosuid` neutralises the whole class of question without needing to audit the vendor's code — at the cost of breaking the helper if it genuinely needed the privilege. That tradeoff is the conversation to have with the vendor. Options go in the mount entry for the filesystem, and are visible per mount at runtime. A caveat worth knowing: on a **bind mount**, the flags are a property of the mount, and changing them requires a separate remount of the bind (`mount -o remount,bind,nosuid <target>`) rather than passing the option on the original bind command. A second caveat: `noexec` and `nosuid` protect different things. `noexec` can be sidestepped for scripts by handing the file to an interpreter you already have — `sh /tmp/x` never execs `/tmp/x` — whereas `nosuid` is applied on the kernel's exec path itself and cannot be worked around that way. ## The judgment to show Say the risk in one sentence — every local user can invoke root-privileged code, so the binary's bugs are the machine's bugs — then give two answers rather than one: audit and minimise the set of privileged binaries, and structurally neutralise the ones you cannot vouch for by mounting their filesystem `nosuid`.
- Does mounting nosuid remove the bits from the files?No. `nosuid` is a property of the mount, not of the inodes: the bits remain on disk and reappear the moment the filesystem is mounted without the flag, or mounted somewhere else. Treat it as a containment control rather than a fix — the durable fix is clearing the bit with `chmod u-s`, or not shipping the binary at all.
- Why are /tmp and /home so often mounted nosuid,nodev?Because users can write there. If an attacker can place a file in a directory and also find any way to get a privileged process to set the bit — or restore a backup, or extract an archive as root — a writable filesystem that honours set-user-ID turns a small bug into root. `nodev` closes the parallel trick of creating a device node that grants raw access to disks or memory.
- A helper needs one privileged operation, such as binding a low port. Is setuid root the right tool?Rarely. Set-user-ID is all-or-nothing: it hands over the owner's entire identity, when the program needs one narrow power. The right instinct is to grant the narrowest thing the kernel can express, or to have a small, audited privileged service perform the operation on request, and to keep the general-purpose code unprivileged.
- Is noexec on /tmp equivalent protection?No, they cover different holes. `noexec` refuses to exec binaries from the mount, but a script can still be run by handing it to an interpreter that lives elsewhere, so it is easily sidestepped. `nosuid` is enforced by the kernel on the exec path itself: the program may still run, it simply never gains the file owner's identity. Use both.
saying these in an interview costs you the question
- Says a setuid binary is safe because only root can install it.
- Thinks nosuid removes or clears the bits on disk.
- Assumes noexec and nosuid protect against the same thing.
- Believes the bit grants only the access the program needs.
- Ignores environment and argument input as an attack path.