我正在尝试
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));
}
}
如果我使用
sudo
运行可执行文件,那么通常不会出现错误。但是,如果我以普通用户身份运行,我会得到 sudo
进程: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$
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
为什么会发生这种情况以及如何创建锁定文件以便在这两种情况下两个进程都可以访问?
通常,Linux 系统具有由
/tmp
拥有(和组拥有)的 root
目录,并具有模式 1777/drwxrwxrwt
,这意味着设置了“粘性”位。
之后:
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
open()
调用失败,errno
设置为EACCES
,因为当前用户是root
,文件/tmp/test.lock
已经存在,文件的所有者r
既不是当前用户,也不是包含目录/tmp
,并且包含目录是全局或组可写且粘性的。此错误情况记录在 Linux open(2) 手册页中:
EACCES 当指定 O_CREAT 时,protected_fifos 或 protected_regular sysctl 已启用,文件已 存在并且是 FIFO 或常规文件,其所有者 文件既不是当前用户也不是该文件的所有者 包含目录,并且包含目录都是 世界或组可写且粘性。有关详细信息,请参阅 /proc/sys/fs/protected_fifos 的描述和 /proc/sys/fs/protected_regular 在 proc(5) 中。
相关文件是常规文件,因此
fs.protected_regular
sysctl 设置控制行为。它记录在 Linux proc(5) 手册页中:
/proc/sys/fs/protected_regular(自 Linux 4.19 起) 该文件中的值可以设置为以下之一 下列的: 0 写入常规文件不受限制。 1 不允许在常规文件上使用 O_CREAT open(2) 调用者不拥有世界可写粘性 目录,除非常规文件属于 目录的所有者。 2 与值1相同,但也有限制 到组可写粘性目录。 上述保护的目的类似于 protected_fifos,但允许应用程序避免写入 到攻击者控制的常规文件,其中 应用程序期望创建一个。
如有必要,可以使用
sysctl
命令在运行时禁用该设置(请参阅 sysctl(8)):
sudo sysctl fs.protected_regular=0
可以在系统引导期间通过编辑
/etc/sysctl.conf
或 /etc/sysctl.d/*.conf
文件来设置该设置(请参阅 sysctl.conf(5):
fs.protected_regular = 0
但是,更改设置会使系统更容易受到攻击。