Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
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
28static 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
46static 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
69static 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 */
89FIXTURE(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
102FIXTURE_SETUP(scoped_domains)
103{
104}
105
106FIXTURE_TEARDOWN(scoped_domains)
107{
108}
109
110/* Test PTRACE_TRACEME and PTRACE_ATTACH for parent and child. */
111TEST_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
295static 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
312FIXTURE(audit)
313{
314 struct audit_filter audit_filter;
315 int audit_fd;
316};
317
318FIXTURE_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
327FIXTURE_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. */
333TEST_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
346 yama_ptrace_scope = get_yama_ptrace_scope();
347 ASSERT_LE(0, yama_ptrace_scope);
348
349 if (yama_ptrace_scope > YAMA_SCOPE_DISABLED)
350 TH_LOG("Incomplete tests due to Yama restrictions (scope %d)",
351 yama_ptrace_scope);
352
353 /*
354 * Removes all effective and permitted capabilities to not interfere
355 * with cap_ptrace_access_check() in case of PTRACE_MODE_FSCREDS.
356 */
357 drop_caps(_metadata);
358
359 ASSERT_EQ(0, pipe2(pipe_child, O_CLOEXEC));
360 ASSERT_EQ(0, pipe2(pipe_parent, O_CLOEXEC));
361
362 child = fork();
363 ASSERT_LE(0, child);
364 if (child == 0) {
365 char buf_child;
366
367 ASSERT_EQ(0, close(pipe_parent[1]));
368 ASSERT_EQ(0, close(pipe_child[0]));
369
370 /* Waits for the parent to be in a domain, if any. */
371 ASSERT_EQ(1, read(pipe_parent[0], &buf_child, 1));
372
373 /* Tests child PTRACE_TRACEME. */
374 EXPECT_EQ(-1, ptrace(PTRACE_TRACEME));
375 EXPECT_EQ(EPERM, errno);
376 /* We should see the child process. */
377 EXPECT_EQ(0, matches_log_ptrace(_metadata, self->audit_fd,
378 getpid()));
379
380 EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
381 EXPECT_EQ(0, records.access);
382 /* Checks for a domain creation. */
383 EXPECT_EQ(1, records.domain);
384
385 /*
386 * Signals that the PTRACE_ATTACH test is done and the
387 * PTRACE_TRACEME test is ongoing.
388 */
389 ASSERT_EQ(1, write(pipe_child[1], ".", 1));
390
391 /* Waits for the parent PTRACE_ATTACH test. */
392 ASSERT_EQ(1, read(pipe_parent[0], &buf_child, 1));
393 _exit(_metadata->exit_code);
394 return;
395 }
396
397 ASSERT_EQ(0, close(pipe_child[1]));
398 ASSERT_EQ(0, close(pipe_parent[0]));
399 create_domain(_metadata);
400
401 /* Signals that the parent is in a domain. */
402 ASSERT_EQ(1, write(pipe_parent[1], ".", 1));
403
404 /*
405 * Waits for the child to test PTRACE_ATTACH on the parent and start
406 * testing PTRACE_TRACEME.
407 */
408 ASSERT_EQ(1, read(pipe_child[0], &buf_parent, 1));
409
410 /* The child should not be traced by the parent. */
411 EXPECT_EQ(-1, ptrace(PTRACE_DETACH, child, NULL, 0));
412 EXPECT_EQ(ESRCH, errno);
413
414 /* Tests PTRACE_ATTACH on the child. */
415 EXPECT_EQ(-1, ptrace(PTRACE_ATTACH, child, NULL, 0));
416 EXPECT_EQ(EPERM, errno);
417 EXPECT_EQ(0, matches_log_ptrace(_metadata, self->audit_fd, child));
418
419 /* Signals that the parent PTRACE_ATTACH test is done. */
420 ASSERT_EQ(1, write(pipe_parent[1], ".", 1));
421 ASSERT_EQ(child, waitpid(child, &status, 0));
422 if (WIFSIGNALED(status) || !WIFEXITED(status) ||
423 WEXITSTATUS(status) != EXIT_SUCCESS)
424 _metadata->exit_code = KSFT_FAIL;
425
426 /* Makes sure there is no superfluous logged records. */
427 EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
428 EXPECT_EQ(0, records.access);
429 EXPECT_EQ(0, records.domain);
430}
431
432TEST_HARNESS_MAIN