1. Overview
In Linux, we know that files can have read, write, and execute (rwx) permission flags.
In addition to those standard permissions, there are still three special permissions available.
In this tutorial, let’s take a look at the special types of permissions and learn how to set and remove those flags using Linux commands.
2. The setuid Bit
Normally, when a process starts in a Unix-like operating system, it runs with the effective user id and group id of the user who started it, with the corresponding privileges. However, this behavior can be changed if we set special permissions on executable files.
setuid means “set user id”. If we set the setuid bit on an executable file, the file always runs with the privileges of the file owner, no matter who launches it.
The setuid bit only makes sense if it’s set on executable files. There’s no practical meaning if we set the setuid bit on a non-executable file or a directory.
The passwd command is an example with this special bit set:
$ ls -l /bin/passwd
-rwsr-xr-x 1 root root 63624 Dec 15 21:06 /bin/passwd
We notice that the execute permission for the owner is a lower-case “s” instead of the usual “x”. This “s” indicates the file has the setuid bit set. The passwd command will always run with root privileges no matter who launches it because the owner of the file is root.
We can use the chmod command to set the setuid bit on a file:
chmod u+s FILE
Only the owner of the file or the root user can set the setuid bit.
Let’s see an example of setting the setuid bit on a file:
$ ls -l file
-rwxr-xr-x 1 kent kent 0 Feb 2 12:22 file
$ chmod u+s file
$ ls -l file
-rwsr-xr-x 1 kent kent 0 Feb 2 12:22 file
Alternatively, we can also set the setuid bit using octal notations by prepending a “4” to the mode:
$ chmod 4755 file
-rwsr-xr-x 1 kent kent 0 Feb 2 12:22 file
To remove the setuid bit, we pass u-s to the chmod command:
$ chmod u-s file
$ ls -l file
-rwxr-xr-x 1 kent kent 0 Feb 2 12:22 file
3. The setgid Bit
3.1. setgid Bit on a File
setgid is short for “set group id”. If we set the setgid bit on an executable file, no matter who launches the file, it runs with privileges of the owning group.
The locate command is an example of a file with the setgid bit set:
$ ls -l /usr/bin/locate
-rwxr-sr-x 1 root locate 43048 Nov 13 18:09 /usr/bin/locate
Similar to the setuid bit, we notice a lower-case “s” in the ls output, except that it’s in the group section instead of the owner section.
We can set the setgid bit on a file by passing g+s to the chmod command:
$ ls -l file2
-rwxr-xr-x 1 kent kent 0 Feb 2 22:35 file2
$ chmod g+s file2
$ ls -l file2
-rwxr-sr-x 1 kent kent 0 Feb 2 22:35 file2
Alternatively, we can set the setgid bit using octal notations by prepending a “2” to the mode:
chmod 2755 file2
If we want to remove the setgid bit on a file, we pass g-s to the chmod command:
$ chmod g-s file2
$ ls -l file2
-rwxr-xr-x 1 kent kent 0 Feb 2 22:35 file2
3.2. setgid Bit on a Directory
If we set the setgid bit on a directory, all newly created files and subdirectories in the directory will inherit the group of that directory. However, the existing files and directories will not apply the group change.
Let’s see an example to clarify this behavior.
First, we prepare a directory parent containing two files:
$ ls -ld parent
drwxrwxrwx 2 root kent 4096 Feb 3 00:33 parent/
$ ls -l parent
total 2
-rwxr-xr-x 1 guest guest 0 Feb 3 00:30 existing_grp_guest1
-rwxr-xr-x 1 guest guest 0 Feb 3 00:30 existing_grp_guest2
parent is owned by the user root and the group kent. It contains two files, and the group guest owns both.
Next, let’s set the setgid bit on parent using chmod:
root# chmod g+s parent
root# ls -ld parent
drwxrwsrwx 2 root kent 4096 Feb 3 00:33 parent/
Now, we’re going to create a new file and a subdirectory under parent with root:
root# touch parent/new_file_by_root
root# mkdir parent/new_dir_by_root
Then, we’ll check the group owners of all the files and subdirectories under parent:
root# ls -l parent
total 4
-rwxr-xr-x 1 guest guest 0 Feb 3 00:30 existing_grp_guest1
-rwxr-xr-x 1 guest guest 0 Feb 3 00:30 existing_grp_guest2
drwxr-sr-x 2 root kent 4096 Feb 3 00:54 new_dir_by_root/
-rw-r--r-- 1 root kent 0 Feb 3 00:54 new_file_by_root
In the output above, we see that the two existing files have not changed after we set the setuid bit on parent.
However, the newly created file and subdirectory are owned by kent instead of root, even though root created them. This is because parent had the setgid bit set, and the newly created files and directories under it inherited parent‘s group.
4. The Sticky Bit
4.1. The Sticky Bit
The sticky bit is to protect the files within a directory. If we set the sticky bit on a directory, a file under this directory can be deleted only by one of the following:
- the owner of the file
- the owner of the directory
- the root user
In other words, this special permission prevents a user from deleting other users’ files in a public directory.
A typical real-world sticky bit example is the /tmp directory:
$ ls -ld /tmp
drwxrwxrwt 24 root root 980 Feb 3 21:41 /tmp/
Due to the “w” in the “other” permission section, we know that any user can create and remove any files under the /tmp directory.
But if we read the above ls output carefully, we see the execute permission bit in the “other” section is a lower-case “t”, instead of the usual “x”.
This lower-case “t” indicates that the /tmp directory has the sticky bit set. With the sticky bit, any user can still create files under /tmp. However, a user can only delete files owned by himself.
4.2. The Sticky Bit on a Directory
To set the sticky bit on a directory, we can still use the chmod command with the mode +t:
chmod +t DIRECTORY
Alternatively, we can prepend a “1” to the mode of a directory to set the sticky bit as well:
chmod 1777 DIRECTORY
We can also remove the sticky bit from a directory using -t:
chmod -t DIRECTORY
As usual, let’s see an example to understand how the sticky bit can protect the files under a directory and how to set and remove the sticky bit on a directory.
Let’s start from preparing a public directory called public and allow all users to write to it:
$ ls -ld public
drwxrwxrwx 2 root root 40 Feb 3 22:22 public/
Next, we’ll create some files under public by different users:
$ ls -l
-rw-r--r-- 1 guest guest 0 Feb 3 22:28 file1_by_guest
-rw-r--r-- 1 guest guest 0 Feb 3 22:28 file2_by_guest
-rw-r--r-- 1 kent kent 0 Feb 3 22:28 file_by_kent
So far, we haven’t set the sticky bit anywhere. Let’s see if the user kent can delete a file owned by guest:
kent$ rm file1_by_guest
rm: remove write-protected regular empty file 'file1_by_guest'? y
kent$ ls -l
-rw-r--r-- 1 guest guest 0 Feb 3 22:28 file2_by_guest
-rw-r--r-- 1 kent kent 0 Feb 3 22:28 file_by_kent
So, without the sticky bit, we can remove files owned by other users.
Now, let’s set the sticky bit and see if there are any changes:
root# chmod +t public
root# ls -ld public
drwxrwxrwt 2 root root 80 Feb 3 22:33 public/
root# su kent
kent$ rm file2_by_guest
rm: remove write-protected regular empty file 'file2_by_guest'? y
rm: cannot remove 'file2_by_guest': Operation not permitted
kent$ ls -l
-rw-r--r-- 1 guest guest 0 Feb 3 22:28 file2_by_guest
-rw-r--r-- 1 kent kent 0 Feb 3 22:28 file_by_kent
After we set the sticky bit*,* the files under public could only be deleted by the file owners.
5. Security
The setuid bit could be quite convenient in various applications. However, we must be cautious when we set those special permissions since it can create security concerns.
For example, a typical user can gain superuser privileges by executing a program which sets the UID to root.
5.1. Privilege Escalation
It is a good practice that we monitor our system for any suspicious usages of the setuid bits to gain superuser privileges. We can find all files owned by root and with setuid bits using the find command:
root# find / -user root -perm -4000 -exec ls -ldb {} \;
...
-rwsr-xr-x 1 root root 30744 Dec 12 22:11 /usr/lib/virtualbox/VBoxNetAdpCtl
-rwsr-xr-x 1 root root 161720 Dec 12 22:11 /usr/lib/virtualbox/VBoxNetDHCP
-rwsr-xr-x 1 root root 71728 Dec 15 21:06 /usr/bin/chage
-rwsr-xr-x 1 root root 145176 Jan 1 13:17 /usr/bin/sudo
-rwsr-sr-x 1 root root 38664 Nov 13 18:49 /usr/bin/unix_chkpwd
-rwsr-xr-x 1 root root 12360 Dec 15 2013 /usr/bin/sflock
...
5.2. setuid and Interpreted Executables
An interpreted executable file is usually an executable file, which declares the interpreter by a shebang. Examples are Bash files starting with “*#!/bin/bash” or an executable Python source file starting with “#!/usr/bin/env python*“.
Linux ignores the setuid bit on all interpreted executables for security reasons. If we want our shell script to have the setuid permission, we can use the sudo command to gain privileges of the owner of the script file.
6. Conclusion
In this article, we’ve discussed three special file permission flags in Linux: the setuid bit, setgid bit, and the sticky bit.
We’ve talked about how they work and learned how to manage them with chmod.
These three special flags are not as standard as the primary read, write, and execute permissions. However, they are convenient when we are facing particular problems, such as tasks that need different privileges than the user is granted.