FreeBSD, being a direct descendant of BSD UNIX®, is based on several key UNIX concepts. The first and most pronounced is that FreeBSD is a multi-user operating system. The system can handle several users all working simultaneously on completely unrelated tasks. The system is responsible for properly sharing and managing requests for hardware devices, peripherals, memory, and CPU time fairly to each user.
Because the system is capable of supporting multiple users, everything the system manages has a set of permissions governing who can read, write, and execute the resource. These permissions are stored as three octets broken into three pieces, one for the owner of the file, one for the group that the file belongs to, and one for everyone else. This numerical representation works like this:
Value | Permission | Directory Listing |
---|---|---|
0 | No read, no write, no execute | --- |
1 | No read, no write, execute | --x |
2 | No read, write, no execute | -w- |
3 | No read, write, execute | -wx |
4 | Read, no write, no execute | r-- |
5 | Read, no write, execute | r-x |
6 | Read, write, no execute | rw- |
7 | Read, write, execute | rwx |
You can use the -l
command line argument to ls(1) to view a long
directory listing that includes a column with information about a file's permissions for
the owner, group, and everyone else. For example, a ls -l in an
arbitrary directory may show:
% ls -l total 530 -rw-r--r-- 1 root wheel 512 Sep 5 12:31 myfile -rw-r--r-- 1 root wheel 512 Sep 5 12:31 otherfile -rw-r--r-- 1 root wheel 7680 Sep 5 12:31 email.txt ...
Here is how the first column of ls -l is broken up:
-rw-r--r--
The first (leftmost) character tells if this file is a regular file, a directory, a special character device, a socket, or any other special pseudo-file device. In this case, the - indicates a regular file. The next three characters, rw- in this example, give the permissions for the owner of the file. The next three characters, r--, give the permissions for the group that the file belongs to. The final three characters, r--, give the permissions for the rest of the world. A dash means that the permission is turned off. In the case of this file, the permissions are set so the owner can read and write to the file, the group can read the file, and the rest of the world can only read the file. According to the table above, the permissions for this file would be 644, where each digit represents the three parts of the file's permission.
This is all well and good, but how does the system control permissions on devices? FreeBSD actually treats most hardware devices as a file that programs can open, read, and write data to just like any other file. These special device files are stored on the /dev directory.
Directories are also treated as files. They have read, write, and execute permissions. The executable bit for a directory has a slightly different meaning than that of files. When a directory is marked executable, it means it can be traversed into, that is, it is possible to “cd” (change directory) into it. This also means that within the directory it is possible to access files whose names are known (subject, of course, to the permissions on the files themselves).
In particular, in order to perform a directory listing, read permission must be set on the directory, whilst to delete a file that one knows the name of, it is necessary to have write and execute permissions to the directory containing the file.
There are more permission bits, but they are primarily used in special circumstances such as setuid binaries and sticky directories. If you want more information on file permissions and how to set them, be sure to look at the chmod(1) manual page.
Symbolic permissions, sometimes referred to as symbolic expressions, use characters in place of octal values to assign permissions to files or directories. Symbolic expressions use the syntax of (who) (action) (permissions), where the following values are available:
Option | Letter | Represents |
---|---|---|
(who) | u | User |
(who) | g | Group owner |
(who) | o | Other |
(who) | a | All (“world”) |
(action) | + | Adding permissions |
(action) | - | Removing permissions |
(action) | = | Explicitly set permissions |
(permissions) | r | Read |
(permissions) | w | Write |
(permissions) | x | Execute |
(permissions) | t | Sticky bit |
(permissions) | s | Set UID or GID |
These values are used with the chmod(1) command just like before, but with letters. For an example, you could use the following command to block other users from accessing FILE:
% chmod go= FILE
A comma separated list can be provided when more than one set of changes to a file must be made. For example the following command will remove the group and “world” write permission on FILE, then it adds the execute permissions for everyone:
% chmod go-w,a+x FILE
In addition to file permissions discussed previously, FreeBSD supports the use of “file flags.” These flags add an additional level of security and control over files, but not directories.
These file flags add an additional level of control over files, helping to ensure that in some cases not even the root can remove or alter files.
File flags are altered by using the chflags(1) utility, using a simple interface. For example, to enable the system undeletable flag on the file file1, issue the following command:
# chflags sunlink file1
And to disable the system undeletable flag, issue the previous command with
“no” in front of the sunlink
. Observe:
# chflags nosunlink file1
To view the flags of this file, use the ls(1) command
with the -lo
flags:
# ls -lo file1
The output should look like the following:
-rw-r--r-- 1 trhodes trhodes sunlnk 0 Mar 1 05:54 file1
Several flags may only added or removed to files by the root user. In other cases, the file owner may set these flags. It is recommended that administrators read over the chflags(1) and chflags(2) manual pages for more information.
Other than the permissions already discussed, there are three other specific settings that all administrators should know about. They are the setuid, setgid and sticky permissions.
These settings are important for some UNIX operations as they provide functionality not normally granted to normal users. To understand them, the difference between the real user ID and effective user ID must also be noted.
The real user ID is the UID who owns or starts the process. The effective UID is the user ID the process runs as. As an example, the passwd(1) utility runs with the real user ID as the user changing their password; however, to manipulate the password database, it runs as the effective ID of the root user. This is what allows normal users to change their passwords without seeing a “Permission Denied” error.
Note: The nosuid mount(8) option will cause these binaries to silently fail. That is, they will fail to execute without ever alerting the user. That option is also not completely reliable as a nosuid wrapper may be able to circumvent it; according to the mount(8) manual page.
The setuid permission may be set by prefixing a permission set with the number four (4) as shown in the following example:
# chmod 4755 suidexample.sh
The permissions on the suidexample.sh file should now look like the following:
-rwsr-xr-x 1 trhodes trhodes 63 Aug 29 06:36 suidexample.sh
It should be noticeable from this example that an s is now part of the permission set designated for the file owner, replacing the executable bit. This allows utilities which need elevated permissions, such as passwd.
To view this in real time, open two terminals. On one, start the passwd process as a normal user. While it waits for a new password, check the process table and look at the user information of the passwd command.
In terminal A:
Changing local password for trhodes Old Password:
In terminal B:
# ps aux | grep passwd
trhodes 5232 0.0 0.2 3420 1608 0 R+ 2:10AM 0:00.00 grep passwd root 5211 0.0 0.2 3620 1724 2 I+ 2:09AM 0:00.01 passwd
As stated above, the passwd is run by a normal user, but is using the effective UID of root.
The setgid permission performs the same function as the setuid permission; except that it alters the group settings. When an application or utility is ran with this setting, it will be granted the permissions based on the group that owns the file, not the user who started the process.
To set the setgid permission on a file, provide the chmod command with a leading two (2) as in the following example:
# chmod 2755 sgidexample.sh
The new setting may be viewed as before, notice the s is now in the field designated for the group permission settings:
-rwxr-sr-x 1 trhodes trhodes 44 Aug 31 01:49 sgidexample.sh
Note: In these examples, even though the shell script in question is an executable file, it will not run with a different EUID or effective user ID. This is because shell scripts may not access the setuid(2) system calls.
The first two special permission bits we discussed (the setuid and setgid permission bits) may lower system security, by allowing for elevated permissions. There is a third special permission bit that can strengthen the security of a system: the sticky bit.
The sticky bit, when set on a directory, allows file deletion only by the file owner. This permission set is useful to prevent file deletion in public directories, such as /tmp, by users who do not own the file. To utilize this permission, prefix the permission with a one (1). For example:
# chmod 1777 /tmp
Now, it is possible to see the effect by using the ls command:
# ls -al / | grep tmp
drwxrwxrwt 10 root wheel 512 Aug 31 01:49 tmp
The sticky bit permission is distinguishable from the t at the very end of the set.