当用gcc编译并通过sudo ./a.out运行时,以下程序输出

a.out: open 13: Permission denied

并返回EXIT_FAILURE.Why does it fail?

当在没有sudo的情况下运行时,程序成功并创建文件test.lock.当前的工作目录似乎没有什么不同.

#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <linux/capability.h>
#include <stdlib.h>
#include <sys/syscall.h>
#include <unistd.h>

int main(void) {
        /* get capabilities */
        struct __user_cap_header_struct hdr = {
                .pid = 0,
                .version = _LINUX_CAPABILITY_VERSION_3,
        };
        struct __user_cap_data_struct data[_LINUX_CAPABILITY_U32S_3];
        if (syscall(SYS_capget, &hdr, data) == -1)
                err(EXIT_FAILURE, "SYS_capget %d", errno);

        /* update and set capabilities */
        data[0].effective &= ~(1 << CAP_DAC_OVERRIDE);
        if (syscall(SYS_capset, &hdr, data) == -1)
                err(EXIT_FAILURE, "SYS_capset %d", errno);

        /* open file */
        if (open("test.lock", O_CREAT|O_RDONLY|O_CLOEXEC, S_IRUSR|S_IWUSR) == -1)
                err(EXIT_FAILURE, "open %d", errno);

        return EXIT_SUCCESS;
}

Additional environment info:

$ uname --kernel-release
4.18.0-477.27.1.el8_8.x86_64
$ gcc --version
gcc (GCC) 8.5.0 20210514 (Red Hat 8.5.0-18)
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ rpm --query glibc
glibc-2.28-225.el8_8.6.x86_64
glibc-2.28-225.el8_8.6.i686
$ cat /etc/os-release
NAME="Red Hat Enterprise Linux"
VERSION="8.9 (Ootpa)"
ID="rhel"
ID_LIKE="fedora"
VERSION_ID="8.9"
PLATFORM_ID="platform:el8"
PRETTY_NAME="Red Hat Enterprise Linux 8.9 (Ootpa)"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:redhat:enterprise_linux:8::baseos"
HOME_URL="https://www.redhat.com/"
DOCUMENTATION_URL="https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/8"
BUG_REPORT_URL="https://bugzilla.redhat.com/"

REDHAT_BUGZILLA_PRODUCT="Red Hat Enterprise Linux 8"
REDHAT_BUGZILLA_PRODUCT_VERSION=8.9
REDHAT_SUPPORT_PRODUCT="Red Hat Enterprise Linux"
REDHAT_SUPPORT_PRODUCT_VERSION="8.9"

推荐答案

When you run the program as yourself,它不需要CAP_DAC_OVERRIDE功能来在对您可写的目录中创建文件,或者打开对您可读的现有文件进行读取.事实上,除非您将功能分配给二进制VIA setcap,否则进程一开始就不会拥有该功能.这并不值得注意,如果您在对您不可写的目录中运行程序,程序也会失败.

When you use 100 to run the program,它以用户0(超级用户)身份运行.凭借这一点,它从其有效集合中的所有能力开始.正是这一点,而不是uid 0本身,才是该进程能够绕过自由访问控制的基础,例如,在不同用户和组拥有的目录中创建文件,并且该文件不是完全可写的.例如(很可能)您的主目录及其所有子目录.如果关闭CAP_DAC_OVERRIDE,则该进程将无法再执行此操作.

那是你写的

当前的工作目录似乎没有什么不同.

...但我倾向于认为工作目录实际上确实起到了作用.我预计,如果您在一个目录中通过sudo运行该程序,该目录对根目录是可写的,而无需执行CAP_DAC_OVERRIDE,那么它将会成功.您的系统上不应该有很多完全可写的目录,并且在根拥有的大多数目录(特别是那些您可以自己访问的目录)中进行测试是不明智的,但是/tmp将是一个合理的测试目录.如果以这两种方式进行测试,请确保在使用sudo测试之前删除锁定文件,以免阻止访问的是该文件上的权限,而不是目录上的权限.

C++相关问答推荐

你能用自己的地址声明一个C指针吗?

Ebpf内核代码:permission denied:invalid access to map value

为什么可以通过指向常量int的指针间接地改变整数的值?

数据包未从DPDK端口传输到内核端口

SDL 2.0-从数组渲染纹理

struct 上的OpenMP缩减

如何将长字符串转换为较小的缩写,该缩写由第一个字符、最后一个字符和中间的字符数组成?

如果dim指定数组中的数据量,使用dim-1会不会潜在地导致丢失一个元素?

在Apple Silicon上编译x86的Fortran/C程序

防止规范模式在C++中 echo 特殊字符

强制转换变量以在 struct 中蚕食

Boyer Moore算法的简单版本中的未定义行为

CS50判断灯泡运动的问题,判断时多出一个灯泡,但不在终端上

通过k&;r语法的c声明无效

使用Open62541向OPCUA服务器发送读请求时内存泄漏

问题:C#Define上的初始值设定项元素不是常量

在文件描述符上设置FD_CLOEXEC与将其传递给POSIX_SPOWN_FILE_ACTIONS_ADCLOSE有区别吗?

C中2个数字的加法 - 简单的人类方法

如何修复数组数据与列标题未对齐的问题?

为什么创建局部变量的指针需要过程在堆栈上分配空间?