简体   繁体   English

在运行时请求 Linux 功能

[英]Request Linux Capabilities During Runtime

I am developing a program in C that requires temporary use of some capabilities that require elevation to acquire and would rather not just have users issue sudo because it will be one time setup.我正在用 C 开发一个程序,它需要临时使用一些需要提升才能获得的功能,而不仅仅是让用户发出 sudo,因为它将是一次性设置。

How would I go about granting capabilities such as CAP_CHOWN to enable changing file ownership or similar actions guarded by a capability?我将如何授予诸如 CAP_CHOWN 之类的功能以启用更改文件所有权或由功能保护的类似操作?

A note on possible duplicates关于可能重复的说明

When I asked this before it got closed as a duplicate.当我在它作为副本关闭之前问这个问题时。 The question that was cited as the original question isn't the same question I had posted.被引用为原始问题的问题与我发布的问题不同。 I want a very specific set of capabilities, not root access.我想要一组非常具体的功能,而不是 root 访问权限。

The most common method to do provide extra capabilities to a process is to assign filesystem capabilities to its binary.为进程提供额外功能的最常见方法是为其二进制文件分配文件系统功能。

For example, if you want the processes executing /sbin/yourprog to have the CAP_CHOWN capability, add that capability to the permitted and effective sets of that file: sudo setcap cap_chown=ep /sbin/yourprog .例如,如果您希望执行/sbin/yourprog的进程具有CAP_CHOWN功能,请CAP_CHOWN功能添加到该文件的允许和有效集合中: sudo setcap cap_chown=ep /sbin/yourprog

The setcap utility is provided by the libcap2-bin package, and is installed by default on most Linux distributions. setcap实用程序由 libcap2-bin 包提供,默认情况下安装在大多数 Linux 发行版上。

It is also possible to provide the capabilities to the original process, and have that process manipulate its effective capability set as needed.还可以为原始流程提供能力,并让该流程根据需要操纵其有效能力集。 For example, Wireshark's dumpcap is typically installed with CAP_NET_ADMIN and CAP_NET_RAW filesystem capabilities in the effective, permitted, and inheritable sets.例如,Wireshark 的dumpcap通常与 CAP_NET_ADMIN 和 CAP_NET_RAW 文件系统功能一起安装在有效、允许和可继承的集合中。

I dislike the idea of adding any filesystem capabilities to the inheritable set.我不喜欢将任何文件系统功能添加到可继承集的想法。 When the capabilities are not in the inheritable set, executing another binary causes the kernel to drop those capabilities (assuming KEEPCAPS is zero; see prctl(PR_SET_KEEPCAPS) and man 7 capabilities for details).当功能不在可继承集中时,执行另一个二进制文件会导致内核删除这些功能(假设 KEEPCAPS 为零;有关详细信息,请参阅prctl(PR_SET_KEEPCAPS)man 7 功能)。

As an example, if you granted /sbin/yourprog only the CAP_CHOWN capability and only in the permitted set ( sudo setcap cap_chown=p /sbin/yourprog ), then the CAP_CHOWN capability will not be automatically effective, and it will be dropped if the process executes some other binary.例如,如果您仅授予/sbin/yourprog CAP_CHOWN 能力并且仅在允许的集合中( sudo setcap cap_chown=p /sbin/yourprog ),则 CAP_CHOWN 能力将不会自动生效,如果进程执行其他一些二进制文件。 To use the CAP_CHOWN capability, a thread can add the capability to its effective set for the duration of the operations needed, then remove it from the effective set (but keep it in the permitted set), via prctl() calls.要使用 CAP_CHOWN 功能,线程可以在所需操作的持续时间内将该功能添加到其有效集中,然后通过prctl()调用将其从有效集中删除(但将其保留在允许的集中)。 Note that the libcap cap_get_proc() / cap_set_proc() interface applies the changes to all threads in the process, which may not be what you want.请注意,libcap cap_get_proc() / cap_set_proc()接口将更改应用于进程中的所有线程,这可能不是您想要的。

For temporarily granting a capability, a worker sub-process can be used.为了临时授予能力,可以使用工作子进程。 This makes sense for a complex process, as it allows delegating/separating the privileged operations to a separate binary.这对于复杂的过程是有意义的,因为它允许将特权操作委托/分离到单独的二进制文件。 A child process is forked, connected to the parent via an Unix domain stream or datagram socket created via socketpair(), and executes the helper binary that grants it the necessary capabilities.子进程被分叉,通过 Unix 域流或通过 socketpair() 创建的数据报套接字连接到父进程,并执行授予必要功能的帮助程序二进制文件。 It then uses the Unix domain stream socket to verify the identity (process ID, user ID, group ID, and via the process ID, the executable the other end of the socket is executing).然后它使用 Unix 域流套接字来验证身份(进程 ID、用户 ID、组 ID,并通过进程 ID,套接字的另一端正在执行的可执行文件)。 The reason a pipe is not used, is that an Unix domain stream socket or datagram socketpair socket is needed to use the SO_PEERCRED socket option to query the kernel the identity of the other end of the socket.不使用管道的原因是需要 Unix 域流套接字或数据报套接字对套接字来使用SO_PEERCRED套接字选项向内核查询套接字另一端的身份。

