Linux Security Modules development
 help / color / mirror / Atom feed
From: Justin Suess <utilityemal77@gmail.com>
To: gnoack3000@gmail.com, mic@digikod.net
Cc: linux-kernel@vger.kernel.org,
	linux-security-module@vger.kernel.org,
	Justin Suess <utilityemal77@gmail.com>
Subject: [PATCH v8 09/10] selftests/landlock: Add selftests for LANDLOCK_ADD_RULE_NO_INHERIT
Date: Thu, 28 May 2026 21:52:08 -0400	[thread overview]
Message-ID: <20260529015210.500291-10-utilityemal77@gmail.com> (raw)
In-Reply-To: <20260529015210.500291-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, 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.

Signed-off-by: Justin Suess <utilityemal77@gmail.com>
---

Notes:
    v7..v8 changes:
    
      * Reorganized the new fs_test.c coverage around fixtures and
        variants instead of one TEST_F_FORK per scenario:
    
        - New layout1_no_inherit fixture with five FIXTURE_VARIANT_ADD
          cases (rw_parent_ro_leaf, rw_parent_ro_middle, rw_parent_ro_root,
          ro_parent_rw_middle, rw_parent_read_file) collapse what were
          eight near-duplicate layout1 tests in v7 into three shared
          tests (blocks_inheritance, seals_topology, layered_no_inherit).
    
        - New layout4_disconnected_leafs variant 'no_inherit_mount' with a
          single 'no_inherit_seals_mount' test replaces the four
          v7 layout4 tests (no_inherit_mount_parent_{rename,rmdir,link}
          and no_inherit_source_parent_rename) by exercising all four
          sealed topology operations in one test.
    
        - New audit_no_inherit fixture with three variants
          (parent_is_logged, blocks_quiet_inheritance, quiet_parent)
          covers the quiet/no_inherit interaction previously inlined
          into an ad hoc audit test.
    
      * Net change: 705 added lines in v7 -> 419 added lines in v8, with
        equivalent coverage.

 tools/testing/selftests/landlock/fs_test.c | 419 +++++++++++++++++++++
 1 file changed, 419 insertions(+)

diff --git a/tools/testing/selftests/landlock/fs_test.c b/tools/testing/selftests/landlock/fs_test.c
index 2e32295258f9..625ff1afecb0 100644
--- a/tools/testing/selftests/landlock/fs_test.c
+++ b/tools/testing/selftests/landlock/fs_test.c
@@ -1429,6 +1429,224 @@ 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;
+	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",
+	.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",
+	.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",
+	.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",
+	.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",
+	.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 (variant->desc_file != variant->ni_file) {
+		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);
+
+	/*
+	 * Content inside the NO_INHERIT directory is still mutable
+	 * (if the access rights permit it).
+	 */
+	if (variant->ni_access & LANDLOCK_ACCESS_FS_REMOVE_FILE) {
+		ASSERT_EQ(0, unlink(variant->ni_file));
+	} else {
+		ASSERT_EQ(-1, unlink(variant->ni_file));
+	}
+
+	/* 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 struct rule layer_rules[] = {
+		{
+			.path = TMP_DIR,
+			.access = ACCESS_RW | LANDLOCK_ACCESS_FS_REMOVE_FILE,
+		},
+		{},
+	};
+	int ruleset_fd;
+
+	/* Layer 1: RW on TMP_DIR. */
+	ruleset_fd = create_ruleset(_metadata,
+				    ACCESS_RW | LANDLOCK_ACCESS_FS_REMOVE_FILE,
+				    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,
+				    ACCESS_RW | LANDLOCK_ACCESS_FS_REMOVE_FILE,
+				    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));
+
+	/* The target path cannot be renamed. */
+	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 +5789,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 +6060,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 +6188,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 +7679,104 @@ 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, parent_is_logged) {
+	/* clang-format on */
+	.parent_quiet = false,
+	.test_path = TMP_DIR "/s1d1/s1d2/f1",
+	.expect_audit_log = true,
+};
+
+/* 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.53.0


  parent reply	other threads:[~2026-05-29  1:52 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-05-29  1:51 [PATCH v8 00/10] Implement LANDLOCK_ADD_RULE_NO_INHERIT Justin Suess
2026-05-29  1:52 ` [PATCH v8 01/10] landlock: Add landlock_walk_path_up() helper Justin Suess
2026-05-29  1:52 ` [PATCH v8 02/10] landlock: Use landlock_walk_path_up() in is_access_to_paths_allowed() Justin Suess
2026-05-29  1:52 ` [PATCH v8 03/10] landlock: Use landlock_walk_path_up() in collect_domain_accesses() Justin Suess
2026-05-29  1:52 ` [PATCH v8 04/10] landlock: Add LANDLOCK_ADD_RULE_NO_INHERIT user API Justin Suess
2026-05-29  1:52 ` [PATCH v8 05/10] landlock: Return inserted rule from landlock_insert_rule() Justin Suess
2026-05-29  1:52 ` [PATCH v8 06/10] landlock: Implement LANDLOCK_ADD_RULE_NO_INHERIT Justin Suess
2026-05-29  1:52 ` [PATCH v8 07/10] landlock: Add documentation for LANDLOCK_ADD_RULE_NO_INHERIT Justin Suess
2026-05-29  1:52 ` [PATCH v8 08/10] samples/landlock: Add LANDLOCK_ADD_RULE_NO_INHERIT to landlock-sandboxer Justin Suess
2026-05-29  1:52 ` Justin Suess [this message]
2026-05-29  1:52 ` [PATCH v8 10/10] 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=20260529015210.500291-10-utilityemal77@gmail.com \
    --to=utilityemal77@gmail.com \
    --cc=gnoack3000@gmail.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-security-module@vger.kernel.org \
    --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