xref: /linux/tools/testing/selftests/landlock/ptrace_test.c (revision 90a855e75a99f2932b19f4d04bac1edef158d95e)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Landlock tests - Ptrace
4  *
5  * Copyright © 2017-2020 Mickaël Salaün <mic@digikod.net>
6  * Copyright © 2019-2020 ANSSI
7  * Copyright © 2024-2025 Microsoft Corporation
8  */
9 
10 #define _GNU_SOURCE
11 #include <errno.h>
12 #include <fcntl.h>
13 #include <linux/landlock.h>
14 #include <signal.h>
15 #include <sys/prctl.h>
16 #include <sys/ptrace.h>
17 #include <sys/types.h>
18 #include <sys/wait.h>
19 #include <unistd.h>
20 
21 #include "audit.h"
22 #include "common.h"
23 
24 /* Copied from security/yama/yama_lsm.c */
25 #define YAMA_SCOPE_DISABLED 0
26 #define YAMA_SCOPE_RELATIONAL 1
27 
create_domain(struct __test_metadata * const _metadata)28 static void create_domain(struct __test_metadata *const _metadata)
29 {
30 	int ruleset_fd;
31 	struct landlock_ruleset_attr ruleset_attr = {
32 		.handled_access_fs = LANDLOCK_ACCESS_FS_MAKE_BLOCK,
33 	};
34 
35 	ruleset_fd =
36 		landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
37 	EXPECT_LE(0, ruleset_fd)
38 	{
39 		TH_LOG("Failed to create a ruleset: %s", strerror(errno));
40 	}
41 	EXPECT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0));
42 	EXPECT_EQ(0, landlock_restrict_self(ruleset_fd, 0));
43 	EXPECT_EQ(0, close(ruleset_fd));
44 }
45 
test_ptrace_read(const pid_t pid)46 static int test_ptrace_read(const pid_t pid)
47 {
48 	static const char path_template[] = "/proc/%d/environ";
49 	char procenv_path[sizeof(path_template) + 10];
50 	int procenv_path_size, fd;
51 
52 	procenv_path_size = snprintf(procenv_path, sizeof(procenv_path),
53 				     path_template, pid);
54 	if (procenv_path_size >= sizeof(procenv_path))
55 		return E2BIG;
56 
57 	fd = open(procenv_path, O_RDONLY | O_CLOEXEC);
58 	if (fd < 0)
59 		return errno;
60 	/*
61 	 * Mixing error codes from close(2) and open(2) should not lead to any
62 	 * (access type) confusion for this test.
63 	 */
64 	if (close(fd) != 0)
65 		return errno;
66 	return 0;
67 }
68 
get_yama_ptrace_scope(void)69 static int get_yama_ptrace_scope(void)
70 {
71 	int ret;
72 	char buf[2] = {};
73 	const int fd = open("/proc/sys/kernel/yama/ptrace_scope", O_RDONLY);
74 
75 	if (fd < 0)
76 		return 0;
77 
78 	if (read(fd, buf, 1) < 0) {
79 		close(fd);
80 		return -1;
81 	}
82 
83 	ret = atoi(buf);
84 	close(fd);
85 	return ret;
86 }
87 
88 /* clang-format off */
FIXTURE(scoped_domains)89 FIXTURE(scoped_domains) {};
90 /* clang-format on */
91 
92 /*
93  * Test multiple tracing combinations between a parent process P1 and a child
94  * process P2.
95  *
96  * Yama's scoped ptrace is presumed disabled.  If enabled, this optional
97  * restriction is enforced in addition to any Landlock check, which means that
98  * all P2 requests to trace P1 would be denied.
99  */
100 #include "scoped_base_variants.h"
101 
FIXTURE_SETUP(scoped_domains)102 FIXTURE_SETUP(scoped_domains)
103 {
104 }
105 
FIXTURE_TEARDOWN(scoped_domains)106 FIXTURE_TEARDOWN(scoped_domains)
107 {
108 }
109 
110 /* Test PTRACE_TRACEME and PTRACE_ATTACH for parent and child. */
TEST_F(scoped_domains,trace)111 TEST_F(scoped_domains, trace)
112 {
113 	pid_t child, parent;
114 	int status, err_proc_read;
115 	int pipe_child[2], pipe_parent[2];
116 	int yama_ptrace_scope;
117 	char buf_parent;
118 	long ret;
119 	bool can_read_child, can_trace_child, can_read_parent, can_trace_parent;
120 
121 	yama_ptrace_scope = get_yama_ptrace_scope();
122 	ASSERT_LE(0, yama_ptrace_scope);
123 
124 	if (yama_ptrace_scope > YAMA_SCOPE_DISABLED)
125 		TH_LOG("Incomplete tests due to Yama restrictions (scope %d)",
126 		       yama_ptrace_scope);
127 
128 	/*
129 	 * can_read_child is true if a parent process can read its child
130 	 * process, which is only the case when the parent process is not
131 	 * isolated from the child with a dedicated Landlock domain.
132 	 */
133 	can_read_child = !variant->domain_parent;
134 
135 	/*
136 	 * can_trace_child is true if a parent process can trace its child
137 	 * process.  This depends on two conditions:
138 	 * - The parent process is not isolated from the child with a dedicated
139 	 *   Landlock domain.
140 	 * - Yama allows tracing children (up to YAMA_SCOPE_RELATIONAL).
141 	 */
142 	can_trace_child = can_read_child &&
143 			  yama_ptrace_scope <= YAMA_SCOPE_RELATIONAL;
144 
145 	/*
146 	 * can_read_parent is true if a child process can read its parent
147 	 * process, which is only the case when the child process is not
148 	 * isolated from the parent with a dedicated Landlock domain.
149 	 */
150 	can_read_parent = !variant->domain_child;
151 
152 	/*
153 	 * can_trace_parent is true if a child process can trace its parent
154 	 * process.  This depends on two conditions:
155 	 * - The child process is not isolated from the parent with a dedicated
156 	 *   Landlock domain.
157 	 * - Yama is disabled (YAMA_SCOPE_DISABLED).
158 	 */
159 	can_trace_parent = can_read_parent &&
160 			   yama_ptrace_scope <= YAMA_SCOPE_DISABLED;
161 
162 	/*
163 	 * Removes all effective and permitted capabilities to not interfere
164 	 * with cap_ptrace_access_check() in case of PTRACE_MODE_FSCREDS.
165 	 */
166 	drop_caps(_metadata);
167 
168 	parent = getpid();
169 	ASSERT_EQ(0, pipe2(pipe_child, O_CLOEXEC));
170 	ASSERT_EQ(0, pipe2(pipe_parent, O_CLOEXEC));
171 	if (variant->domain_both) {
172 		create_domain(_metadata);
173 		if (!__test_passed(_metadata))
174 			/* Aborts before forking. */
175 			return;
176 	}
177 
178 	child = fork();
179 	ASSERT_LE(0, child);
180 	if (child == 0) {
181 		char buf_child;
182 
183 		ASSERT_EQ(0, close(pipe_parent[1]));
184 		ASSERT_EQ(0, close(pipe_child[0]));
185 		if (variant->domain_child)
186 			create_domain(_metadata);
187 
188 		/* Waits for the parent to be in a domain, if any. */
189 		ASSERT_EQ(1, read(pipe_parent[0], &buf_child, 1));
190 
191 		/* Tests PTRACE_MODE_READ on the parent. */
192 		err_proc_read = test_ptrace_read(parent);
193 		if (can_read_parent) {
194 			EXPECT_EQ(0, err_proc_read);
195 		} else {
196 			EXPECT_EQ(EACCES, err_proc_read);
197 		}
198 
199 		/* Tests PTRACE_ATTACH on the parent. */
200 		ret = ptrace(PTRACE_ATTACH, parent, NULL, 0);
201 		if (can_trace_parent) {
202 			EXPECT_EQ(0, ret);
203 		} else {
204 			EXPECT_EQ(-1, ret);
205 			EXPECT_EQ(EPERM, errno);
206 		}
207 		if (ret == 0) {
208 			ASSERT_EQ(parent, waitpid(parent, &status, 0));
209 			ASSERT_EQ(1, WIFSTOPPED(status));
210 			ASSERT_EQ(0, ptrace(PTRACE_DETACH, parent, NULL, 0));
211 		}
212 
213 		/* Tests child PTRACE_TRACEME. */
214 		ret = ptrace(PTRACE_TRACEME);
215 		if (can_trace_child) {
216 			EXPECT_EQ(0, ret);
217 		} else {
218 			EXPECT_EQ(-1, ret);
219 			EXPECT_EQ(EPERM, errno);
220 		}
221 
222 		/*
223 		 * Signals that the PTRACE_ATTACH test is done and the
224 		 * PTRACE_TRACEME test is ongoing.
225 		 */
226 		ASSERT_EQ(1, write(pipe_child[1], ".", 1));
227 
228 		if (can_trace_child) {
229 			ASSERT_EQ(0, raise(SIGSTOP));
230 		}
231 
232 		/* Waits for the parent PTRACE_ATTACH test. */
233 		ASSERT_EQ(1, read(pipe_parent[0], &buf_child, 1));
234 		_exit(_metadata->exit_code);
235 		return;
236 	}
237 
238 	ASSERT_EQ(0, close(pipe_child[1]));
239 	ASSERT_EQ(0, close(pipe_parent[0]));
240 	if (variant->domain_parent)
241 		create_domain(_metadata);
242 
243 	/* Signals that the parent is in a domain, if any. */
244 	ASSERT_EQ(1, write(pipe_parent[1], ".", 1));
245 
246 	/*
247 	 * Waits for the child to test PTRACE_ATTACH on the parent and start
248 	 * testing PTRACE_TRACEME.
249 	 */
250 	ASSERT_EQ(1, read(pipe_child[0], &buf_parent, 1));
251 
252 	/* Tests child PTRACE_TRACEME. */
253 	if (can_trace_child) {
254 		ASSERT_EQ(child, waitpid(child, &status, 0));
255 		ASSERT_EQ(1, WIFSTOPPED(status));
256 		ASSERT_EQ(0, ptrace(PTRACE_DETACH, child, NULL, 0));
257 	} else {
258 		/* The child should not be traced by the parent. */
259 		EXPECT_EQ(-1, ptrace(PTRACE_DETACH, child, NULL, 0));
260 		EXPECT_EQ(ESRCH, errno);
261 	}
262 
263 	/* Tests PTRACE_MODE_READ on the child. */
264 	err_proc_read = test_ptrace_read(child);
265 	if (can_read_child) {
266 		EXPECT_EQ(0, err_proc_read);
267 	} else {
268 		EXPECT_EQ(EACCES, err_proc_read);
269 	}
270 
271 	/* Tests PTRACE_ATTACH on the child. */
272 	ret = ptrace(PTRACE_ATTACH, child, NULL, 0);
273 	if (can_trace_child) {
274 		EXPECT_EQ(0, ret);
275 	} else {
276 		EXPECT_EQ(-1, ret);
277 		EXPECT_EQ(EPERM, errno);
278 	}
279 
280 	if (ret == 0) {
281 		ASSERT_EQ(child, waitpid(child, &status, 0));
282 		ASSERT_EQ(1, WIFSTOPPED(status));
283 		ASSERT_EQ(0, ptrace(PTRACE_DETACH, child, NULL, 0));
284 	}
285 
286 	/* Signals that the parent PTRACE_ATTACH test is done. */
287 	ASSERT_EQ(1, write(pipe_parent[1], ".", 1));
288 	ASSERT_EQ(child, waitpid(child, &status, 0));
289 
290 	if (WIFSIGNALED(status) || !WIFEXITED(status) ||
291 	    WEXITSTATUS(status) != EXIT_SUCCESS)
292 		_metadata->exit_code = KSFT_FAIL;
293 }
294 
matches_log_ptrace(struct __test_metadata * const _metadata,int audit_fd,const pid_t opid)295 static int matches_log_ptrace(struct __test_metadata *const _metadata,
296 			      int audit_fd, const pid_t opid)
297 {
298 	static const char log_template[] = REGEX_LANDLOCK_PREFIX
299 		" blockers=ptrace opid=%d ocomm=\"ptrace_test\"$";
300 	char log_match[sizeof(log_template) + 10];
301 	int log_match_len;
302 
303 	log_match_len =
304 		snprintf(log_match, sizeof(log_match), log_template, opid);
305 	if (log_match_len > sizeof(log_match))
306 		return -E2BIG;
307 
308 	return audit_match_record(audit_fd, AUDIT_LANDLOCK_ACCESS, log_match,
309 				  NULL);
310 }
311 
FIXTURE(audit)312 FIXTURE(audit)
313 {
314 	struct audit_filter audit_filter;
315 	int audit_fd;
316 };
317 
FIXTURE_SETUP(audit)318 FIXTURE_SETUP(audit)
319 {
320 	disable_caps(_metadata);
321 	set_cap(_metadata, CAP_AUDIT_CONTROL);
322 	self->audit_fd = audit_init_with_exe_filter(&self->audit_filter);
323 	EXPECT_LE(0, self->audit_fd);
324 	clear_cap(_metadata, CAP_AUDIT_CONTROL);
325 }
326 
FIXTURE_TEARDOWN_PARENT(audit)327 FIXTURE_TEARDOWN_PARENT(audit)
328 {
329 	EXPECT_EQ(0, audit_cleanup(-1, NULL));
330 }
331 
332 /* Test PTRACE_TRACEME and PTRACE_ATTACH for parent and child. */
TEST_F(audit,trace)333 TEST_F(audit, trace)
334 {
335 	pid_t child;
336 	int status;
337 	int pipe_child[2], pipe_parent[2];
338 	int yama_ptrace_scope;
339 	char buf_parent;
340 	struct audit_records records;
341 
342 	/* Makes sure there is no superfluous logged records. */
343 	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
344 	EXPECT_EQ(0, records.access);
345 	EXPECT_EQ(0, records.domain);
346 
347 	yama_ptrace_scope = get_yama_ptrace_scope();
348 	ASSERT_LE(0, yama_ptrace_scope);
349 
350 	if (yama_ptrace_scope > YAMA_SCOPE_DISABLED)
351 		TH_LOG("Incomplete tests due to Yama restrictions (scope %d)",
352 		       yama_ptrace_scope);
353 
354 	/*
355 	 * Removes all effective and permitted capabilities to not interfere
356 	 * with cap_ptrace_access_check() in case of PTRACE_MODE_FSCREDS.
357 	 */
358 	drop_caps(_metadata);
359 
360 	ASSERT_EQ(0, pipe2(pipe_child, O_CLOEXEC));
361 	ASSERT_EQ(0, pipe2(pipe_parent, O_CLOEXEC));
362 
363 	child = fork();
364 	ASSERT_LE(0, child);
365 	if (child == 0) {
366 		char buf_child;
367 
368 		ASSERT_EQ(0, close(pipe_parent[1]));
369 		ASSERT_EQ(0, close(pipe_child[0]));
370 
371 		/* Waits for the parent to be in a domain, if any. */
372 		ASSERT_EQ(1, read(pipe_parent[0], &buf_child, 1));
373 
374 		/* Tests child PTRACE_TRACEME. */
375 		EXPECT_EQ(-1, ptrace(PTRACE_TRACEME));
376 		EXPECT_EQ(EPERM, errno);
377 		/* We should see the child process. */
378 		EXPECT_EQ(0, matches_log_ptrace(_metadata, self->audit_fd,
379 						getpid()));
380 
381 		EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
382 		EXPECT_EQ(0, records.access);
383 		/* Checks for a domain creation. */
384 		EXPECT_EQ(1, records.domain);
385 
386 		/*
387 		 * Signals that the PTRACE_ATTACH test is done and the
388 		 * PTRACE_TRACEME test is ongoing.
389 		 */
390 		ASSERT_EQ(1, write(pipe_child[1], ".", 1));
391 
392 		/* Waits for the parent PTRACE_ATTACH test. */
393 		ASSERT_EQ(1, read(pipe_parent[0], &buf_child, 1));
394 		_exit(_metadata->exit_code);
395 		return;
396 	}
397 
398 	ASSERT_EQ(0, close(pipe_child[1]));
399 	ASSERT_EQ(0, close(pipe_parent[0]));
400 	create_domain(_metadata);
401 
402 	/* Signals that the parent is in a domain. */
403 	ASSERT_EQ(1, write(pipe_parent[1], ".", 1));
404 
405 	/*
406 	 * Waits for the child to test PTRACE_ATTACH on the parent and start
407 	 * testing PTRACE_TRACEME.
408 	 */
409 	ASSERT_EQ(1, read(pipe_child[0], &buf_parent, 1));
410 
411 	/* The child should not be traced by the parent. */
412 	EXPECT_EQ(-1, ptrace(PTRACE_DETACH, child, NULL, 0));
413 	EXPECT_EQ(ESRCH, errno);
414 
415 	/* Tests PTRACE_ATTACH on the child. */
416 	EXPECT_EQ(-1, ptrace(PTRACE_ATTACH, child, NULL, 0));
417 	EXPECT_EQ(EPERM, errno);
418 	EXPECT_EQ(0, matches_log_ptrace(_metadata, self->audit_fd, child));
419 
420 	/* Signals that the parent PTRACE_ATTACH test is done. */
421 	ASSERT_EQ(1, write(pipe_parent[1], ".", 1));
422 	ASSERT_EQ(child, waitpid(child, &status, 0));
423 	if (WIFSIGNALED(status) || !WIFEXITED(status) ||
424 	    WEXITSTATUS(status) != EXIT_SUCCESS)
425 		_metadata->exit_code = KSFT_FAIL;
426 
427 	/* Makes sure there is no superfluous logged records. */
428 	EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
429 	EXPECT_EQ(0, records.access);
430 	EXPECT_EQ(0, records.domain);
431 }
432 
433 TEST_HARNESS_MAIN
434