xref: /linux/tools/testing/selftests/exec/check-exec.c (revision e814f3fd16acfb7f9966773953de8f740a1e3202)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Test execveat(2) with AT_EXECVE_CHECK, and prctl(2) with
4  * SECBIT_EXEC_RESTRICT_FILE, SECBIT_EXEC_DENY_INTERACTIVE, and their locked
5  * counterparts.
6  *
7  * Copyright © 2018-2020 ANSSI
8  * Copyright © 2024 Microsoft Corporation
9  *
10  * Author: Mickaël Salaün <mic@digikod.net>
11  */
12 
13 #include <asm-generic/unistd.h>
14 #include <errno.h>
15 #include <fcntl.h>
16 #include <linux/prctl.h>
17 #include <linux/securebits.h>
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <sys/capability.h>
21 #include <sys/mount.h>
22 #include <sys/prctl.h>
23 #include <sys/socket.h>
24 #include <sys/stat.h>
25 #include <sys/sysmacros.h>
26 #include <unistd.h>
27 
28 /* Defines AT_EXECVE_CHECK without type conflicts. */
29 #define _ASM_GENERIC_FCNTL_H
30 #include <linux/fcntl.h>
31 
32 #include "../kselftest_harness.h"
33 
34 static void drop_privileges(struct __test_metadata *const _metadata)
35 {
36 	const unsigned int noroot = SECBIT_NOROOT | SECBIT_NOROOT_LOCKED;
37 	cap_t cap_p;
38 
39 	if ((cap_get_secbits() & noroot) != noroot)
40 		EXPECT_EQ(0, cap_set_secbits(noroot));
41 
42 	cap_p = cap_get_proc();
43 	EXPECT_NE(NULL, cap_p);
44 	EXPECT_NE(-1, cap_clear(cap_p));
45 
46 	/*
47 	 * Drops everything, especially CAP_SETPCAP, CAP_DAC_OVERRIDE, and
48 	 * CAP_DAC_READ_SEARCH.
49 	 */
50 	EXPECT_NE(-1, cap_set_proc(cap_p));
51 	EXPECT_NE(-1, cap_free(cap_p));
52 }
53 
54 static int test_secbits_set(const unsigned int secbits)
55 {
56 	int err;
57 
58 	err = prctl(PR_SET_SECUREBITS, secbits);
59 	if (err)
60 		return errno;
61 	return 0;
62 }
63 
64 FIXTURE(access)
65 {
66 	int memfd, pipefd;
67 	int pipe_fds[2], socket_fds[2];
68 };
69 
70 FIXTURE_VARIANT(access)
71 {
72 	const bool mount_exec;
73 	const bool file_exec;
74 };
75 
76 /* clang-format off */
77 FIXTURE_VARIANT_ADD(access, mount_exec_file_exec) {
78 	/* clang-format on */
79 	.mount_exec = true,
80 	.file_exec = true,
81 };
82 
83 /* clang-format off */
84 FIXTURE_VARIANT_ADD(access, mount_exec_file_noexec) {
85 	/* clang-format on */
86 	.mount_exec = true,
87 	.file_exec = false,
88 };
89 
90 /* clang-format off */
91 FIXTURE_VARIANT_ADD(access, mount_noexec_file_exec) {
92 	/* clang-format on */
93 	.mount_exec = false,
94 	.file_exec = true,
95 };
96 
97 /* clang-format off */
98 FIXTURE_VARIANT_ADD(access, mount_noexec_file_noexec) {
99 	/* clang-format on */
100 	.mount_exec = false,
101 	.file_exec = false,
102 };
103 
104 static const char binary_path[] = "./false";
105 static const char workdir_path[] = "./test-mount";
106 static const char reg_file_path[] = "./test-mount/regular_file";
107 static const char dir_path[] = "./test-mount/directory";
108 static const char block_dev_path[] = "./test-mount/block_device";
109 static const char char_dev_path[] = "./test-mount/character_device";
110 static const char fifo_path[] = "./test-mount/fifo";
111 
112 FIXTURE_SETUP(access)
113 {
114 	int procfd_path_size;
115 	static const char path_template[] = "/proc/self/fd/%d";
116 	char procfd_path[sizeof(path_template) + 10];
117 
118 	/* Makes sure we are not already restricted nor locked. */
119 	EXPECT_EQ(0, test_secbits_set(0));
120 
121 	/*
122 	 * Cleans previous workspace if any error previously happened (don't
123 	 * check errors).
124 	 */
125 	umount(workdir_path);
126 	rmdir(workdir_path);
127 
128 	/* Creates a clean mount point. */
129 	ASSERT_EQ(0, mkdir(workdir_path, 00700));
130 	ASSERT_EQ(0, mount("test", workdir_path, "tmpfs",
131 			   MS_MGC_VAL | (variant->mount_exec ? 0 : MS_NOEXEC),
132 			   "mode=0700,size=9m"));
133 
134 	/* Creates a regular file. */
135 	ASSERT_EQ(0, mknod(reg_file_path,
136 			   S_IFREG | (variant->file_exec ? 0700 : 0600), 0));
137 	/* Creates a directory. */
138 	ASSERT_EQ(0, mkdir(dir_path, variant->file_exec ? 0700 : 0600));
139 	/* Creates a character device: /dev/null. */
140 	ASSERT_EQ(0, mknod(char_dev_path, S_IFCHR | 0400, makedev(1, 3)));
141 	/* Creates a block device: /dev/loop0 */
142 	ASSERT_EQ(0, mknod(block_dev_path, S_IFBLK | 0400, makedev(7, 0)));
143 	/* Creates a fifo. */
144 	ASSERT_EQ(0, mknod(fifo_path, S_IFIFO | 0600, 0));
145 
146 	/* Creates a regular file without user mount point. */
147 	self->memfd = memfd_create("test-exec-probe", MFD_CLOEXEC);
148 	ASSERT_LE(0, self->memfd);
149 	/* Sets mode, which must be ignored by the exec check. */
150 	ASSERT_EQ(0, fchmod(self->memfd, variant->file_exec ? 0700 : 0600));
151 
152 	/* Creates a pipefs file descriptor. */
153 	ASSERT_EQ(0, pipe(self->pipe_fds));
154 	procfd_path_size = snprintf(procfd_path, sizeof(procfd_path),
155 				    path_template, self->pipe_fds[0]);
156 	ASSERT_LT(procfd_path_size, sizeof(procfd_path));
157 	self->pipefd = open(procfd_path, O_RDWR | O_CLOEXEC);
158 	ASSERT_LE(0, self->pipefd);
159 	ASSERT_EQ(0, fchmod(self->pipefd, variant->file_exec ? 0700 : 0600));
160 
161 	/* Creates a socket file descriptor. */
162 	ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0,
163 				self->socket_fds));
164 }
165 
166 FIXTURE_TEARDOWN_PARENT(access)
167 {
168 	/* There is no need to unlink the test files. */
169 	EXPECT_EQ(0, umount(workdir_path));
170 	EXPECT_EQ(0, rmdir(workdir_path));
171 }
172 
173 static void fill_exec_fd(struct __test_metadata *_metadata, const int fd_out)
174 {
175 	char buf[1024];
176 	size_t len;
177 	int fd_in;
178 
179 	fd_in = open(binary_path, O_CLOEXEC | O_RDONLY);
180 	ASSERT_LE(0, fd_in);
181 	/* Cannot use copy_file_range(2) because of EXDEV. */
182 	len = read(fd_in, buf, sizeof(buf));
183 	EXPECT_LE(0, len);
184 	while (len > 0) {
185 		EXPECT_EQ(len, write(fd_out, buf, len))
186 		{
187 			TH_LOG("Failed to write: %s (%d)", strerror(errno),
188 			       errno);
189 		}
190 		len = read(fd_in, buf, sizeof(buf));
191 		EXPECT_LE(0, len);
192 	}
193 	EXPECT_EQ(0, close(fd_in));
194 }
195 
196 static void fill_exec_path(struct __test_metadata *_metadata,
197 			   const char *const path)
198 {
199 	int fd_out;
200 
201 	fd_out = open(path, O_CLOEXEC | O_WRONLY);
202 	ASSERT_LE(0, fd_out)
203 	{
204 		TH_LOG("Failed to open %s: %s", path, strerror(errno));
205 	}
206 	fill_exec_fd(_metadata, fd_out);
207 	EXPECT_EQ(0, close(fd_out));
208 }
209 
210 static void test_exec_fd(struct __test_metadata *_metadata, const int fd,
211 			 const int err_code)
212 {
213 	char *const argv[] = { "", NULL };
214 	int access_ret, access_errno;
215 
216 	/*
217 	 * If we really execute fd, filled with the "false" binary, the current
218 	 * thread will exits with an error, which will be interpreted by the
219 	 * test framework as an error.  With AT_EXECVE_CHECK, we only check a
220 	 * potential successful execution.
221 	 */
222 	access_ret =
223 		execveat(fd, "", argv, NULL, AT_EMPTY_PATH | AT_EXECVE_CHECK);
224 	access_errno = errno;
225 	if (err_code) {
226 		EXPECT_EQ(-1, access_ret);
227 		EXPECT_EQ(err_code, access_errno)
228 		{
229 			TH_LOG("Wrong error for execveat(2): %s (%d)",
230 			       strerror(access_errno), errno);
231 		}
232 	} else {
233 		EXPECT_EQ(0, access_ret)
234 		{
235 			TH_LOG("Access denied: %s", strerror(access_errno));
236 		}
237 	}
238 }
239 
240 static void test_exec_path(struct __test_metadata *_metadata,
241 			   const char *const path, const int err_code)
242 {
243 	int flags = O_CLOEXEC;
244 	int fd;
245 
246 	/* Do not block on pipes. */
247 	if (path == fifo_path)
248 		flags |= O_NONBLOCK;
249 
250 	fd = open(path, flags | O_RDONLY);
251 	ASSERT_LE(0, fd)
252 	{
253 		TH_LOG("Failed to open %s: %s", path, strerror(errno));
254 	}
255 	test_exec_fd(_metadata, fd, err_code);
256 	EXPECT_EQ(0, close(fd));
257 }
258 
259 /* Tests that we don't get ENOEXEC. */
260 TEST_F(access, regular_file_empty)
261 {
262 	const int exec = variant->mount_exec && variant->file_exec;
263 
264 	test_exec_path(_metadata, reg_file_path, exec ? 0 : EACCES);
265 
266 	drop_privileges(_metadata);
267 	test_exec_path(_metadata, reg_file_path, exec ? 0 : EACCES);
268 }
269 
270 TEST_F(access, regular_file_elf)
271 {
272 	const int exec = variant->mount_exec && variant->file_exec;
273 
274 	fill_exec_path(_metadata, reg_file_path);
275 
276 	test_exec_path(_metadata, reg_file_path, exec ? 0 : EACCES);
277 
278 	drop_privileges(_metadata);
279 	test_exec_path(_metadata, reg_file_path, exec ? 0 : EACCES);
280 }
281 
282 /* Tests that we don't get ENOEXEC. */
283 TEST_F(access, memfd_empty)
284 {
285 	const int exec = variant->file_exec;
286 
287 	test_exec_fd(_metadata, self->memfd, exec ? 0 : EACCES);
288 
289 	drop_privileges(_metadata);
290 	test_exec_fd(_metadata, self->memfd, exec ? 0 : EACCES);
291 }
292 
293 TEST_F(access, memfd_elf)
294 {
295 	const int exec = variant->file_exec;
296 
297 	fill_exec_fd(_metadata, self->memfd);
298 
299 	test_exec_fd(_metadata, self->memfd, exec ? 0 : EACCES);
300 
301 	drop_privileges(_metadata);
302 	test_exec_fd(_metadata, self->memfd, exec ? 0 : EACCES);
303 }
304 
305 TEST_F(access, non_regular_files)
306 {
307 	test_exec_path(_metadata, dir_path, EACCES);
308 	test_exec_path(_metadata, block_dev_path, EACCES);
309 	test_exec_path(_metadata, char_dev_path, EACCES);
310 	test_exec_path(_metadata, fifo_path, EACCES);
311 	test_exec_fd(_metadata, self->socket_fds[0], EACCES);
312 	test_exec_fd(_metadata, self->pipefd, EACCES);
313 }
314 
315 /* clang-format off */
316 FIXTURE(secbits) {};
317 /* clang-format on */
318 
319 FIXTURE_VARIANT(secbits)
320 {
321 	const bool is_privileged;
322 	const int error;
323 };
324 
325 /* clang-format off */
326 FIXTURE_VARIANT_ADD(secbits, priv) {
327 	/* clang-format on */
328 	.is_privileged = true,
329 	.error = 0,
330 };
331 
332 /* clang-format off */
333 FIXTURE_VARIANT_ADD(secbits, unpriv) {
334 	/* clang-format on */
335 	.is_privileged = false,
336 	.error = EPERM,
337 };
338 
339 FIXTURE_SETUP(secbits)
340 {
341 	/* Makes sure no exec bits are set. */
342 	EXPECT_EQ(0, test_secbits_set(0));
343 	EXPECT_EQ(0, prctl(PR_GET_SECUREBITS));
344 
345 	if (!variant->is_privileged)
346 		drop_privileges(_metadata);
347 }
348 
349 FIXTURE_TEARDOWN(secbits)
350 {
351 }
352 
353 TEST_F(secbits, legacy)
354 {
355 	EXPECT_EQ(variant->error, test_secbits_set(0));
356 }
357 
358 #define CHILD(...)                     \
359 	do {                           \
360 		pid_t child = vfork(); \
361 		EXPECT_LE(0, child);   \
362 		if (child == 0) {      \
363 			__VA_ARGS__;   \
364 			_exit(0);      \
365 		}                      \
366 	} while (0)
367 
368 TEST_F(secbits, exec)
369 {
370 	unsigned int secbits = prctl(PR_GET_SECUREBITS);
371 
372 	secbits |= SECBIT_EXEC_RESTRICT_FILE;
373 	EXPECT_EQ(0, test_secbits_set(secbits));
374 	EXPECT_EQ(secbits, prctl(PR_GET_SECUREBITS));
375 	CHILD(EXPECT_EQ(secbits, prctl(PR_GET_SECUREBITS)));
376 
377 	secbits |= SECBIT_EXEC_DENY_INTERACTIVE;
378 	EXPECT_EQ(0, test_secbits_set(secbits));
379 	EXPECT_EQ(secbits, prctl(PR_GET_SECUREBITS));
380 	CHILD(EXPECT_EQ(secbits, prctl(PR_GET_SECUREBITS)));
381 
382 	secbits &= ~(SECBIT_EXEC_RESTRICT_FILE | SECBIT_EXEC_DENY_INTERACTIVE);
383 	EXPECT_EQ(0, test_secbits_set(secbits));
384 	EXPECT_EQ(secbits, prctl(PR_GET_SECUREBITS));
385 	CHILD(EXPECT_EQ(secbits, prctl(PR_GET_SECUREBITS)));
386 }
387 
388 TEST_F(secbits, check_locked_set)
389 {
390 	unsigned int secbits = prctl(PR_GET_SECUREBITS);
391 
392 	secbits |= SECBIT_EXEC_RESTRICT_FILE;
393 	EXPECT_EQ(0, test_secbits_set(secbits));
394 	secbits |= SECBIT_EXEC_RESTRICT_FILE_LOCKED;
395 	EXPECT_EQ(0, test_secbits_set(secbits));
396 
397 	/* Checks lock set but unchanged. */
398 	EXPECT_EQ(variant->error, test_secbits_set(secbits));
399 	CHILD(EXPECT_EQ(variant->error, test_secbits_set(secbits)));
400 
401 	secbits &= ~SECBIT_EXEC_RESTRICT_FILE;
402 	EXPECT_EQ(EPERM, test_secbits_set(0));
403 	CHILD(EXPECT_EQ(EPERM, test_secbits_set(0)));
404 }
405 
406 TEST_F(secbits, check_locked_unset)
407 {
408 	unsigned int secbits = prctl(PR_GET_SECUREBITS);
409 
410 	secbits |= SECBIT_EXEC_RESTRICT_FILE_LOCKED;
411 	EXPECT_EQ(0, test_secbits_set(secbits));
412 
413 	/* Checks lock unset but unchanged. */
414 	EXPECT_EQ(variant->error, test_secbits_set(secbits));
415 	CHILD(EXPECT_EQ(variant->error, test_secbits_set(secbits)));
416 
417 	secbits &= ~SECBIT_EXEC_RESTRICT_FILE;
418 	EXPECT_EQ(EPERM, test_secbits_set(0));
419 	CHILD(EXPECT_EQ(EPERM, test_secbits_set(0)));
420 }
421 
422 TEST_F(secbits, restrict_locked_set)
423 {
424 	unsigned int secbits = prctl(PR_GET_SECUREBITS);
425 
426 	secbits |= SECBIT_EXEC_DENY_INTERACTIVE;
427 	EXPECT_EQ(0, test_secbits_set(secbits));
428 	secbits |= SECBIT_EXEC_DENY_INTERACTIVE_LOCKED;
429 	EXPECT_EQ(0, test_secbits_set(secbits));
430 
431 	/* Checks lock set but unchanged. */
432 	EXPECT_EQ(variant->error, test_secbits_set(secbits));
433 	CHILD(EXPECT_EQ(variant->error, test_secbits_set(secbits)));
434 
435 	secbits &= ~SECBIT_EXEC_DENY_INTERACTIVE;
436 	EXPECT_EQ(EPERM, test_secbits_set(0));
437 	CHILD(EXPECT_EQ(EPERM, test_secbits_set(0)));
438 }
439 
440 TEST_F(secbits, restrict_locked_unset)
441 {
442 	unsigned int secbits = prctl(PR_GET_SECUREBITS);
443 
444 	secbits |= SECBIT_EXEC_DENY_INTERACTIVE_LOCKED;
445 	EXPECT_EQ(0, test_secbits_set(secbits));
446 
447 	/* Checks lock unset but unchanged. */
448 	EXPECT_EQ(variant->error, test_secbits_set(secbits));
449 	CHILD(EXPECT_EQ(variant->error, test_secbits_set(secbits)));
450 
451 	secbits &= ~SECBIT_EXEC_DENY_INTERACTIVE;
452 	EXPECT_EQ(EPERM, test_secbits_set(0));
453 	CHILD(EXPECT_EQ(EPERM, test_secbits_set(0)));
454 }
455 
456 TEST_HARNESS_MAIN
457