首页 > 解决方案 > 在运行时请求 Linux 功能

问题描述

我正在用 C 语言开发一个程序,该程序需要临时使用一些需要提升才能获得的功能,并且宁愿不只是让用户发出 sudo,因为它将是一次性设置。

我将如何授予诸如 CAP_CHOWN 之类的功能以启用更改文件所有权或由功能保护的类似操作?

关于可能重复的注释

当我在它作为副本关闭之前问这个问题时。被引用为原始问题的问题与我发布的问题不同。我想要一组非常具体的功能,而不是 root 访问权限。

标签: clinuxlinux-capabilities

解决方案


为进程提供额外功能的最常见方法是将文件系统功能分配给其二进制文件。

例如,如果您希望执行的进程/sbin/yourprog具有该 CAP_CHOWN功能,请将该功能添加到该文件的允许和有效集合中:sudo setcap cap_chown=ep /sbin/yourprog.

setcap实用程序由 libcap2-bin 软件包提供,并且默认安装在大多数 Linux 发行版上

也可以为原始流程提供能力,并让该流程根据需要操纵其有效的能力集。例如,Wiresharkdumpcap通常在有效、允许和可继承集中安装 CAP_NET_ADMIN 和 CAP_NET_RAW 文件系统功能。

我不喜欢将任何文件系统功能添加到可继承集的想法。当功能不在可继承集中时,执行另一个二进制文件会导致内核放弃这些功能(假设 KEEPCAPS 为零;有关详细信息,请参见prctl(PR_SET_KEEPCAPS)man 7 功能)。

例如,如果您/sbin/yourprog仅授予 CAP_CHOWN 能力并且只在允许的集合 ( sudo setcap cap_chown=p /sbin/yourprog) 中授予,则 CAP_CHOWN 能力将不会自动生效,并且如果进程执行其他一些二进制文件,它将被删除。要使用 CAP_CHOWN 功能,线程可以在所需操作期间将功能添加到其有效集,然后通过prctl()调用将其从有效集中删除(但将其保留在允许集中)。请注意,libcap cap_get_proc()/cap_set_proc()接口将更改应用于进程中的所有线程,这可能不是您想要的。

对于临时授予能力,可以使用工作子进程。这对于复杂的过程是有意义的,因为它允许将特权操作委托/分离到单独的二进制文件。子进程被分叉,通过 Unix 域流或通过 socketpair() 创建的数据报套接字连接到父进程,并执行授予必要功能的辅助二进制文件。然后它使用 Unix 域流套接字来验证身份(进程 ID、用户 ID、组 ID,并通过进程 ID,套接字的另一端正在执行的可执行文件)。不使用管道的原因是需要 Unix 域流套接字或数据报套接字对套接字才能使用SO_PEERCRED套接字选项向内核查询套接字另一端的身份。

存在需要预测和阻止的已知攻击模式。最常见的攻击模式是导致父进程在分叉并执行特权子进程后立即执行受损的二进制文件,时间恰到好处,因此有能力的子进程相信另一端是其正确的父进程执行正确的二进制文件,但实际上控制已被转移到一个完全不同的、受损的或不可信的二进制文件中。

关于如何安全地做到这一点的详细信息是一个软件工程问题,而不是一个编程问题,但是使用socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, fdpair)和验证套接字对等点是父进程仍然在开始时不止一次执行预期的二进制文件,是需要的关键步骤.


我能想到的最简单的例子是仅在允许的集合中使用 prctl() 和 CAP_NET_BIND_SERVICE 文件系统功能,以便其他非特权进程可以使用特权端口(1-1024,最好是在根目录中定义/列出的系统范围的子集或管理员拥有的配置文件位于 /etc 下)以提供网络服务。如果服务将在被告知时关闭并重新打开其侦听套接字(可能通过 SIGUSR1 信号),则不能简单地在开始时创建一次然后删除侦听套接字。它非常适合“保留在允许的集合中,但只添加到实际需要它的线程的有效集合,然后立即删除它”模式。

对于 CAP_CHOWN,示例程序可能会通过文件系统功能将其获取到其有效和允许的集合中,但使用受信任的配置文件(仅限 root/admin 可修改)列出基于真实用户和组允许进行的所有权更改运行进程的身份。考虑一个专用的“sudo”风格的“chown”实用程序,旨在让组织允许团队领导在其团队成员之间转移文件所有权,但不使用 sudo。)


推荐阅读