Saturday, June 8, 2013

What is SetUserId bit and when should it be set?

In unix for every running process, the resources(say a file for example) which it can access is determined by the effective user id and effective group id.

In addition to this there is also a real user id and real group id for every process. The values of the real user id and real group id are the user id and group id of the user who started the process. So what would be the values for effective user id and effective group id??

For normal programs, the effective user/group id's would be the same as real user/group id's. But if the seuid is set for the program, then the effective user/group id of the process would be the user/group id of the program.


Take a look at the below program. When the program is run, it prints the real and effective id's.


/*printID.C
 *
 *Outputs the real/effective user id and real/effective group id.  
 *
 */

#include <sys/types.h>
#include <unistd.h>

int main(int argc, char** argv)
{
printf("\nReal UserID:%d", getuid());
printf("\nEffective UserID:%d", geteuid());

printf("\nReal GroupID:%d", getgid());
printf("\nEffective GroupID:%d", getegid());
}

As root user, if the program is run we would get the following ouput.

root@bala-VirtualBox:/home/bala/MyTrials/permissions# whoami
root

root@bala-VirtualBox:/home/bala/MyTrials/permissions# gcc -o printId printID.c
root@bala-VirtualBox:/home/bala/MyTrials/permissions# ./printId

Real UserID:0
Effective UserID:0
Real GroupID:0
Effective GroupID:0


root@bala-VirtualBox:/home/bala/MyTrials/permissions# ls -lrt
total 12
-rw-r--r-- 1 root root 271 2012-05-06 14:47 printID.c
-rwxr-xr-x 1 root root 7317 2012-05-06 14:47 printID

As the setuid bit is not set for printID program, the real and effective id's of the process was same as the user id and group id of the user who started the program, which was 'root' in the above case.

Below is the output when the program was run as user 'bala' (UserId:1000, GroupId:1000).


root@bala-VirtualBox:~/MyTrials/permissions$ sudo -u bala ./printID

Real UserID:1000
Effective UserID:1000
Real GroupID:1000
Effective GroupID:1000

The output is smilar to the one we got when we ran the program as 'root' user. Both the real and effective id's are 1000 which is  the user id and group id of the user 'bala'

If the setuid bit and setgid bit is set for printID and it is run as user 'bala', the output would be slightly different.


root@bala-VirtualBox:/home/bala/MyTrials/permissions# chmod u+s printID
root@bala-VirtualBox:/home/bala/MyTrials/permissions# chmod g+s printID

root@bala-VirtualBox:/home/bala/MyTrials/permissions# sudo -u bala ./printID

Real UserID:1000
Effective UserID:0
Real GroupID:1000
Effective GroupID:0

Real user id and real group id would equal the user id and group id of the user(bala) who started the program.

Effective user id and real group id would equal the user id and group id of the owner(root) of  the program.

When should SetUserIdBit should be set?

The best way to understand the usage of setuserid bit is to look at the 'passwd' program. It allows  users to update their passwords in the '/etc/passwd' file.  Take a look at the permission of the 'passwd' file.


root@bala-VirtualBox:/home/bala# ls -l /etc/passwd 
-rw-r--r-- 1 root root 1857 2013-06-08 16:45 /etc/passwd

As you can see only 'root' user would be able to write to the '/etc/passwd' file . This prevents other users from editing the '/etc/passwd' file . But every user should be allowed to update their password anytime they want  without having to rely on the 'root' user. Here the setuserid bit comes to the rescue. See the permissions of 'passwd' program.


root@bala-VirtualBox:/home/bala# ls -l /usr/bin/passwd 
-rwsr-xr-x 1 root root 41284 2011-06-24 15:06 /usr/bin/passwd

As the 'setuserid' bit is set , when  users use the 'passwd' program to update their password, the effective userid of the process becomes '0' (userid of 'root') thus giving the process the permission to edit the '/etc/passwd' file.

NOTE: The setuid and setgid bit are applicable only for binary executables. They are normally ignored for shell scripts.