You already know what "rwx" is when run ls -l
: readable, writable and executable. For example:
$ ls -l /usr/bin/curl
-rwxr-xr-x 1 root root 223304 Sep 6 01:27 /usr/bin/curl
Occasionally, you will see the a "s" in rws
instead of "x", for example:
ls -l /usr/bin/passwd
-rwsr-xr-x 1 root root 59640 Jan 25 2018 /usr/bin/passwd
Do you notice the "s" in the first part "rws"? So what is this "s"?
Before we answer it, let's check another problem:
Who can modify /etc/shadow
?
In a previous post I explained how linux store user's password - it will hash user's password and store it in file /etc/shadow
. Let's check this file's permission:
$ ls -l /etc/shadow
-rw-r----- 1 root shadow 1104 Oct 15 2018 /etc/shadow
Ok, so clearly only root
user can change the file content. Now let's say we logged in as user "john" and wants to change our password using the passwd
cli:
$ whoami
john
$ passwd
Changing password for john.
(current) UNIX password:
After we typed our password, this password will be hashed and saved to /etc/shadow
file. But in this process, we never su to root user, and we know only root user can change the content of /etc/shadow
. So why the set-password process as "john" still succeeded?
The "s" in "rws"
The answer lays on the "s" in "rws". It means "set-uid" when run this program: the program doesn't run with the privilege of user who ran it, instead, with the privilege of file owner. For example:
ls -l /usr/bin/passwd
-rwsr-xr-x 1 root root 59640 Jan 25 2018 /usr/bin/passwd
The passwd
cli belongs to the root
user and because of this "s", anyone run the passwd
program will be run as the root
user. That's why as a non-root user, we can still call passwd
to change the /etc/shadow
file.
Let's prove it:
$ whoami
john
$ passwd
Changing password for john.
(current) UNIX password:
Don't set the password, now open another terminal window, run:
$ ps axu | grep passwd
root 2397 0.0 0.3 52736 3612 pts/0 S+ 14:50 0:00 passwd
You can see the actual user who runs passwd
is root
!
How to set this "set-uid" flag?
In Linux we can simply use chmod u+s
to set the "set-uid" flag. Let's have a try. First we write a program as a non-root user "vagrant":
#include <stdio.h>
int main() {
int answer = 0;
printf("1+1=?\n");
scanf("%d", &answer);
if (answer ==2 ) {
printf("Correct!\n");
} else {
printf("Try again!\n");
}
return 0;
}
Compile it: gcc example.c -o example
, if we run ls -l
, we see "rwx":
$ ls -l ./example
-rwxrwxr-x 1 vagrant vagrant 8400 Jan 21 15:48 ./example
Now let's switch to another user coder
and run this program:
$ su coder
$ ./example
In another terminal run ps axu | grep example
, we can see the program runs under coder
(remember we haven't set the set-uid flag yet):
coder 2468 0.0 0.0 4508 820 pts/0 S+ 15:49 0:00 ./example
Now let's switch back to user "vagrant" and add the "set-uid" flag with chmod u+s
:
$ chmod u+s ./example
$ ls -l ./example
-rwsrwxr-x 1 vagrant vagrant 8400 Jan 21 15:48 ./example
We can see the "s" is set. Now switch back to user "coder", run this program ./example
again. In the other terminal run ps axu | grep example
:
vagrant 2493 0.0 0.0 4508 744 pts/0 S+ 15:57 0:00 ./example
You can see although current user is "coder", now the program runs under user "vagrant", which is the file owner.
But what is "rwS"?
Very rarely you will see an uppercase "S" in "rwS". If we do this:
$ echo "" > a.txt
$ chmod u+s a.txt
$ ls -l a.txt
-rwSrw-r-- 1 vagrant vagrant 1 Jan 21 16:02 a.txt
Do you notice the uppercase "S" here? It indicates that this file's "set-uid" flag is set, but the executable flag "x" is not set. If we set this file to be executable, it will show the lowercase "s":
$ chmod +x a.txt
$ ls -l a.txt
-rwsrwxr-x 1 vagrant vagrant 1 Jan 21 16:02 a.txt
The point is, the "set-uid" flag and the "executable" flag are separated. Set "+s" doesn't mean it will be auto set with "+x".
Caveat
You should be careful on using this "set-uid" flag. Imagine a program's owner is root and has this "set-uid" flag set, means any non-root user will be promoted to the root user to run this program, which might be dangerous. So only set this flag when it is really necessary.
Top comments (2)
Huh, TIL. Thanks.
TIL capital S.