Executability check

TheAT_EXECVE_CHECKexecveat(2) flag, and theSECBIT_EXEC_RESTRICT_FILE andSECBIT_EXEC_DENY_INTERACTIVE securebitsare intended for script interpreters and dynamic linkers to enforce aconsistent execution security policy handled by the kernel. See thesamples/check-exec/inc.c example.

Whether an interpreter should check these securebits or not depends on thesecurity risk of running malicious scripts with respect to the executionenvironment, and whether the kernel can check if a script is trustworthy ornot. For instance, Python scripts running on a server can use arbitrarysyscalls and access arbitrary files. Such interpreters should then beenlighten to use these securebits and let users define their security policy.However, a JavaScript engine running in a web browser should already besandboxed and then should not be able to harm the user’s environment.

Script interpreters or dynamic linkers built for tailored execution environments(e.g. hardened Linux distributions or hermetic container images) could useAT_EXECVE_CHECK without checking the related securebits if backwardcompatibility is handled by something else (e.g. atomic update ensuring thatall legitimate libraries are allowed to be executed). It is then recommendedfor script interpreters and dynamic linkers to check the securebits at run timeby default, but also to provide the ability for custom builds to behave like ifSECBIT_EXEC_RESTRICT_FILE orSECBIT_EXEC_DENY_INTERACTIVE were alwaysset to 1 (i.e. always enforce restrictions).

AT_EXECVE_CHECK

Passing theAT_EXECVE_CHECK flag toexecveat(2) only performs acheck on a regular file and returns 0 if execution of this file would beallowed, ignoring the file format and then the related interpreter dependencies(e.g. ELF libraries, script’s shebang).

Programs should always perform this check to apply kernel-level checks againstfiles that are not directly executed by the kernel but passed to a user spaceinterpreter instead. All files that contain executable code, from the point ofview of the interpreter, should be checked. However the result of this checkshould only be enforced according toSECBIT_EXEC_RESTRICT_FILE orSECBIT_EXEC_DENY_INTERACTIVE..

The main purpose of this flag is to improve the security and consistency of anexecution environment to ensure that direct file execution (e.g../script.sh) and indirect file execution (e.g.shscript.sh) lead tothe same result. For instance, this can be used to check if a file istrustworthy according to the caller’s environment.

In a secure environment, libraries and any executable dependencies should alsobe checked. For instance, dynamic linking should make sure that all librariesare allowed for execution to avoid trivial bypass (e.g. usingLD_PRELOAD).For such secure execution environment to make sense, only trusted code shouldbe executable, which also requires integrity guarantees.

To avoid race conditions leading to time-of-check to time-of-use issues,AT_EXECVE_CHECK should be used withAT_EMPTY_PATH to check against afile descriptor instead of a path.

SECBIT_EXEC_RESTRICT_FILE and SECBIT_EXEC_DENY_INTERACTIVE

WhenSECBIT_EXEC_RESTRICT_FILE is set, a process should only interpret orexecute a file if a call toexecveat(2) with the related filedescriptor and theAT_EXECVE_CHECK flag succeed.

This secure bit may be set by user session managers, service managers,container runtimes, sandboxer tools... Except for test environments, therelatedSECBIT_EXEC_RESTRICT_FILE_LOCKED bit should also be set.

Programs should only enforce consistent restrictions according to thesecurebits but without relying on any other user-controlled configuration.Indeed, the use case for these securebits is to only trust executable codevetted by the system configuration (through the kernel), so we should becareful to not let untrusted users control this configuration.

However, script interpreters may still use user configuration such asenvironment variables as long as it is not a way to disable the securebitschecks. For instance, thePATH andLD_PRELOAD variables can be set bya script’s caller. Changing these variables may lead to unintended codeexecutions, but only from vetted executable programs, which is OK. For this tomake sense, the system should provide a consistent security policy to avoidarbitrary code execution e.g., by enforcing a write xor execute policy.

WhenSECBIT_EXEC_DENY_INTERACTIVE is set, a process should never interpretinteractive user commands (e.g. scripts). However, if such commands are passedthrough a file descriptor (e.g. stdin), its content should be interpreted if acall toexecveat(2) with the related file descriptor and theAT_EXECVE_CHECK flag succeed.

For instance, script interpreters called with a script snippet as argumentshould always deny such execution ifSECBIT_EXEC_DENY_INTERACTIVE is set.

This secure bit may be set by user session managers, service managers,container runtimes, sandboxer tools... Except for test environments, therelatedSECBIT_EXEC_DENY_INTERACTIVE_LOCKED bit should also be set.

Here is the expected behavior for a script interpreter according to combinationof any exec securebits:

  1. SECBIT_EXEC_RESTRICT_FILE=0 andSECBIT_EXEC_DENY_INTERACTIVE=0

    Always interpret scripts, and allow arbitrary user commands (default).

    No threat, everyone and everything is trusted, but we can get ahead ofpotential issues thanks to the call toexecveat(2) withAT_EXECVE_CHECK which should always be performed but ignored by thescript interpreter. Indeed, this check is still important to enable systemsadministrators to verify requests (e.g. with audit) and prepare formigration to a secure mode.

  2. SECBIT_EXEC_RESTRICT_FILE=1 andSECBIT_EXEC_DENY_INTERACTIVE=0

    Deny script interpretation if they are not executable, but allowarbitrary user commands.

    The threat is (potential) malicious scripts run by trusted (and not fooled)users. That can protect against unintended script executions (e.g.sh/tmp/*.sh). This makes sense for (semi-restricted) user sessions.

  3. SECBIT_EXEC_RESTRICT_FILE=0 andSECBIT_EXEC_DENY_INTERACTIVE=1

    Always interpret scripts, but deny arbitrary user commands.

    This use case may be useful for secure services (i.e. without interactiveuser session) where scripts’ integrity is verified (e.g. with IMA/EVM ordm-verity/IPE) but where access rights might not be ready yet. Indeed,arbitrary interactive commands would be much more difficult to check.

  4. SECBIT_EXEC_RESTRICT_FILE=1 andSECBIT_EXEC_DENY_INTERACTIVE=1

    Deny script interpretation if they are not executable, and also denyany arbitrary user commands.

    The threat is malicious scripts run by untrusted users (but trusted code).This makes sense for system services that may only execute trusted scripts.