当用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++相关问答推荐

如何启用ss(另一个调查套接字的实用程序)来查看Linux主机上加入的多播组IP地址?

为什么getchar()挂起了,尽管poll()返回了一个好的值?""

在使用GTK 4 Columnview列表模型时,如何为多列添加排序函数.C编码,Linux/GNOME环境

在C中使用动态内存分配找到最小的负数

ESP32在vTaskDelay上崩溃

是否所有C编译器在将浮点数转换为整型数时都会隐式删除小数?

Ruby C Api处理异常

如何将常量char*复制到char数组

通过描述符查找文件路径时出现问题

仅从限制指针参数声明推断非混叠

试图创建一个基本的Word克隆,但遇到了障碍

C语言中奇怪的输出打印数组

C中的char**v*char[]

区分MySQL C界面中的文本和BLOB字段

Linux Posix消息队列

C语言中的指针和多维数组

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

strlen 可以是[[未排序]]吗?

c 中符号表缺少项目

在 C 中有效返回多个值