162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Landlock tests - Ptrace 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright © 2017-2020 Mickaël Salaün <mic@digikod.net> 662306a36Sopenharmony_ci * Copyright © 2019-2020 ANSSI 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#define _GNU_SOURCE 1062306a36Sopenharmony_ci#include <errno.h> 1162306a36Sopenharmony_ci#include <fcntl.h> 1262306a36Sopenharmony_ci#include <linux/landlock.h> 1362306a36Sopenharmony_ci#include <signal.h> 1462306a36Sopenharmony_ci#include <sys/prctl.h> 1562306a36Sopenharmony_ci#include <sys/ptrace.h> 1662306a36Sopenharmony_ci#include <sys/types.h> 1762306a36Sopenharmony_ci#include <sys/wait.h> 1862306a36Sopenharmony_ci#include <unistd.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#include "common.h" 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci/* Copied from security/yama/yama_lsm.c */ 2362306a36Sopenharmony_ci#define YAMA_SCOPE_DISABLED 0 2462306a36Sopenharmony_ci#define YAMA_SCOPE_RELATIONAL 1 2562306a36Sopenharmony_ci#define YAMA_SCOPE_CAPABILITY 2 2662306a36Sopenharmony_ci#define YAMA_SCOPE_NO_ATTACH 3 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistatic void create_domain(struct __test_metadata *const _metadata) 2962306a36Sopenharmony_ci{ 3062306a36Sopenharmony_ci int ruleset_fd; 3162306a36Sopenharmony_ci struct landlock_ruleset_attr ruleset_attr = { 3262306a36Sopenharmony_ci .handled_access_fs = LANDLOCK_ACCESS_FS_MAKE_BLOCK, 3362306a36Sopenharmony_ci }; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci ruleset_fd = 3662306a36Sopenharmony_ci landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0); 3762306a36Sopenharmony_ci EXPECT_LE(0, ruleset_fd) 3862306a36Sopenharmony_ci { 3962306a36Sopenharmony_ci TH_LOG("Failed to create a ruleset: %s", strerror(errno)); 4062306a36Sopenharmony_ci } 4162306a36Sopenharmony_ci EXPECT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)); 4262306a36Sopenharmony_ci EXPECT_EQ(0, landlock_restrict_self(ruleset_fd, 0)); 4362306a36Sopenharmony_ci EXPECT_EQ(0, close(ruleset_fd)); 4462306a36Sopenharmony_ci} 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistatic int test_ptrace_read(const pid_t pid) 4762306a36Sopenharmony_ci{ 4862306a36Sopenharmony_ci static const char path_template[] = "/proc/%d/environ"; 4962306a36Sopenharmony_ci char procenv_path[sizeof(path_template) + 10]; 5062306a36Sopenharmony_ci int procenv_path_size, fd; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci procenv_path_size = snprintf(procenv_path, sizeof(procenv_path), 5362306a36Sopenharmony_ci path_template, pid); 5462306a36Sopenharmony_ci if (procenv_path_size >= sizeof(procenv_path)) 5562306a36Sopenharmony_ci return E2BIG; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci fd = open(procenv_path, O_RDONLY | O_CLOEXEC); 5862306a36Sopenharmony_ci if (fd < 0) 5962306a36Sopenharmony_ci return errno; 6062306a36Sopenharmony_ci /* 6162306a36Sopenharmony_ci * Mixing error codes from close(2) and open(2) should not lead to any 6262306a36Sopenharmony_ci * (access type) confusion for this test. 6362306a36Sopenharmony_ci */ 6462306a36Sopenharmony_ci if (close(fd) != 0) 6562306a36Sopenharmony_ci return errno; 6662306a36Sopenharmony_ci return 0; 6762306a36Sopenharmony_ci} 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_cistatic int get_yama_ptrace_scope(void) 7062306a36Sopenharmony_ci{ 7162306a36Sopenharmony_ci int ret; 7262306a36Sopenharmony_ci char buf[2] = {}; 7362306a36Sopenharmony_ci const int fd = open("/proc/sys/kernel/yama/ptrace_scope", O_RDONLY); 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci if (fd < 0) 7662306a36Sopenharmony_ci return 0; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci if (read(fd, buf, 1) < 0) { 7962306a36Sopenharmony_ci close(fd); 8062306a36Sopenharmony_ci return -1; 8162306a36Sopenharmony_ci } 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci ret = atoi(buf); 8462306a36Sopenharmony_ci close(fd); 8562306a36Sopenharmony_ci return ret; 8662306a36Sopenharmony_ci} 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci/* clang-format off */ 8962306a36Sopenharmony_ciFIXTURE(hierarchy) {}; 9062306a36Sopenharmony_ci/* clang-format on */ 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ciFIXTURE_VARIANT(hierarchy) 9362306a36Sopenharmony_ci{ 9462306a36Sopenharmony_ci const bool domain_both; 9562306a36Sopenharmony_ci const bool domain_parent; 9662306a36Sopenharmony_ci const bool domain_child; 9762306a36Sopenharmony_ci}; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci/* 10062306a36Sopenharmony_ci * Test multiple tracing combinations between a parent process P1 and a child 10162306a36Sopenharmony_ci * process P2. 10262306a36Sopenharmony_ci * 10362306a36Sopenharmony_ci * Yama's scoped ptrace is presumed disabled. If enabled, this optional 10462306a36Sopenharmony_ci * restriction is enforced in addition to any Landlock check, which means that 10562306a36Sopenharmony_ci * all P2 requests to trace P1 would be denied. 10662306a36Sopenharmony_ci */ 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci/* 10962306a36Sopenharmony_ci * No domain 11062306a36Sopenharmony_ci * 11162306a36Sopenharmony_ci * P1-. P1 -> P2 : allow 11262306a36Sopenharmony_ci * \ P2 -> P1 : allow 11362306a36Sopenharmony_ci * 'P2 11462306a36Sopenharmony_ci */ 11562306a36Sopenharmony_ci/* clang-format off */ 11662306a36Sopenharmony_ciFIXTURE_VARIANT_ADD(hierarchy, allow_without_domain) { 11762306a36Sopenharmony_ci /* clang-format on */ 11862306a36Sopenharmony_ci .domain_both = false, 11962306a36Sopenharmony_ci .domain_parent = false, 12062306a36Sopenharmony_ci .domain_child = false, 12162306a36Sopenharmony_ci}; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci/* 12462306a36Sopenharmony_ci * Child domain 12562306a36Sopenharmony_ci * 12662306a36Sopenharmony_ci * P1--. P1 -> P2 : allow 12762306a36Sopenharmony_ci * \ P2 -> P1 : deny 12862306a36Sopenharmony_ci * .'-----. 12962306a36Sopenharmony_ci * | P2 | 13062306a36Sopenharmony_ci * '------' 13162306a36Sopenharmony_ci */ 13262306a36Sopenharmony_ci/* clang-format off */ 13362306a36Sopenharmony_ciFIXTURE_VARIANT_ADD(hierarchy, allow_with_one_domain) { 13462306a36Sopenharmony_ci /* clang-format on */ 13562306a36Sopenharmony_ci .domain_both = false, 13662306a36Sopenharmony_ci .domain_parent = false, 13762306a36Sopenharmony_ci .domain_child = true, 13862306a36Sopenharmony_ci}; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci/* 14162306a36Sopenharmony_ci * Parent domain 14262306a36Sopenharmony_ci * .------. 14362306a36Sopenharmony_ci * | P1 --. P1 -> P2 : deny 14462306a36Sopenharmony_ci * '------' \ P2 -> P1 : allow 14562306a36Sopenharmony_ci * ' 14662306a36Sopenharmony_ci * P2 14762306a36Sopenharmony_ci */ 14862306a36Sopenharmony_ci/* clang-format off */ 14962306a36Sopenharmony_ciFIXTURE_VARIANT_ADD(hierarchy, deny_with_parent_domain) { 15062306a36Sopenharmony_ci /* clang-format on */ 15162306a36Sopenharmony_ci .domain_both = false, 15262306a36Sopenharmony_ci .domain_parent = true, 15362306a36Sopenharmony_ci .domain_child = false, 15462306a36Sopenharmony_ci}; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci/* 15762306a36Sopenharmony_ci * Parent + child domain (siblings) 15862306a36Sopenharmony_ci * .------. 15962306a36Sopenharmony_ci * | P1 ---. P1 -> P2 : deny 16062306a36Sopenharmony_ci * '------' \ P2 -> P1 : deny 16162306a36Sopenharmony_ci * .---'--. 16262306a36Sopenharmony_ci * | P2 | 16362306a36Sopenharmony_ci * '------' 16462306a36Sopenharmony_ci */ 16562306a36Sopenharmony_ci/* clang-format off */ 16662306a36Sopenharmony_ciFIXTURE_VARIANT_ADD(hierarchy, deny_with_sibling_domain) { 16762306a36Sopenharmony_ci /* clang-format on */ 16862306a36Sopenharmony_ci .domain_both = false, 16962306a36Sopenharmony_ci .domain_parent = true, 17062306a36Sopenharmony_ci .domain_child = true, 17162306a36Sopenharmony_ci}; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci/* 17462306a36Sopenharmony_ci * Same domain (inherited) 17562306a36Sopenharmony_ci * .-------------. 17662306a36Sopenharmony_ci * | P1----. | P1 -> P2 : allow 17762306a36Sopenharmony_ci * | \ | P2 -> P1 : allow 17862306a36Sopenharmony_ci * | ' | 17962306a36Sopenharmony_ci * | P2 | 18062306a36Sopenharmony_ci * '-------------' 18162306a36Sopenharmony_ci */ 18262306a36Sopenharmony_ci/* clang-format off */ 18362306a36Sopenharmony_ciFIXTURE_VARIANT_ADD(hierarchy, allow_sibling_domain) { 18462306a36Sopenharmony_ci /* clang-format on */ 18562306a36Sopenharmony_ci .domain_both = true, 18662306a36Sopenharmony_ci .domain_parent = false, 18762306a36Sopenharmony_ci .domain_child = false, 18862306a36Sopenharmony_ci}; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci/* 19162306a36Sopenharmony_ci * Inherited + child domain 19262306a36Sopenharmony_ci * .-----------------. 19362306a36Sopenharmony_ci * | P1----. | P1 -> P2 : allow 19462306a36Sopenharmony_ci * | \ | P2 -> P1 : deny 19562306a36Sopenharmony_ci * | .-'----. | 19662306a36Sopenharmony_ci * | | P2 | | 19762306a36Sopenharmony_ci * | '------' | 19862306a36Sopenharmony_ci * '-----------------' 19962306a36Sopenharmony_ci */ 20062306a36Sopenharmony_ci/* clang-format off */ 20162306a36Sopenharmony_ciFIXTURE_VARIANT_ADD(hierarchy, allow_with_nested_domain) { 20262306a36Sopenharmony_ci /* clang-format on */ 20362306a36Sopenharmony_ci .domain_both = true, 20462306a36Sopenharmony_ci .domain_parent = false, 20562306a36Sopenharmony_ci .domain_child = true, 20662306a36Sopenharmony_ci}; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci/* 20962306a36Sopenharmony_ci * Inherited + parent domain 21062306a36Sopenharmony_ci * .-----------------. 21162306a36Sopenharmony_ci * |.------. | P1 -> P2 : deny 21262306a36Sopenharmony_ci * || P1 ----. | P2 -> P1 : allow 21362306a36Sopenharmony_ci * |'------' \ | 21462306a36Sopenharmony_ci * | ' | 21562306a36Sopenharmony_ci * | P2 | 21662306a36Sopenharmony_ci * '-----------------' 21762306a36Sopenharmony_ci */ 21862306a36Sopenharmony_ci/* clang-format off */ 21962306a36Sopenharmony_ciFIXTURE_VARIANT_ADD(hierarchy, deny_with_nested_and_parent_domain) { 22062306a36Sopenharmony_ci /* clang-format on */ 22162306a36Sopenharmony_ci .domain_both = true, 22262306a36Sopenharmony_ci .domain_parent = true, 22362306a36Sopenharmony_ci .domain_child = false, 22462306a36Sopenharmony_ci}; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci/* 22762306a36Sopenharmony_ci * Inherited + parent and child domain (siblings) 22862306a36Sopenharmony_ci * .-----------------. 22962306a36Sopenharmony_ci * | .------. | P1 -> P2 : deny 23062306a36Sopenharmony_ci * | | P1 . | P2 -> P1 : deny 23162306a36Sopenharmony_ci * | '------'\ | 23262306a36Sopenharmony_ci * | \ | 23362306a36Sopenharmony_ci * | .--'---. | 23462306a36Sopenharmony_ci * | | P2 | | 23562306a36Sopenharmony_ci * | '------' | 23662306a36Sopenharmony_ci * '-----------------' 23762306a36Sopenharmony_ci */ 23862306a36Sopenharmony_ci/* clang-format off */ 23962306a36Sopenharmony_ciFIXTURE_VARIANT_ADD(hierarchy, deny_with_forked_domain) { 24062306a36Sopenharmony_ci /* clang-format on */ 24162306a36Sopenharmony_ci .domain_both = true, 24262306a36Sopenharmony_ci .domain_parent = true, 24362306a36Sopenharmony_ci .domain_child = true, 24462306a36Sopenharmony_ci}; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ciFIXTURE_SETUP(hierarchy) 24762306a36Sopenharmony_ci{ 24862306a36Sopenharmony_ci} 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ciFIXTURE_TEARDOWN(hierarchy) 25162306a36Sopenharmony_ci{ 25262306a36Sopenharmony_ci} 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci/* Test PTRACE_TRACEME and PTRACE_ATTACH for parent and child. */ 25562306a36Sopenharmony_ciTEST_F(hierarchy, trace) 25662306a36Sopenharmony_ci{ 25762306a36Sopenharmony_ci pid_t child, parent; 25862306a36Sopenharmony_ci int status, err_proc_read; 25962306a36Sopenharmony_ci int pipe_child[2], pipe_parent[2]; 26062306a36Sopenharmony_ci int yama_ptrace_scope; 26162306a36Sopenharmony_ci char buf_parent; 26262306a36Sopenharmony_ci long ret; 26362306a36Sopenharmony_ci bool can_read_child, can_trace_child, can_read_parent, can_trace_parent; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci yama_ptrace_scope = get_yama_ptrace_scope(); 26662306a36Sopenharmony_ci ASSERT_LE(0, yama_ptrace_scope); 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci if (yama_ptrace_scope > YAMA_SCOPE_DISABLED) 26962306a36Sopenharmony_ci TH_LOG("Incomplete tests due to Yama restrictions (scope %d)", 27062306a36Sopenharmony_ci yama_ptrace_scope); 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci /* 27362306a36Sopenharmony_ci * can_read_child is true if a parent process can read its child 27462306a36Sopenharmony_ci * process, which is only the case when the parent process is not 27562306a36Sopenharmony_ci * isolated from the child with a dedicated Landlock domain. 27662306a36Sopenharmony_ci */ 27762306a36Sopenharmony_ci can_read_child = !variant->domain_parent; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci /* 28062306a36Sopenharmony_ci * can_trace_child is true if a parent process can trace its child 28162306a36Sopenharmony_ci * process. This depends on two conditions: 28262306a36Sopenharmony_ci * - The parent process is not isolated from the child with a dedicated 28362306a36Sopenharmony_ci * Landlock domain. 28462306a36Sopenharmony_ci * - Yama allows tracing children (up to YAMA_SCOPE_RELATIONAL). 28562306a36Sopenharmony_ci */ 28662306a36Sopenharmony_ci can_trace_child = can_read_child && 28762306a36Sopenharmony_ci yama_ptrace_scope <= YAMA_SCOPE_RELATIONAL; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci /* 29062306a36Sopenharmony_ci * can_read_parent is true if a child process can read its parent 29162306a36Sopenharmony_ci * process, which is only the case when the child process is not 29262306a36Sopenharmony_ci * isolated from the parent with a dedicated Landlock domain. 29362306a36Sopenharmony_ci */ 29462306a36Sopenharmony_ci can_read_parent = !variant->domain_child; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci /* 29762306a36Sopenharmony_ci * can_trace_parent is true if a child process can trace its parent 29862306a36Sopenharmony_ci * process. This depends on two conditions: 29962306a36Sopenharmony_ci * - The child process is not isolated from the parent with a dedicated 30062306a36Sopenharmony_ci * Landlock domain. 30162306a36Sopenharmony_ci * - Yama is disabled (YAMA_SCOPE_DISABLED). 30262306a36Sopenharmony_ci */ 30362306a36Sopenharmony_ci can_trace_parent = can_read_parent && 30462306a36Sopenharmony_ci yama_ptrace_scope <= YAMA_SCOPE_DISABLED; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci /* 30762306a36Sopenharmony_ci * Removes all effective and permitted capabilities to not interfere 30862306a36Sopenharmony_ci * with cap_ptrace_access_check() in case of PTRACE_MODE_FSCREDS. 30962306a36Sopenharmony_ci */ 31062306a36Sopenharmony_ci drop_caps(_metadata); 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci parent = getpid(); 31362306a36Sopenharmony_ci ASSERT_EQ(0, pipe2(pipe_child, O_CLOEXEC)); 31462306a36Sopenharmony_ci ASSERT_EQ(0, pipe2(pipe_parent, O_CLOEXEC)); 31562306a36Sopenharmony_ci if (variant->domain_both) { 31662306a36Sopenharmony_ci create_domain(_metadata); 31762306a36Sopenharmony_ci if (!_metadata->passed) 31862306a36Sopenharmony_ci /* Aborts before forking. */ 31962306a36Sopenharmony_ci return; 32062306a36Sopenharmony_ci } 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci child = fork(); 32362306a36Sopenharmony_ci ASSERT_LE(0, child); 32462306a36Sopenharmony_ci if (child == 0) { 32562306a36Sopenharmony_ci char buf_child; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci ASSERT_EQ(0, close(pipe_parent[1])); 32862306a36Sopenharmony_ci ASSERT_EQ(0, close(pipe_child[0])); 32962306a36Sopenharmony_ci if (variant->domain_child) 33062306a36Sopenharmony_ci create_domain(_metadata); 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci /* Waits for the parent to be in a domain, if any. */ 33362306a36Sopenharmony_ci ASSERT_EQ(1, read(pipe_parent[0], &buf_child, 1)); 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci /* Tests PTRACE_MODE_READ on the parent. */ 33662306a36Sopenharmony_ci err_proc_read = test_ptrace_read(parent); 33762306a36Sopenharmony_ci if (can_read_parent) { 33862306a36Sopenharmony_ci EXPECT_EQ(0, err_proc_read); 33962306a36Sopenharmony_ci } else { 34062306a36Sopenharmony_ci EXPECT_EQ(EACCES, err_proc_read); 34162306a36Sopenharmony_ci } 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci /* Tests PTRACE_ATTACH on the parent. */ 34462306a36Sopenharmony_ci ret = ptrace(PTRACE_ATTACH, parent, NULL, 0); 34562306a36Sopenharmony_ci if (can_trace_parent) { 34662306a36Sopenharmony_ci EXPECT_EQ(0, ret); 34762306a36Sopenharmony_ci } else { 34862306a36Sopenharmony_ci EXPECT_EQ(-1, ret); 34962306a36Sopenharmony_ci EXPECT_EQ(EPERM, errno); 35062306a36Sopenharmony_ci } 35162306a36Sopenharmony_ci if (ret == 0) { 35262306a36Sopenharmony_ci ASSERT_EQ(parent, waitpid(parent, &status, 0)); 35362306a36Sopenharmony_ci ASSERT_EQ(1, WIFSTOPPED(status)); 35462306a36Sopenharmony_ci ASSERT_EQ(0, ptrace(PTRACE_DETACH, parent, NULL, 0)); 35562306a36Sopenharmony_ci } 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci /* Tests child PTRACE_TRACEME. */ 35862306a36Sopenharmony_ci ret = ptrace(PTRACE_TRACEME); 35962306a36Sopenharmony_ci if (can_trace_child) { 36062306a36Sopenharmony_ci EXPECT_EQ(0, ret); 36162306a36Sopenharmony_ci } else { 36262306a36Sopenharmony_ci EXPECT_EQ(-1, ret); 36362306a36Sopenharmony_ci EXPECT_EQ(EPERM, errno); 36462306a36Sopenharmony_ci } 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci /* 36762306a36Sopenharmony_ci * Signals that the PTRACE_ATTACH test is done and the 36862306a36Sopenharmony_ci * PTRACE_TRACEME test is ongoing. 36962306a36Sopenharmony_ci */ 37062306a36Sopenharmony_ci ASSERT_EQ(1, write(pipe_child[1], ".", 1)); 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci if (can_trace_child) { 37362306a36Sopenharmony_ci ASSERT_EQ(0, raise(SIGSTOP)); 37462306a36Sopenharmony_ci } 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci /* Waits for the parent PTRACE_ATTACH test. */ 37762306a36Sopenharmony_ci ASSERT_EQ(1, read(pipe_parent[0], &buf_child, 1)); 37862306a36Sopenharmony_ci _exit(_metadata->passed ? EXIT_SUCCESS : EXIT_FAILURE); 37962306a36Sopenharmony_ci return; 38062306a36Sopenharmony_ci } 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci ASSERT_EQ(0, close(pipe_child[1])); 38362306a36Sopenharmony_ci ASSERT_EQ(0, close(pipe_parent[0])); 38462306a36Sopenharmony_ci if (variant->domain_parent) 38562306a36Sopenharmony_ci create_domain(_metadata); 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci /* Signals that the parent is in a domain, if any. */ 38862306a36Sopenharmony_ci ASSERT_EQ(1, write(pipe_parent[1], ".", 1)); 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci /* 39162306a36Sopenharmony_ci * Waits for the child to test PTRACE_ATTACH on the parent and start 39262306a36Sopenharmony_ci * testing PTRACE_TRACEME. 39362306a36Sopenharmony_ci */ 39462306a36Sopenharmony_ci ASSERT_EQ(1, read(pipe_child[0], &buf_parent, 1)); 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci /* Tests child PTRACE_TRACEME. */ 39762306a36Sopenharmony_ci if (can_trace_child) { 39862306a36Sopenharmony_ci ASSERT_EQ(child, waitpid(child, &status, 0)); 39962306a36Sopenharmony_ci ASSERT_EQ(1, WIFSTOPPED(status)); 40062306a36Sopenharmony_ci ASSERT_EQ(0, ptrace(PTRACE_DETACH, child, NULL, 0)); 40162306a36Sopenharmony_ci } else { 40262306a36Sopenharmony_ci /* The child should not be traced by the parent. */ 40362306a36Sopenharmony_ci EXPECT_EQ(-1, ptrace(PTRACE_DETACH, child, NULL, 0)); 40462306a36Sopenharmony_ci EXPECT_EQ(ESRCH, errno); 40562306a36Sopenharmony_ci } 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci /* Tests PTRACE_MODE_READ on the child. */ 40862306a36Sopenharmony_ci err_proc_read = test_ptrace_read(child); 40962306a36Sopenharmony_ci if (can_read_child) { 41062306a36Sopenharmony_ci EXPECT_EQ(0, err_proc_read); 41162306a36Sopenharmony_ci } else { 41262306a36Sopenharmony_ci EXPECT_EQ(EACCES, err_proc_read); 41362306a36Sopenharmony_ci } 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci /* Tests PTRACE_ATTACH on the child. */ 41662306a36Sopenharmony_ci ret = ptrace(PTRACE_ATTACH, child, NULL, 0); 41762306a36Sopenharmony_ci if (can_trace_child) { 41862306a36Sopenharmony_ci EXPECT_EQ(0, ret); 41962306a36Sopenharmony_ci } else { 42062306a36Sopenharmony_ci EXPECT_EQ(-1, ret); 42162306a36Sopenharmony_ci EXPECT_EQ(EPERM, errno); 42262306a36Sopenharmony_ci } 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci if (ret == 0) { 42562306a36Sopenharmony_ci ASSERT_EQ(child, waitpid(child, &status, 0)); 42662306a36Sopenharmony_ci ASSERT_EQ(1, WIFSTOPPED(status)); 42762306a36Sopenharmony_ci ASSERT_EQ(0, ptrace(PTRACE_DETACH, child, NULL, 0)); 42862306a36Sopenharmony_ci } 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci /* Signals that the parent PTRACE_ATTACH test is done. */ 43162306a36Sopenharmony_ci ASSERT_EQ(1, write(pipe_parent[1], ".", 1)); 43262306a36Sopenharmony_ci ASSERT_EQ(child, waitpid(child, &status, 0)); 43362306a36Sopenharmony_ci if (WIFSIGNALED(status) || !WIFEXITED(status) || 43462306a36Sopenharmony_ci WEXITSTATUS(status) != EXIT_SUCCESS) 43562306a36Sopenharmony_ci _metadata->passed = 0; 43662306a36Sopenharmony_ci} 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ciTEST_HARNESS_MAIN 439