Skip to content

Commit 21266b8

Browse files
committed
Merge tag 'AT_EXECVE_CHECK-v6.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux
Pull AT_EXECVE_CHECK from Kees Cook: - Implement AT_EXECVE_CHECK flag to execveat(2) (Mickaël Salaün) - Implement EXEC_RESTRICT_FILE and EXEC_DENY_INTERACTIVE securebits (Mickaël Salaün) - Add selftests and samples for AT_EXECVE_CHECK (Mickaël Salaün) * tag 'AT_EXECVE_CHECK-v6.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux: ima: instantiate the bprm_creds_for_exec() hook samples/check-exec: Add an enlighten "inc" interpreter and 28 tests selftests: ktap_helpers: Fix uninitialized variable samples/check-exec: Add set-exec selftests/landlock: Add tests for execveat + AT_EXECVE_CHECK selftests/exec: Add 32 tests for AT_EXECVE_CHECK and exec securebits security: Add EXEC_RESTRICT_FILE and EXEC_DENY_INTERACTIVE securebits exec: Add a new AT_EXECVE_CHECK flag to execveat(2)
2 parents 5ab889f + 95b3cda commit 21266b8

File tree

29 files changed

+1341
-14
lines changed

29 files changed

+1341
-14
lines changed
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
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

Documentation/userspace-api/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ Security-related interfaces
3535
mfd_noexec
3636
spec_ctrl
3737
tee
38+
check_exec
3839

3940
Devices and I/O
4041
===============

fs/exec.c

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -892,7 +892,8 @@ static struct file *do_open_execat(int fd, struct filename *name, int flags)
892892
.lookup_flags = LOOKUP_FOLLOW,
893893
};
894894

895-
if ((flags & ~(AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) != 0)
895+
if ((flags &
896+
~(AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH | AT_EXECVE_CHECK)) != 0)
896897
return ERR_PTR(-EINVAL);
897898
if (flags & AT_SYMLINK_NOFOLLOW)
898899
open_exec_flags.lookup_flags &= ~LOOKUP_FOLLOW;
@@ -1564,6 +1565,21 @@ static struct linux_binprm *alloc_bprm(int fd, struct filename *filename, int fl
15641565
}
15651566
bprm->interp = bprm->filename;
15661567

1568+
/*
1569+
* At this point, security_file_open() has already been called (with
1570+
* __FMODE_EXEC) and access control checks for AT_EXECVE_CHECK will
1571+
* stop just after the security_bprm_creds_for_exec() call in
1572+
* bprm_execve(). Indeed, the kernel should not try to parse the
1573+
* content of the file with exec_binprm() nor change the calling
1574+
* thread, which means that the following security functions will not
1575+
* be called:
1576+
* - security_bprm_check()
1577+
* - security_bprm_creds_from_file()
1578+
* - security_bprm_committing_creds()
1579+
* - security_bprm_committed_creds()
1580+
*/
1581+
bprm->is_check = !!(flags & AT_EXECVE_CHECK);
1582+
15671583
retval = bprm_mm_init(bprm);
15681584
if (!retval)
15691585
return bprm;
@@ -1845,7 +1861,7 @@ static int bprm_execve(struct linux_binprm *bprm)
18451861

18461862
/* Set the unchanging part of bprm->cred */
18471863
retval = security_bprm_creds_for_exec(bprm);
1848-
if (retval)
1864+
if (retval || bprm->is_check)
18491865
goto out;
18501866

18511867
retval = exec_binprm(bprm);

include/linux/binfmts.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,12 @@ struct linux_binprm {
4444
*/
4545
point_of_no_return:1,
4646
/* Set when "comm" must come from the dentry. */
47-
comm_from_dentry:1;
47+
comm_from_dentry:1,
48+
/*
49+
* Set by user space to check executability according to the
50+
* caller's environment.
51+
*/
52+
is_check:1;
4853
struct file *executable; /* Executable to pass to the interpreter */
4954
struct file *interpreter;
5055
struct file *file;

include/uapi/linux/audit.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@
161161
#define AUDIT_INTEGRITY_RULE 1805 /* policy rule */
162162
#define AUDIT_INTEGRITY_EVM_XATTR 1806 /* New EVM-covered xattr */
163163
#define AUDIT_INTEGRITY_POLICY_RULE 1807 /* IMA policy rules */
164+
#define AUDIT_INTEGRITY_USERSPACE 1808 /* Userspace enforced data integrity */
164165

165166
#define AUDIT_KERNEL 2000 /* Asynchronous audit record. NOT A REQUEST. */
166167

include/uapi/linux/fcntl.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,4 +155,8 @@
155155
#define AT_HANDLE_MNT_ID_UNIQUE 0x001 /* Return the u64 unique mount ID. */
156156
#define AT_HANDLE_CONNECTABLE 0x002 /* Request a connectable file handle */
157157

158+
/* Flags for execveat2(2). */
159+
#define AT_EXECVE_CHECK 0x10000 /* Only perform a check if execution
160+
would be allowed. */
161+
158162
#endif /* _UAPI_LINUX_FCNTL_H */

include/uapi/linux/securebits.h

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,32 @@
5252
#define SECBIT_NO_CAP_AMBIENT_RAISE_LOCKED \
5353
(issecure_mask(SECURE_NO_CAP_AMBIENT_RAISE_LOCKED))
5454

55+
/* See Documentation/userspace-api/check_exec.rst */
56+
#define SECURE_EXEC_RESTRICT_FILE 8
57+
#define SECURE_EXEC_RESTRICT_FILE_LOCKED 9 /* make bit-8 immutable */
58+
59+
#define SECBIT_EXEC_RESTRICT_FILE (issecure_mask(SECURE_EXEC_RESTRICT_FILE))
60+
#define SECBIT_EXEC_RESTRICT_FILE_LOCKED \
61+
(issecure_mask(SECURE_EXEC_RESTRICT_FILE_LOCKED))
62+
63+
/* See Documentation/userspace-api/check_exec.rst */
64+
#define SECURE_EXEC_DENY_INTERACTIVE 10
65+
#define SECURE_EXEC_DENY_INTERACTIVE_LOCKED 11 /* make bit-10 immutable */
66+
67+
#define SECBIT_EXEC_DENY_INTERACTIVE \
68+
(issecure_mask(SECURE_EXEC_DENY_INTERACTIVE))
69+
#define SECBIT_EXEC_DENY_INTERACTIVE_LOCKED \
70+
(issecure_mask(SECURE_EXEC_DENY_INTERACTIVE_LOCKED))
71+
5572
#define SECURE_ALL_BITS (issecure_mask(SECURE_NOROOT) | \
5673
issecure_mask(SECURE_NO_SETUID_FIXUP) | \
5774
issecure_mask(SECURE_KEEP_CAPS) | \
58-
issecure_mask(SECURE_NO_CAP_AMBIENT_RAISE))
75+
issecure_mask(SECURE_NO_CAP_AMBIENT_RAISE) | \
76+
issecure_mask(SECURE_EXEC_RESTRICT_FILE) | \
77+
issecure_mask(SECURE_EXEC_DENY_INTERACTIVE))
5978
#define SECURE_ALL_LOCKS (SECURE_ALL_BITS << 1)
6079

