Introduction
On how Linux really handle privileges on processes has always felt like a black box to me. You type a command, and sometimes the system says “permission denied,” sometimes “okay, you’re root now,” and you shrug. You think it’s magic. But today, after spending hours staring into /proc, reading task_struct, tracing execve(), and watching UIDs dance around, I finally see what’s really happening. Linux isn’t magic at all it’s mechanical, almost brutally logical.simple yet powerfull and perfect. Every privilege, every setuid program, every sudo call, every login shell is enforced in code. No luck, no wizardry just a lot of careful kernel work.
I’m going to break it all down. Strap in.
UIDs: The Kernel Doesn’t Give a Damn About Names
Okay, now, let me catch your thought: “wait, but what about /etc/passwd and usernames?” Yeah, I get you. That’s the trap most people fall into. The kernel does not care about your username. Zero. The kernel only cares about numbers: UIDs and GIDs. That’s it.
Every process has a task_struct. Inside that is a cred struct that tracks all the UIDs and GIDs relevant to the process:
struct cred {
kuid_t ruid; // Real UID: the user who launched the process
kuid_t euid; // Effective UID: what you can actually do right now
kuid_t suid; // Saved UID: what you can regain if you drop privileges temporarily
kgid_t rgid; // Real GID
kgid_t egid; // Effective GID
kgid_t sgid; // Saved GID
};
- ruid (Real UID): Think of it like your “birth certificate” in Linux.its who spawned you. This almost never changes unless a privileged syscall explicitly allows it.
-
euid (Effective UID): This is what the kernel actually checks for privileges. Want to open
/etc/shadow? Kernel checks this. Want to bind port 80? Kernel checks this. - suid (Saved UID): This is your “back door” to regain privileges you temporarily dropped. I’ll show why this matters with setuid programs.
Rule: The kernel is the boss. Userspace tools like sudo or su just orchestrate things.the kernel is the one making all the actual decisions.
Setuid: Privilege Already Baked Before You Touch Anything
Next up, the setuid. That infamous +s bit. This is literally the kernel saying:
“When this program runs, I’m going to temporarily treat it as if it belongs to the file owner, not the person executing it.”
Let me break it down. You have /usr/bin/passwd (owned by root, setuid). When alice runs it:
ruid = 1000 (alice)
euid = 0 (root)
suid = 0 (root)
Now, look closely:
-
ruidstays alice —> she is still herself. -
euidis root —> kernel checks this for every privileged syscall. -
suidis root —> the “return ticket” if alice temporarily drops privileges.
Yes, the saved UID exists because without it, once you drop privileges, you could never regain them. That’s the entire point.
Dropping and Regaining Privileges Safely
Setuid programs don’t just run full power the entire time cause that would be insane. They often drop privileges temporarily while doing risky stuff. Then, when needed, they regain them:
seteuid(ruid); // drop privileges
// do unprivileged work
seteuid(suid); // regain privileges
Timeline (simplified):
Execve setuid-root:
ruid=alice euid=root suid=root
Drop privileges:
seteuid(ruid)
ruid=alice euid=alice suid=root
Regain privileges:
seteuid(suid)
ruid=alice euid=root suid=root
Notice that suid never changes when you temporarily switch euid. It’s a fixed “return ticket.”
When Setuid Is Not Set
Now, let’s be clear: if a file doesn’t have +s, the kernel does something simple:
ruid = caller UID
euid = caller UID
suid = caller UID
Nothing magical. You can’t elevate yourself arbitrarily. Only root (or a setuid-root binary) can raise privileges.
Rules of Privilege Escalation
Now, now, I know what you’re thinking: “so, only root can become anyone else, right?” Exactly. Let’s spell it out:
- euid=0 (root): can change ruid/euid/suid to anything. Full control.
- Normal users: can only lower privileges (drop euid). No raising to someone else’s UID.
- Setuid files: allow a controlled, kernel-enforced elevation to the file owner’s UID.
- ruid: almost immutable; it’s your original identity.
Example scenario:
User1: UID 1001
User2: UID 1002
- User1 cannot become 1002.
- User2 cannot become 1001.
- Only root could switch to either.
Login Shells and TTYs: The “Fall From Grace”
Alright, now I know exactly what you’re thinking if u read it till now,: “if the ruid is the one who start the process,who the hell owns the TTY I log in to?” Let me untangle this.
Before you log in, every virtual terminal (VTY) is essentially owned by root. That’s right,before login, you are like an all-powerful god sitting in /dev/tty1…6.
Then systemd or init starts getty (or agetty), which listens for login attempts. getty itself is root-owned. it has to be, because it’s going to spawn login shells, check passwords, and eventually drop privileges safely.
When you finally log in:
-
loginverifies your credentials - then spawns your login shell (bash, zsh, whatever)
- and suddenly you fall from grace:
ruid = your UID
euid = your UID
suid = your UID
Haha, right? All-powerful god → mortal user in one instant. This is why root privileges are tightly controlled: you can’t just pick up random UIDs at will. The kernel enforces this rigorously.
here check this image ive attached below if u still find this tty thing confusing..
sudo, su, and Variants
Here’s the part most people misunderstand: sudo and su aren’t magical at all they’re setuid-root programs that orchestrate privilege elevation under kernel rules.
-
sudo: Runs as root (setuid), checks
/etc/sudoers, then temporarily switches euid to root for your command. -
sudo -i: Starts an interactive root shell (
euid=0). - su: Switch user; requires root privileges to switch to another user.
-
su -: Switch user and simulate login environment (
PATH, environment variables, etc.).
Without the kernel enforcing UIDs, all of this would be meaningless. When you run sudo, the kernel sees:
ruid = original user
euid = root (because sudo binary is setuid-root)
suid = root
And everything is checked at the syscall level. Permissions aren’t faked.they are real.
Process Startup: Everything Happens in Order
Timeline, kernel-first:
Parent calls execve(path, argv, envp)
↓
Kernel checks permissions, filesystem flags, LSM
↓
Kernel sets credentials (ruid, euid, suid) → includes setuid handling
↓
Kernel loads ELF segments into memory
↓
Kernel builds stack with argc, argv, envp, auxv
↓
Kernel switches to user mode at _start
↓
C runtime extracts argc, argv, envp
↓
main(argc, argv, envp) runs
Key point: credentials are applied before the environment exists, before the program executes a single instruction, and before it can touch syscalls. That’s why setuid works safely.
Mental Model
Think of Linux privileges like this:
execve() → kernel enforces creds (ruid/euid/suid)
↓
ELF loaded, stack built (argc/argv/envp)
↓
_enter_user_mode()
↓
C runtime sets up main()
↓
program executes, syscalls checked against euid
- Setuid program: ruid = caller, euid = file owner, suid = file owner
- Normal program: ruid = euid = suid = caller
- Drop privileges temporarily → regain via suid → safe privilege handling
- Only root or setuid-root binaries can elevate euid arbitrarily
Why This Matters
Once you understand this:
-
sudo,su, login shells, daemons, and setuid-root programs stop being mysterious. - Everything funnels down to kernel-enforced credentials.
- Understanding ruid/euid/suid, setuid, and process startup explains why Linux is secure and why miswritten setuid programs are a security nightmare.
Linux isn’t magic. It’s just mechanical, precise, and enforced at every step. Once you see it, everything clicks.

Top comments (0)