A few weeks ago, while explaining how to create photo slideshows with as little software as possible, I wrote: if you want to know what [SUID] is, come back next week. OK, this is not really “next week”, but here I am. SUID and GUID are something that you should understand, if you use Linux in any way.

Why does all this matter to me?

SELINUX and other recent schemes have overcome some of its limitations, but the basic, decades old Linux system to control access to files is always there. Online there are thousands of scripts and programs that were specifically written assuming, if not needing, that architecture. This is why you should really know certain concepts if you use Linux. Even if you never touch a command line, those scripts may be “hidden” behind some menu entry.

File permissions in the UNIX world

The traditional system defines three ways, or modes, to use a file, and three levels of access rights to those operations. You can (r)ead, (w)rite or e(x)ecute, that is launch, a file.

The levels are owner, group and public (or “world” in many manuals). The owner is the single user who, well, “owns” a file, either because she created it, or… because the administrator says so. Groups connect different users that must share certain access rights to some files or programs. The three rights are listed in sequence, for each level, using the letters above:

  [marco@polaris ~]$ ls -l sample_file_*
  -rwxr-xr-- 1 test_user test_group 0 Aug 10 10:28 sample_file_1
  -r-x------ 1 test_user test_group 0 Aug 10 10:29 sample_file_2

A file listing like this means that the test_user has all permissions (rwx) on sample_file_1; users members of test_group can only read or execute it (r-w), and all other users only have read access (r–). The sample_file_2, instead, can be read, executed but not modified (r-x) by its owner test_user, but nobody else can access it in any way.


Some files have an “s” where the first or second “x” should be:

-rwsr-xr-- 1 test_user test_group 0 Aug 10 10:28 sample_file_1

An “s” in the first position means that the SETUID (or SUID) bit was set (the GUID bit is the same thing, at the group level). Linux runs an executable file with the SETUID bit set with the User ID (that is, the privileges!) of the owner of that file, not the one of the user who launched it. How to make a program SETUID is explained here. Linux administrators may inhibit this behavior on a whole file system, by mounting it with the nosuid option.

The SUID bit must not be confused with the sticky bit, that in Linux is normally used, and honored, only on directories. When set, that bit means that only the owner of a directory (or root, of course) can unlink, delete or rename the files it contains. For more details, check the sticky bit Wikipedia entry.

Why shell scripts are not SUID

SETUID programs can be very dangerous, unless they are both written and used with great care. Interpreted scripts are, worse from this point of view, than compiled programs. That’s because, very often:

  • They just call (many) other scripts and programs, which may have themselves plenty of security holes completely unknown to the script author.
  • They start as a quick and dirty fix to some occasional problem, but are never thoroughly tested for security, even if they go “into production.”

Another risk is the way the “shebang” works. The shebang is those “#!” characters at the beginning of an executable text file, telling Linux that that file should be interpreted. The shebang may be abused by crackers to get an interactive prompt, maybe with root privileges, from which he may issue any command he wants (here are the gory details).

For all these reasons, the Linux kernel normally ignores the setuid bit on all executable files starting with a shebang.

Possible workarounds

If you really, really have a script that should run SETUID (and in many cases you’ll probably realize that it doesn’t really need to), there are several solutions. The simplest one is to put a dash right after the interpreter name in the script:

#!/bin/sh -

thus telling the kernel that whatever comes next is not more (potentially dangerous) options for the interpreter (details, again, are here). Another solution is to set up a sudo entry, without need to type the password, to allow your users to run a specific script with its owner’s ID.

Geekier fixes, all described in the above page or here, include using Perl with the -wT option to write the script, or “wrapping” it into a C program, whose only function would be to launch the script with the right ID.

Finding files with unexpected permission bits

The right tool for this job is the find command. If you are only interested in finding executable files, use the -executable switch. When looking specifically for SUID stuff, instead, go for the almost unknown perm option:

-perm mode

This will find all files whose permissions match exactly those you wrote as mode. If mode is equal to g=w, you’ll only get files whose only permission set is “group, write”.
To find files that have all the permissions you specify, regardless of the others, put a dash right before the mode string (-perm -g=w’). A slash in the same position, instead, means “find the files that have any of these permissions set.”

Therefore, the way to find all the SUID files and folders on your system yuo should run, as root:

find / -perm -4000

The details, with many more examples, are in the find man page. I hope this quick introduction will be enough to help you understand what SUID scripts are, and why you should keep an eye on them.