80+
#define SECURE_ALL_UNPRIVILEGED (issecure_mask(SECURE_EXEC_RESTRICT_FILE) | \
81+
issecure_mask(SECURE_EXEC_DENY_INTERACTIVE))
82+
6183
#endif /* _UAPI_LINUX_SECUREBITS_H */

samples/Kconfig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,15 @@ config SAMPLE_CGROUP
291291
help
292292
Build samples that demonstrate the usage of the cgroup API.
293293

294+
config SAMPLE_CHECK_EXEC
295+
bool "Exec secure bits examples"
296+
depends on CC_CAN_LINK && HEADERS_INSTALL
297+
help
298+
Build a tool to easily configure SECBIT_EXEC_RESTRICT_FILE and
299+
SECBIT_EXEC_DENY_INTERACTIVE, and a simple script interpreter to
300+
demonstrate how they should be used with execveat(2) +
301+
AT_EXECVE_CHECK.
302+
294303
source "samples/rust/Kconfig"
295304

296305
endif # SAMPLES

samples/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
subdir-$(CONFIG_SAMPLE_AUXDISPLAY) += auxdisplay
55
subdir-$(CONFIG_SAMPLE_ANDROID_BINDERFS) += binderfs
6+
subdir-$(CONFIG_SAMPLE_CHECK_EXEC) += check-exec
67
subdir-$(CONFIG_SAMPLE_CGROUP) += cgroup
78
obj-$(CONFIG_SAMPLE_CONFIGFS) += configfs/
89
obj-$(CONFIG_SAMPLE_CONNECTOR) += connector/

samples/check-exec/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/inc
2+
/set-exec

samples/check-exec/Makefile

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# SPDX-License-Identifier: BSD-3-Clause
2+
3+
userprogs-always-y := \
4+
inc \
5+
set-exec
6+
7+
userccflags += -I usr/include
8+
9+
.PHONY: all clean
10+
11+
all:
12+
$(MAKE) -C ../.. samples/check-exec/
13+
14+
clean:
15+
$(MAKE) -C ../.. M=samples/check-exec/ clean

0 commit comments

Comments
 (0)