Credentials and Access Control in Linux

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.

相關文章
相關標籤/搜索