Technical Verification of Linux File Permission Structure and umask Calculation

Organizes the Octal notation in the POSIX access control model, bitwise subtraction via umask, behavior of SUID/SGID/Sticky Bit, and troubleshooting procedures for Permission Denied on Web servers.

In multi-tenant infrastructure scaling and automated deployment pipeline operations, permission inconsistencies in the file system immediately trigger HTTP 403 Forbidden errors for static assets and risks of process privilege escalation. In particular, misunderstandings of umask specifications—which dictate the permissions of intermediate files generated by automation scripts—and path hierarchy traversal failures caused by missing execution permissions (x bit) on parent directories are frequent failure patterns in production environments.

This article provides a detailed analysis of the POSIX standard access control model, permission flags via Octal notation, the bitwise logical operation mechanism of umask, and the internal behavior of special permissions (SUID/SGID/Sticky Bit).

POSIX Permission Model and Notation Structure

The Linux file system categorizes access targets into three scopes (u: User, g: Group, o: Others) and assigns three permission modes to each: r (Read), w (Write), and x (Execute).

The structure of the permission string output by the ls -l command is as follows:

- rwx r-x r--
|  |   |   |
|  |   |   +--> Others (o) : Read-only (r--)
|  |   +------> Group (g)  : Read and execute (r-x)
|  +----------> Owner (u)  : Read, write, and execute (rwx)
+-------------> File type (- = regular file, d = directory)

The behavior of access permissions differs significantly depending on whether the target is a file or a directory.

SymbolModeBehavior on FileBehavior on Directory
rReadViewing/reading file contents (cat, less)Listing file names within the directory (ls)
wWriteModifying, overwriting, appending to file contentsCreating, deleting, renaming files within the directory
xExecuteExecuting the file as a programNavigating/traversing path into the directory (cd, accessing internal files)

Having only r permission on a directory is insufficient to access internal files. To traverse the path and reference objects inside, x permission must be granted to all hierarchy levels up to the target directory.

Octal Notation and Calculation Model

The Linux kernel internally maintains permissions for each scope as a 3-bit binary mask and represents this using octal numbers from 0 to 7.

  • Read (r) = $2^2 = 4$
  • Write (w) = $2^1 = 2$
  • Execute (x) = $2^0 = 1$

Any permission state is represented by adding these values together.

  • rwx = $4 + 2 + 1 = 7$
  • rw- = $4 + 2 + 0 = 6$
  • r-x = $4 + 0 + 1 = 5$
  • r-- = $4 + 0 + 0 = 4$

Typical Production Configuration Patterns

  • 755 (rwxr-xr-x): Executable binaries, system scripts, standard public directories.
  • 644 (rw-r--r--): Static configuration files, web server assets, documents requiring no execution privileges.
  • 600 (rw-------): SSH private keys (id_rsa), SSL/TLS private keys, database connection credentials.
  • 777 (rwxrwxrwx): Unrestricted access across all scopes. A security configuration anti-pattern.

Internal Architecture and Bitwise Operations of umask

umask (User Mask) is a logical mask that specifies permission bits to be excluded by default when creating new files and directories.

The initial base permissions assigned by the Linux kernel are configured as follows:

  • File Base Permission: 666 (rw-rw-rw-) *For security reasons, execution permission x is not granted by default.
  • Directory Base Permission: 777 (rwxrwxrwx) *Includes x to allow directory traversal.

The final effective permissions are calculated via an AND operation between the base permission and the bitwise NOT of the umask.

$$\text{Effective Permission} = \text{Base Permission} \land \neg(\text{umask})$$

The calculation results when applying a standard umask 0022 are as follows:

  1. New File Calculation:
  • Base Permission: 666 (rw-rw-rw-)
  • umask: 0022 (--- -w- -w-)
  • Applied Result: $666 - 0022 = 644$ (rw-r--r--)
  1. New Directory Calculation:
  • Base Permission: 777 (rwxrwxrwx)
  • umask: 0022 (--- -w- -w-)
  • Applied Result: $777 - 0022 = 755$ (rwxr-xr-x)

Special Permissions (SUID, SGID, Sticky Bit)

As an extension to standard access permissions, Linux provides special flags.

1. Set User ID (SUID)

  • Mechanism: When executing an executable file, the process is launched with the privileges of the file owner rather than the executor.

  • Configuration Command:

    chmod u+s /usr/bin/custom-executable
    # Octal表記: chmod 4755 /usr/bin/custom-executable
    

2. Set Group ID (SGID)

  • Mechanism: When set on a directory, newly created files and directories within it automatically inherit the owner group of the parent directory instead of the primary group of the creator.

  • Configuration Command:

    chmod g+s /var/shared/
    # Octal表記: chmod 2755 /var/shared/
    

3. Sticky Bit

  • Mechanism: When set on a directory, it prevents other users from deleting or renaming files owned by someone else (deletion is restricted to the file owner, directory owner, or root).

  • Configuration Command:

    chmod +t /tmp
    # Octal表記: chmod 1777 /tmp
    

Troubleshooting

1. Permission Denied Due to Lack of Directory Traversal

When a web server or application cannot access assets, there are cases where a parent directory in the path lacks x permission, even if the permissions on the target file itself are 644.

Remediation Steps: Verify the permission state of all parent paths using the namei command and grant x permission to the directory hierarchy.

namei -om /var/www/html/app/index.html```

### 2. Failures Due to Misuse of chmod -R 777 and Remediation Steps

Executing `chmod -R 777` to resolve access denial grants irreversible execution permissions to all configuration files, causing security checking tools or the SSH daemon to reject connections.


<b>Remediation Steps</b>:
Use the `find` command to separate files and directories and batch-apply appropriate permissions.



```bash
sudo chown -R nginx:nginx /var/www/html
  find /var/www/html -type d -exec chmod 755 {} +
  find /var/www/html -type f -exec chmod 644 {} +```

## Operational Verification Protocol

Output results verifying the permission structure and traversal viability after applying settings in a system environment.



```text
# 1. Check permission structure and SELinux contexts
  $ ls -laZ /var/www/html
  drwxr-xr-x. 2 nginx nginx unconfined_u:object_r:httpd_sys_content_t:s0 4096 Sep 21 10:00 .
  drwxr-xr-x. 3 root  root  system_u:object_r:var_t:s0                 4096 Sep 21 09:50 ..
  -rw-r--r--. 1 nginx nginx unconfined_u:object_r:httpd_sys_content_t:s0  245 Sep 21 10:00 index.html

  # 2. Verify the umask value in the current shell session
  $ umask
  0022

  # 3. Determine HTTP response status
  $ curl -I http://localhost/index.html
  HTTP/1.1 200 OK
  Server: nginx/1.24.0
  Date: Sun, 21 Sep 2026 10:05:00 GMT
  Content-Type: text/html
  Content-Length: 245
  Connection: keep-alive```

## Operational Notes

- When performing recursive permission changes, avoid executing a single `chmod -R` and ensure separate application using `find -type d` and `find -type f`.
- As a rule, granting access to service accounts (such as web processes) should be resolved through correct ownership reassignment using `chown`, rather than excessive granting of permission bits.
- When operating shared directories, appropriately combining SGID (`2755`) and the Sticky Bit (`1777`) prevents access permission conflicts in multi-user environments.
Built with Hugo
Theme Stack designed by Jimmy
Privacy Policy Disclaimer Contact