|
| 1 | +.. SPDX-License-Identifier: GPL-2.0 |
| 2 | +.. Copyright © 2024 Microsoft Corporation |
| 3 | +
|
| 4 | +=================== |
| 5 | +Executability check |
| 6 | +=================== |
| 7 | + |
| 8 | +The ``AT_EXECVE_CHECK`` :manpage:`execveat(2)` flag, and the |
| 9 | +``SECBIT_EXEC_RESTRICT_FILE`` and ``SECBIT_EXEC_DENY_INTERACTIVE`` securebits |
| 10 | +are intended for script interpreters and dynamic linkers to enforce a |
| 11 | +consistent execution security policy handled by the kernel. See the |
| 12 | +`samples/check-exec/inc.c`_ example. |
| 13 | + |
| 14 | +Whether an interpreter should check these securebits or not depends on the |
| 15 | +security risk of running malicious scripts with respect to the execution |
| 16 | +environment, and whether the kernel can check if a script is trustworthy or |
| 17 | +not. For instance, Python scripts running on a server can use arbitrary |
| 18 | +syscalls and access arbitrary files. Such interpreters should then be |
| 19 | +enlighten to use these securebits and let users define their security policy. |
| 20 | +However, a JavaScript engine running in a web browser should already be |
| 21 | +sandboxed and then should not be able to harm the user's environment. |
| 22 | + |
| 23 | +Script interpreters or dynamic linkers built for tailored execution environments |
| 24 | +(e.g. hardened Linux distributions or hermetic container images) could use |
| 25 | +``AT_EXECVE_CHECK`` without checking the related securebits if backward |
| 26 | +compatibility is handled by something else (e.g. atomic update ensuring that |
| 27 | +all legitimate libraries are allowed to be executed). It is then recommended |
| 28 | +for script interpreters and dynamic linkers to check the securebits at run time |
| 29 | +by default, but also to provide the ability for custom builds to behave like if |
| 30 | +``SECBIT_EXEC_RESTRICT_FILE`` or ``SECBIT_EXEC_DENY_INTERACTIVE`` were always |
| 31 | +set to 1 (i.e. always enforce restrictions). |
| 32 | + |
| 33 | +AT_EXECVE_CHECK |
| 34 | +=============== |
| 35 | + |
| 36 | +Passing the ``AT_EXECVE_CHECK`` flag to :manpage:`execveat(2)` only performs a |
| 37 | +check on a regular file and returns 0 if execution of this file would be |
| 38 | +allowed, ignoring the file format and then the related interpreter dependencies |
| 39 | +(e.g. ELF libraries, script's shebang). |
| 40 | + |
| 41 | +Programs should always perform this check to apply kernel-level checks against |
| 42 | +files that are not directly executed by the kernel but passed to a user space |
| 43 | +interpreter instead. All files that contain executable code, from the point of |
| 44 | +view of the interpreter, should be checked. However the result of this check |
| 45 | +should only be enforced according to ``SECBIT_EXEC_RESTRICT_FILE`` or |
| 46 | +``SECBIT_EXEC_DENY_INTERACTIVE.``. |
| 47 | + |
| 48 | +The main purpose of this flag is to improve the security and consistency of an |
| 49 | +execution environment to ensure that direct file execution (e.g. |
| 50 | +``./script.sh``) and indirect file execution (e.g. ``sh script.sh``) lead to |
| 51 | +the same result. For instance, this can be used to check if a file is |
| 52 | +trustworthy according to the caller's environment. |
| 53 | + |
| 54 | +In a secure environment, libraries and any executable dependencies should also |
| 55 | +be checked. For instance, dynamic linking should make sure that all libraries |
| 56 | +are allowed for execution to avoid trivial bypass (e.g. using ``LD_PRELOAD``). |
| 57 | +For such secure execution environment to make sense, only trusted code should |
| 58 | +be executable, which also requires integrity guarantees. |
| 59 | + |
| 60 | +To avoid race conditions leading to time-of-check to time-of-use issues, |
| 61 | +``AT_EXECVE_CHECK`` should be used with ``AT_EMPTY_PATH`` to check against a |
| 62 | +file descriptor instead of a path. |
| 63 | + |
| 64 | +SECBIT_EXEC_RESTRICT_FILE and SECBIT_EXEC_DENY_INTERACTIVE |
| 65 | +========================================================== |
| 66 | + |
| 67 | +When ``SECBIT_EXEC_RESTRICT_FILE`` is set, a process should only interpret or |
| 68 | +execute a file if a call to :manpage:`execveat(2)` with the related file |
| 69 | +descriptor and the ``AT_EXECVE_CHECK`` flag succeed. |
| 70 | + |
| 71 | +This secure bit may be set by user session managers, service managers, |
| 72 | +container runtimes, sandboxer tools... Except for test environments, the |
| 73 | +related ``SECBIT_EXEC_RESTRICT_FILE_LOCKED`` bit should also be set. |
| 74 | + |
| 75 | +Programs should only enforce consistent restrictions according to the |
| 76 | +securebits but without relying on any other user-controlled configuration. |
| 77 | +Indeed, the use case for these securebits is to only trust executable code |
| 78 | +vetted by the system configuration (through the kernel), so we should be |
| 79 | +careful to not let untrusted users control this configuration. |
| 80 | + |
| 81 | +However, script interpreters may still use user configuration such as |
| 82 | +environment variables as long as it is not a way to disable the securebits |
| 83 | +checks. For instance, the ``PATH`` and ``LD_PRELOAD`` variables can be set by |
| 84 | +a script's caller. Changing these variables may lead to unintended code |
| 85 | +executions, but only from vetted executable programs, which is OK. For this to |
| 86 | +make sense, the system should provide a consistent security policy to avoid |
| 87 | +arbitrary code execution e.g., by enforcing a write xor execute policy. |
| 88 | + |
| 89 | +When ``SECBIT_EXEC_DENY_INTERACTIVE`` is set, a process should never interpret |
| 90 | +interactive user commands (e.g. scripts). However, if such commands are passed |
| 91 | +through a file descriptor (e.g. stdin), its content should be interpreted if a |
| 92 | +call to :manpage:`execveat(2)` with the related file descriptor and the |
| 93 | +``AT_EXECVE_CHECK`` flag succeed. |
| 94 | + |
| 95 | +For instance, script interpreters called with a script snippet as argument |
| 96 | +should always deny such execution if ``SECBIT_EXEC_DENY_INTERACTIVE`` is set. |
| 97 | + |
| 98 | +This secure bit may be set by user session managers, service managers, |
| 99 | +container runtimes, sandboxer tools... Except for test environments, the |
| 100 | +related ``SECBIT_EXEC_DENY_INTERACTIVE_LOCKED`` bit should also be set. |
| 101 | + |
| 102 | +Here is the expected behavior for a script interpreter according to combination |
| 103 | +of any exec securebits: |
| 104 | + |
| 105 | +1. ``SECBIT_EXEC_RESTRICT_FILE=0`` and ``SECBIT_EXEC_DENY_INTERACTIVE=0`` |
| 106 | + |
| 107 | + Always interpret scripts, and allow arbitrary user commands (default). |
| 108 | + |
| 109 | + No threat, everyone and everything is trusted, but we can get ahead of |
| 110 | + potential issues thanks to the call to :manpage:`execveat(2)` with |
| 111 | + ``AT_EXECVE_CHECK`` which should always be performed but ignored by the |
| 112 | + script interpreter. Indeed, this check is still important to enable systems |
| 113 | + administrators to verify requests (e.g. with audit) and prepare for |
| 114 | + migration to a secure mode. |
| 115 | + |
| 116 | +2. ``SECBIT_EXEC_RESTRICT_FILE=1`` and ``SECBIT_EXEC_DENY_INTERACTIVE=0`` |
| 117 | + |
| 118 | + Deny script interpretation if they are not executable, but allow |
| 119 | + arbitrary user commands. |
| 120 | + |
| 121 | + The threat is (potential) malicious scripts run by trusted (and not fooled) |
| 122 | + users. That can protect against unintended script executions (e.g. ``sh |
| 123 | + /tmp/*.sh``). This makes sense for (semi-restricted) user sessions. |
| 124 | + |
| 125 | +3. ``SECBIT_EXEC_RESTRICT_FILE=0`` and ``SECBIT_EXEC_DENY_INTERACTIVE=1`` |
| 126 | + |
| 127 | + Always interpret scripts, but deny arbitrary user commands. |
| 128 | + |
| 129 | + This use case may be useful for secure services (i.e. without interactive |
| 130 | + user session) where scripts' integrity is verified (e.g. with IMA/EVM or |
| 131 | + dm-verity/IPE) but where access rights might not be ready yet. Indeed, |
| 132 | + arbitrary interactive commands would be much more difficult to check. |
| 133 | + |
| 134 | +4. ``SECBIT_EXEC_RESTRICT_FILE=1`` and ``SECBIT_EXEC_DENY_INTERACTIVE=1`` |
| 135 | + |
| 136 | + Deny script interpretation if they are not executable, and also deny |
| 137 | + any arbitrary user commands. |
| 138 | + |
| 139 | + The threat is malicious scripts run by untrusted users (but trusted code). |
| 140 | + This makes sense for system services that may only execute trusted scripts. |
| 141 | + |
| 142 | +.. Links |
| 143 | +.. _samples/check-exec/inc.c: |
| 144 | + https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/samples/check-exec/inc.c |
0 commit comments