Interactive lab · kernel internals
Linux permissions, visually
Eight passes over the same question: which identity does the kernel actually compare against an inode? Step the newgrp syscall sequence, toggle the 16 bits of i_mode, and run the DAC cascade yourself.
The stale groups dilemma — why usermod -aG fails open shells
When an admin adds you to a group, your open terminal does not inherit it. Step through the lifecycle.
Linux processes never poll /etc/group. Credentials are an immutable, reference-counted in-kernel object.
Kernel structure: task_struct → struct cred
Every thread has a task_struct pointing at its struct cred. Four distinct ID pairs live there, and only one of them decides file access.
| Credential field | Name | Kernel role |
|---|---|---|
uid / gid | Real ID | Identifies the user who spawned the process. Determines signal delivery permissions — who may kill it. |
euid / egid | Effective ID | Used for general authorization, creating IPC primitives, and evaluating privileged capabilities. |
suid / sgid | Saved set-ID | Preserves the prior effective ID across a setuid binary, so a process can drop and re-elevate privilege safely. |
fsuid / fsgid | Filesystem ID | The ID actually used for file access. When the kernel checks inode permissions in the VFS it compares against fsuid, not euid. |
NFS servers and other userspace file servers are why fsuid exists: they can impersonate a user for file access without also inheriting that user’s signal permissions.
Interactive newgrp syscall player
Six steps, from fork() to the refreshed shell. Watch which credential fields change at each one.
Bash forks a child process. The child inherits identical copies of every credential pointer from the parent shell.
| ID type | UID (user) | GID (group) | Supplementary groups |
|---|---|---|---|
| Real | 1000 (alice) | 1000 (alice) | 1000 (alice) |
| Effective | 1000 (alice) | 1000 (alice) | 1000 (alice) |
| Saved | 1000 (alice) | 1000 (alice) | 1000 (alice) |
| Filesystem | 1000 (alice) | 1000 (alice) | 1000 (alice) |
newgrp is setuid-root. Its privileged setgid() call changes all four GID fields — real, effective, saved and filesystem — not just the effective one.
Inodes & dentry path resolution
Opening /var/log/app.log walks three layers of cache before any disk block is touched.
The kernel checks its hash table of directory entries, resolving the filename string to an inode number in a sub-microsecond RAM lookup.
Reads the block group descriptor and inode bitmap from disk, loading a struct inode of 128 or 256 bytes holding i_mode, i_uid, i_gid, size and the extent tree.
Reads the extent pointers out of the inode and streams 4 KB physical blocks into the system page cache.
Interactive i_mode 16-bit grid
Toggle any bit, or load a preset, and watch the octal mode, the ls -l string and the file type stay in sync.
- Octal mode
- 0755
- ls -l string
- -rwxr-xr-x
- File type
- Regular file
- Special flags
- None
The execute column carries two meanings at once. A set-id or sticky bit replaces x with s or t, and uppercases it when the execute bit underneath is clear — which is how ls shows you a set-id bit that can never actually fire.
Interactive DAC flowchart (generic_permission)
Four actors attempt a write to a file owned by alice:developers, mode 0640 (-rw-r-----).
- Check owner
current->fsuid == inode->i_uidMatch: fsuid 1000 == i_uid 1000, and the owner bits carry 'w' (rw-).
- Check group
current->fsgid == inode->i_gid, or in supplementary groupsSkipped — the owner already matched.
- Check others
fall through to the last three mode bitsSkipped.
- Root override
capable_wrt_inode_uidgid(CAP_DAC_OVERRIDE)Skipped.
Access granted — owner write permitted
Root’s override comes last. The kernel first checks whether the permission bits naturally permit access; only on refusal does it test for CAP_DAC_OVERRIDE.
SGID directory demo
What changes about file creation when the setgid bit is applied to a directory.
owned by alice:developers
$ touch /data/plain/report.txt
$ ls -l /data/plain/report.txt
-rw-r--r-- 1 bob bob 0 Oct 25 10:00 report.txt
The file's group defaults to Bob's primary group, so team members in developers cannot write to it.
drwxrwsr-x)owned by alice:developers, SGID set
$ touch /data/collab/report.txt
$ ls -l /data/collab/report.txt
-rw-r--r-- 1 bob developers 0 Oct 25 10:00 report.txt
The kernel inherits the parent directory's GID. New subdirectories inherit the SGID bit as well.
Try it yourself
Run these in any Linux shell to read your own live credentials and inode metadata.
# 1. Inspect all four UIDs and GIDs of your current shell process
grep -E 'Uid|Gid|Groups' /proc/$$/status
# 2. Inspect inode metadata, permissions and the raw octal mode
stat -c "File: %n | Inode: %i | Octal: %a | Access: %A | Owner: %U(%u):%G(%g)" /etc/passwd
# 3. Simulate newgrp and observe the subshell's GIDs
newgrp developers
grep -E 'Gid|Groups' /proc/$$/status
exit