From: Justin Suess <utilityemal77@gmail.com>
To: linux-security-module@vger.kernel.org, mic@digikod.net
Cc: m@maowtm.org, gnoack@google.com, gnoack3000@gmail.com,
matthieu@buffet.re, Justin Suess <utilityemal77@gmail.com>
Subject: [PATCH v9 8/9] selftests/landlock: Add selftests for LANDLOCK_ADD_RULE_NO_INHERIT
Date: Sat, 20 Jun 2026 23:52:21 -0400 [thread overview]
Message-ID: <20260621035223.2651547-9-utilityemal77@gmail.com> (raw)
In-Reply-To: <20260621035223.2651547-1-utilityemal77@gmail.com>
Add test coverage for the new flag:
- New layout1_no_inherit fixture with five variants covering NO_INHERIT
on leaf, middle, and root directories, RW-over-RO expansion, and a
regular file target. Three tests per variant exercise inheritance
blocking, topology sealing (reparenting and same-directory rename,
hard-link of a sealed file, and removal), and layered (multi-domain)
NO_INHERIT.
- A new layout4_disconnected_leafs variant exercising NO_INHERIT applied
through a bind mount, asserting that ancestors in both the bind and
source paths are sealed.
- A new audit_no_inherit fixture verifying that the flag interacts
correctly with the quiet flag: a quiet ancestor does not suppress
audit on a descendant that has crossed a NO_INHERIT boundary.
- Two rejection tests in base_test, modeled on the equivalent quiet
flag tests: useless_no_inherit_rule_fs checks that NO_INHERIT is
rejected on a ruleset that handles no filesystem access, and
no_inherit_rule_net checks that NO_INHERIT (a filesystem-only flag) is
rejected on a network rule.
Signed-off-by: Justin Suess <utilityemal77@gmail.com>
---
Notes:
Changes since v8:
- Added two base_test rejection tests: useless_no_inherit_rule_fs
(NO_INHERIT on a ruleset handling no filesystem access -> EINVAL) and
no_inherit_rule_net (NO_INHERIT on a network rule -> EINVAL).
- blocks_inheritance now also asserts a same-directory rename and a hard
link of a sealed file are denied with EACCES, and unconditionally
expects unlink of the target to fail; added ni_samedir/ni_link fields
to the layout1_no_inherit variants.
- seals_topology (layered) now handles LANDLOCK_ACCESS_FS_REFER in both
rulesets via a shared handled mask.
- Dropped the redundant parent_is_logged variant from the
audit_no_inherit fixture.
- Rebased onto mic/next.
tools/testing/selftests/landlock/base_test.c | 58 +++
tools/testing/selftests/landlock/fs_test.c | 425 +++++++++++++++++++
2 files changed, 483 insertions(+)
diff --git a/tools/testing/selftests/landlock/base_test.c b/tools/testing/selftests/landlock/base_test.c
index b8b5fa1042ba..f4435d9a92a8 100644
--- a/tools/testing/selftests/landlock/base_test.c
+++ b/tools/testing/selftests/landlock/base_test.c
@@ -584,6 +584,64 @@ TEST(useless_quiet_rule_net)
ASSERT_EQ(0, close(ruleset_fd));
}
+TEST(useless_no_inherit_rule_fs)
+{
+ struct landlock_ruleset_attr ruleset_attr = {
+ .handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP,
+ };
+ struct landlock_path_beneath_attr path_beneath_attr = {
+ .allowed_access = 0,
+ };
+ int ruleset_fd, root_fd;
+
+ drop_caps(_metadata);
+ ruleset_fd =
+ landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
+ ASSERT_LE(0, ruleset_fd);
+
+ root_fd = open("/", O_PATH | O_CLOEXEC);
+ ASSERT_LE(0, root_fd);
+ path_beneath_attr.parent_fd = root_fd;
+
+ /*
+ * A seal is only ever consulted for a domain that handles some
+ * filesystem access, so a no-inherit rule on a ruleset with no handled
+ * filesystem access would be silently inert.
+ */
+ ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
+ &path_beneath_attr,
+ LANDLOCK_ADD_RULE_NO_INHERIT));
+ ASSERT_EQ(EINVAL, errno);
+
+ ASSERT_EQ(0, close(root_fd));
+ ASSERT_EQ(0, close(ruleset_fd));
+}
+
+TEST(no_inherit_rule_net)
+{
+ struct landlock_ruleset_attr ruleset_attr = {
+ .handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP,
+ };
+ struct landlock_net_port_attr net_port_attr = {
+ .allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP,
+ .port = 1024,
+ };
+ int ruleset_fd;
+
+ drop_caps(_metadata);
+ ruleset_fd =
+ landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
+ ASSERT_LE(0, ruleset_fd);
+
+ /* LANDLOCK_ADD_RULE_NO_INHERIT is a filesystem-only flag. */
+ ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT,
+ &net_port_attr,
+ LANDLOCK_ADD_RULE_NO_INHERIT));
+ ASSERT_EQ(EINVAL, errno);
+
+ ASSERT_EQ(0, close(ruleset_fd));
+}
+
TEST(invalid_quiet_bits_1)
{
const struct landlock_ruleset_attr ruleset_attr_fs = {
diff --git a/tools/testing/selftests/landlock/fs_test.c b/tools/testing/selftests/landlock/fs_test.c
index 86e08aa6e0a7..e5d4fa6a169a 100644
--- a/tools/testing/selftests/landlock/fs_test.c
+++ b/tools/testing/selftests/landlock/fs_test.c
@@ -1429,6 +1429,238 @@ TEST_F_FORK(layout1, inherit_superset)
ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY));
}
+FIXTURE(layout1_no_inherit) {};
+
+FIXTURE_SETUP(layout1_no_inherit)
+{
+ prepare_layout(_metadata);
+ create_layout1(_metadata);
+}
+
+FIXTURE_TEARDOWN_PARENT(layout1_no_inherit)
+{
+ remove_layout1(_metadata);
+ cleanup_layout(_metadata);
+}
+
+FIXTURE_VARIANT(layout1_no_inherit)
+{
+ const char *ni_path;
+ const __u64 ni_access;
+ const char *ni_file;
+ const char *desc_file;
+ /* Sibling of ni_path within the same parent, for same-dir rename. */
+ const char *ni_samedir;
+ /* Hard-link target for a sealed file (NULL when ni_path is a dir). */
+ const char *ni_link;
+ const int expected_ni_write;
+ const int expected_ni_read;
+ const int expected_desc_write;
+ const int expected_desc_read;
+};
+
+/* NO_INHERIT on leaf directory: blocks parent's RW, grants only RO. */
+/* clang-format off */
+FIXTURE_VARIANT_ADD(layout1_no_inherit, rw_parent_ro_leaf) {
+ /* clang-format on */
+ .ni_path = TMP_DIR "/s1d1/s1d2/s1d3",
+ .ni_access = ACCESS_RO,
+ .ni_file = TMP_DIR "/s1d1/s1d2/s1d3/f1",
+ .desc_file = TMP_DIR "/s1d1/s1d2/s1d3/f2",
+ .ni_samedir = TMP_DIR "/s1d1/s1d2/s1d3_renamed",
+ .expected_ni_write = EACCES,
+ .expected_ni_read = 0,
+ .expected_desc_write = EACCES,
+ .expected_desc_read = 0,
+};
+
+/* NO_INHERIT on middle directory: blocks parent's RW for all descendants. */
+/* clang-format off */
+FIXTURE_VARIANT_ADD(layout1_no_inherit, rw_parent_ro_middle) {
+ /* clang-format on */
+ .ni_path = TMP_DIR "/s1d1/s1d2",
+ .ni_access = ACCESS_RO,
+ .ni_file = TMP_DIR "/s1d1/s1d2/f1",
+ .desc_file = TMP_DIR "/s1d1/s1d2/s1d3/f1",
+ .ni_samedir = TMP_DIR "/s1d1/s1d2_renamed",
+ .expected_ni_write = EACCES,
+ .expected_ni_read = 0,
+ .expected_desc_write = EACCES,
+ .expected_desc_read = 0,
+};
+
+/* NO_INHERIT on root directory: blocks parent's RW for entire subtree. */
+/* clang-format off */
+FIXTURE_VARIANT_ADD(layout1_no_inherit, rw_parent_ro_root) {
+ /* clang-format on */
+ .ni_path = TMP_DIR "/s1d1",
+ .ni_access = ACCESS_RO,
+ .ni_file = TMP_DIR "/s1d1/f1",
+ .desc_file = TMP_DIR "/s1d1/s1d2/s1d3/f1",
+ .ni_samedir = TMP_DIR "/s1d1_renamed",
+ .expected_ni_write = EACCES,
+ .expected_ni_read = 0,
+ .expected_desc_write = EACCES,
+ .expected_desc_read = 0,
+};
+
+/* NO_INHERIT with RW access expands parent's RO to RW. */
+/* clang-format off */
+FIXTURE_VARIANT_ADD(layout1_no_inherit, ro_parent_rw_middle) {
+ /* clang-format on */
+ .ni_path = TMP_DIR "/s1d1/s1d2",
+ .ni_access = ACCESS_RW,
+ .ni_file = TMP_DIR "/s1d1/s1d2/f1",
+ .desc_file = TMP_DIR "/s1d1/s1d2/s1d3/f1",
+ .ni_samedir = TMP_DIR "/s1d1/s1d2_renamed",
+ .expected_ni_write = 0,
+ .expected_ni_read = 0,
+ .expected_desc_write = 0,
+ .expected_desc_read = 0,
+};
+
+/* NO_INHERIT on a file: file gets only its explicit READ_FILE access. */
+/* clang-format off */
+FIXTURE_VARIANT_ADD(layout1_no_inherit, rw_parent_read_file) {
+ /* clang-format on */
+ .ni_path = TMP_DIR "/s1d1/s1d2/f1",
+ .ni_access = LANDLOCK_ACCESS_FS_READ_FILE,
+ .ni_file = TMP_DIR "/s1d1/s1d2/f1",
+ .desc_file = TMP_DIR "/s1d1/s1d2/f2",
+ .ni_samedir = TMP_DIR "/s1d1/s1d2/f1_renamed",
+ .ni_link = TMP_DIR "/s1d1/s1d2/f1_link",
+ .expected_ni_write = EACCES,
+ .expected_ni_read = 0,
+ .expected_desc_write = 0,
+ .expected_desc_read = 0,
+};
+
+TEST_F_FORK(layout1_no_inherit, blocks_inheritance)
+{
+ struct landlock_ruleset_attr ruleset_attr = {
+ .handled_access_fs = ACCESS_RW,
+ };
+ int ruleset_fd;
+
+ /* RO variants: TMP_DIR gets RO instead of RW. */
+ if (variant->ni_access == ACCESS_RW)
+ ruleset_attr.handled_access_fs |= LANDLOCK_ACCESS_FS_READ_DIR;
+
+ ruleset_fd =
+ landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
+ ASSERT_LE(0, ruleset_fd);
+
+ if (variant->ni_access == ACCESS_RW)
+ add_path_beneath(_metadata, ruleset_fd, ACCESS_RO, TMP_DIR, 0);
+ else
+ add_path_beneath(_metadata, ruleset_fd, ACCESS_RW, TMP_DIR, 0);
+
+ add_path_beneath(_metadata, ruleset_fd, variant->ni_access,
+ variant->ni_path, LANDLOCK_ADD_RULE_NO_INHERIT);
+
+ enforce_ruleset(_metadata, ruleset_fd);
+ ASSERT_EQ(0, close(ruleset_fd));
+
+ EXPECT_EQ(variant->expected_ni_write,
+ test_open(variant->ni_file, O_WRONLY));
+ EXPECT_EQ(variant->expected_ni_read,
+ test_open(variant->ni_file, O_RDONLY));
+
+ if (strcmp(variant->desc_file, variant->ni_file) != 0) {
+ EXPECT_EQ(variant->expected_desc_write,
+ test_open(variant->desc_file, O_WRONLY));
+ EXPECT_EQ(variant->expected_desc_read,
+ test_open(variant->desc_file, O_RDONLY));
+ }
+}
+
+TEST_F_FORK(layout1_no_inherit, seals_topology)
+{
+ int ruleset_fd;
+ struct landlock_ruleset_attr ruleset_attr = {
+ .handled_access_fs = ACCESS_RW | LANDLOCK_ACCESS_FS_REFER |
+ LANDLOCK_ACCESS_FS_REMOVE_FILE |
+ LANDLOCK_ACCESS_FS_REMOVE_DIR,
+ };
+
+ ruleset_fd =
+ landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
+ ASSERT_LE(0, ruleset_fd);
+
+ add_path_beneath(_metadata, ruleset_fd,
+ ACCESS_RW | LANDLOCK_ACCESS_FS_REFER |
+ LANDLOCK_ACCESS_FS_REMOVE_FILE |
+ LANDLOCK_ACCESS_FS_REMOVE_DIR,
+ TMP_DIR, 0);
+ add_path_beneath(_metadata, ruleset_fd, variant->ni_access,
+ variant->ni_path, LANDLOCK_ADD_RULE_NO_INHERIT);
+
+ enforce_ruleset(_metadata, ruleset_fd);
+ ASSERT_EQ(0, close(ruleset_fd));
+
+ /* The directory bearing NO_INHERIT cannot be renamed or removed. */
+ ASSERT_EQ(-1, rename(variant->ni_path, TMP_DIR "/ni_renamed"));
+ ASSERT_EQ(EACCES, errno);
+
+ /* A same-directory rename (no REFER needed) is also denied. */
+ ASSERT_EQ(-1, rename(variant->ni_path, variant->ni_samedir));
+ ASSERT_EQ(EACCES, errno);
+
+ /* Hard-linking a sealed file is denied (dirs can't be linked). */
+ if (variant->ni_link) {
+ ASSERT_EQ(-1, link(variant->ni_path, variant->ni_link));
+ ASSERT_EQ(EACCES, errno);
+ }
+
+ /*
+ * Removal is not granted by any variant's NO_INHERIT access, so
+ * unlinking content inside the sealed directory is denied.
+ */
+ ASSERT_EQ(-1, unlink(variant->ni_file));
+ ASSERT_EQ(EACCES, errno);
+
+ /* Unrelated operations outside the sealed branch still work. */
+ ASSERT_EQ(0, unlink(file1_s2d1));
+ ASSERT_EQ(0, mknod(file1_s2d1, S_IFREG | 0700, 0));
+}
+
+TEST_F_FORK(layout1_no_inherit, layered_no_inherit)
+{
+ const __u64 handled = ACCESS_RW | LANDLOCK_ACCESS_FS_REMOVE_FILE |
+ LANDLOCK_ACCESS_FS_REFER;
+ const struct rule layer_rules[] = {
+ {
+ .path = TMP_DIR,
+ .access = handled,
+ },
+ {},
+ };
+ int ruleset_fd;
+
+ /* Layer 1: RW + REFER on TMP_DIR. */
+ ruleset_fd = create_ruleset(_metadata, handled, layer_rules);
+ ASSERT_LE(0, ruleset_fd);
+ enforce_ruleset(_metadata, ruleset_fd);
+ ASSERT_EQ(0, close(ruleset_fd));
+
+ /* Layer 2: NO_INHERIT on the target. */
+ ruleset_fd = create_ruleset(_metadata, handled, layer_rules);
+ ASSERT_LE(0, ruleset_fd);
+ add_path_beneath(_metadata, ruleset_fd, variant->ni_access,
+ variant->ni_path, LANDLOCK_ADD_RULE_NO_INHERIT);
+ enforce_ruleset(_metadata, ruleset_fd);
+ ASSERT_EQ(0, close(ruleset_fd));
+
+ ASSERT_EQ(-1, rename(variant->ni_path, TMP_DIR "/ni_renamed_layered"));
+ ASSERT_EQ(EACCES, errno);
+
+ /* Content at NI path respects the NO_INHERIT access from layer 2. */
+ EXPECT_EQ(variant->expected_ni_write,
+ test_open(variant->ni_file, O_WRONLY));
+ EXPECT_EQ(variant->expected_ni_read,
+ test_open(variant->ni_file, O_RDONLY));
+}
+
TEST_F_FORK(layout0, max_layers)
{
int i, err;
@@ -5571,6 +5803,25 @@ FIXTURE_VARIANT(layout4_disconnected_leafs)
const int expected_exchange_result;
/* Expected result of the call to renameat([fd:s1d42]/f4, [fd:s1d42]/f5). */
const int expected_same_dir_rename_result;
+
+ /*
+ * If true, a NO_INHERIT rule is set on s1d41 (via the bind mount
+ * at s2d2). Used by the no_inherit_mount test.
+ */
+ bool no_inherit_on_s1d41;
+ /*
+ * Access rights used for the optional NO_INHERIT rule on s1d41.
+ */
+ const __u64 no_inherit_access;
+ /*
+ * Expected result of renaming s1d31 (parent of s1d41 within the
+ * mount) when no_inherit_on_s1d41 is set.
+ */
+ const int expected_parent_rename;
+ /*
+ * Expected result of rmdir on s1d31, when no_inherit_on_s1d41 is set.
+ */
+ const int expected_parent_rmdir;
};
/* clang-format off */
@@ -5823,6 +6074,26 @@ FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, f1_f2_f3) {
.expected_exchange_result = EACCES,
};
+/*
+ * NO_INHERIT variant: s1d41 is protected with ACCESS_RO via the bind mount.
+ * Parents within the mount are sealed against topology changes.
+ */
+/* clang-format off */
+FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, no_inherit_mount) {
+ /* clang-format on */
+ .allowed_f1 = LANDLOCK_ACCESS_FS_READ_FILE,
+ .allowed_f2 = LANDLOCK_ACCESS_FS_READ_FILE,
+ .allowed_f3 = LANDLOCK_ACCESS_FS_READ_FILE,
+ .expected_read_result = 0,
+ .expected_rename_result = EACCES,
+ .expected_exchange_result = EACCES,
+ .expected_same_dir_rename_result = EACCES,
+ .no_inherit_on_s1d41 = true,
+ .no_inherit_access = ACCESS_RO,
+ .expected_parent_rename = EACCES,
+ .expected_parent_rmdir = EACCES,
+};
+
TEST_F_FORK(layout4_disconnected_leafs, read_rename_exchange)
{
const __u64 handled_access =
@@ -5931,6 +6202,70 @@ TEST_F_FORK(layout4_disconnected_leafs, read_rename_exchange)
test_renameat(s1d42_bind_fd, "f4", s1d42_bind_fd, "f5"));
}
+/*
+ * When s1d41 (accessed via the bind mount at s2d2) is protected with
+ * NO_INHERIT, its parent directories within the mount are sealed from
+ * topology changes. Other variants do not exercise NO_INHERIT and skip
+ * this test.
+ */
+TEST_F_FORK(layout4_disconnected_leafs, no_inherit_seals_mount)
+{
+ struct landlock_ruleset_attr ruleset_attr = {
+ .handled_access_fs = ACCESS_RW | LANDLOCK_ACCESS_FS_REFER |
+ LANDLOCK_ACCESS_FS_REMOVE_FILE |
+ LANDLOCK_ACCESS_FS_REMOVE_DIR,
+ };
+ int ruleset_fd, s1d41_bind_fd;
+
+ if (!variant->no_inherit_on_s1d41)
+ SKIP(return, "variant does not set NO_INHERIT on s1d41");
+
+ ruleset_fd =
+ landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
+ ASSERT_LE(0, ruleset_fd);
+
+ add_path_beneath(_metadata, ruleset_fd,
+ ACCESS_RW | LANDLOCK_ACCESS_FS_REFER |
+ LANDLOCK_ACCESS_FS_REMOVE_FILE |
+ LANDLOCK_ACCESS_FS_REMOVE_DIR,
+ TMP_DIR, 0);
+
+ s1d41_bind_fd = open(TMP_DIR "/s2d1/s2d2/s1d31/s1d41",
+ O_DIRECTORY | O_PATH | O_CLOEXEC);
+ ASSERT_LE(0, s1d41_bind_fd);
+
+ ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
+ &(struct landlock_path_beneath_attr){
+ .parent_fd = s1d41_bind_fd,
+ .allowed_access =
+ variant->no_inherit_access,
+ },
+ LANDLOCK_ADD_RULE_NO_INHERIT));
+ EXPECT_EQ(0, close(s1d41_bind_fd));
+
+ enforce_ruleset(_metadata, ruleset_fd);
+ ASSERT_EQ(0, close(ruleset_fd));
+
+ /* Parent of s1d41 within the mount is sealed. */
+ ASSERT_EQ(-1, rmdir(TMP_DIR "/s2d1/s2d2/s1d31"));
+ ASSERT_EQ(variant->expected_parent_rmdir, errno);
+
+ ASSERT_EQ(-1, rename(TMP_DIR "/s2d1/s2d2/s1d31",
+ TMP_DIR "/s2d1/s2d2/s1d31_renamed"));
+ ASSERT_EQ(variant->expected_parent_rename, errno);
+
+ /* Sibling directories outside the sealed chain are free. */
+ ASSERT_EQ(0, rename(TMP_DIR "/s2d1/s2d2/s1d32",
+ TMP_DIR "/s2d1/s2d2/s1d32_renamed"));
+ ASSERT_EQ(0, rename(TMP_DIR "/s2d1/s2d2/s1d32_renamed",
+ TMP_DIR "/s2d1/s2d2/s1d32"));
+
+ /* The mount source parent hierarchy is also sealed. */
+ ASSERT_EQ(-1, rename(TMP_DIR "/s1d1/s1d2/s1d31",
+ TMP_DIR "/s1d1/s1d2/s1d31_renamed"));
+ ASSERT_EQ(variant->expected_parent_rename, errno);
+}
+
/*
* layout5_disconnected_branch before rename:
*
@@ -7358,6 +7693,96 @@ TEST_F(audit_layout1, write_file)
EXPECT_EQ(1, records.domain);
}
+FIXTURE(audit_no_inherit)
+{
+ struct audit_filter audit_filter;
+ int audit_fd;
+};
+
+FIXTURE_SETUP(audit_no_inherit)
+{
+ prepare_layout(_metadata);
+ create_layout1(_metadata);
+
+ set_cap(_metadata, CAP_AUDIT_CONTROL);
+ self->audit_fd = audit_init_with_exe_filter(&self->audit_filter);
+ EXPECT_LE(0, self->audit_fd);
+ clear_cap(_metadata, CAP_AUDIT_CONTROL);
+}
+
+FIXTURE_TEARDOWN_PARENT(audit_no_inherit)
+{
+ remove_layout1(_metadata);
+ cleanup_layout(_metadata);
+
+ EXPECT_EQ(0, audit_cleanup(-1, NULL));
+}
+
+FIXTURE_VARIANT(audit_no_inherit)
+{
+ bool parent_quiet;
+ const char *test_path;
+ bool expect_audit_log;
+};
+
+/* clang-format off */
+FIXTURE_VARIANT_ADD(audit_no_inherit, blocks_quiet_inheritance) {
+ /* clang-format on */
+ .parent_quiet = true,
+ .test_path = TMP_DIR "/s1d1/s1d2/s1d3/f1",
+ .expect_audit_log = true,
+};
+
+/* clang-format off */
+FIXTURE_VARIANT_ADD(audit_no_inherit, quiet_parent) {
+ /* clang-format on */
+ .parent_quiet = true,
+ .test_path = TMP_DIR "/s1d1/f1",
+ .expect_audit_log = false,
+};
+
+TEST_F(audit_no_inherit, no_inherit_audit)
+{
+ struct audit_records records;
+ struct landlock_ruleset_attr ruleset_attr = {
+ .handled_access_fs = ACCESS_RW,
+ .quiet_access_fs = variant->parent_quiet ? ACCESS_RW : 0,
+ };
+ int ruleset_fd;
+
+ ruleset_fd = landlock_create_ruleset(&ruleset_attr,
+ sizeof(ruleset_attr), 0);
+ ASSERT_LE(0, ruleset_fd);
+
+ if (variant->parent_quiet)
+ add_path_beneath(_metadata, ruleset_fd, ACCESS_RO, dir_s1d1,
+ LANDLOCK_ADD_RULE_QUIET);
+ else
+ add_path_beneath(_metadata, ruleset_fd, ACCESS_RO, dir_s1d1, 0);
+
+ add_path_beneath(_metadata, ruleset_fd, ACCESS_RO, dir_s1d3,
+ LANDLOCK_ADD_RULE_NO_INHERIT);
+
+ enforce_ruleset(_metadata, ruleset_fd);
+
+ EXPECT_EQ(EACCES, test_open(variant->test_path, O_WRONLY));
+ if (variant->expect_audit_log) {
+ EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd,
+ "fs\\.write_file",
+ variant->test_path));
+ } else {
+ EXPECT_NE(0, matches_log_fs(_metadata, self->audit_fd,
+ "fs\\.write_file",
+ variant->test_path));
+ }
+
+ EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
+ EXPECT_EQ(0, records.access);
+ EXPECT_EQ(variant->expect_audit_log ? 1 : 0, records.domain);
+
+ EXPECT_EQ(0, close(ruleset_fd));
+}
+
TEST_F(audit_layout1, read_file)
{
struct audit_records records;
--
2.54.0
next prev parent reply other threads:[~2026-06-21 3:52 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-21 3:52 [PATCH v9 0/9] Implement LANDLOCK_ADD_RULE_NO_INHERIT Justin Suess
2026-06-21 3:52 ` [PATCH v9 1/9] landlock: Add and use landlock_walk_path_up() helper Justin Suess
2026-06-21 3:52 ` [PATCH v9 2/9] landlock: Add LANDLOCK_ADD_RULE_NO_INHERIT user API Justin Suess
2026-06-21 3:52 ` [PATCH v9 3/9] landlock: Return inserted rule from landlock_insert_rule() Justin Suess
2026-06-21 3:52 ` [PATCH v9 4/9] landlock: Move log_fs_change_topology_dentry() above current_check_refer_path() Justin Suess
2026-06-21 3:52 ` [PATCH v9 5/9] landlock: Implement LANDLOCK_ADD_RULE_NO_INHERIT Justin Suess
2026-06-21 3:52 ` [PATCH v9 6/9] landlock: Add documentation for LANDLOCK_ADD_RULE_NO_INHERIT Justin Suess
2026-06-21 3:52 ` [PATCH v9 7/9] samples/landlock: Add LANDLOCK_ADD_RULE_NO_INHERIT to landlock-sandboxer Justin Suess
2026-06-21 3:52 ` Justin Suess [this message]
2026-06-21 3:52 ` [PATCH v9 9/9] landlock: Add KUnit tests for LANDLOCK_ADD_RULE_NO_INHERIT Justin Suess
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260621035223.2651547-9-utilityemal77@gmail.com \
--to=utilityemal77@gmail.com \
--cc=gnoack3000@gmail.com \
--cc=gnoack@google.com \
--cc=linux-security-module@vger.kernel.org \
--cc=m@maowtm.org \
--cc=matthieu@buffet.re \
--cc=mic@digikod.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox