@@ -19,6 +19,12 @@
#include "common.h"
+/* copy from 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 pid)
return 0;
}
+static int get_yama_ptrace_scope(void)
+{
+ int ret;
+ char buf[2] = {};
+ 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,49 @@ 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_trace_child, can_trace_parent;
+
+ yama_ptrace_scope = get_yama_ptrace_scope();
+ ASSERT_LE(0, yama_ptrace_scope);
+
+ if (yama_ptrace_scope >= YAMA_SCOPE_NO_ATTACH)
+ SKIP(return, "Yama forbids any ptrace use (scope %d)",
+ yama_ptrace_scope);
+
+ /*
+ * can_trace_child: if a parent process can trace its child process.
+ *
+ * There are two conditions concerning landlock:
+ * 1> the parent and child processes are in the same landlock domain or
+ * one beneath it (case: domain_both = true).
+ * 2> yama allows tracing children (up to YAMA_SCOPE_RELATIONAL).
+ * Both 1 and 2 need to be met for can_trace_child to be true.
+ *
+ * If a parent process has its own domain not shared with the child
+ * process (case:domain_parent = true), then the parent can't trace the
+ * child.
+ */
+ can_trace_child = !variant->domain_parent &&
+ yama_ptrace_scope < YAMA_SCOPE_CAPABILITY;
+
+ /*
+ * can_trace_parent: if a child process can trace its parent process.
+ *
+ * There are two conditions concerning landlock:
+ * 1> the parent and child process are in the same landlock domain or
+ * one beneath it.(case: domain_both = true).
+ * 2> yama is disabled (YAMA_SCOPE_DISABLED).
+ * Both 1 and 2 need to be met for can_trace_parent to be true.
+ *
+ * If a child process has its own domain not shared with the parent
+ * process (case:domain_child = true, then the child can't trace the
+ * parent.
+ */
+ can_trace_parent = !variant->domain_child &&
+ yama_ptrace_scope < YAMA_SCOPE_RELATIONAL;
/*
* Removes all effective and permitted capabilities to not interfere
@@ -267,7 +333,7 @@ TEST_F(hierarchy, trace)
/* Tests PTRACE_ATTACH and PTRACE_MODE_READ on the parent. */
err_proc_read = test_ptrace_read(parent);
ret = ptrace(PTRACE_ATTACH, parent, NULL, 0);
- if (variant->domain_child) {
+ if (!can_trace_parent) {
EXPECT_EQ(-1, ret);
EXPECT_EQ(EPERM, errno);
EXPECT_EQ(EACCES, err_proc_read);
@@ -283,7 +349,7 @@ TEST_F(hierarchy, trace)
/* Tests child PTRACE_TRACEME. */
ret = ptrace(PTRACE_TRACEME);
- if (variant->domain_parent) {
+ if (!can_trace_child) {
EXPECT_EQ(-1, ret);
EXPECT_EQ(EPERM, errno);
} else {
@@ -296,9 +362,8 @@ 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));
- }
/* Waits for the parent PTRACE_ATTACH test. */
ASSERT_EQ(1, read(pipe_parent[0], &buf_child, 1));
@@ -321,7 +386,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));
@@ -334,7 +399,7 @@ TEST_F(hierarchy, trace)
/* Tests PTRACE_ATTACH and PTRACE_MODE_READ on the child. */
err_proc_read = test_ptrace_read(child);
ret = ptrace(PTRACE_ATTACH, child, NULL, 0);
- if (variant->domain_parent) {
+ if (!can_trace_child) {
EXPECT_EQ(-1, ret);
EXPECT_EQ(EPERM, errno);
EXPECT_EQ(EACCES, err_proc_read);
@@ -354,6 +419,11 @@ TEST_F(hierarchy, trace)
if (WIFSIGNALED(status) || !WIFEXITED(status) ||
WEXITSTATUS(status) != EXIT_SUCCESS)
_metadata->passed = 0;
+
+ if (yama_ptrace_scope > 0)
+ SKIP(return,
+ "Incomplete tests due to Yama restrictions (scope %d)",
+ yama_ptrace_scope);
}
TEST_HARNESS_MAIN