clinuxfile-permissionssudo

File permission is 0666, but can not open even as root


I am experimenting with flock:

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

int main(){
    mode_t m = umask(0);
    int fd = open("/tmp/test.lock", O_RDWR | O_CREAT, 0666);
    if(fd == -1){
        printf("open failed. errno: %d, %s\n", errno, strerror(errno));
    }
    umask(m);
    int res = flock(fd, LOCK_EX);
    if(res != 0){
        printf("flock failed. errno: %d, %s\n", errno, strerror(errno));
    }
}

If I run the executable with sudo, then normally, there is no error. However, if I run as a normal user, I get for the sudo process: open failed. errno: 13, Permission denied:

r@rvb-my:~/work$ gcc test.cpp
r@rvb-my:~/work$ ./a.out 
r@rvb-my:~/work$ ls -l /tmp/test.lock 
-rw-rw-rw- 1 r r 0 Jan 23 15:09 /tmp/test.lock
r@rvb-my:~/work$ sudo ./a.out 
open failed. errno: 13, Permission denied
flock failed. errno: 9, Bad file descriptor
r@rvb-my:~/work$ rm /tmp/test.lock 
r@rvb-my:~/work$ sudo ./a.out 
r@rvb-my:~/work$ ls -l /tmp/test.lock 
-rw-rw-rw- 1 root root 0 Jan 23 15:09 /tmp/test.lock
r@rvb-my:~/work$ ./a.out 
r@rvb-my:~/work$ ls -l /tmp/test.lock 
-rw-rw-rw- 1 root root 0 Jan 23 15:09 /tmp/test.lock

Why is this happening and how can I create the lock file to be accessible for both processes in both cases?


Solution

  • Typically, Linux systems have the /tmp directory owned (and group-owned) by root and it has mode 1777/drwxrwxrwt, which means that the "sticky" bit is set.

    After:

    r@rvb-my:~/work$ ./a.out 
    r@rvb-my:~/work$ ls -l /tmp/test.lock 
    -rw-rw-rw- 1 r r 0 Jan 23 15:09 /tmp/test.lock
    r@rvb-my:~/work$ sudo ./a.out 
    open failed. errno: 13, Permission denied
    

    The open() call failed with errno set to EACCES because the current user is root, the file /tmp/test.lock already exists, the owner r of the file is neither the current user nor the owner of the containing directory /tmp, and the containing directory is both world- or group-writable and sticky. This error situation is documented in the Linux open(2) man page:

           EACCES Where O_CREAT is specified, the protected_fifos or
                  protected_regular sysctl is enabled, the file already
                  exists and is a FIFO or regular file, the owner of the
                  file is neither the current user nor the owner of the
                  containing directory, and the containing directory is both
                  world- or group-writable and sticky.  For details, see the
                  descriptions of /proc/sys/fs/protected_fifos and
                  /proc/sys/fs/protected_regular in proc(5).
    

    The file in question is a regular file so the fs.protected_regular sysctl setting controls the behavior. It is documented in the Linux proc(5) man page:

           /proc/sys/fs/protected_regular (since Linux 4.19)
                  The value in this file is/can be set to one of the
                  following:
    
                  0   Writing to regular files is unrestricted.
    
                  1   Don't allow O_CREAT open(2) on regular files that the
                      caller doesn't own in world-writable sticky
                      directories, unless the regular file is owned by the
                      owner of the directory.
    
                  2   As for the value 1, but the restriction also applies
                      to group-writable sticky directories.
    
                  The intent of the above protections is similar to
                  protected_fifos, but allows an application to avoid writes
                  to an attacker-controlled regular file, where the
                  application expected to create one.
    

    If necessary, the setting could be disabled at runtime using the sysctl command (see sysctl(8)):

    sudo sysctl fs.protected_regular=0
    

    The setting may be set during system boot by editing the /etc/sysctl.conf or /etc/sysctl.d/*.conf files (see sysctl.conf(5)):

    fs.protected_regular = 0
    

    However, changing the setting would make the system more vulnerable to attack.