Articles

Users, groups and permissions in practice: ownership, umask and the effective identity

How a process's effective identity, the mode bits and umask decide file access.

Reading: 5 minServer & Virtualization

Article cover: Users, groups and permissions in practice: ownership, umask and the effective identity

A process never touches a file “as its human owner”. The kernel gives it an identity — a user ID, an effective group ID and a set of supplementary groups — and compares that with the file’s owner, group and mode bits. Most “permission denied” incidents are a mismatch between the identity a process actually has and the ownership someone assumed, not a broken filesystem.

The identity the kernel actually uses

The permission bits are three groups of three. Which of the three groups applies is decided by a single rule:

  • the first group applies when the process’s effective user ID equals the file’s owner ID;
  • the second applies when the file’s group ID equals the process’s effective group ID, or is one of the process’s supplementary group IDs;
  • otherwise the third group applies.

So group membership is not a property of the file, it is evaluated against the groups the process currently carries. On Linux the IDs used for path resolution are specifically the filesystem user and group IDs together with the supplementary groups, and the kernel keeps the filesystem ID in step whenever the effective ID changes. After login the real and effective IDs usually coincide; sudo raises the effective ID for the command it runs, and a setuid program raises it at execve. id prints the result — the uid, the gid and the groups — which answers “as whom does this actually run?” better than reading /etc/passwd.

Ownership and the mode bits

chown sets the owner and/or the group: chown alice:web file changes both, chown alice file only the owner, and --reference copies them from another file. Who may do it is narrowly defined: only a privileged process (one with CAP_CHOWN) may change a file’s owner, while the owner may move the file to any group they are a member of.

chmod writes the mode. It accepts a symbolic form, [ugoa...][[-+=][perms...]...] (with perms from rwxXst), or an octal number of one to four digits: the first digit sets setuid (4), setgid (2) and the sticky bit (1), and the next three select user, group and other. stat -c '%a %U %G' file prints the mode in octal and the two owner names, which is the fastest way to compare “what someone remembered” with what is on disk.

For a directory the three bits mean something slightly different: x is the right to traverse it, r to list its entries, w to add or remove entries. A file can be readable while its directory is not traversable, and the error is the same EACCES.

umask: the mode a new file is born with

A new file does not get the mode you might expect. Creation calls start from a base mode — 0666 for a regular file, 0777 for a directory — and the process’s umask turns bits off from the requested mode. With the common default 022, a file created with 0666 becomes 0644, that is rw-r--r--. A server account running with 077 produces 0600 files, readable and writable by its owner alone. The umask is inherited by child processes across fork and left unchanged by execve, so a mask set in a shell spreads to everything the shell starts.

sudo and the effective identity

sudo executes a command as another user (root by default) according to the policy in sudoers: a rule names a user or a %group, the hosts it applies to, an optional (runas) target and the commands allowed, with NOPASSWD: to skip the password. Authentication is cached per terminal for five minutes by default. The part that matters for permissions is what happens after the check: the command runs with the runas user’s effective identity, and it is that identity the kernel compares with the file’s bits — not the human who typed the command. sudo -i opens a shell as that user, sudo -u runs one command as a named user.

The special bits

  • setuid (4) on a regular file — at execve the process’s effective user ID becomes the file owner’s, giving the program the owner’s rights. This is the mechanism behind classic privileged helpers, and the reason a setuid binary is security-sensitive.
  • setgid (2) on a regular file — the same idea for the group: the effective group ID becomes the file’s group.
  • setgid (2) on a directory — Linux applies BSD semantics when the directory’s setgid bit is set, so the group ID of a new file inside it is taken from the parent directory rather than from the creating process. This is how shared team directories keep a stable group.
  • sticky (1) on a directory — with it set, an unprivileged user may not remove or rename an entry they do not own, which is what makes a world-writable /tmp usable.

Two quiet removals to remember: changing an executable’s owner or group as an unprivileged user clears its setuid and setgid bits, and a filesystem mounted nosuid — or a process under no_new_privs — makes those bits ineffective regardless of what chmod shows.

What actually bites in practice

  • “I added the account to the group”. Adding a user to a group does not rewrite any file’s group, and the check uses the group set a process was given when it started: a new login session picks the membership up, a service already running does not.
  • A hardened umask you forgot about. A service started with umask 077 writes 0600 files; a second account on the same host, however well grouped, cannot read them.
  • A setuid helper that is not one. The bit is there, the mount is nosuid, and the program quietly runs with the caller’s identity.

Level and prerequisites

L2 — operational: read an identity, read a mode, and explain which one decided an access. Prerequisites are the L1 file-and-directory model and basic shell use; access-control lists, SELinux contexts and PAM belong to other sheets.

Where to go next

References