There are known attack patterns that need to be anticipated and thwarted.存在需要预测和阻止的已知攻击模式。 The most common attack pattern is causing the parent process to immediately execute a compromised binary after forking and executing the privileged child process, timed just right so the capabled child process trusts the other end is its proper parent executing the proper binary, but in fact control has been transferred to a completely different, compromised or untrustworthy binary.最常见的攻击模式是导致父进程在派生并执行特权子进程后立即执行受感染的二进制文件,时间恰到好处,因此有能力的子进程信任另一端是其正确的父进程执行正确的二进制文件,但实际上是控制已转移到一个完全不同的、受损的或不可信的二进制文件。

The details on exactly how to do this securely are a software engineering question much more than a programming question, but using socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, fdpair) and verifying the socket peer is the parent process still executing the expected binary more than just once at the beginning, are the key steps needed.关于如何安全地做到这一点的细节是一个软件工程问题,而不是一个编程问题,但使用socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, fdpair)并验证套接字对等体是父进程仍在执行预期的二进制文件更多不仅仅是一开始,是需要的关键步骤。


The simplest example I can think of is using prctl() and CAP_NET_BIND_SERVICE filesystem capability only in the permitted set, so that an otherwise unprivileged process can use a privileged port (1-1024, preferably a system-wide subset defined/listed in a root or admin-owned configuration file somewhere under /etc) to provide a network service.我能想到的最简单的例子是仅在允许的集合中使用 prctl() 和 CAP_NET_BIND_SERVICE 文件系统功能,以便其他非特权进程可以使用特权端口(1-1024,最好是在根目录中定义/列出的系统范围子集或 /etc 下某处管理员拥有的配置文件)以提供网络服务。 If the service will close and reopen its listening socket when told to do so (perhaps via SIGUSR1 signal), the listening socket cannot simply be created once at the beginning then dropped.如果服务在被告知关闭并重新打开其侦听套接字时(可能通过 SIGUSR1 信号),则不能简单地在开始时创建一次然后删除侦听套接字。 It is a pretty good match for the "keep in permitted set, but only add to effective set of the thread that actually needs it, then drop it immediately afterwards" pattern.它非常适合“保留在允许的集合中,但只添加到实际需要它的线程的有效集合中,然后立即删除它”模式。

For CAP_CHOWN, an example program might acquire it into its effective and permitted sets via the filesystem capability, but use a trusted configuration file (root/admin modifiable only) to list the ownership changes it is allowed to do based on the real user and group identity running the process.对于 CAP_CHOWN,示例程序可能会通过文件系统功能将其获取到其有效和允许的集合中,但使用受信任的配置文件(仅限 root/admin 可修改)列出允许基于真实用户和组进行的所有权更改身份运行过程。 Consider a dedicated "sudo"-style "chown" utility, intended for say organizations to allow team leads to shift file ownership between their team members, but one that does not use sudo.)考虑一个专用的“sudo”风格的“chown”实用程序,用于组织允许团队领导在其团队成员之间转移文件所有权,但不使用 sudo。)

It is not realistically possible to gain capabilities during runtime.在运行时获得能力实际上是不可能的。 The capabilities need to be already set before your software is started.您的软件启动之前,需要已经设置这些功能。

Some API functions like capset and cap_set_proc exist, but don't expect magic because the situation in which you could gain more capabilities will be both rare and a security oversight .一些 API 函数如capsetcap_set_proc存在,但不要指望魔法,因为您可以获得更多功能的情况既罕见安全疏忽

There are a few general ways of giving your software the required capabilities.有几种通用方法可以为您的软件提供所需的功能。

  1. Set a specific capability on your binary with the setcap tool.使用setcap工具在二进制文件上设置特定功能。
  2. Use sudo to call your program.使用sudo调用您的程序。 You already mentioned this yourself.你自己已经提到了这一点。
  3. Set the setuid bit on your binary and set ownership to root .在二进制文件上设置setuid位并将所有权设置为root In this particular case that will be largely equivalent to calling your program with sudo .在这种特殊情况下,这在很大程度上等同于使用sudo调用您的程序。
  4. Create a utility program that you apply one of the other methods on.创建一个应用其他方法之一的实用程序。 Typically you would find such utility in a place like /usr/libexec .通常,您会在/usr/libexec之类的地方找到此类实用程序。 You then call the utility as a subprocess.然后将该实用程序作为子进程调用。 I would consider this unnecessarily complex for simple situations.对于简单的情况,我会认为这不必要地复杂。 However, depending on the situations, this may be preferred over having a potential security risk of your software constantly running with too many privileges.但是,根据具体情况,这可能比让您的软件以过多权限持续运行存在潜在安全风险更可取。

The first method should be considered the desired way.第一种方法应该被认为是理想的方式。 Your software should drop the capability as soon as it no longer requires it.您的软件应在不再需要该功能时立即删除该功能。

The CAP_CHOWN could be used for example to change ownership of /etc/shadow .例如,CAP_CHOWN 可用于更改/etc/shadow所有权。 The new owner could then change password for other users such as root , so effectively it could be equivalent to granting all capabilities.然后,新所有者可以更改其他用户(例如root密码,因此它实际上等同于授予所有root Hence, this capability is -like many others- potentially dangerous.因此,与许多其他功能一样,此功能具有潜在危险。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM