在运行时请求 Linux 能力
Request Linux Capabilities During Runtime
我正在用 C 语言开发一个程序,它需要临时使用一些需要提升才能获得的功能,并且不希望只让用户发出 sudo,因为这将是一次性设置。
我将如何授予 CAP_CHOWN 等功能以启用更改文件所有权或由功能保护的类似操作?
关于可能重复的注释
当我在它作为副本关闭之前问过它。被引用为原始问题的问题与我发布的问题不同。我想要一组非常具体的功能,而不是 root 访问权限。
为进程提供额外功能的最常见方法是将文件系统功能分配给它的二进制文件。
例如,如果您希望执行 /sbin/yourprog
的进程具有 CAP_CHOWN
能力,请将该能力添加到该文件的允许和有效集中:sudo setcap cap_chown=ep /sbin/yourprog
.
setcap 实用程序由 libcap2-bin 软件包提供,默认安装在大多数 Linux 发行版上。
也可以向原始流程提供功能,并让该流程根据需要操纵其有效功能集。例如,Wireshark 的 dumpcap
通常与 CAP_NET_ADMIN 和 CAP_NET_RAW 文件系统功能一起安装在有效、允许和可继承的集合中。
我不喜欢将任何文件系统功能添加到可继承集的想法。当功能不在可继承集中时,执行另一个二进制文件会导致内核删除这些功能(假设 KEEPCAPS 为零;有关详细信息,请参阅 prctl(PR_SET_KEEPCAPS) and man 7 capabilities)。
例如,如果您仅授予 /sbin/yourprog
CAP_CHOWN 能力并且仅在允许集 (sudo setcap cap_chown=p /sbin/yourprog
) 中,则 CAP_CHOWN 能力将不会被授予自动生效,如果进程执行其他二进制文件,它将被删除。要使用 CAP_CHOWN 能力,线程可以在所需操作期间将能力添加到其有效集中,然后通过 prctl() 来电。请注意,libcap cap_get_proc()
/cap_set_proc()
接口将更改应用于进程中的 all 个线程,这可能不是您想要的。
对于临时授予能力,可以使用工作子进程。这对于复杂的进程是有意义的,因为它允许 delegating/separating 对单独的二进制文件进行特权操作。子进程被分叉,通过 Unix 域流或通过 socketpair() 创建的数据报套接字连接到父进程,并执行授予 it 必要功能的辅助二进制文件。然后它使用 Unix 域流套接字来验证身份(进程 ID、用户 ID、组 ID,并通过进程 ID,套接字的另一端正在执行的可执行文件)。不使用管道的原因是,需要 Unix 域流套接字或数据报套接字对套接字才能使用 SO_PEERCRED
套接字选项查询内核套接字另一端的身份。
有一些已知的攻击模式需要预测和阻止。最常见的攻击模式是导致父进程在分叉并执行特权子进程后立即执行受损二进制文件,时间恰到好处,因此有能力的子进程相信另一端是其正确的父进程执行正确的二进制文件,但实际上控制已转移到完全不同的、受损的或不可信的二进制文件。
关于如何安全地执行此操作的详细信息是一个软件工程问题,而不仅仅是一个编程问题,但是使用 socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, fdpair)
并验证套接字对等体是父进程仍在执行预期的二进制文件,而不仅仅是一旦开始,就是需要的关键步骤。
我能想到的最简单的例子是仅在允许的集合中使用 prctl() 和 CAP_NET_BIND_SERVICE 文件系统功能,以便其他非特权进程可以使用特权端口(1-1024,最好是系统-wide 子集 defined/listed 在 /etc 下某处的根或管理员拥有的配置文件中)以提供网络服务。如果服务将关闭并在被告知(可能通过 SIGUSR1 信号)时重新打开其侦听套接字,则不能简单地在开始时创建一次然后删除侦听套接字。它非常适合 “保留在允许的集合中,但只添加到实际需要它的线程的有效集合,然后立即将其删除” 模式。
对于 CAP_CHOWN,一个示例程序可能会通过文件系统功能将其获取到其有效和允许的集合中,但使用受信任的配置文件(root/admin 仅可修改)列出所有权更改它允许做基于真实用户和组身份的 运行 过程。考虑一个专用的“sudo”风格的“chown”实用程序,旨在让组织允许团队领导在其团队成员之间转移文件所有权,但不使用 sudo。)
在运行时获得能力实际上是不可能的。需要在您的软件启动之前设置这些功能。
一些 API 功能如 capset
和 cap_set_proc
存在,但不要指望魔法,因为你可以获得更多功能的情况将是 罕见和安全监督。
有几种通用方法可以为您的软件提供所需的功能。
- 使用
setcap
工具为二进制文件设置特定功能。
- 使用
sudo
调用您的程序。你自己已经提到了这一点。
- 在您的二进制文件上设置
setuid
位并将所有权设置为 root
。在这种特殊情况下,这在很大程度上等同于使用 sudo
. 调用您的程序
- 创建一个应用其他方法之一的实用程序。通常你会在像
/usr/libexec
这样的地方找到这样的实用程序。然后您将该实用程序作为子进程调用。对于简单的情况,我会认为这不必要地复杂。但是,根据具体情况,这可能比让您的软件不断 运行 太多权限的潜在安全风险更可取。
第一种方法应该被认为是理想的方式。您的软件应该在不再需要该功能时立即删除该功能。
CAP_CHOWN 可用于更改 /etc/shadow
的所有权。然后新所有者可以更改其他用户的密码,例如 root
,因此实际上相当于授予所有权限。因此,与许多其他功能一样,此功能具有潜在危险。
我正在用 C 语言开发一个程序,它需要临时使用一些需要提升才能获得的功能,并且不希望只让用户发出 sudo,因为这将是一次性设置。
我将如何授予 CAP_CHOWN 等功能以启用更改文件所有权或由功能保护的类似操作?
关于可能重复的注释
当我在它作为副本关闭之前问过它。被引用为原始问题的问题与我发布的问题不同。我想要一组非常具体的功能,而不是 root 访问权限。
为进程提供额外功能的最常见方法是将文件系统功能分配给它的二进制文件。
例如,如果您希望执行 /sbin/yourprog
的进程具有 CAP_CHOWN
能力,请将该能力添加到该文件的允许和有效集中:sudo setcap cap_chown=ep /sbin/yourprog
.
setcap 实用程序由 libcap2-bin 软件包提供,默认安装在大多数 Linux 发行版上。
也可以向原始流程提供功能,并让该流程根据需要操纵其有效功能集。例如,Wireshark 的 dumpcap
通常与 CAP_NET_ADMIN 和 CAP_NET_RAW 文件系统功能一起安装在有效、允许和可继承的集合中。
我不喜欢将任何文件系统功能添加到可继承集的想法。当功能不在可继承集中时,执行另一个二进制文件会导致内核删除这些功能(假设 KEEPCAPS 为零;有关详细信息,请参阅 prctl(PR_SET_KEEPCAPS) and man 7 capabilities)。
例如,如果您仅授予 /sbin/yourprog
CAP_CHOWN 能力并且仅在允许集 (sudo setcap cap_chown=p /sbin/yourprog
) 中,则 CAP_CHOWN 能力将不会被授予自动生效,如果进程执行其他二进制文件,它将被删除。要使用 CAP_CHOWN 能力,线程可以在所需操作期间将能力添加到其有效集中,然后通过 prctl() 来电。请注意,libcap cap_get_proc()
/cap_set_proc()
接口将更改应用于进程中的 all 个线程,这可能不是您想要的。
对于临时授予能力,可以使用工作子进程。这对于复杂的进程是有意义的,因为它允许 delegating/separating 对单独的二进制文件进行特权操作。子进程被分叉,通过 Unix 域流或通过 socketpair() 创建的数据报套接字连接到父进程,并执行授予 it 必要功能的辅助二进制文件。然后它使用 Unix 域流套接字来验证身份(进程 ID、用户 ID、组 ID,并通过进程 ID,套接字的另一端正在执行的可执行文件)。不使用管道的原因是,需要 Unix 域流套接字或数据报套接字对套接字才能使用 SO_PEERCRED
套接字选项查询内核套接字另一端的身份。
有一些已知的攻击模式需要预测和阻止。最常见的攻击模式是导致父进程在分叉并执行特权子进程后立即执行受损二进制文件,时间恰到好处,因此有能力的子进程相信另一端是其正确的父进程执行正确的二进制文件,但实际上控制已转移到完全不同的、受损的或不可信的二进制文件。
关于如何安全地执行此操作的详细信息是一个软件工程问题,而不仅仅是一个编程问题,但是使用 socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, fdpair)
并验证套接字对等体是父进程仍在执行预期的二进制文件,而不仅仅是一旦开始,就是需要的关键步骤。
我能想到的最简单的例子是仅在允许的集合中使用 prctl() 和 CAP_NET_BIND_SERVICE 文件系统功能,以便其他非特权进程可以使用特权端口(1-1024,最好是系统-wide 子集 defined/listed 在 /etc 下某处的根或管理员拥有的配置文件中)以提供网络服务。如果服务将关闭并在被告知(可能通过 SIGUSR1 信号)时重新打开其侦听套接字,则不能简单地在开始时创建一次然后删除侦听套接字。它非常适合 “保留在允许的集合中,但只添加到实际需要它的线程的有效集合,然后立即将其删除” 模式。
对于 CAP_CHOWN,一个示例程序可能会通过文件系统功能将其获取到其有效和允许的集合中,但使用受信任的配置文件(root/admin 仅可修改)列出所有权更改它允许做基于真实用户和组身份的 运行 过程。考虑一个专用的“sudo”风格的“chown”实用程序,旨在让组织允许团队领导在其团队成员之间转移文件所有权,但不使用 sudo。)
在运行时获得能力实际上是不可能的。需要在您的软件启动之前设置这些功能。
一些 API 功能如 capset
和 cap_set_proc
存在,但不要指望魔法,因为你可以获得更多功能的情况将是 罕见和安全监督。
有几种通用方法可以为您的软件提供所需的功能。
- 使用
setcap
工具为二进制文件设置特定功能。 - 使用
sudo
调用您的程序。你自己已经提到了这一点。 - 在您的二进制文件上设置
setuid
位并将所有权设置为root
。在这种特殊情况下,这在很大程度上等同于使用sudo
. 调用您的程序
- 创建一个应用其他方法之一的实用程序。通常你会在像
/usr/libexec
这样的地方找到这样的实用程序。然后您将该实用程序作为子进程调用。对于简单的情况,我会认为这不必要地复杂。但是,根据具体情况,这可能比让您的软件不断 运行 太多权限的潜在安全风险更可取。
第一种方法应该被认为是理想的方式。您的软件应该在不再需要该功能时立即删除该功能。
CAP_CHOWN 可用于更改 /etc/shadow
的所有权。然后新所有者可以更改其他用户的密码,例如 root
,因此实际上相当于授予所有权限。因此,与许多其他功能一样,此功能具有潜在危险。