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.