Credentials and Access Control in Linux
=======================================node
File ower and permission [important]
------------------------------------
File mode (permission), user ID and group ID are contained in the corresponding
inode of the file.
An inode at least contains the following members:
*) size
*) device ID (the device containing the file)
*) user ID
*) group ID
*) file mode
*) timestamp
*) link count (number of hard links)
*) pointers to the disk blocks
A direct deduction of the above statement is that if a file changes (content,
timestamp, user ID, group ID, file mode, etc.), all hardlinks pointint to it
also changes, as all these hard links share a common inode.linux
Process Credentials [important]
-------------------------------
Process Identifers:
*) process ID
*) parent process ID
*) process group ID
*) session ID
*) real user ID | who owns the process
*) real group ID |
*) effective user ID |used by kernel for access control to shared resources
*) effective group ID |such as message queues, semaphores, etc.)
*) file system user ID | together with supplementary group IDs, used to
*) file system group ID | determine permissions for accessing files
*) supplementary group ID | used for permission checks for accessing files
*) saved set-user-ID | used to save a copy of corresponding effective IDs when
*) saved set-group-ID | the process was executedsession
Related System Calls [important]
--------------------------------
*) getpid
Get process IDapp
*) getppid
Get parent process IDui
*) getsid
Get session IDthis
*) getpgrp
Get process group IDrest
*) setsid
Create a new session. The calling process becomes the session leader.component
*) setpgid
Set process's group membershiporm
*) getuid
Get the process's real user IDip
*) setuid
If the caller is not root, setuid sets the effective user ID of the calling
processs; if the caller is root, setuid also sets the real user ID and the
saved user ID.
*) seteuid
Set the effective user ID of the calling process. An unprivileged user
process could only set the effective user ID to real user ID, effective
user ID and saved user ID.
*) setfsuid
Set a process's file system user ID. It's used to make the file system user
ID to differ from the process's effective user ID.
*) setreuid
Set real and effective user ID.
*) getgid
Get the process's real group ID.
*) getegid
Set effective group ID.
*) getresgid
Get real, effective and saved group ID.
*) setgid
Completely analogous to setuid.
*) setregid
Set real and effective group ID.
*) setfsgid
Set file system group ID.
*) getgroups
Get supplementary group IDs of a process
*) setgroups
Set supplementary group IDs of a process
*) setresuid
Set real, effective and saved user ID.
*) setresgid
set real, effective and saved group ID.
Potential problem with suid programs [important]
------------------------------------------------
suid programs have potential security problems if not well programmed.
E.g.
User 'chenqi' doesn't have read permission for /etc/shadow, but if a program
owned by root has set-user-ID bit and it could be executed by 'chenqi', then
it's possible that the user 'chenqi' can make use of the setuid program to get
the contents of /etc/shadow.
chenqi@pek-qchen1-d1:~/projects/mypro/linux/miscs$ cat test.c
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#ifndef MAXLINE
#define MAXLINE 4096
#endif
int main(int argc, char *argv[]) {
if (argc != 2) {
fprintf(stderr, "%s <file>\n", argv[0]);
exit(EXIT_FAILURE);
}
FILE *fp = fopen(argv[1], "r");
if (fp == NULL) {
perror("open file failed");
exit(EXIT_FAILURE);
}
char buf[MAXLINE];
while (fgets(buf, MAXLINE, fp) != NULL) {
if (fputs(buf, stdout) == EOF) {
perror("output error");
exit(EXIT_FAILURE);
}
}
if (fp != NULL)
fclose(fp);
exit(EXIT_SUCCESS);
}
chenqi@pek-qchen1-d1:~/projects/mypro/linux/miscs$ ls -l test
-rwsr-sr-x 1 root root 8774 Oct 12 15:37 test
chenqi@pek-qchen1-d1:~/projects/mypro/linux/miscs$ cat /etc/shadow
cat: /etc/shadow: Permission denied
chenqi@pek-qchen1-d1:~/projects/mypro/linux/miscs$ ./test /etc/shadow
root:<encrypted passwd for root>:15555:0:99999:7:::
daemon:*:15455:0:99999:7:::
bin:*:15455:0:99999:7:::
<the rest of the contents omitted>
It's not quite straightforward that the above program is poorly programmed,
providing that the programmer knows that the program will be made suid
One possible way to address the above problem is to temporarily drop privilege
to real user ID when opening the file.
chenqi@pek-qchen1-d1:~/projects/mypro/linux/miscs$ ls test -l
-rwsr-sr-x 1 root root 9156 Oct 12 16:01 test
chenqi@pek-qchen1-d1:~/projects/mypro/linux/miscs$ ./test test.c
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#ifndef MAXLINE
#define MAXLINE 4096
#endif
static void xseteuid(uid_t euid) {
if (seteuid(euid)) {
perror("seteuid");
exit(EXIT_FAILURE);
}
}
static void xsetegid(gid_t egid) {
if (setegid(egid)) {
perror("setegid");
exit(EXIT_FAILURE);
}
}
int main(int argc, char *argv[]) {
if (argc != 2) {
fprintf(stderr, "%s <file>\n", argv[0]);
exit(EXIT_FAILURE);
}
uid_t old_euid = geteuid();
gid_t old_egid = getegid();
xseteuid(getuid());
xsetegid(getgid());
FILE *fp = fopen(argv[1], "r");
if (fp == NULL) {
perror("open file failed");
exit(EXIT_FAILURE);
}
xseteuid(old_euid);
xsetegid(old_egid);
char buf[MAXLINE];
while (fgets(buf, MAXLINE, fp) != NULL) {
if (fputs(buf, stdout) == EOF) {
perror("output error");
exit(EXIT_FAILURE);
}
}
if (fp != NULL)
fclose(fp);
exit(EXIT_SUCCESS);
}
chenqi@pek-qchen1-d1:~/projects/mypro/linux/miscs$ ./test /etc/shadow
open file failed: Permission denied
Q & A [important]
-----------------
1. If the euid of a process is not zero (superuser), is it possible for
the program to change its euid to zero and gain privilege?
It depends. If the saved uid is zero, the answer is yes. Because the seteuid
system call could set the effective uid to only the real uid or saved uid.
Note the case above usually indicates that a process has dropped its
privilege temporarily and it's trying to restore its privilege.
2. (r, e, s) = (x, x, 0) where x != 0, is it possible to change (r, e, s) to
(0, x, 0) using setresuid()? What about using setreuid()?
Both can. The setreuid() user manual is not accurate. It states as follows.
"Unprivileged users may only set the real user ID to the real user ID or the
effective user ID."
However, for an unprivileged user, the real user ID could be set to the saved
user ID.
e.g.
chenqi@pek-qchen1-d1:~/projects/mypro/linux/miscs$ ./test
16079: (1000, 0, 0)
16079: (1000, 1000, 0)
16079: (0, 1000, 0)
3. Is it possible to clear the SETUID capability bit in a process whose
effective uid is zero?
No. The kernel has fixed this bug.
Notes [important]
-----------------
1. We need to know that user privilege and process privilege are two different
things. The user privilege is determined by the real user ID of the process,
i.e., the owner of the process; the process privilege is determined by the
effective user ID of the process.
2. The execute permission bit of a diretory is often called the search bit, as
whenever we want to open any type of file by name, we must have execute
permission in each directory mensioned in the name. That's why the default
permission of a directory is 0775(rwxrwxr-x) or 0755(rwxr-xr-x).
3. Read permission of a directory and execute permission of a directory
Read permission for a directory lets us read the directory, obtaining a list
of all filenames in the directory.
Execute permisssion lets us pass through the directory when it is a component
of a pathname that we are trying to access.
e.g.
chenqi@chenqi-Vostro-2420:~/tests$ stat foo/ | grep 'Access: ('
Access: (0775/drwxrwxr-x) Uid: ( 1001/ chenqi) Gid: ( 1001/ chenqi)
chenqi@chenqi-Vostro-2420:~/tests$ chmod o-r foo/
chenqi@chenqi-Vostro-2420:~/tests$ su lfs
lfs@chenqi-Vostro-2420:/home/chenqi/tests$ ls foo/
ls: cannot open directory foo/: Permission denied
lfs@chenqi-Vostro-2420:/home/chenqi/tests$ ls foo/bar
1
lfs@chenqi-Vostro-2420:/home/chenqi/tests$ cat foo/bar/1
hello world
lfs@chenqi-Vostro-2420:/home/chenqi/tests$ exit
exit
chenqi@chenqi-Vostro-2420:~/tests$ chmod o+r foo/
chenqi@chenqi-Vostro-2420:~/tests$ chmod o-x foo/
chenqi@chenqi-Vostro-2420:~/tests$ stat foo/ | grep 'Access: ('
Access: (0774/drwxrwxr--) Uid: ( 1001/ chenqi) Gid: ( 1001/ chenqi)
chenqi@chenqi-Vostro-2420:~/tests$ su lfs
lfs@chenqi-Vostro-2420:/home/chenqi/tests$ ls foo/
bar
lfs@chenqi-Vostro-2420:/home/chenqi/tests$ ls foo/bar
ls: cannot access foo/bar: Permission denied
lfs@chenqi-Vostro-2420:/home/chenqi/tests$ cat foo/bar/1
cat: foo/bar/1: Permission denied
4. The kernel perform access tests using the file's st_uid and st_gid and the effective user and group IDs. However, there are times when a process wants to test accessiility based on the real user and group IDs. The access function bases its tests on the real user and group IDs. So it's possible that access to a file fails but open that file succeeds. This happens when the real user ID is, for example, chenqi, and the effective user ID is root, and the permission of the file is 0400.