This is a note to let you know that I've just added the patch titled selftests/landlock: Test ptrace as much as possible with Yama to the 6.2-stable tree which can be found at: http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary The filename of the patch is: selftests-landlock-test-ptrace-as-much-as-possible-with-yama.patch and it can be found in the queue-6.2 subdirectory. If you, or anyone else, feels it should not be added to the stable tree, please let <stable@xxxxxxxxxxxxxxx> know about it. >From 8677e555f17f51321d0730b945aeb7d4b95f998f Mon Sep 17 00:00:00 2001 From: Jeff Xu <jeffxu@xxxxxxxxxx> Date: Sat, 14 Jan 2023 02:03:06 +0000 Subject: selftests/landlock: Test ptrace as much as possible with Yama MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From: Jeff Xu <jeffxu@xxxxxxxxxx> commit 8677e555f17f51321d0730b945aeb7d4b95f998f upstream. Update ptrace tests according to all potential Yama security policies. This is required to make such tests pass even if Yama is enabled. Tests are not skipped but they now check both Landlock and Yama boundary restrictions at run time to keep a maximum test coverage (i.e. positive and negative testing). Signed-off-by: Jeff Xu <jeffxu@xxxxxxxxxx> Link: https://lore.kernel.org/r/20230114020306.1407195-2-jeffxu@xxxxxxxxxx Cc: stable@xxxxxxxxxxxxxxx [mic: Add curly braces around EXPECT_EQ() to make it build, and improve commit message] Co-developed-by: Mickaël Salaün <mic@xxxxxxxxxxx> Signed-off-by: Mickaël Salaün <mic@xxxxxxxxxxx> Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx> --- tools/testing/selftests/landlock/ptrace_test.c | 113 +++++++++++++++++++++---- 1 file changed, 96 insertions(+), 17 deletions(-) --- a/tools/testing/selftests/landlock/ptrace_test.c +++ b/tools/testing/selftests/landlock/ptrace_test.c @@ -19,6 +19,12 @@ #include "common.h" +/* Copied from security/yama/yama_lsm.c */ +#define YAMA_SCOPE_DISABLED 0 +#define YAMA_SCOPE_RELATIONAL 1 +#define YAMA_SCOPE_CAPABILITY 2 +#define YAMA_SCOPE_NO_ATTACH 3 + static void create_domain(struct __test_metadata *const _metadata) { int ruleset_fd; @@ -60,6 +66,25 @@ static int test_ptrace_read(const pid_t return 0; } +static int get_yama_ptrace_scope(void) +{ + int ret; + char buf[2] = {}; + const int fd = open("/proc/sys/kernel/yama/ptrace_scope", O_RDONLY); + + if (fd < 0) + return 0; + + if (read(fd, buf, 1) < 0) { + close(fd); + return -1; + } + + ret = atoi(buf); + close(fd); + return ret; +} + /* clang-format off */ FIXTURE(hierarchy) {}; /* clang-format on */ @@ -232,8 +257,51 @@ TEST_F(hierarchy, trace) pid_t child, parent; int status, err_proc_read; int pipe_child[2], pipe_parent[2]; + int yama_ptrace_scope; char buf_parent; long ret; + bool can_read_child, can_trace_child, can_read_parent, can_trace_parent; + + yama_ptrace_scope = get_yama_ptrace_scope(); + ASSERT_LE(0, yama_ptrace_scope); + + if (yama_ptrace_scope > YAMA_SCOPE_DISABLED) + TH_LOG("Incomplete tests due to Yama restrictions (scope %d)", + yama_ptrace_scope); + + /* + * can_read_child is true if a parent process can read its child + * process, which is only the case when the parent process is not + * isolated from the child with a dedicated Landlock domain. + */ + can_read_child = !variant->domain_parent; + + /* + * can_trace_child is true if a parent process can trace its child + * process. This depends on two conditions: + * - The parent process is not isolated from the child with a dedicated + * Landlock domain. + * - Yama allows tracing children (up to YAMA_SCOPE_RELATIONAL). + */ + can_trace_child = can_read_child && + yama_ptrace_scope <= YAMA_SCOPE_RELATIONAL; + + /* + * can_read_parent is true if a child process can read its parent + * process, which is only the case when the child process is not + * isolated from the parent with a dedicated Landlock domain. + */ + can_read_parent = !variant->domain_child; + + /* + * can_trace_parent is true if a child process can trace its parent + * process. This depends on two conditions: + * - The child process is not isolated from the parent with a dedicated + * Landlock domain. + * - Yama is disabled (YAMA_SCOPE_DISABLED). + */ + can_trace_parent = can_read_parent && + yama_ptrace_scope <= YAMA_SCOPE_DISABLED; /* * Removes all effective and permitted capabilities to not interfere @@ -264,16 +332,21 @@ TEST_F(hierarchy, trace) /* Waits for the parent to be in a domain, if any. */ ASSERT_EQ(1, read(pipe_parent[0], &buf_child, 1)); - /* Tests PTRACE_ATTACH and PTRACE_MODE_READ on the parent. */ + /* Tests PTRACE_MODE_READ on the parent. */ err_proc_read = test_ptrace_read(parent); + if (can_read_parent) { + EXPECT_EQ(0, err_proc_read); + } else { + EXPECT_EQ(EACCES, err_proc_read); + } + + /* Tests PTRACE_ATTACH on the parent. */ ret = ptrace(PTRACE_ATTACH, parent, NULL, 0); - if (variant->domain_child) { + if (can_trace_parent) { + EXPECT_EQ(0, ret); + } else { EXPECT_EQ(-1, ret); EXPECT_EQ(EPERM, errno); - EXPECT_EQ(EACCES, err_proc_read); - } else { - EXPECT_EQ(0, ret); - EXPECT_EQ(0, err_proc_read); } if (ret == 0) { ASSERT_EQ(parent, waitpid(parent, &status, 0)); @@ -283,11 +356,11 @@ TEST_F(hierarchy, trace) /* Tests child PTRACE_TRACEME. */ ret = ptrace(PTRACE_TRACEME); - if (variant->domain_parent) { + if (can_trace_child) { + EXPECT_EQ(0, ret); + } else { EXPECT_EQ(-1, ret); EXPECT_EQ(EPERM, errno); - } else { - EXPECT_EQ(0, ret); } /* @@ -296,7 +369,7 @@ TEST_F(hierarchy, trace) */ ASSERT_EQ(1, write(pipe_child[1], ".", 1)); - if (!variant->domain_parent) { + if (can_trace_child) { ASSERT_EQ(0, raise(SIGSTOP)); } @@ -321,7 +394,7 @@ TEST_F(hierarchy, trace) ASSERT_EQ(1, read(pipe_child[0], &buf_parent, 1)); /* Tests child PTRACE_TRACEME. */ - if (!variant->domain_parent) { + if (can_trace_child) { ASSERT_EQ(child, waitpid(child, &status, 0)); ASSERT_EQ(1, WIFSTOPPED(status)); ASSERT_EQ(0, ptrace(PTRACE_DETACH, child, NULL, 0)); @@ -331,17 +404,23 @@ TEST_F(hierarchy, trace) EXPECT_EQ(ESRCH, errno); } - /* Tests PTRACE_ATTACH and PTRACE_MODE_READ on the child. */ + /* Tests PTRACE_MODE_READ on the child. */ err_proc_read = test_ptrace_read(child); + if (can_read_child) { + EXPECT_EQ(0, err_proc_read); + } else { + EXPECT_EQ(EACCES, err_proc_read); + } + + /* Tests PTRACE_ATTACH on the child. */ ret = ptrace(PTRACE_ATTACH, child, NULL, 0); - if (variant->domain_parent) { + if (can_trace_child) { + EXPECT_EQ(0, ret); + } else { EXPECT_EQ(-1, ret); EXPECT_EQ(EPERM, errno); - EXPECT_EQ(EACCES, err_proc_read); - } else { - EXPECT_EQ(0, ret); - EXPECT_EQ(0, err_proc_read); } + if (ret == 0) { ASSERT_EQ(child, waitpid(child, &status, 0)); ASSERT_EQ(1, WIFSTOPPED(status)); Patches currently in stable-queue which might be from jeffxu@xxxxxxxxxx are queue-6.2/selftests-landlock-skip-overlayfs-tests-when-not-supported.patch queue-6.2/selftests-landlock-test-ptrace-as-much-as-possible-with-yama.patch