可执行性检查

AT_EXECVE_CHECK execveat(2) 标志,以及 SECBIT_EXEC_RESTRICT_FILESECBIT_EXEC_DENY_INTERACTIVE 安全位,旨在让脚本解释器和动态链接器强制执行由内核处理的一致的执行安全策略。 参见 samples/check-exec/inc.c 示例。

解释器是否应该检查这些安全位,取决于运行恶意脚本相对于执行环境的安全风险,以及内核是否可以检查脚本是否可信。 例如,在服务器上运行的 Python 脚本可以使用任意系统调用并访问任意文件。 这样的解释器应该被启发使用这些安全位,并让用户定义他们的安全策略。 然而,在 Web 浏览器中运行的 JavaScript 引擎应该已经被沙箱化,因此不应该能够损害用户的环境。

为定制执行环境(例如,加固的 Linux 发行版或封闭容器镜像)构建的脚本解释器或动态链接器可以使用 AT_EXECVE_CHECK,而无需检查相关的安全位,如果向后兼容性由其他东西处理(例如,原子更新确保所有合法的库都可以执行)。 因此,建议脚本解释器和动态链接器默认在运行时检查安全位,但也提供自定义构建的能力,使其表现得好像 SECBIT_EXEC_RESTRICT_FILESECBIT_EXEC_DENY_INTERACTIVE 始终设置为 1(即始终强制执行限制)。

AT_EXECVE_CHECK

AT_EXECVE_CHECK 标志传递给 execveat(2) 只会对常规文件执行检查,如果允许执行该文件则返回 0,忽略文件格式以及相关的解释器依赖项(例如,ELF 库、脚本的 shebang)。

程序应始终执行此检查,以将内核级别的检查应用于不由内核直接执行而是传递给用户空间解释器的文件。 从解释器的角度来看,所有包含可执行代码的文件都应进行检查。 但是,此检查的结果应仅根据 SECBIT_EXEC_RESTRICT_FILESECBIT_EXEC_DENY_INTERACTIVE.强制执行。

此标志的主要目的是提高执行环境的安全性和一致性,以确保直接文件执行(例如,./script.sh)和间接文件执行(例如,sh script.sh)导致相同的结果。 例如,这可以用于根据调用者的环境检查文件是否可信。

在安全环境中,还应检查库和任何可执行依赖项。 例如,动态链接应确保允许执行所有库,以避免简单的绕过(例如,使用 LD_PRELOAD)。 为了使这种安全的执行环境有意义,只有可信的代码才能执行,这还需要完整性保证。

为了避免导致 time-of-check to time-of-use 问题的竞争条件,AT_EXECVE_CHECK 应与 AT_EMPTY_PATH 一起使用,以针对文件描述符而不是路径进行检查。

SECBIT_EXEC_RESTRICT_FILE 和 SECBIT_EXEC_DENY_INTERACTIVE

当设置了 SECBIT_EXEC_RESTRICT_FILE 时,只有当调用 execveat(2),使用相关的文件描述符和 AT_EXECVE_CHECK 标志成功时,进程才应解释或执行文件。

此安全位可以由用户会话管理器、服务管理器、容器运行时、沙箱工具等设置。 除了测试环境,相关的 SECBIT_EXEC_RESTRICT_FILE_LOCKED 位也应设置。

程序应仅根据安全位强制执行一致的限制,而不依赖于任何其他用户控制的配置。 实际上,这些安全位的使用案例是仅信任由系统配置(通过内核)审查的可执行代码,因此我们应小心不要让不受信任的用户控制此配置。

但是,脚本解释器仍然可以使用用户配置,例如环境变量,只要它不是禁用安全位检查的一种方式。 例如,PATHLD_PRELOAD 变量可以由脚本的调用者设置。 更改这些变量可能会导致意外的代码执行,但仅来自经过审查的可执行程序,这是可以接受的。 为了使这有意义,系统应提供一致的安全策略,以避免任意代码执行,例如,通过强制执行写入异或执行策略。

当设置了 SECBIT_EXEC_DENY_INTERACTIVE 时,进程绝不应解释交互式用户命令(例如,脚本)。 但是,如果此类命令通过文件描述符(例如,stdin)传递,如果调用 execveat(2),使用相关的文件描述符和 AT_EXECVE_CHECK 标志成功时,则应解释其内容。

例如,使用脚本片段作为参数调用的脚本解释器,如果设置了 SECBIT_EXEC_DENY_INTERACTIVE,则应始终拒绝此类执行。

此安全位可以由用户会话管理器、服务管理器、容器运行时、沙箱工具等设置。 除了测试环境,相关的 SECBIT_EXEC_DENY_INTERACTIVE_LOCKED 位也应设置。

以下是脚本解释器根据任何执行安全位的组合的预期行为

  1. SECBIT_EXEC_RESTRICT_FILE=0SECBIT_EXEC_DENY_INTERACTIVE=0

    始终解释脚本,并允许任意用户命令(默认)。

    没有威胁,每个人和每件事都是可信的,但由于调用 execveat(2)AT_EXECVE_CHECK,我们可以先于潜在的问题,脚本解释器应始终执行但忽略此调用。 实际上,此检查对于使系统管理员能够验证请求(例如,使用审计)并为迁移到安全模式做准备仍然很重要。

  2. SECBIT_EXEC_RESTRICT_FILE=1SECBIT_EXEC_DENY_INTERACTIVE=0

    如果脚本不可执行,则拒绝脚本解释,但允许任意用户命令。

    威胁是由受信任(且未被愚弄)的用户运行的(潜在的)恶意脚本。 这可以防止意外的脚本执行(例如,sh /tmp/*.sh)。 这对于(半受限)用户会话是有意义的。

  3. SECBIT_EXEC_RESTRICT_FILE=0SECBIT_EXEC_DENY_INTERACTIVE=1

    始终解释脚本,但拒绝任意用户命令。

    此用例可能对安全服务(即没有交互式用户会话)有用,其中脚本的完整性经过验证(例如,使用 IMA/EVM 或 dm-verity/IPE),但访问权限可能尚未准备好。 实际上,任意交互式命令将更难以检查。

  4. SECBIT_EXEC_RESTRICT_FILE=1SECBIT_EXEC_DENY_INTERACTIVE=1

    如果脚本不可执行,则拒绝脚本解释,并且还拒绝任何任意用户命令。

    威胁是由不受信任的用户(但受信任的代码)运行的恶意脚本。 这对于可能仅执行受信任脚本的系统服务是有意义的。