> For the complete documentation index, see [llms.txt](https://book.bsdcn.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://book.bsdcn.org/ask/flat/chapter-14-user-accounts-and-permissions/di-14.2-jie-quan-xian.md).

# 14.2 Permissions

The file system permission mechanism is the cornerstone of the security architecture of UNIX-like systems.

In FreeBSD, each file and directory is associated with a set of permissions, and there are various tools available for viewing and modifying these permissions.

Permissions determine which files a user can access, and whether they can modify or execute files that do not belong to them.

Basic UNIX permissions are assigned using three access types: read, write, and execute. These access types are used to determine the file access permissions for the file owner, group, and other users.

This section discusses the traditional UNIX permissions used in FreeBSD and does not cover fine-grained permissions.

## Discretionary Access Control (DAC) Model

The traditional UNIX permission model adopted by FreeBSD falls under the category of Discretionary Access Control (DAC). The core characteristic of DAC is that the owner of an object has the authority to independently decide whether to grant access permissions to other subjects or revoke their access permissions. In UNIX systems, the owner of a file can modify the file's permission bits to determine other users' access capabilities to the file. Since access control decisions are made by the object owner rather than centrally by the system administrator, this model is called "discretionary."

The theoretical foundation of the DAC model can be traced back to multi-user operating system security research in the 1960s-1970s. The Trusted Computer System Evaluation Criteria (TCSEC, also known as the "Orange Book") published by the U.S. Department of Defense in 1985 defines DAC as: an access control mechanism that limits access to objects based on the identity of subjects and/or the groups to which they belong, where the owner of an object can specify or modify access permissions (Source: Department of Defense. DoD 5200.28-STD: Trusted Computer System Evaluation Criteria\[S]. Washington, D.C.: Department of Defense, 1985.).

The traditional UNIX DAC model has the following characteristics and limitations:

* **Coarse-grained control**: Only distinguishes between three categories of subjects — owner, owning group, and other users — and cannot grant fine-grained permissions to individual users or multiple groups.
* **Permission propagation**: File owners can grant permissions to any user, including granting write permissions to untrusted users, which may lead to permission leakage.
* **Superuser bypass**: The root user is not constrained by DAC and can access any file. While this design provides administrative convenience, it also constitutes a potential security risk; once root privileges are illegally obtained, the entire system's security defense line collapses.

To compensate for the shortcomings of the traditional DAC model, FreeBSD provides the following enhancement mechanisms:

* **Access Control Lists (ACL)**: The ACL mechanism based on the POSIX.1e draft standard allows setting fine-grained access permissions for individual users or groups, breaking through the limitation of traditional DAC that only supports three categories of subjects.
* **Mandatory Access Control (MAC)**: The TrustedBSD MAC framework provides policy-based mandatory access control capabilities, including the Biba integrity model, MLS multi-level security model, and others. Unlike DAC, MAC access control decisions are enforced by system security policies, and object owners cannot modify them on their own.
* **File Flags**: FreeBSD supports setting file flags via chflags(1), such as `schg` (system immutable flag) and `sappnd` (system append-only flag); even the root user cannot modify files with these flags (unless the flags are removed first). File flags add an additional layer of security and control; even root cannot delete or modify these files.
* **Capsicum Sandbox Framework**: Limits the range of system resources accessible to a process through the capability mechanism, implementing the principle of least privilege.

## Permission Expressions

Observe the following `ls` command output example to understand the composition of permission expressions:

```sh
# ls -al /home/ykla  # Display detailed file listing under /home/ykla directory
total 74
drwxr-xr-x  17 ykla ykla    27 Mar 19 17:57 .
drwxr-xr-x   3 root wheel    4 Mar 19 16:05 ..
drwx------   4 ykla ykla     4 Mar 10 16:21 .mozilla
-rw-r--r--   1 ykla ykla   966 Feb 24 12:18 .profile
-rw-------   1 ykla ykla   200 Mar 19 17:57 .sh_history
-rw-r--r--   1 ykla ykla  1003 Feb 24 12:18 .shrc
drwxr-xr-x   2 ykla ykla     2 Mar  9 23:48 .themes
drwxr-xr-x   2 ykla ykla     2 Mar  9 20:45 Desktop
```

Observe again:

```sh
----------   1 root wheel         0 Mar 19 22:26 test
```

FreeBSD file access permissions can be represented using 10 flag bits (the reader should verify whether the first column is 10 characters), and these 10 flag bits consist of 4 parts:

Separated by slashes: `-/---/---/---`

```sh
- / --- / --- / ---
|   |     |     |
|   |     |     └─── Fourth part: other users permissions (others)
|   |     └───────── Third part: group users permissions (group)
|   └─────────────── Second part: owner permissions (owner)
└─────────────────── First part: file type / device type
```

The first part is bit 1, representing the file type / device type:

| Character | Type                  |
| --------- | --------------------- |
| `d`       | Directory             |
| `-`       | Regular file          |
| `l`       | Symbolic link file    |
| `b`       | Block device file     |
| `p`       | Pipe file             |
| `c`       | Character device file |
| `s`       | Socket file           |

The second part consists of bits 2, 3, and 4, representing the file owner's access permissions to the file, using `rwx` to denote read, write, and execute permissions (for directories, this means access permissions, such as `ls`, `cd`); no permission is written as `-`.

The third part consists of bits 5, 6, and 7, identifying the access permissions of the file's group members to the file.

The fourth part consists of bits 8, 9, and 10, identifying the access permissions of other users to the file.

Read, write, and execute permissions, in addition to being represented by `rwx`, can also correspond to the numbers 4, 2, and 1 respectively; no permission is 0. The numbers corresponding to each three-bit permission are added together and combined to form a 3-digit numeric representation (mnemonic: "read 4 write 2 execute 1").

The possible numeric and alphabetic combinations are as follows.

**UNIX Permissions**

| Value | Permission Description                   | Directory Listing |
| ----- | ---------------------------------------- | ----------------- |
| 0     | No read, no write, no execute permission | `---`             |
| 1     | No read, no write, execute permission    | `--x`             |
| 2     | No read, write, no execute permission    | `-w-`             |
| 3     | No read, write, execute permission       | `-wx`             |
| 4     | Read, no write, no execute permission    | `r--`             |
| 5     | Read, no write, execute permission       | `r-x`             |
| 6     | Read, write, no execute permission       | `rw-`             |
| 7     | Read, write, execute permission          | `rwx`             |

The code for the above numbers representing permissions can be found in [main/sys/sys/stat.h](https://github.com/freebsd/freebsd-src/blob/main/sys/sys/stat.h), defined by the IEEE Std 1003.1 specification:

```c
#define     S_IRWXU 0000700                 /* Owner's read, write, execute (RWX) permission mask */
#define     S_IRUSR 0000400                 /* Owner's read (Read) permission */
#define     S_IWUSR 0000200                 /* Owner's write (Write) permission */
#define     S_IXUSR 0000100                 /* Owner's execute (Execute) permission */
```

The mechanism by which the system controls device permissions is based on the traditional UNIX philosophy of "everything is a file," which treats most hardware devices as files that programs can open, read, and write. These special device files are stored in the **/dev/** directory.

A typical **/dev/** directory:

```sh
$ ls /dev
acpi                efi             mixer0          pci             ttyv6
apm         fd              mlx5ctl         pfil            ttyv7
apmctl              fido            nda0            psm0            ttyv8
atkbd0              full            nda0p1          pts             ttyv9
audit               geom.ctl        nda0p2          random          ttyva
auditpipe   gpt             nda0p3          reroot          ttyvb
bpf         hpet0           netdump         sndstat         ufssuspend
bpf0                input           netmap          stderr          ugen0.1
bpsm0               io              null            stdin           ugen0.2
cd0         iso9660         nvd0            stdout          ugen0.3
console             kbd0            nvd0p1          sysmouse        uinput
consolectl  kbd1            nvd0p2          tcp_log         urandom
ctty                kbdmux0         nvd0p3          ttyv0           usb
devctl              klog            nvme0           ttyv1           usbctl
devctl2             kmem            nvme0n1         ttyv2           xpt0
devstat             log             nvme0ns1        ttyv3           zero
dsp0                mdctl           pass0           ttyv4           zfs
dumpdev             mem             pass1           ttyv5
```

> **Thought Question**
>
> > `drw-------`, i.e., `600`, this is a directory where only the owning user can read and write.
>
> Is this statement correct? Is it meaningful? Why? How do you understand this design paradox?

Directories are also treated as files, handled the same way, and also have read, write, and execute permissions. The execute bit for directories is slightly different from files; when a directory is set as executable, it means the `cd` command can be used to enter that directory.

This also means that to access files in that directory, the prerequisite is that the file's own permissions allow access:

```sh
$ cd test/
cd: test/: Permission denied        # Permission denied
$ ls -ld test/      # Browse directory permissions
drw-------  2 ykla ykla 2 Apr 28 00:24 test/
```

To list the contents of a directory, the directory must have read permission. To delete a file with a known name, you must have both write and execute permissions on the directory containing the file.

There are also additional permission bits, primarily used for special scenarios, such as setuid executable files and sticky directories.

## Symbolic Permissions

Symbolic permissions use characters rather than octal values to assign permissions to files or directories. The syntax is `(target)(operator)(permission)`, where the available values are as follows:

| Option     | Letter | Represents                |
| ---------- | ------ | ------------------------- |
| Target     | u      | User                      |
| Target     | g      | Group owner               |
| Target     | o      | Other                     |
| Target     | a      | All (ALL)                 |
| Operator   | +      | Add permission            |
| Operator   | -      | Remove permission         |
| Operator   | =      | Explicitly set permission |
| Permission | r      | Read                      |
| Permission | w      | Write                     |
| Permission | x      | Execute                   |
| Permission | t      | Sticky bit                |
| Permission | s      | Set UID or GID            |

> **Note**
>
> The `t` (sticky bit) in chmod(1) symbolic mode is marked as an XSI extension option in the POSIX standard, not a POSIX base requirement. When operating `s` (set UID or GID) or `t` flag (sticky bit) on the "other" permission (`o`) alone, it will be ignored. To set the sticky bit, use `+t` or `a+t`, not `o+t`.

These values are used with chmod(1), but using letters instead of numbers. For example, the following command will prevent group members and all other users associated with test from accessing test:

```sh
% chmod go= test
```

~~Here, "go" does not mean "go forward," but rather "group owner" and "other." And the space after the equals sign is necessary.~~

When multiple changes to file permissions are needed, a comma-separated list can be provided. For example, the following command removes group and "world" write permissions from test and adds execute permission for all users:

```sh
% chmod go-w,a+x test
```

> **Tip**
>
> The `X` permission in chmod(1) symbolic mode only sets the execute bit when the file is already executable or is a directory, commonly used in `chmod =rw,+X` to preserve existing execute permissions.

### Operator Method

Grant execute permission to all users for the test.sh script:

```sh
$ chmod a+x test.sh
```

In `a+x`:

* `a` indicates that the operation target is all users. Other options include: `u` for the owning user, `g` for the owning group, `o` for other users; if omitted, the system default target is used;
* `+` is the operator, meaning to add permission; the alternative `-` removes permission;
* `rwx` is the permission mode. `r` means read, `w` means write, `x` means execute. The option `s` means setting the process owner or group to the file's owner or group when the file is executed.

### Numeric Method

Set the permissions of `test.sh` to owner read/write/execute, group users read/execute, other users no permission:

```sh
$ chmod 750 test.sh
```

Where:

* `7`: The owning user has read, write, and execute permissions
* `5`: Group users have read and execute permissions
* `0`: Other users have no permissions

Here, the `-R` option can recursively modify permissions.

Example:

```sh
# chmod -R 777 /tmp # Allow any user to read, write, and execute all files under /tmp directory
# chmod -R a+rwx /tmp # Allow any user to read, write, and execute all files under /tmp directory
```

## umask: File Creation Mask

In UNIX systems, when a process calls system calls such as open(2) or mkdir(2) to create a file or directory, the kernel uses the file creation mask (umask) to determine the final permissions. umask is a process-level attribute that specifies which permission bits should be masked (removed) during file creation. The umask mechanism ensures that newly created files do not accidentally have overly permissive permissions.

In fact, the permission values are octal, not decimal. Converting octal 755 to binary yields: 111 101 101. The specific calculation process:

```sh
7
= 4 + 2 + 1
= 1x2^2 + 1x2^1 + 1x2^0
= 111_2

5
= 4 + 0 + 1
= 1x2^2 + 0x2^1 + 1x2^0
= 101_2

5
= 4 + 0 + 1
= 1x2^2 + 0x2^1 + 1x2^0
= 101_2

Combine (final number = sum of (digit x base^position), position starts from 0, from right to left, sum represents the total):

111 101 101_2
```

> **Tip**
>
> Generally, any non-zero number raised to the power of 0 equals 1.

Specifically, the initial permissions of a new file are determined by performing a bitwise AND operation between the mode parameter in the creation request and the negated umask:

```sh
Final permissions = Requested mode & ~umask
```

> **Tip**
>
> Bitwise AND `&`:
>
> Bitwise NOT:
>
> ```sh
> umask:   000 010 010   (022)
> ~umask:  111 101 101   (755)
> ```

| Bit 1 | Bit 2 | Result |
| ----- | ----- | ------ |
| 1     | 1     | 1      |
| 1     | 0     | 0      |
| 0     | 1     | 0      |
| 0     | 0     | 0      |

For example, when a process requests to create a file with mode `0666` (read/write for all users) and the current umask is `0022`:

```sh
  110 110 110   (0666)
& 111 101 101   (~0022)
--------------
  110 100 100
```

The final permissions are `0666 & ~0022 = 0644` (owner read/write, group and other users read-only).

```sh
  111 111 111   (0777)
& 111 101 101   (~0022)
--------------
  111 101 101
```

For directories, the typical request mode is `0777`, which with a umask of `0022` results in `0755`.

FreeBSD's default umask is `0022`, which can be viewed and set via the umask(2) system call or the shell built-in `umask` command:

```sh
% umask      # Display current umask (octal)
0022
% umask -S   # Display in symbolic form
u=rwx,g=rx,o=rx
% umask 027  # Set umask to 027 (do not execute in production environments)
```

| umask Value | New File Permissions (request 0666) | New Directory Permissions (request 0777) | Notes                                                 |
| ----------- | ----------------------------------- | ---------------------------------------- | ----------------------------------------------------- |
| `0022`      | `0644` (rw-r--r--)                  | `0755` (rwxr-xr-x)                       | Default value                                         |
| `0027`      | `0640` (rw-r-----)                  | `0750` (rwxr-x---)                       | More restrictive, prevents other users from accessing |
| `0077`      | `0600` (rw-------)                  | `0700` (rwx------)                       | Most restrictive, only owner can access               |

umask is set in shell startup files (such as **\~/.profile** or **\~/.cshrc**). In csh/tcsh, use `umask 022`; in sh/bash, also use `umask 022`.

> **Note**
>
> * umask only affects the initial permissions at file creation time and does not modify the permissions of existing files.
> * In Jail containers, umask is inherited from the host system's process environment and is not directly affected by Jail configuration.

## The `chown` Command

The chown(8) command is used to change the owner of a file, including the owning user and owning group. Only root can change the owner of a file.

> **Note**
>
> Symbolic notation: `user:group` modifies both owner and group simultaneously; `:group` modifies only the group; `user:` modifies the owner and sets the group to the specified user's login group.

Example: Change the owner of `t.sh` to `test1`.

```sh
# chown test1 t.sh
```

Example: Change the owner of `t.sh` to user `test1` and group `test`.

```sh
# chown test1:test t.sh
```

Example: Change the owner of all files under the **/tmp** directory to user `test1` and group `test`.

```sh
# chown -R test1:test /tmp
```

Here, the `-R` option can recursively modify the owner.

## Special Permission Bits: setuid, setgid, and sticky bit

In addition to the basic read, write, and execute permissions, UNIX systems also define three special permission bits that provide functionality not normally granted to regular users. To understand these permission bits, it is necessary to note the distinction between the real user ID and the effective user ID: the real user ID is the UID of the user who owns or started the process, while the effective UID is the UID under which the process runs.

### setuid (Set User ID)

When an executable file has the setuid bit set, regardless of which user executes the file, the process's effective user ID (EUID) will be set to the UID of the file owner, rather than the executor's UID. This mechanism allows regular users to temporarily obtain the file owner's permissions to perform specific operations.

The setuid bit is represented in the permission expression by an `s` in the owner execute position (e.g., `-r-sr-xr-x`).

The most typical application scenario for setuid is the passwd(1) command.

```sh
# ls -al /usr/bin/passwd
-r-sr-xr-x  1 root wheel 8368 Apr 13 12:38 /usr/bin/passwd
```

When a regular user changes their password, they need to update the **/etc/master.passwd** file, which only root has write permission to. Through the setuid mechanism, the `passwd` command runs with root's EUID, thereby gaining permission to modify the password file. passwd(1) runs with the regular user's real user ID, but to update the password database, the command runs with root's effective ID, allowing the user to change their password without encountering a "Permission Denied" error.

In numeric notation, the setuid bit is indicated by prefixing the three-digit permission code with `4` (e.g., `4555`). Use the following command to display full permissions (including type and special bits, in octal):

```sh
# stat -f "%p" /usr/bin/passwd
104555
```

> **Warning**
>
> The setuid mechanism is a double-edged sword: if a setuid program has security vulnerabilities, attackers may be able to exploit the program to execute arbitrary code with the file owner's (typically root) privileges. Therefore, system administrators should minimize the number of setuid programs and regularly audit setuid files on the system. The `nosuid` mount option causes the kernel to ignore the setuid/setgid bits of executable files on the file system; programs can still run but will not gain privilege escalation.

### setgid (Set Group ID)

setgid works similarly to setuid, but applies to groups rather than users. When an executable file has the setgid bit set, the process's effective group ID (EGID) will be set to the GID of the file's owning group. When a directory has the setgid bit set, new files created in that directory will inherit the directory's owning group rather than the creator's primary group.

The setgid bit is represented in the permission expression by an `s` in the group execute position (e.g., `-r-xr-sr-x`):

```sh
# stat -f "%Sp" /usr/libexec/dma
-r-xr-sr-x
```

In numeric notation, the setgid bit is indicated by prefixing the three-digit permission code with `2` (e.g., `2555`):

```sh
# stat -f "%p" /usr/libexec/dma
102555
```

### sticky bit

The sticky bit was originally used to "stick" the code segment of executable files in swap space to improve repeated launch speed, but this use is no longer applicable in modern systems. Currently, the sticky bit is primarily used for directories: when a directory has the sticky bit set, only the file owner (or root) can delete or rename files in that directory, even if other users have write permission to the directory.

The most common application scenario for the sticky bit is the **/tmp** directory. This directory has write permissions open to all users, but the sticky bit prevents users from deleting other people's temporary files. When a directory has the sticky bit set, only the file owner can delete files in that directory, which is very useful for preventing non-owners from deleting files in public directories.

The sticky bit is represented in the permission expression by a `t` in the other users execute position (e.g., `drwxrwxrwt`):

```sh
# ls -ald /tmp
drwxrwxrwt  6 root wheel 6 Apr 27 21:55 /tmp
```

In numeric notation, the sticky bit is indicated by prefixing the three-digit permission code with `1` (e.g., `1777`):

```sh
# stat -f "%p" /tmp
41777
```

## FreeBSD File Flags

In addition to file permissions, FreeBSD also supports the use of "file flags." These flags add an additional layer of security and control, applicable to both files and directories; through file flags, even root can be prevented from deleting or modifying files.

Commonly used flags are as follows:

| Flag                              | Description             | Notes                                                                        |
| --------------------------------- | ----------------------- | ---------------------------------------------------------------------------- |
| `schg` / `schange` / `simmutable` | System immutable flag   | Only superuser can set; cannot be cleared when securelevel is greater than 0 |
| `sappnd` / `sappend`              | System append-only flag | Only superuser can set; also subject to securelevel restrictions             |
| `uchg` / `uchange` / `uimmutable` | User immutable flag     | File owner or superuser can set; not subject to securelevel restrictions     |
| `uappnd` / `uappend`              | User append-only flag   | File owner or superuser can set                                              |
| `nodump`                          | No dump flag            | File owner or superuser can set; dump(8) will skip such files                |
| `sunlnk` / `sunlink`              | System undeletable flag | Only superuser can set                                                       |
| `uunlnk` / `uunlink`              | User undeletable flag   | File owner or superuser can set                                              |

> **Note**
>
> * Prefixing a flag with `no` clears that flag, e.g., `nouchg` clears the user immutable flag.
> * The ability to modify certain flags depends on the current kernel securelevel; see security(7).
> * Only a limited number of tools support chflags, including ls(1), cp(1), find(1), install(1), dump(8), restore(8); currently pax(1) does not support chflags.

Use chflags(1) to modify file flags. chflags(1) first appeared in 4.4BSD and is a BSD-specific feature; Linux does not natively support it (similar functionality is achieved through the `chattr` and `lsattr` commands). To view a file's flags, use the `-lo` option of ls(1):

```sh
# ls -lo test
-rwx--x--x  1 ykla ykla uarch 0 Apr 16 12:44 test
```

> **Note**
>
> If using the ZFS file system, all files may have the archive flag `uarch`, which is expected behavior.

For example, to enable the system undeletable flag on the file `test`, execute the following command:

```sh
# chflags sunlink test
```

After execution, view the file:

```sh
# ls -lo test
-rwx--x--x  1 ykla ykla sunlnk,uarch 0 Apr 16 12:44 test
```

To disable the system undeletable flag, add "no" before sunlink:

```sh
# chflags nosunlink test
```

File flags can typically only be added or removed by the root user:

```sh
$ ls -lo
-rwx--x--x  1 ykla ykla     0 Apr 16 12:44 test
$ chflags sunlink test
chflags: test: Operation not permitted
```

Otherwise, the system will return an operation not permitted error.

### References

* FreeBSD Forums. File flag defaults on ZFS\[EB/OL]. (2020-09-22)\[2026-04-27]. <https://forums.freebsd.org/threads/file-flag-defaults-on-zfs.77088/>.

## Exercises

1. Review the core source code for permission checking in the FreeBSD kernel and try to make it more fine-grained.
2. Modify the default permission configuration of a system directory (such as **/var/tmp**) and record the impact of the modification on file creation and process access behavior under that directory.
3. The Unix rwx three-level permission model has been in use since the 1970s. Compare the expressiveness of this model with SELinux's Type Enforcement and AppArmor's pathname restrictions, and analyze whether mixing three mechanisms on a single system would introduce policy conflicts.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://book.bsdcn.org/ask/flat/chapter-14-user-accounts-and-permissions/di-14.2-jie-quan-xian.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
