Search code examples
csuid

Executable file set root suid, but access(path, W_OK) still return -1?


Why executable file set root suid, but access(path, W_OK) still return -1?

Code:

#include <stdio.h>
#include <unistd.h>

int main()
{
    printf("privilege => %d\n", access("/usr/local/etc/t.conf", W_OK));
    return 0;
}

Test run:

[www@mypy access]$ ll
总用量 12
-rwsrwxr-x. 1 root root 6600 1月  22 10:05 access
-rw-rw-r--. 1 www  www   135 1月  22 10:05 access.c

[www@mypy access]$ ./access 
privilege => -1

[root@mypy access]# ./access 
privilege => 0

Solution

  • The access library function deliberately checks the access rights of the real user, ignoring the fact that the executable has a different effective UID/GID.

    If you only want to know whether read or write access is possible, you can open the file and see if there was an error. However, careful setuid executables often want to know whether the real user would have been able to perform an action on the file. To find out, they can use the access library function.

    This is explained in man 2 access:

    The check is done using the calling process's real UID and GID, rather than the effective IDs as is done when actually attempting an operation (e.g., open(2)) on the file.…

    This allows set-user-ID programs and capability-endowed programs to easily determine the invoking user's authority. In other words, access() does not answer the "can I read/write/execute this file?" question. It answers a slightly different question: "(assuming I'm a setuid binary) can the user who invoked me read/write/execute this file?", which gives set-user-ID programs the possibility to prevent malicious users from causing them to read files which users shouldn't be able to read.