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 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 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 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 */ 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 102 FIXTURE_SETUP(scoped_domains) 103 { 104 } 105 106 FIXTURE_TEARDOWN(scoped_domains) 107 { 108 } 109 110 /* Test PTRACE_TRACEME and PTRACE_ATTACH for parent and child. */ 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 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 312 FIXTURE(audit) 313 { 314 struct audit_filter audit_filter; 315 int audit_fd; 316 }; 317 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 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. */ 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