Credentials and Access Control in Linux ======================================= 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. 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 executed Related System Calls [important] -------------------------------- *) getpid Get process ID *) getppid Get parent process ID *) getsid Get session ID *) getpgrp Get process group ID *) setsid Create a new session. The calling process becomes the session leader. *) setpgid Set process's group membership *) getuid Get the process's real user ID *) 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.