All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v6 00/17] Network support for Landlock
@ 2022-06-21  8:22 Konstantin Meskhidze
  2022-06-21  8:22 ` [PATCH v6 01/17] landlock: renames access mask Konstantin Meskhidze
                   ` (17 more replies)
  0 siblings, 18 replies; 53+ messages in thread
From: Konstantin Meskhidze @ 2022-06-21  8:22 UTC (permalink / raw)
  To: mic
  Cc: willemdebruijn.kernel, linux-security-module, netdev,
	netfilter-devel, yusongping, anton.sirazetdinov

Hi,
This is a new V6 patch related to Landlock LSM network confinement.
It is based on the latest landlock-wip branch on top of v5.19-rc2:
https://git.kernel.org/pub/scm/linux/kernel/git/mic/linux.git/log/?h=landlock-wip

It brings refactoring of previous patch version V5:
    - Fixes some logic errors and typos.
    - Adds additional FIXTURE_VARIANT and FIXTURE_VARIANT_ADD helpers
    to support both ip4 and ip6 families and shorten seltests' code.
    - Makes TCP sockets confinement support optional in sandboxer demo.
    - Formats the code with clang-format-14

All test were run in QEMU evironment and compiled with
 -static flag.
 1. network_test: 18/18 tests passed.
 2. base_test: 7/7 tests passed.
 3. fs_test: 59/59 tests passed.
 4. ptrace_test: 8/8 tests passed.

Still have issue with base_test were compiled without -static flag
(landlock-wip branch without network support)
1. base_test: 6/7 tests passed.
 Error:
 #  RUN           global.inconsistent_attr ...
 # base_test.c:54:inconsistent_attr:Expected ENOMSG (42) == errno (22)
 # inconsistent_attr: Test terminated by assertion
 #          FAIL  global.inconsistent_attr
not ok 1 global.inconsistent_attr

LCOV - code coverage report:
            Hit  Total  Coverage
Lines:      952  1010    94.3 %
Functions:  79   82      96.3 %

Previous versions:
v5: https://lore.kernel.org/linux-security-module/20220516152038.39594-1-konstantin.meskhidze@huawei.com
v4: https://lore.kernel.org/linux-security-module/20220309134459.6448-1-konstantin.meskhidze@huawei.com/
v3: https://lore.kernel.org/linux-security-module/20220124080215.265538-1-konstantin.meskhidze@huawei.com/
v2: https://lore.kernel.org/linux-security-module/20211228115212.703084-1-konstantin.meskhidze@huawei.com/
v1: https://lore.kernel.org/linux-security-module/20211210072123.386713-1-konstantin.meskhidze@huawei.com/

Konstantin Meskhidze (17):
  landlock: renames access mask
  landlock: refactors landlock_find/insert_rule
  landlock: refactors merge and inherit functions
  landlock: moves helper functions
  landlock: refactors helper functions
  landlock: refactors landlock_add_rule syscall
  landlock: user space API network support
  landlock: adds support network rules
  landlock: implements TCP network hooks
  seltests/landlock: moves helper function
  seltests/landlock: adds tests for bind() hooks
  seltests/landlock: adds tests for connect() hooks
  seltests/landlock: adds AF_UNSPEC family test
  seltests/landlock: adds rules overlapping test
  seltests/landlock: adds ruleset expanding test
  seltests/landlock: adds invalid input data test
  samples/landlock: adds network demo

 include/uapi/linux/landlock.h               |  49 ++
 samples/landlock/sandboxer.c                | 118 ++-
 security/landlock/Kconfig                   |   1 +
 security/landlock/Makefile                  |   2 +
 security/landlock/fs.c                      | 162 +---
 security/landlock/limits.h                  |   8 +-
 security/landlock/net.c                     | 155 ++++
 security/landlock/net.h                     |  26 +
 security/landlock/ruleset.c                 | 448 +++++++++--
 security/landlock/ruleset.h                 |  91 ++-
 security/landlock/setup.c                   |   2 +
 security/landlock/syscalls.c                | 168 +++--
 tools/testing/selftests/landlock/common.h   |  10 +
 tools/testing/selftests/landlock/config     |   4 +
 tools/testing/selftests/landlock/fs_test.c  |  10 -
 tools/testing/selftests/landlock/net_test.c | 774 ++++++++++++++++++++
 16 files changed, 1737 insertions(+), 291 deletions(-)
 create mode 100644 security/landlock/net.c
 create mode 100644 security/landlock/net.h
 create mode 100644 tools/testing/selftests/landlock/net_test.c

--
2.25.1


^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH v6 01/17] landlock: renames access mask
  2022-06-21  8:22 [PATCH v6 00/17] Network support for Landlock Konstantin Meskhidze
@ 2022-06-21  8:22 ` Konstantin Meskhidze
  2022-07-01 17:08   ` Mickaël Salaün
  2022-06-21  8:22 ` [PATCH v6 02/17] landlock: refactors landlock_find/insert_rule Konstantin Meskhidze
                   ` (16 subsequent siblings)
  17 siblings, 1 reply; 53+ messages in thread
From: Konstantin Meskhidze @ 2022-06-21  8:22 UTC (permalink / raw)
  To: mic
  Cc: willemdebruijn.kernel, linux-security-module, netdev,
	netfilter-devel, yusongping, anton.sirazetdinov

To support network type rules,
this modification extends and renames
ruleset's access masks.
This patch adds filesystem helper functions
to set and get filesystem mask. Also the
modification adds a helper structure
landlock_access_mask to support managing
multiple access mask.

Signed-off-by: Konstantin Meskhidze <konstantin.meskhidze@huawei.com>
---

Changes since v5:
* Changes access_mask_t to u32.
* Formats code with clang-format-14.

Changes since v4:
* Deletes struct landlock_access_mask.

Changes since v3:
* Splits commit.
* Adds get_mask, set_mask helpers for filesystem.
* Adds new struct landlock_access_mask.

---
 security/landlock/fs.c       |  7 ++++---
 security/landlock/ruleset.c  | 18 +++++++++---------
 security/landlock/ruleset.h  | 25 ++++++++++++++++++++-----
 security/landlock/syscalls.c |  7 ++++---
 4 files changed, 37 insertions(+), 20 deletions(-)

diff --git a/security/landlock/fs.c b/security/landlock/fs.c
index ec5a6247cd3e..e6da08ed99d1 100644
--- a/security/landlock/fs.c
+++ b/security/landlock/fs.c
@@ -167,7 +167,8 @@ int landlock_append_fs_rule(struct landlock_ruleset *const ruleset,
 		return -EINVAL;

 	/* Transforms relative access rights to absolute ones. */
-	access_rights |= LANDLOCK_MASK_ACCESS_FS & ~ruleset->fs_access_masks[0];
+	access_rights |= LANDLOCK_MASK_ACCESS_FS &
+			 ~landlock_get_fs_access_mask(ruleset, 0);
 	object = get_inode_object(d_backing_inode(path->dentry));
 	if (IS_ERR(object))
 		return PTR_ERR(object);
@@ -286,7 +287,7 @@ get_handled_accesses(const struct landlock_ruleset *const domain)

 		for (layer_level = 0; layer_level < domain->num_layers;
 		     layer_level++) {
-			if (domain->fs_access_masks[layer_level] &
+			if (landlock_get_fs_access_mask(domain, layer_level) &
 			    BIT_ULL(access_bit)) {
 				access_dom |= BIT_ULL(access_bit);
 				break;
@@ -316,7 +317,7 @@ init_layer_masks(const struct landlock_ruleset *const domain,

 		for_each_set_bit(access_bit, &access_req,
 				 ARRAY_SIZE(*layer_masks)) {
-			if (domain->fs_access_masks[layer_level] &
+			if (landlock_get_fs_access_mask(domain, layer_level) &
 			    BIT_ULL(access_bit)) {
 				(*layer_masks)[access_bit] |=
 					BIT_ULL(layer_level);
diff --git a/security/landlock/ruleset.c b/security/landlock/ruleset.c
index 996484f98bfd..a3fd58d01f09 100644
--- a/security/landlock/ruleset.c
+++ b/security/landlock/ruleset.c
@@ -29,7 +29,7 @@ static struct landlock_ruleset *create_ruleset(const u32 num_layers)
 	struct landlock_ruleset *new_ruleset;

 	new_ruleset =
-		kzalloc(struct_size(new_ruleset, fs_access_masks, num_layers),
+		kzalloc(struct_size(new_ruleset, access_masks, num_layers),
 			GFP_KERNEL_ACCOUNT);
 	if (!new_ruleset)
 		return ERR_PTR(-ENOMEM);
@@ -40,22 +40,22 @@ static struct landlock_ruleset *create_ruleset(const u32 num_layers)
 	/*
 	 * hierarchy = NULL
 	 * num_rules = 0
-	 * fs_access_masks[] = 0
+	 * access_masks[] = 0
 	 */
 	return new_ruleset;
 }

 struct landlock_ruleset *
-landlock_create_ruleset(const access_mask_t fs_access_mask)
+landlock_create_ruleset(const access_mask_t access_mask)
 {
 	struct landlock_ruleset *new_ruleset;

 	/* Informs about useless ruleset. */
-	if (!fs_access_mask)
+	if (!access_mask)
 		return ERR_PTR(-ENOMSG);
 	new_ruleset = create_ruleset(1);
 	if (!IS_ERR(new_ruleset))
-		new_ruleset->fs_access_masks[0] = fs_access_mask;
+		landlock_set_fs_access_mask(new_ruleset, access_mask, 0);
 	return new_ruleset;
 }

@@ -117,7 +117,7 @@ static void build_check_ruleset(void)
 		.num_rules = ~0,
 		.num_layers = ~0,
 	};
-	typeof(ruleset.fs_access_masks[0]) fs_access_mask = ~0;
+	typeof(ruleset.access_masks[0]) fs_access_mask = ~0;

 	BUILD_BUG_ON(ruleset.num_rules < LANDLOCK_MAX_NUM_RULES);
 	BUILD_BUG_ON(ruleset.num_layers < LANDLOCK_MAX_NUM_LAYERS);
@@ -281,7 +281,7 @@ static int merge_ruleset(struct landlock_ruleset *const dst,
 		err = -EINVAL;
 		goto out_unlock;
 	}
-	dst->fs_access_masks[dst->num_layers - 1] = src->fs_access_masks[0];
+	dst->access_masks[dst->num_layers - 1] = src->access_masks[0];

 	/* Merges the @src tree. */
 	rbtree_postorder_for_each_entry_safe(walker_rule, next_rule, &src->root,
@@ -340,8 +340,8 @@ static int inherit_ruleset(struct landlock_ruleset *const parent,
 		goto out_unlock;
 	}
 	/* Copies the parent layer stack and leaves a space for the new layer. */
-	memcpy(child->fs_access_masks, parent->fs_access_masks,
-	       flex_array_size(parent, fs_access_masks, parent->num_layers));
+	memcpy(child->access_masks, parent->access_masks,
+	       flex_array_size(parent, access_masks, parent->num_layers));

 	if (WARN_ON_ONCE(!parent->hierarchy)) {
 		err = -EINVAL;
diff --git a/security/landlock/ruleset.h b/security/landlock/ruleset.h
index d43231b783e4..bd7ab39859bf 100644
--- a/security/landlock/ruleset.h
+++ b/security/landlock/ruleset.h
@@ -19,7 +19,7 @@
 #include "limits.h"
 #include "object.h"

-typedef u16 access_mask_t;
+typedef u32 access_mask_t;
 /* Makes sure all filesystem access rights can be stored. */
 static_assert(BITS_PER_TYPE(access_mask_t) >= LANDLOCK_NUM_ACCESS_FS);
 /* Makes sure for_each_set_bit() and for_each_clear_bit() calls are OK. */
@@ -110,7 +110,7 @@ struct landlock_ruleset {
 		 * section.  This is only used by
 		 * landlock_put_ruleset_deferred() when @usage reaches zero.
 		 * The fields @lock, @usage, @num_rules, @num_layers and
-		 * @fs_access_masks are then unused.
+		 * @access_masks are then unused.
 		 */
 		struct work_struct work_free;
 		struct {
@@ -137,7 +137,7 @@ struct landlock_ruleset {
 			 */
 			u32 num_layers;
 			/**
-			 * @fs_access_masks: Contains the subset of filesystem
+			 * @access_masks: Contains the subset of filesystem
 			 * actions that are restricted by a ruleset.  A domain
 			 * saves all layers of merged rulesets in a stack
 			 * (FAM), starting from the first layer to the last
@@ -148,13 +148,13 @@ struct landlock_ruleset {
 			 * layers are set once and never changed for the
 			 * lifetime of the ruleset.
 			 */
-			access_mask_t fs_access_masks[];
+			access_mask_t access_masks[];
 		};
 	};
 };

 struct landlock_ruleset *
-landlock_create_ruleset(const access_mask_t fs_access_mask);
+landlock_create_ruleset(const access_mask_t access_mask);

 void landlock_put_ruleset(struct landlock_ruleset *const ruleset);
 void landlock_put_ruleset_deferred(struct landlock_ruleset *const ruleset);
@@ -177,4 +177,19 @@ static inline void landlock_get_ruleset(struct landlock_ruleset *const ruleset)
 		refcount_inc(&ruleset->usage);
 }

+/* A helper function to set a filesystem mask. */
+static inline void
+landlock_set_fs_access_mask(struct landlock_ruleset *ruleset,
+			    const access_mask_t access_maskset, u16 mask_level)
+{
+	ruleset->access_masks[mask_level] = access_maskset;
+}
+
+/* A helper function to get a filesystem mask. */
+static inline u32
+landlock_get_fs_access_mask(const struct landlock_ruleset *ruleset,
+			    u16 mask_level)
+{
+	return ruleset->access_masks[mask_level];
+}
 #endif /* _SECURITY_LANDLOCK_RULESET_H */
diff --git a/security/landlock/syscalls.c b/security/landlock/syscalls.c
index 735a0865ea11..5836736ce9d7 100644
--- a/security/landlock/syscalls.c
+++ b/security/landlock/syscalls.c
@@ -346,10 +346,11 @@ SYSCALL_DEFINE4(landlock_add_rule, const int, ruleset_fd,
 	}
 	/*
 	 * Checks that allowed_access matches the @ruleset constraints
-	 * (ruleset->fs_access_masks[0] is automatically upgraded to 64-bits).
+	 * (ruleset->access_masks[0] is automatically upgraded to 64-bits).
 	 */
-	if ((path_beneath_attr.allowed_access | ruleset->fs_access_masks[0]) !=
-	    ruleset->fs_access_masks[0]) {
+	if ((path_beneath_attr.allowed_access |
+	     landlock_get_fs_access_mask(ruleset, 0)) !=
+	    landlock_get_fs_access_mask(ruleset, 0)) {
 		err = -EINVAL;
 		goto out_put_ruleset;
 	}
--
2.25.1


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v6 02/17] landlock: refactors landlock_find/insert_rule
  2022-06-21  8:22 [PATCH v6 00/17] Network support for Landlock Konstantin Meskhidze
  2022-06-21  8:22 ` [PATCH v6 01/17] landlock: renames access mask Konstantin Meskhidze
@ 2022-06-21  8:22 ` Konstantin Meskhidze
  2022-07-07 16:44   ` Mickaël Salaün
  2022-07-07 16:46   ` Mickaël Salaün
  2022-06-21  8:22 ` [PATCH v6 03/17] landlock: refactors merge and inherit functions Konstantin Meskhidze
                   ` (15 subsequent siblings)
  17 siblings, 2 replies; 53+ messages in thread
From: Konstantin Meskhidze @ 2022-06-21  8:22 UTC (permalink / raw)
  To: mic
  Cc: willemdebruijn.kernel, linux-security-module, netdev,
	netfilter-devel, yusongping, anton.sirazetdinov

Adds a new object union to support a socket port
rule type. Refactors landlock_insert_rule() and
landlock_find_rule() to support coming network
modifications. Now adding or searching a rule
in a ruleset depends on a rule_type argument
provided in refactored functions mentioned above.

Signed-off-by: Konstantin Meskhidze <konstantin.meskhidze@huawei.com>
---

Changes since v5:
* Formats code with clang-format-14.

Changes since v4:
* Refactors insert_rule() and create_rule() functions by deleting
rule_type from their arguments list, it helps to reduce useless code.

Changes since v3:
* Splits commit.
* Refactors landlock_insert_rule and landlock_find_rule functions.
* Rename new_ruleset->root_inode.

---
 security/landlock/fs.c      |   7 ++-
 security/landlock/ruleset.c | 105 ++++++++++++++++++++++++++----------
 security/landlock/ruleset.h |  27 +++++-----
 3 files changed, 96 insertions(+), 43 deletions(-)

diff --git a/security/landlock/fs.c b/security/landlock/fs.c
index e6da08ed99d1..46aedc2a05a8 100644
--- a/security/landlock/fs.c
+++ b/security/landlock/fs.c
@@ -173,7 +173,8 @@ int landlock_append_fs_rule(struct landlock_ruleset *const ruleset,
 	if (IS_ERR(object))
 		return PTR_ERR(object);
 	mutex_lock(&ruleset->lock);
-	err = landlock_insert_rule(ruleset, object, access_rights);
+	err = landlock_insert_rule(ruleset, object, 0, access_rights,
+				   LANDLOCK_RULE_PATH_BENEATH);
 	mutex_unlock(&ruleset->lock);
 	/*
 	 * No need to check for an error because landlock_insert_rule()
@@ -204,7 +205,9 @@ find_rule(const struct landlock_ruleset *const domain,
 	inode = d_backing_inode(dentry);
 	rcu_read_lock();
 	rule = landlock_find_rule(
-		domain, rcu_dereference(landlock_inode(inode)->object));
+		domain,
+		(uintptr_t)rcu_dereference(landlock_inode(inode)->object),
+		LANDLOCK_RULE_PATH_BENEATH);
 	rcu_read_unlock();
 	return rule;
 }
diff --git a/security/landlock/ruleset.c b/security/landlock/ruleset.c
index a3fd58d01f09..5f13f8a12aee 100644
--- a/security/landlock/ruleset.c
+++ b/security/landlock/ruleset.c
@@ -35,7 +35,7 @@ static struct landlock_ruleset *create_ruleset(const u32 num_layers)
 		return ERR_PTR(-ENOMEM);
 	refcount_set(&new_ruleset->usage, 1);
 	mutex_init(&new_ruleset->lock);
-	new_ruleset->root = RB_ROOT;
+	new_ruleset->root_inode = RB_ROOT;
 	new_ruleset->num_layers = num_layers;
 	/*
 	 * hierarchy = NULL
@@ -69,7 +69,8 @@ static void build_check_rule(void)
 }

 static struct landlock_rule *
-create_rule(struct landlock_object *const object,
+create_rule(struct landlock_object *const object_ptr,
+	    const uintptr_t object_data,
 	    const struct landlock_layer (*const layers)[], const u32 num_layers,
 	    const struct landlock_layer *const new_layer)
 {
@@ -90,8 +91,15 @@ create_rule(struct landlock_object *const object,
 	if (!new_rule)
 		return ERR_PTR(-ENOMEM);
 	RB_CLEAR_NODE(&new_rule->node);
-	landlock_get_object(object);
-	new_rule->object = object;
+
+	if (object_ptr) {
+		landlock_get_object(object_ptr);
+		new_rule->object.ptr = object_ptr;
+	} else if (object_ptr && object_data) {
+		WARN_ON_ONCE(1);
+		return ERR_PTR(-EINVAL);
+	}
+
 	new_rule->num_layers = new_num_layers;
 	/* Copies the original layer stack. */
 	memcpy(new_rule->layers, layers,
@@ -107,7 +115,7 @@ static void free_rule(struct landlock_rule *const rule)
 	might_sleep();
 	if (!rule)
 		return;
-	landlock_put_object(rule->object);
+	landlock_put_object(rule->object.ptr);
 	kfree(rule);
 }

@@ -143,26 +151,42 @@ static void build_check_ruleset(void)
  * access rights.
  */
 static int insert_rule(struct landlock_ruleset *const ruleset,
-		       struct landlock_object *const object,
+		       struct landlock_object *const object_ptr,
+		       uintptr_t object_data, u16 rule_type,
 		       const struct landlock_layer (*const layers)[],
 		       size_t num_layers)
 {
 	struct rb_node **walker_node;
 	struct rb_node *parent_node = NULL;
 	struct landlock_rule *new_rule;
+	struct rb_root *root;

 	might_sleep();
 	lockdep_assert_held(&ruleset->lock);
-	if (WARN_ON_ONCE(!object || !layers))
+	if (WARN_ON_ONCE(!layers))
 		return -ENOENT;
-	walker_node = &(ruleset->root.rb_node);
+	if (WARN_ON_ONCE(object_ptr && object_data))
+		return -EINVAL;
+	/* Chooses rb_tree structure depending on a rule type. */
+	switch (rule_type) {
+	case LANDLOCK_RULE_PATH_BENEATH:
+		if (WARN_ON_ONCE(!object_ptr))
+			return -ENOENT;
+		object_data = (uintptr_t)object_ptr;
+		root = &ruleset->root_inode;
+		break;
+	default:
+		WARN_ON_ONCE(1);
+		return -EINVAL;
+	}
+	walker_node = &root->rb_node;
 	while (*walker_node) {
 		struct landlock_rule *const this =
 			rb_entry(*walker_node, struct landlock_rule, node);

-		if (this->object != object) {
+		if (this->object.data != object_data) {
 			parent_node = *walker_node;
-			if (this->object < object)
+			if (this->object.data < object_data)
 				walker_node = &((*walker_node)->rb_right);
 			else
 				walker_node = &((*walker_node)->rb_left);
@@ -194,11 +218,16 @@ static int insert_rule(struct landlock_ruleset *const ruleset,
 		 * Intersects access rights when it is a merge between a
 		 * ruleset and a domain.
 		 */
-		new_rule = create_rule(object, &this->layers, this->num_layers,
-				       &(*layers)[0]);
+		switch (rule_type) {
+		case LANDLOCK_RULE_PATH_BENEATH:
+			new_rule = create_rule(object_ptr, 0, &this->layers,
+					       this->num_layers, &(*layers)[0]);
+			break;
+		}
 		if (IS_ERR(new_rule))
 			return PTR_ERR(new_rule);
-		rb_replace_node(&this->node, &new_rule->node, &ruleset->root);
+		rb_replace_node(&this->node, &new_rule->node,
+				&ruleset->root_inode);
 		free_rule(this);
 		return 0;
 	}
@@ -207,11 +236,15 @@ static int insert_rule(struct landlock_ruleset *const ruleset,
 	build_check_ruleset();
 	if (ruleset->num_rules >= LANDLOCK_MAX_NUM_RULES)
 		return -E2BIG;
-	new_rule = create_rule(object, layers, num_layers, NULL);
+	switch (rule_type) {
+	case LANDLOCK_RULE_PATH_BENEATH:
+		new_rule = create_rule(object_ptr, 0, layers, num_layers, NULL);
+		break;
+	}
 	if (IS_ERR(new_rule))
 		return PTR_ERR(new_rule);
 	rb_link_node(&new_rule->node, parent_node, walker_node);
-	rb_insert_color(&new_rule->node, &ruleset->root);
+	rb_insert_color(&new_rule->node, &ruleset->root_inode);
 	ruleset->num_rules++;
 	return 0;
 }
@@ -229,8 +262,9 @@ static void build_check_layer(void)

 /* @ruleset must be locked by the caller. */
 int landlock_insert_rule(struct landlock_ruleset *const ruleset,
-			 struct landlock_object *const object,
-			 const access_mask_t access)
+			 struct landlock_object *const object_ptr,
+			 const uintptr_t object_data,
+			 const access_mask_t access, const u16 rule_type)
 {
 	struct landlock_layer layers[] = { {
 		.access = access,
@@ -239,7 +273,8 @@ int landlock_insert_rule(struct landlock_ruleset *const ruleset,
 	} };

 	build_check_layer();
-	return insert_rule(ruleset, object, &layers, ARRAY_SIZE(layers));
+	return insert_rule(ruleset, object_ptr, object_data, rule_type, &layers,
+			   ARRAY_SIZE(layers));
 }

 static inline void get_hierarchy(struct landlock_hierarchy *const hierarchy)
@@ -284,8 +319,8 @@ static int merge_ruleset(struct landlock_ruleset *const dst,
 	dst->access_masks[dst->num_layers - 1] = src->access_masks[0];

 	/* Merges the @src tree. */
-	rbtree_postorder_for_each_entry_safe(walker_rule, next_rule, &src->root,
-					     node) {
+	rbtree_postorder_for_each_entry_safe(walker_rule, next_rule,
+					     &src->root_inode, node) {
 		struct landlock_layer layers[] = { {
 			.level = dst->num_layers,
 		} };
@@ -299,7 +334,8 @@ static int merge_ruleset(struct landlock_ruleset *const dst,
 			goto out_unlock;
 		}
 		layers[0].access = walker_rule->layers[0].access;
-		err = insert_rule(dst, walker_rule->object, &layers,
+		err = insert_rule(dst, walker_rule->object.ptr, 0,
+				  LANDLOCK_RULE_PATH_BENEATH, &layers,
 				  ARRAY_SIZE(layers));
 		if (err)
 			goto out_unlock;
@@ -327,8 +363,9 @@ static int inherit_ruleset(struct landlock_ruleset *const parent,

 	/* Copies the @parent tree. */
 	rbtree_postorder_for_each_entry_safe(walker_rule, next_rule,
-					     &parent->root, node) {
-		err = insert_rule(child, walker_rule->object,
+					     &parent->root_inode, node) {
+		err = insert_rule(child, walker_rule->object.ptr, 0,
+				  LANDLOCK_RULE_PATH_BENEATH,
 				  &walker_rule->layers,
 				  walker_rule->num_layers);
 		if (err)
@@ -361,7 +398,8 @@ static void free_ruleset(struct landlock_ruleset *const ruleset)
 	struct landlock_rule *freeme, *next;

 	might_sleep();
-	rbtree_postorder_for_each_entry_safe(freeme, next, &ruleset->root, node)
+	rbtree_postorder_for_each_entry_safe(freeme, next, &ruleset->root_inode,
+					     node)
 		free_rule(freeme);
 	put_hierarchy(ruleset->hierarchy);
 	kfree(ruleset);
@@ -453,20 +491,29 @@ landlock_merge_ruleset(struct landlock_ruleset *const parent,
  */
 const struct landlock_rule *
 landlock_find_rule(const struct landlock_ruleset *const ruleset,
-		   const struct landlock_object *const object)
+		   const uintptr_t object_data, const u16 rule_type)
 {
 	const struct rb_node *node;

-	if (!object)
+	if (!object_data)
 		return NULL;
-	node = ruleset->root.rb_node;
+
+	switch (rule_type) {
+	case LANDLOCK_RULE_PATH_BENEATH:
+		node = ruleset->root_inode.rb_node;
+		break;
+	default:
+		WARN_ON_ONCE(1);
+		return NULL;
+	}
+
 	while (node) {
 		struct landlock_rule *this =
 			rb_entry(node, struct landlock_rule, node);

-		if (this->object == object)
+		if (this->object.data == object_data)
 			return this;
-		if (this->object < object)
+		if (this->object.data < object_data)
 			node = node->rb_right;
 		else
 			node = node->rb_left;
diff --git a/security/landlock/ruleset.h b/security/landlock/ruleset.h
index bd7ab39859bf..a22d132c32a7 100644
--- a/security/landlock/ruleset.h
+++ b/security/landlock/ruleset.h
@@ -53,15 +53,17 @@ struct landlock_rule {
 	 */
 	struct rb_node node;
 	/**
-	 * @object: Pointer to identify a kernel object (e.g. an inode).  This
-	 * is used as a key for this ruleset element.  This pointer is set once
-	 * and never modified.  It always points to an allocated object because
-	 * each rule increments the refcount of its object.
-	 */
-	struct landlock_object *object;
-	/**
-	 * @num_layers: Number of entries in @layers.
+	 * @object: A union to identify either a kernel object (e.g. an inode) or
+	 * a raw data value (e.g. a network socket port). This is used as a key
+	 * for this ruleset element. This pointer/@object.ptr/ is set once and
+	 * never modified. It always points to an allocated object because each
+	 * rule increments the refcount of its object (for inodes).;
 	 */
+	union {
+		struct landlock_object *ptr;
+		uintptr_t data;
+	} object;
+
 	u32 num_layers;
 	/**
 	 * @layers: Stack of layers, from the latest to the newest, implemented
@@ -98,7 +100,7 @@ struct landlock_ruleset {
 	 * nodes.  Once a ruleset is tied to a process (i.e. as a domain), this
 	 * tree is immutable until @usage reaches zero.
 	 */
-	struct rb_root root;
+	struct rb_root root_inode;
 	/**
 	 * @hierarchy: Enables hierarchy identification even when a parent
 	 * domain vanishes.  This is needed for the ptrace protection.
@@ -160,8 +162,9 @@ void landlock_put_ruleset(struct landlock_ruleset *const ruleset);
 void landlock_put_ruleset_deferred(struct landlock_ruleset *const ruleset);

 int landlock_insert_rule(struct landlock_ruleset *const ruleset,
-			 struct landlock_object *const object,
-			 const access_mask_t access);
+			 struct landlock_object *const object_ptr,
+			 const uintptr_t object_data,
+			 const access_mask_t access, const u16 rule_type);

 struct landlock_ruleset *
 landlock_merge_ruleset(struct landlock_ruleset *const parent,
@@ -169,7 +172,7 @@ landlock_merge_ruleset(struct landlock_ruleset *const parent,

 const struct landlock_rule *
 landlock_find_rule(const struct landlock_ruleset *const ruleset,
-		   const struct landlock_object *const object);
+		   const uintptr_t object_data, const u16 rule_type);

 static inline void landlock_get_ruleset(struct landlock_ruleset *const ruleset)
 {
--
2.25.1


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v6 03/17] landlock: refactors merge and inherit functions
  2022-06-21  8:22 [PATCH v6 00/17] Network support for Landlock Konstantin Meskhidze
  2022-06-21  8:22 ` [PATCH v6 01/17] landlock: renames access mask Konstantin Meskhidze
  2022-06-21  8:22 ` [PATCH v6 02/17] landlock: refactors landlock_find/insert_rule Konstantin Meskhidze
@ 2022-06-21  8:22 ` Konstantin Meskhidze
  2022-06-21  8:23 ` [PATCH v6 04/17] landlock: moves helper functions Konstantin Meskhidze
                   ` (14 subsequent siblings)
  17 siblings, 0 replies; 53+ messages in thread
From: Konstantin Meskhidze @ 2022-06-21  8:22 UTC (permalink / raw)
  To: mic
  Cc: willemdebruijn.kernel, linux-security-module, netdev,
	netfilter-devel, yusongping, anton.sirazetdinov

Refactors merge_ruleset() and inherit_ruleset()
functions to support new rule types. This patch adds
tree_merge() and tree_copy() helpers. Each has
rule_type argument to choose a particular rb_tree
structure in a ruleset.

Signed-off-by: Konstantin Meskhidze <konstantin.meskhidze@huawei.com>
---

Changes since v5:
* Refactors some logic errors.
* Formats code with clang-format-14.

Changes since v4:
* None

---
 security/landlock/ruleset.c | 153 +++++++++++++++++++++++++-----------
 1 file changed, 105 insertions(+), 48 deletions(-)

diff --git a/security/landlock/ruleset.c b/security/landlock/ruleset.c
index 5f13f8a12aee..820b6e6a4496 100644
--- a/security/landlock/ruleset.c
+++ b/security/landlock/ruleset.c
@@ -110,12 +110,16 @@ create_rule(struct landlock_object *const object_ptr,
 	return new_rule;
 }

-static void free_rule(struct landlock_rule *const rule)
+static void free_rule(struct landlock_rule *const rule, const u16 rule_type)
 {
 	might_sleep();
 	if (!rule)
 		return;
-	landlock_put_object(rule->object.ptr);
+	switch (rule_type) {
+	case LANDLOCK_RULE_PATH_BENEATH:
+		landlock_put_object(rule->object.ptr);
+		break;
+	}
 	kfree(rule);
 }

@@ -222,13 +226,13 @@ static int insert_rule(struct landlock_ruleset *const ruleset,
 		case LANDLOCK_RULE_PATH_BENEATH:
 			new_rule = create_rule(object_ptr, 0, &this->layers,
 					       this->num_layers, &(*layers)[0]);
+			if (IS_ERR(new_rule))
+				return PTR_ERR(new_rule);
+			rb_replace_node(&this->node, &new_rule->node,
+					&ruleset->root_inode);
+			free_rule(this, rule_type);
 			break;
 		}
-		if (IS_ERR(new_rule))
-			return PTR_ERR(new_rule);
-		rb_replace_node(&this->node, &new_rule->node,
-				&ruleset->root_inode);
-		free_rule(this);
 		return 0;
 	}

@@ -239,13 +243,13 @@ static int insert_rule(struct landlock_ruleset *const ruleset,
 	switch (rule_type) {
 	case LANDLOCK_RULE_PATH_BENEATH:
 		new_rule = create_rule(object_ptr, 0, layers, num_layers, NULL);
+		if (IS_ERR(new_rule))
+			return PTR_ERR(new_rule);
+		rb_link_node(&new_rule->node, parent_node, walker_node);
+		rb_insert_color(&new_rule->node, &ruleset->root_inode);
+		ruleset->num_rules++;
 		break;
 	}
-	if (IS_ERR(new_rule))
-		return PTR_ERR(new_rule);
-	rb_link_node(&new_rule->node, parent_node, walker_node);
-	rb_insert_color(&new_rule->node, &ruleset->root_inode);
-	ruleset->num_rules++;
 	return 0;
 }

@@ -293,10 +297,54 @@ static void put_hierarchy(struct landlock_hierarchy *hierarchy)
 	}
 }

+static int tree_merge(struct landlock_ruleset *const src,
+		      struct landlock_ruleset *const dst, u16 rule_type)
+{
+	struct landlock_rule *walker_rule, *next_rule;
+	struct rb_root *src_root;
+	int err = 0;
+
+	/* Chooses rb_tree structure depending on a rule type. */
+	switch (rule_type) {
+	case LANDLOCK_RULE_PATH_BENEATH:
+		src_root = &src->root_inode;
+		break;
+	default:
+		return -EINVAL;
+	}
+	/* Merges the @src tree. */
+	rbtree_postorder_for_each_entry_safe(walker_rule, next_rule, src_root,
+					     node) {
+		struct landlock_layer layers[] = { {
+			.level = dst->num_layers,
+		} };
+
+		if (WARN_ON_ONCE(walker_rule->num_layers != 1)) {
+			err = -EINVAL;
+			return err;
+		}
+		if (WARN_ON_ONCE(walker_rule->layers[0].level != 0)) {
+			err = -EINVAL;
+			return err;
+		}
+		layers[0].access = walker_rule->layers[0].access;
+
+		switch (rule_type) {
+		case LANDLOCK_RULE_PATH_BENEATH:
+			err = insert_rule(dst, walker_rule->object.ptr, 0,
+					  rule_type, &layers,
+					  ARRAY_SIZE(layers));
+			break;
+		}
+		if (err)
+			return err;
+	}
+	return err;
+}
+
 static int merge_ruleset(struct landlock_ruleset *const dst,
 			 struct landlock_ruleset *const src)
 {
-	struct landlock_rule *walker_rule, *next_rule;
 	int err = 0;

 	might_sleep();
@@ -318,28 +366,10 @@ static int merge_ruleset(struct landlock_ruleset *const dst,
 	}
 	dst->access_masks[dst->num_layers - 1] = src->access_masks[0];

-	/* Merges the @src tree. */
-	rbtree_postorder_for_each_entry_safe(walker_rule, next_rule,
-					     &src->root_inode, node) {
-		struct landlock_layer layers[] = { {
-			.level = dst->num_layers,
-		} };
-
-		if (WARN_ON_ONCE(walker_rule->num_layers != 1)) {
-			err = -EINVAL;
-			goto out_unlock;
-		}
-		if (WARN_ON_ONCE(walker_rule->layers[0].level != 0)) {
-			err = -EINVAL;
-			goto out_unlock;
-		}
-		layers[0].access = walker_rule->layers[0].access;
-		err = insert_rule(dst, walker_rule->object.ptr, 0,
-				  LANDLOCK_RULE_PATH_BENEATH, &layers,
-				  ARRAY_SIZE(layers));
-		if (err)
-			goto out_unlock;
-	}
+	/* Merges the @src inode tree. */
+	err = tree_merge(src, dst, LANDLOCK_RULE_PATH_BENEATH);
+	if (err)
+		goto out_unlock;

 out_unlock:
 	mutex_unlock(&src->lock);
@@ -347,10 +377,40 @@ static int merge_ruleset(struct landlock_ruleset *const dst,
 	return err;
 }

+static int tree_copy(struct landlock_ruleset *const parent,
+		     struct landlock_ruleset *const child, u16 rule_type)
+{
+	struct landlock_rule *walker_rule, *next_rule;
+	struct rb_root *parent_root;
+	int err = 0;
+
+	/* Chooses rb_tree structure depending on a rule type. */
+	switch (rule_type) {
+	case LANDLOCK_RULE_PATH_BENEATH:
+		parent_root = &parent->root_inode;
+		break;
+	default:
+		return -EINVAL;
+	}
+	/* Copies the @parent inode tree. */
+	rbtree_postorder_for_each_entry_safe(walker_rule, next_rule,
+					     parent_root, node) {
+		switch (rule_type) {
+		case LANDLOCK_RULE_PATH_BENEATH:
+			err = insert_rule(child, walker_rule->object.ptr, 0,
+					  rule_type, &walker_rule->layers,
+					  walker_rule->num_layers);
+			break;
+		}
+		if (err)
+			return err;
+	}
+	return err;
+}
+
 static int inherit_ruleset(struct landlock_ruleset *const parent,
 			   struct landlock_ruleset *const child)
 {
-	struct landlock_rule *walker_rule, *next_rule;
 	int err = 0;

 	might_sleep();
@@ -361,22 +421,19 @@ static int inherit_ruleset(struct landlock_ruleset *const parent,
 	mutex_lock(&child->lock);
 	mutex_lock_nested(&parent->lock, SINGLE_DEPTH_NESTING);

-	/* Copies the @parent tree. */
-	rbtree_postorder_for_each_entry_safe(walker_rule, next_rule,
-					     &parent->root_inode, node) {
-		err = insert_rule(child, walker_rule->object.ptr, 0,
-				  LANDLOCK_RULE_PATH_BENEATH,
-				  &walker_rule->layers,
-				  walker_rule->num_layers);
-		if (err)
-			goto out_unlock;
-	}
+	/* Copies the @parent inode tree. */
+	err = tree_copy(parent, child, LANDLOCK_RULE_PATH_BENEATH);
+	if (err)
+		goto out_unlock;

 	if (WARN_ON_ONCE(child->num_layers <= parent->num_layers)) {
 		err = -EINVAL;
 		goto out_unlock;
 	}
-	/* Copies the parent layer stack and leaves a space for the new layer. */
+	/*
+	 * Copies the parent layer stack and leaves a space
+	 * for the new layer.
+	 */
 	memcpy(child->access_masks, parent->access_masks,
 	       flex_array_size(parent, access_masks, parent->num_layers));

@@ -400,7 +457,7 @@ static void free_ruleset(struct landlock_ruleset *const ruleset)
 	might_sleep();
 	rbtree_postorder_for_each_entry_safe(freeme, next, &ruleset->root_inode,
 					     node)
-		free_rule(freeme);
+		free_rule(freeme, LANDLOCK_RULE_PATH_BENEATH);
 	put_hierarchy(ruleset->hierarchy);
 	kfree(ruleset);
 }
--
2.25.1


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v6 04/17] landlock: moves helper functions
  2022-06-21  8:22 [PATCH v6 00/17] Network support for Landlock Konstantin Meskhidze
                   ` (2 preceding siblings ...)
  2022-06-21  8:22 ` [PATCH v6 03/17] landlock: refactors merge and inherit functions Konstantin Meskhidze
@ 2022-06-21  8:23 ` Konstantin Meskhidze
  2022-06-21  8:23 ` [PATCH v6 05/17] landlock: refactors " Konstantin Meskhidze
                   ` (13 subsequent siblings)
  17 siblings, 0 replies; 53+ messages in thread
From: Konstantin Meskhidze @ 2022-06-21  8:23 UTC (permalink / raw)
  To: mic
  Cc: willemdebruijn.kernel, linux-security-module, netdev,
	netfilter-devel, yusongping, anton.sirazetdinov

This patch moves unmask_layers(),
init_layer_masks() and get_handled_accesses()
helpers to ruleset.c to share with
landlock network implementation in following
commits.

Signed-off-by: Konstantin Meskhidze <konstantin.meskhidze@huawei.com>
---

Changes since v5:
* Splits commit.
* Moves init_layer_masks() and get_handled_accesses() helpers
to ruleset.c and makes then non-static.
* Formats code with clang-format-14.

---
 security/landlock/fs.c      | 107 ------------------------------------
 security/landlock/ruleset.c | 105 +++++++++++++++++++++++++++++++++++
 security/landlock/ruleset.h |  12 ++++
 3 files changed, 117 insertions(+), 107 deletions(-)

diff --git a/security/landlock/fs.c b/security/landlock/fs.c
index 46aedc2a05a8..42fb02141b9c 100644
--- a/security/landlock/fs.c
+++ b/security/landlock/fs.c
@@ -212,60 +212,6 @@ find_rule(const struct landlock_ruleset *const domain,
 	return rule;
 }

-/*
- * @layer_masks is read and may be updated according to the access request and
- * the matching rule.
- *
- * Returns true if the request is allowed (i.e. relevant layer masks for the
- * request are empty).
- */
-static inline bool
-unmask_layers(const struct landlock_rule *const rule,
-	      const access_mask_t access_request,
-	      layer_mask_t (*const layer_masks)[LANDLOCK_NUM_ACCESS_FS])
-{
-	size_t layer_level;
-
-	if (!access_request || !layer_masks)
-		return true;
-	if (!rule)
-		return false;
-
-	/*
-	 * An access is granted if, for each policy layer, at least one rule
-	 * encountered on the pathwalk grants the requested access,
-	 * regardless of its position in the layer stack.  We must then check
-	 * the remaining layers for each inode, from the first added layer to
-	 * the last one.  When there is multiple requested accesses, for each
-	 * policy layer, the full set of requested accesses may not be granted
-	 * by only one rule, but by the union (binary OR) of multiple rules.
-	 * E.g. /a/b <execute> + /a <read> => /a/b <execute + read>
-	 */
-	for (layer_level = 0; layer_level < rule->num_layers; layer_level++) {
-		const struct landlock_layer *const layer =
-			&rule->layers[layer_level];
-		const layer_mask_t layer_bit = BIT_ULL(layer->level - 1);
-		const unsigned long access_req = access_request;
-		unsigned long access_bit;
-		bool is_empty;
-
-		/*
-		 * Records in @layer_masks which layer grants access to each
-		 * requested access.
-		 */
-		is_empty = true;
-		for_each_set_bit(access_bit, &access_req,
-				 ARRAY_SIZE(*layer_masks)) {
-			if (layer->access & BIT_ULL(access_bit))
-				(*layer_masks)[access_bit] &= ~layer_bit;
-			is_empty = is_empty && !(*layer_masks)[access_bit];
-		}
-		if (is_empty)
-			return true;
-	}
-	return false;
-}
-
 /*
  * Allows access to pseudo filesystems that will never be mountable (e.g.
  * sockfs, pipefs), but can still be reachable through
@@ -278,59 +224,6 @@ static inline bool is_nouser_or_private(const struct dentry *dentry)
 		unlikely(IS_PRIVATE(d_backing_inode(dentry))));
 }

-static inline access_mask_t
-get_handled_accesses(const struct landlock_ruleset *const domain)
-{
-	access_mask_t access_dom = 0;
-	unsigned long access_bit;
-
-	for (access_bit = 0; access_bit < LANDLOCK_NUM_ACCESS_FS;
-	     access_bit++) {
-		size_t layer_level;
-
-		for (layer_level = 0; layer_level < domain->num_layers;
-		     layer_level++) {
-			if (landlock_get_fs_access_mask(domain, layer_level) &
-			    BIT_ULL(access_bit)) {
-				access_dom |= BIT_ULL(access_bit);
-				break;
-			}
-		}
-	}
-	return access_dom;
-}
-
-static inline access_mask_t
-init_layer_masks(const struct landlock_ruleset *const domain,
-		 const access_mask_t access_request,
-		 layer_mask_t (*const layer_masks)[LANDLOCK_NUM_ACCESS_FS])
-{
-	access_mask_t handled_accesses = 0;
-	size_t layer_level;
-
-	memset(layer_masks, 0, sizeof(*layer_masks));
-	/* An empty access request can happen because of O_WRONLY | O_RDWR. */
-	if (!access_request)
-		return 0;
-
-	/* Saves all handled accesses per layer. */
-	for (layer_level = 0; layer_level < domain->num_layers; layer_level++) {
-		const unsigned long access_req = access_request;
-		unsigned long access_bit;
-
-		for_each_set_bit(access_bit, &access_req,
-				 ARRAY_SIZE(*layer_masks)) {
-			if (landlock_get_fs_access_mask(domain, layer_level) &
-			    BIT_ULL(access_bit)) {
-				(*layer_masks)[access_bit] |=
-					BIT_ULL(layer_level);
-				handled_accesses |= BIT_ULL(access_bit);
-			}
-		}
-	}
-	return handled_accesses;
-}
-
 /*
  * Check that a destination file hierarchy has more restrictions than a source
  * file hierarchy.  This is only used for link and rename actions.
diff --git a/security/landlock/ruleset.c b/security/landlock/ruleset.c
index 820b6e6a4496..32ec79d6559a 100644
--- a/security/landlock/ruleset.c
+++ b/security/landlock/ruleset.c
@@ -577,3 +577,108 @@ landlock_find_rule(const struct landlock_ruleset *const ruleset,
 	}
 	return NULL;
 }
+
+access_mask_t get_handled_accesses(const struct landlock_ruleset *const domain)
+{
+	access_mask_t access_dom = 0;
+	unsigned long access_bit;
+
+	for (access_bit = 0; access_bit < LANDLOCK_NUM_ACCESS_FS;
+	     access_bit++) {
+		size_t layer_level;
+
+		for (layer_level = 0; layer_level < domain->num_layers;
+		     layer_level++) {
+			if (landlock_get_fs_access_mask(domain, layer_level) &
+			    BIT_ULL(access_bit)) {
+				access_dom |= BIT_ULL(access_bit);
+				break;
+			}
+		}
+	}
+	return access_dom;
+}
+
+/*
+ * @layer_masks is read and may be updated according to the access request and
+ * the matching rule.
+ *
+ * Returns true if the request is allowed (i.e. relevant layer masks for the
+ * request are empty).
+ */
+bool unmask_layers(const struct landlock_rule *const rule,
+		   const access_mask_t access_request,
+		   layer_mask_t (*const layer_masks)[LANDLOCK_NUM_ACCESS_FS])
+{
+	size_t layer_level;
+
+	if (!access_request || !layer_masks)
+		return true;
+	if (!rule)
+		return false;
+
+	/*
+	 * An access is granted if, for each policy layer, at least one rule
+	 * encountered on the pathwalk grants the requested access,
+	 * regardless of its position in the layer stack.  We must then check
+	 * the remaining layers for each inode, from the first added layer to
+	 * the last one.  When there is multiple requested accesses, for each
+	 * policy layer, the full set of requested accesses may not be granted
+	 * by only one rule, but by the union (binary OR) of multiple rules.
+	 * E.g. /a/b <execute> + /a <read> => /a/b <execute + read>
+	 */
+	for (layer_level = 0; layer_level < rule->num_layers; layer_level++) {
+		const struct landlock_layer *const layer =
+			&rule->layers[layer_level];
+		const layer_mask_t layer_bit = BIT_ULL(layer->level - 1);
+		const unsigned long access_req = access_request;
+		unsigned long access_bit;
+		bool is_empty;
+
+		/*
+		 * Records in @layer_masks which layer grants access to each
+		 * requested access.
+		 */
+		is_empty = true;
+		for_each_set_bit(access_bit, &access_req,
+				 ARRAY_SIZE(*layer_masks)) {
+			if (layer->access & BIT_ULL(access_bit))
+				(*layer_masks)[access_bit] &= ~layer_bit;
+			is_empty = is_empty && !(*layer_masks)[access_bit];
+		}
+		if (is_empty)
+			return true;
+	}
+	return false;
+}
+
+access_mask_t
+init_layer_masks(const struct landlock_ruleset *const domain,
+		 const access_mask_t access_request,
+		 layer_mask_t (*const layer_masks)[LANDLOCK_NUM_ACCESS_FS])
+{
+	access_mask_t handled_accesses = 0;
+	size_t layer_level;
+
+	memset(layer_masks, 0, sizeof(*layer_masks));
+	/* An empty access request can happen because of O_WRONLY | O_RDWR. */
+	if (!access_request)
+		return 0;
+
+	/* Saves all handled accesses per layer. */
+	for (layer_level = 0; layer_level < domain->num_layers; layer_level++) {
+		const unsigned long access_req = access_request;
+		unsigned long access_bit;
+
+		for_each_set_bit(access_bit, &access_req,
+				 ARRAY_SIZE(*layer_masks)) {
+			if (landlock_get_fs_access_mask(domain, layer_level) &
+			    BIT_ULL(access_bit)) {
+				(*layer_masks)[access_bit] |=
+					BIT_ULL(layer_level);
+				handled_accesses |= BIT_ULL(access_bit);
+			}
+		}
+	}
+	return handled_accesses;
+}
diff --git a/security/landlock/ruleset.h b/security/landlock/ruleset.h
index a22d132c32a7..ea09ab2f27c4 100644
--- a/security/landlock/ruleset.h
+++ b/security/landlock/ruleset.h
@@ -195,4 +195,16 @@ landlock_get_fs_access_mask(const struct landlock_ruleset *ruleset,
 {
 	return ruleset->access_masks[mask_level];
 }
+
+access_mask_t get_handled_accesses(const struct landlock_ruleset *const domain);
+
+bool unmask_layers(const struct landlock_rule *const rule,
+		   const access_mask_t access_request,
+		   layer_mask_t (*const layer_masks)[LANDLOCK_NUM_ACCESS_FS]);
+
+access_mask_t
+init_layer_masks(const struct landlock_ruleset *const domain,
+		 const access_mask_t access_request,
+		 layer_mask_t (*const layer_masks)[LANDLOCK_NUM_ACCESS_FS]);
+
 #endif /* _SECURITY_LANDLOCK_RULESET_H */
--
2.25.1


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v6 05/17] landlock: refactors helper functions
  2022-06-21  8:22 [PATCH v6 00/17] Network support for Landlock Konstantin Meskhidze
                   ` (3 preceding siblings ...)
  2022-06-21  8:23 ` [PATCH v6 04/17] landlock: moves helper functions Konstantin Meskhidze
@ 2022-06-21  8:23 ` Konstantin Meskhidze
  2022-06-21  8:23 ` [PATCH v6 06/17] landlock: refactors landlock_add_rule syscall Konstantin Meskhidze
                   ` (12 subsequent siblings)
  17 siblings, 0 replies; 53+ messages in thread
From: Konstantin Meskhidze @ 2022-06-21  8:23 UTC (permalink / raw)
  To: mic
  Cc: willemdebruijn.kernel, linux-security-module, netdev,
	netfilter-devel, yusongping, anton.sirazetdinov

Adds new rule_type argument to
unmask_layers(), init_layer_masks() and
get_handled_accesses() helper functions.
This modification supports implementing new rule
types in the next landlock versions.

Signed-off-by: Konstantin Meskhidze <konstantin.meskhidze@huawei.com>
---

Changes since v5:
* Splits commit.
* Formats code with clang-format-14.

Changes since v4:
* Refactors init_layer_masks(), get_handled_accesses()
and unmask_layers() functions to support multiple rule types.
* Refactors landlock_get_fs_access_mask() function with
LANDLOCK_MASK_ACCESS_FS mask.

Changes since v3:
* Splits commit.
* Refactors landlock_unmask_layers functions.

---
 security/landlock/fs.c      | 45 ++++++++++++++++---------
 security/landlock/ruleset.c | 67 +++++++++++++++++++++++--------------
 security/landlock/ruleset.h | 16 +++++----
 3 files changed, 80 insertions(+), 48 deletions(-)

diff --git a/security/landlock/fs.c b/security/landlock/fs.c
index 42fb02141b9c..10f6c67f5c3b 100644
--- a/security/landlock/fs.c
+++ b/security/landlock/fs.c
@@ -400,7 +400,8 @@ static int check_access_path_dual(
 		 * a superset of the meaningful requested accesses).
 		 */
 		access_masked_parent1 = access_masked_parent2 =
-			get_handled_accesses(domain);
+			get_handled_accesses(domain, LANDLOCK_RULE_PATH_BENEATH,
+					     LANDLOCK_NUM_ACCESS_FS);
 		is_dom_check = true;
 	} else {
 		if (WARN_ON_ONCE(dentry_child1 || dentry_child2))
@@ -414,16 +415,22 @@ static int check_access_path_dual(
 	if (unlikely(dentry_child1)) {
 		unmask_layers(find_rule(domain, dentry_child1),
 			      init_layer_masks(domain, LANDLOCK_MASK_ACCESS_FS,
-					       &_layer_masks_child1),
-			      &_layer_masks_child1);
+					       &_layer_masks_child1,
+					       sizeof(_layer_masks_child1),
+					       LANDLOCK_RULE_PATH_BENEATH),
+			      &_layer_masks_child1,
+			      ARRAY_SIZE(_layer_masks_child1));
 		layer_masks_child1 = &_layer_masks_child1;
 		child1_is_directory = d_is_dir(dentry_child1);
 	}
 	if (unlikely(dentry_child2)) {
 		unmask_layers(find_rule(domain, dentry_child2),
 			      init_layer_masks(domain, LANDLOCK_MASK_ACCESS_FS,
-					       &_layer_masks_child2),
-			      &_layer_masks_child2);
+					       &_layer_masks_child2,
+					       sizeof(_layer_masks_child2),
+					       LANDLOCK_RULE_PATH_BENEATH),
+			      &_layer_masks_child2,
+			      ARRAY_SIZE(_layer_masks_child2));
 		layer_masks_child2 = &_layer_masks_child2;
 		child2_is_directory = d_is_dir(dentry_child2);
 	}
@@ -475,15 +482,16 @@ static int check_access_path_dual(
 		}

 		rule = find_rule(domain, walker_path.dentry);
-		allowed_parent1 = unmask_layers(rule, access_masked_parent1,
-						layer_masks_parent1);
-		allowed_parent2 = unmask_layers(rule, access_masked_parent2,
-						layer_masks_parent2);
+		allowed_parent1 = unmask_layers(
+			rule, access_masked_parent1, layer_masks_parent1,
+			ARRAY_SIZE(*layer_masks_parent1));
+		allowed_parent2 = unmask_layers(
+			rule, access_masked_parent2, layer_masks_parent2,
+			ARRAY_SIZE(*layer_masks_parent2));

 		/* Stops when a rule from each layer grants access. */
 		if (allowed_parent1 && allowed_parent2)
 			break;
-
 jump_up:
 		if (walker_path.dentry == walker_path.mnt->mnt_root) {
 			if (follow_up(&walker_path)) {
@@ -539,7 +547,9 @@ static inline int check_access_path(const struct landlock_ruleset *const domain,
 {
 	layer_mask_t layer_masks[LANDLOCK_NUM_ACCESS_FS] = {};

-	access_request = init_layer_masks(domain, access_request, &layer_masks);
+	access_request = init_layer_masks(domain, access_request, &layer_masks,
+					  sizeof(layer_masks),
+					  LANDLOCK_RULE_PATH_BENEATH);
 	return check_access_path_dual(domain, path, access_request,
 				      &layer_masks, NULL, 0, NULL, NULL);
 }
@@ -623,7 +633,8 @@ static bool collect_domain_accesses(
 		return true;

 	access_dom = init_layer_masks(domain, LANDLOCK_MASK_ACCESS_FS,
-				      layer_masks_dom);
+				      layer_masks_dom, sizeof(*layer_masks_dom),
+				      LANDLOCK_RULE_PATH_BENEATH);

 	dget(dir);
 	while (true) {
@@ -631,7 +642,8 @@ static bool collect_domain_accesses(

 		/* Gets all layers allowing all domain accesses. */
 		if (unmask_layers(find_rule(domain, dir), access_dom,
-				  layer_masks_dom)) {
+				  layer_masks_dom,
+				  ARRAY_SIZE(*layer_masks_dom))) {
 			/*
 			 * Stops when all handled accesses are allowed by at
 			 * least one rule in each layer.
@@ -747,7 +759,8 @@ static int current_check_refer_path(struct dentry *const old_dentry,
 		 */
 		access_request_parent1 = init_layer_masks(
 			dom, access_request_parent1 | access_request_parent2,
-			&layer_masks_parent1);
+			&layer_masks_parent1, sizeof(layer_masks_parent1),
+			LANDLOCK_RULE_PATH_BENEATH);
 		return check_access_path_dual(dom, new_dir,
 					      access_request_parent1,
 					      &layer_masks_parent1, NULL, 0,
@@ -755,7 +768,9 @@ static int current_check_refer_path(struct dentry *const old_dentry,
 	}

 	/* Backward compatibility: no reparenting support. */
-	if (!(get_handled_accesses(dom) & LANDLOCK_ACCESS_FS_REFER))
+	if (!(get_handled_accesses(dom, LANDLOCK_RULE_PATH_BENEATH,
+				   LANDLOCK_NUM_ACCESS_FS) &
+	      LANDLOCK_ACCESS_FS_REFER))
 		return -EXDEV;

 	access_request_parent1 |= LANDLOCK_ACCESS_FS_REFER;
diff --git a/security/landlock/ruleset.c b/security/landlock/ruleset.c
index 32ec79d6559a..cbca85f5cc6d 100644
--- a/security/landlock/ruleset.c
+++ b/security/landlock/ruleset.c
@@ -578,23 +578,31 @@ landlock_find_rule(const struct landlock_ruleset *const ruleset,
 	return NULL;
 }

-access_mask_t get_handled_accesses(const struct landlock_ruleset *const domain)
+access_mask_t get_handled_accesses(const struct landlock_ruleset *const domain,
+				   u16 rule_type, u16 num_access)
 {
 	access_mask_t access_dom = 0;
 	unsigned long access_bit;

-	for (access_bit = 0; access_bit < LANDLOCK_NUM_ACCESS_FS;
-	     access_bit++) {
-		size_t layer_level;
-
-		for (layer_level = 0; layer_level < domain->num_layers;
-		     layer_level++) {
-			if (landlock_get_fs_access_mask(domain, layer_level) &
-			    BIT_ULL(access_bit)) {
-				access_dom |= BIT_ULL(access_bit);
-				break;
+	switch (rule_type) {
+	case LANDLOCK_RULE_PATH_BENEATH:
+		for (access_bit = 0; access_bit < LANDLOCK_NUM_ACCESS_FS;
+		     access_bit++) {
+			size_t layer_level;
+
+			for (layer_level = 0; layer_level < domain->num_layers;
+			     layer_level++) {
+				if (landlock_get_fs_access_mask(domain,
+								layer_level) &
+				    BIT_ULL(access_bit)) {
+					access_dom |= BIT_ULL(access_bit);
+					break;
+				}
 			}
 		}
+		break;
+	default:
+		break;
 	}
 	return access_dom;
 }
@@ -608,7 +616,7 @@ access_mask_t get_handled_accesses(const struct landlock_ruleset *const domain)
  */
 bool unmask_layers(const struct landlock_rule *const rule,
 		   const access_mask_t access_request,
-		   layer_mask_t (*const layer_masks)[LANDLOCK_NUM_ACCESS_FS])
+		   layer_mask_t (*const layer_masks)[], size_t masks_array_size)
 {
 	size_t layer_level;

@@ -640,8 +648,7 @@ bool unmask_layers(const struct landlock_rule *const rule,
 		 * requested access.
 		 */
 		is_empty = true;
-		for_each_set_bit(access_bit, &access_req,
-				 ARRAY_SIZE(*layer_masks)) {
+		for_each_set_bit(access_bit, &access_req, masks_array_size) {
 			if (layer->access & BIT_ULL(access_bit))
 				(*layer_masks)[access_bit] &= ~layer_bit;
 			is_empty = is_empty && !(*layer_masks)[access_bit];
@@ -652,15 +659,16 @@ bool unmask_layers(const struct landlock_rule *const rule,
 	return false;
 }

-access_mask_t
-init_layer_masks(const struct landlock_ruleset *const domain,
-		 const access_mask_t access_request,
-		 layer_mask_t (*const layer_masks)[LANDLOCK_NUM_ACCESS_FS])
+access_mask_t init_layer_masks(const struct landlock_ruleset *const domain,
+			       const access_mask_t access_request,
+			       layer_mask_t (*const layer_masks)[],
+			       size_t masks_size, u16 rule_type)
 {
 	access_mask_t handled_accesses = 0;
 	size_t layer_level;

-	memset(layer_masks, 0, sizeof(*layer_masks));
+	memset(layer_masks, 0, masks_size);
+
 	/* An empty access request can happen because of O_WRONLY | O_RDWR. */
 	if (!access_request)
 		return 0;
@@ -670,14 +678,21 @@ init_layer_masks(const struct landlock_ruleset *const domain,
 		const unsigned long access_req = access_request;
 		unsigned long access_bit;

-		for_each_set_bit(access_bit, &access_req,
-				 ARRAY_SIZE(*layer_masks)) {
-			if (landlock_get_fs_access_mask(domain, layer_level) &
-			    BIT_ULL(access_bit)) {
-				(*layer_masks)[access_bit] |=
-					BIT_ULL(layer_level);
-				handled_accesses |= BIT_ULL(access_bit);
+		switch (rule_type) {
+		case LANDLOCK_RULE_PATH_BENEATH:
+			for_each_set_bit(access_bit, &access_req,
+					 LANDLOCK_NUM_ACCESS_FS) {
+				if (landlock_get_fs_access_mask(domain,
+								layer_level) &
+				    BIT_ULL(access_bit)) {
+					(*layer_masks)[access_bit] |=
+						BIT_ULL(layer_level);
+					handled_accesses |= BIT_ULL(access_bit);
+				}
 			}
+			break;
+		default:
+			return 0;
 		}
 	}
 	return handled_accesses;
diff --git a/security/landlock/ruleset.h b/security/landlock/ruleset.h
index ea09ab2f27c4..c1cf7cce2cb5 100644
--- a/security/landlock/ruleset.h
+++ b/security/landlock/ruleset.h
@@ -193,18 +193,20 @@ static inline u32
 landlock_get_fs_access_mask(const struct landlock_ruleset *ruleset,
 			    u16 mask_level)
 {
-	return ruleset->access_masks[mask_level];
+	return (ruleset->access_masks[mask_level] & LANDLOCK_MASK_ACCESS_FS);
 }

-access_mask_t get_handled_accesses(const struct landlock_ruleset *const domain);
+access_mask_t get_handled_accesses(const struct landlock_ruleset *const domain,
+				   u16 rule_type, u16 num_access);

 bool unmask_layers(const struct landlock_rule *const rule,
 		   const access_mask_t access_request,
-		   layer_mask_t (*const layer_masks)[LANDLOCK_NUM_ACCESS_FS]);
+		   layer_mask_t (*const layer_masks)[],
+		   size_t masks_array_size);

-access_mask_t
-init_layer_masks(const struct landlock_ruleset *const domain,
-		 const access_mask_t access_request,
-		 layer_mask_t (*const layer_masks)[LANDLOCK_NUM_ACCESS_FS]);
+access_mask_t init_layer_masks(const struct landlock_ruleset *const domain,
+			       const access_mask_t access_request,
+			       layer_mask_t (*const layer_masks)[],
+			       size_t masks_size, u16 rule_type);

 #endif /* _SECURITY_LANDLOCK_RULESET_H */
--
2.25.1


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v6 06/17] landlock: refactors landlock_add_rule syscall
  2022-06-21  8:22 [PATCH v6 00/17] Network support for Landlock Konstantin Meskhidze
                   ` (4 preceding siblings ...)
  2022-06-21  8:23 ` [PATCH v6 05/17] landlock: refactors " Konstantin Meskhidze
@ 2022-06-21  8:23 ` Konstantin Meskhidze
  2022-06-21  8:23 ` [PATCH v6 07/17] landlock: user space API network support Konstantin Meskhidze
                   ` (11 subsequent siblings)
  17 siblings, 0 replies; 53+ messages in thread
From: Konstantin Meskhidze @ 2022-06-21  8:23 UTC (permalink / raw)
  To: mic
  Cc: willemdebruijn.kernel, linux-security-module, netdev,
	netfilter-devel, yusongping, anton.sirazetdinov

Modifies landlock_add_rule syscall to support
new rule types in future Landlock versions.
Adds add_rule_path_beneath() helper to support
current filesystem rules.

Signed-off-by: Konstantin Meskhidze <konstantin.meskhidze@huawei.com>
---

Changes since v5:
* Refactors syscall landlock_add_rule() and
add_rule_path_beneath() helper to make argument
check ordering consistent and get rid of partial
revertings in following patches.
* Rolls back refactoring base_test.c seltest.
* Formats code with clang-format-14.

Changes since v4:
* Refactors add_rule_path_beneath() and landlock_add_rule() functions
to optimize code usage.
* Refactors base_test.c seltest: adds LANDLOCK_RULE_PATH_BENEATH
rule type in landlock_add_rule() call.

Changes since v3:
* Split commit.
* Refactors landlock_add_rule syscall.

---
 security/landlock/syscalls.c | 99 +++++++++++++++++++-----------------
 1 file changed, 52 insertions(+), 47 deletions(-)

diff --git a/security/landlock/syscalls.c b/security/landlock/syscalls.c
index 5836736ce9d7..a209fd7d10c6 100644
--- a/security/landlock/syscalls.c
+++ b/security/landlock/syscalls.c
@@ -274,6 +274,47 @@ static int get_path_from_fd(const s32 fd, struct path *const path)
 	return err;
 }

+static int add_rule_path_beneath(struct landlock_ruleset *const ruleset,
+				 const void *const rule_attr)
+{
+	struct landlock_path_beneath_attr path_beneath_attr;
+	struct path path;
+	int res, err;
+	u32 mask;
+
+	/* Copies raw user space buffer, only one type for now. */
+	res = copy_from_user(&path_beneath_attr, rule_attr,
+			     sizeof(path_beneath_attr));
+	if (res)
+		return -EFAULT;
+
+	/*
+	 * Informs about useless rule: empty allowed_access (i.e. deny rules)
+	 * are ignored in path walks.
+	 */
+	if (!path_beneath_attr.allowed_access)
+		return -ENOMSG;
+	/*
+	 * Checks that allowed_access matches the @ruleset constraints
+	 * (ruleset->access_masks[0] is automatically upgraded to 64-bits).
+	 */
+	mask = landlock_get_fs_access_mask(ruleset, 0);
+	if ((path_beneath_attr.allowed_access | mask) != mask)
+		return -EINVAL;
+
+	/* Gets and checks the new rule. */
+	err = get_path_from_fd(path_beneath_attr.parent_fd, &path);
+	if (err)
+		return err;
+
+	/* Imports the new rule. */
+	err = landlock_append_fs_rule(ruleset, &path,
+				      path_beneath_attr.allowed_access);
+	path_put(&path);
+
+	return err;
+}
+
 /**
  * sys_landlock_add_rule - Add a new rule to a ruleset
  *
@@ -292,13 +333,14 @@ static int get_path_from_fd(const s32 fd, struct path *const path)
  *
  * - EOPNOTSUPP: Landlock is supported by the kernel but disabled at boot time;
  * - EINVAL: @flags is not 0, or inconsistent access in the rule (i.e.
- *   &landlock_path_beneath_attr.allowed_access is not a subset of the
- *   ruleset handled accesses);
+ *   &landlock_path_beneath_attr.allowed_access is not a subset of the rule's
+ *   accesses);
  * - ENOMSG: Empty accesses (e.g. &landlock_path_beneath_attr.allowed_access);
  * - EBADF: @ruleset_fd is not a file descriptor for the current thread, or a
  *   member of @rule_attr is not a file descriptor as expected;
  * - EBADFD: @ruleset_fd is not a ruleset file descriptor, or a member of
- *   @rule_attr is not the expected file descriptor type;
+ *   @rule_attr is not the expected file descriptor type (e.g. file open
+ *   without O_PATH);
  * - EPERM: @ruleset_fd has no write access to the underlying ruleset;
  * - EFAULT: @rule_attr inconsistency.
  */
@@ -306,10 +348,8 @@ SYSCALL_DEFINE4(landlock_add_rule, const int, ruleset_fd,
 		const enum landlock_rule_type, rule_type,
 		const void __user *const, rule_attr, const __u32, flags)
 {
-	struct landlock_path_beneath_attr path_beneath_attr;
-	struct path path;
 	struct landlock_ruleset *ruleset;
-	int res, err;
+	int err;

 	if (!landlock_initialized)
 		return -EOPNOTSUPP;
@@ -323,49 +363,14 @@ SYSCALL_DEFINE4(landlock_add_rule, const int, ruleset_fd,
 	if (IS_ERR(ruleset))
 		return PTR_ERR(ruleset);

-	if (rule_type != LANDLOCK_RULE_PATH_BENEATH) {
+	switch (rule_type) {
+	case LANDLOCK_RULE_PATH_BENEATH:
+		err = add_rule_path_beneath(ruleset, rule_attr);
+		break;
+	default:
 		err = -EINVAL;
-		goto out_put_ruleset;
-	}
-
-	/* Copies raw user space buffer, only one type for now. */
-	res = copy_from_user(&path_beneath_attr, rule_attr,
-			     sizeof(path_beneath_attr));
-	if (res) {
-		err = -EFAULT;
-		goto out_put_ruleset;
+		break;
 	}
-
-	/*
-	 * Informs about useless rule: empty allowed_access (i.e. deny rules)
-	 * are ignored in path walks.
-	 */
-	if (!path_beneath_attr.allowed_access) {
-		err = -ENOMSG;
-		goto out_put_ruleset;
-	}
-	/*
-	 * Checks that allowed_access matches the @ruleset constraints
-	 * (ruleset->access_masks[0] is automatically upgraded to 64-bits).
-	 */
-	if ((path_beneath_attr.allowed_access |
-	     landlock_get_fs_access_mask(ruleset, 0)) !=
-	    landlock_get_fs_access_mask(ruleset, 0)) {
-		err = -EINVAL;
-		goto out_put_ruleset;
-	}
-
-	/* Gets and checks the new rule. */
-	err = get_path_from_fd(path_beneath_attr.parent_fd, &path);
-	if (err)
-		goto out_put_ruleset;
-
-	/* Imports the new rule. */
-	err = landlock_append_fs_rule(ruleset, &path,
-				      path_beneath_attr.allowed_access);
-	path_put(&path);
-
-out_put_ruleset:
 	landlock_put_ruleset(ruleset);
 	return err;
 }
--
2.25.1


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v6 07/17] landlock: user space API network support
  2022-06-21  8:22 [PATCH v6 00/17] Network support for Landlock Konstantin Meskhidze
                   ` (5 preceding siblings ...)
  2022-06-21  8:23 ` [PATCH v6 06/17] landlock: refactors landlock_add_rule syscall Konstantin Meskhidze
@ 2022-06-21  8:23 ` Konstantin Meskhidze
  2022-06-21  8:23 ` [PATCH v6 08/17] landlock: adds support network rules Konstantin Meskhidze
                   ` (10 subsequent siblings)
  17 siblings, 0 replies; 53+ messages in thread
From: Konstantin Meskhidze @ 2022-06-21  8:23 UTC (permalink / raw)
  To: mic
  Cc: willemdebruijn.kernel, linux-security-module, netdev,
	netfilter-devel, yusongping, anton.sirazetdinov

Refactors user space API to support
network actions. Adds new network
access flags, network rule and
network attributes.

Signed-off-by: Konstantin Meskhidze <konstantin.meskhidze@huawei.com>
---

Changes since v5:
* Formats code with clang-format-14.

Changes since v4:
* None

Changes since v3:
* Splits commit.
* Refactors User API for network rule type.

---
 include/uapi/linux/landlock.h | 49 +++++++++++++++++++++++++++++++++++
 security/landlock/syscalls.c  |  3 ++-
 2 files changed, 51 insertions(+), 1 deletion(-)

diff --git a/include/uapi/linux/landlock.h b/include/uapi/linux/landlock.h
index 23df4e0e8ace..2a959b2e283d 100644
--- a/include/uapi/linux/landlock.h
+++ b/include/uapi/linux/landlock.h
@@ -31,6 +31,13 @@ struct landlock_ruleset_attr {
 	 * this access right.
 	 */
 	__u64 handled_access_fs;
+
+	/**
+	 * @handled_access_net: Bitmask of actions (cf. `Network flags`_)
+	 * that is handled by this ruleset and should then be forbidden if no
+	 * rule explicitly allow them.
+	 */
+	__u64 handled_access_net;
 };

 /*
@@ -54,6 +61,11 @@ enum landlock_rule_type {
 	 * landlock_path_beneath_attr .
 	 */
 	LANDLOCK_RULE_PATH_BENEATH = 1,
+	/**
+	 * @LANDLOCK_RULE_NET_SERVICE: Type of a &struct
+	 * landlock_net_service_attr .
+	 */
+	LANDLOCK_RULE_NET_SERVICE = 2,
 };

 /**
@@ -79,6 +91,24 @@ struct landlock_path_beneath_attr {
 	 */
 } __attribute__((packed));

+/**
+ * struct landlock_net_service_attr - TCP subnet definition
+ *
+ * Argument of sys_landlock_add_rule().
+ */
+struct landlock_net_service_attr {
+	/**
+	 * @allowed_access: Bitmask of allowed access network for services
+	 * (cf. `Network flags`_).
+	 */
+	__u64 allowed_access;
+	/**
+	 * @port: Network port.
+	 */
+	__u16 port;
+
+} __attribute__((packed));
+
 /**
  * DOC: fs_access
  *
@@ -162,4 +192,23 @@ struct landlock_path_beneath_attr {
 #define LANDLOCK_ACCESS_FS_REFER			(1ULL << 13)
 /* clang-format on */

+/**
+ * DOC: net_access
+ *
+ * Network flags
+ * ~~~~~~~~~~~~~~~~
+ *
+ * These flags enable to restrict a sandboxed process to a set of network
+ * actions.
+ *
+ * TCP sockets with allowed actions:
+ *
+ * - %LANDLOCK_ACCESS_NET_BIND_TCP: Bind a TCP socket to a local port.
+ * - %LANDLOCK_ACCESS_NET_CONNECT_TCP: Connect an active TCP socket to
+ *   a remote port.
+ */
+/* clang-format off */
+#define LANDLOCK_ACCESS_NET_BIND_TCP			(1ULL << 0)
+#define LANDLOCK_ACCESS_NET_CONNECT_TCP			(1ULL << 1)
+/* clang-format on */
 #endif /* _UAPI_LINUX_LANDLOCK_H */
diff --git a/security/landlock/syscalls.c b/security/landlock/syscalls.c
index a209fd7d10c6..246bc48deba3 100644
--- a/security/landlock/syscalls.c
+++ b/security/landlock/syscalls.c
@@ -82,8 +82,9 @@ static void build_check_abi(void)
 	 * struct size.
 	 */
 	ruleset_size = sizeof(ruleset_attr.handled_access_fs);
+	ruleset_size += sizeof(ruleset_attr.handled_access_net);
 	BUILD_BUG_ON(sizeof(ruleset_attr) != ruleset_size);
-	BUILD_BUG_ON(sizeof(ruleset_attr) != 8);
+	BUILD_BUG_ON(sizeof(ruleset_attr) != 16);

 	path_beneath_size = sizeof(path_beneath_attr.allowed_access);
 	path_beneath_size += sizeof(path_beneath_attr.parent_fd);
--
2.25.1


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v6 08/17] landlock: adds support network rules
  2022-06-21  8:22 [PATCH v6 00/17] Network support for Landlock Konstantin Meskhidze
                   ` (6 preceding siblings ...)
  2022-06-21  8:23 ` [PATCH v6 07/17] landlock: user space API network support Konstantin Meskhidze
@ 2022-06-21  8:23 ` Konstantin Meskhidze
  2022-06-21  8:23 ` [PATCH v6 09/17] landlock: implements TCP network hooks Konstantin Meskhidze
                   ` (9 subsequent siblings)
  17 siblings, 0 replies; 53+ messages in thread
From: Konstantin Meskhidze @ 2022-06-21  8:23 UTC (permalink / raw)
  To: mic
  Cc: willemdebruijn.kernel, linux-security-module, netdev,
	netfilter-devel, yusongping, anton.sirazetdinov

This commit adds network rules support
in internal landlock functions
(presented in ruleset.c) and
landlock_create_ruleset syscall.

Signed-off-by: Konstantin Meskhidze <konstantin.meskhidze@huawei.com>
---

Changes since v5:
* Gets rid of partial revert from landlock_add_rule
syscall.
* Formats code with clang-format-14.

Changes since v4:
* Refactors landlock_create_ruleset() - splits ruleset and
masks checks.
* Refactors landlock_create_ruleset() and landlock mask
setters/getters to support two rule types.
* Refactors landlock_add_rule syscall add_rule_path_beneath
function by factoring out get_ruleset_from_fd() and
landlock_put_ruleset().

Changes since v3:
* Splits commit.
* Adds network rule support for internal landlock functions.
* Adds set_mask and get_mask for network.
* Adds rb_root root_net_port.

---
 security/landlock/limits.h   |  8 +++-
 security/landlock/ruleset.c  | 78 +++++++++++++++++++++++++++++++-----
 security/landlock/ruleset.h  | 31 ++++++++++++--
 security/landlock/syscalls.c |  8 +++-
 4 files changed, 111 insertions(+), 14 deletions(-)

diff --git a/security/landlock/limits.h b/security/landlock/limits.h
index b54184ab9439..23694bf05cb7 100644
--- a/security/landlock/limits.h
+++ b/security/landlock/limits.h
@@ -22,6 +22,12 @@
 #define LANDLOCK_MASK_ACCESS_FS		((LANDLOCK_LAST_ACCESS_FS << 1) - 1)
 #define LANDLOCK_NUM_ACCESS_FS		__const_hweight64(LANDLOCK_MASK_ACCESS_FS)

-/* clang-format on */
+#define LANDLOCK_LAST_ACCESS_NET	LANDLOCK_ACCESS_NET_CONNECT_TCP
+#define LANDLOCK_MASK_ACCESS_NET	((LANDLOCK_LAST_ACCESS_NET << 1) - 1)
+#define LANDLOCK_NUM_ACCESS_NET		__const_hweight64(LANDLOCK_MASK_ACCESS_NET)
+#define LANDLOCK_MASK_SHIFT_NET		16
+
+#define LANDLOCK_RULE_TYPE_NUM		LANDLOCK_RULE_NET_SERVICE

+/* clang-format on */
 #endif /* _SECURITY_LANDLOCK_LIMITS_H */
diff --git a/security/landlock/ruleset.c b/security/landlock/ruleset.c
index cbca85f5cc6d..6ca6373b3950 100644
--- a/security/landlock/ruleset.c
+++ b/security/landlock/ruleset.c
@@ -36,6 +36,7 @@ static struct landlock_ruleset *create_ruleset(const u32 num_layers)
 	refcount_set(&new_ruleset->usage, 1);
 	mutex_init(&new_ruleset->lock);
 	new_ruleset->root_inode = RB_ROOT;
+	new_ruleset->root_net_port = RB_ROOT;
 	new_ruleset->num_layers = num_layers;
 	/*
 	 * hierarchy = NULL
@@ -46,16 +47,21 @@ static struct landlock_ruleset *create_ruleset(const u32 num_layers)
 }

 struct landlock_ruleset *
-landlock_create_ruleset(const access_mask_t access_mask)
+landlock_create_ruleset(const access_mask_t access_mask_fs,
+			const access_mask_t access_mask_net)
 {
 	struct landlock_ruleset *new_ruleset;

 	/* Informs about useless ruleset. */
-	if (!access_mask)
+	if (!access_mask_fs && !access_mask_net)
 		return ERR_PTR(-ENOMSG);
 	new_ruleset = create_ruleset(1);
-	if (!IS_ERR(new_ruleset))
-		landlock_set_fs_access_mask(new_ruleset, access_mask, 0);
+	if (IS_ERR(new_ruleset))
+		return new_ruleset;
+	if (access_mask_fs)
+		landlock_set_fs_access_mask(new_ruleset, access_mask_fs, 0);
+	if (access_mask_net)
+		landlock_set_net_access_mask(new_ruleset, access_mask_net, 0);
 	return new_ruleset;
 }

@@ -92,9 +98,11 @@ create_rule(struct landlock_object *const object_ptr,
 		return ERR_PTR(-ENOMEM);
 	RB_CLEAR_NODE(&new_rule->node);

-	if (object_ptr) {
+	if (object_ptr && !object_data) {
 		landlock_get_object(object_ptr);
 		new_rule->object.ptr = object_ptr;
+	} else if (object_data && !object_ptr) {
+		new_rule->object.data = object_data;
 	} else if (object_ptr && object_data) {
 		WARN_ON_ONCE(1);
 		return ERR_PTR(-EINVAL);
@@ -130,10 +138,12 @@ static void build_check_ruleset(void)
 		.num_layers = ~0,
 	};
 	typeof(ruleset.access_masks[0]) fs_access_mask = ~0;
+	typeof(ruleset.access_masks[0]) net_access_mask = ~0;

 	BUILD_BUG_ON(ruleset.num_rules < LANDLOCK_MAX_NUM_RULES);
 	BUILD_BUG_ON(ruleset.num_layers < LANDLOCK_MAX_NUM_LAYERS);
 	BUILD_BUG_ON(fs_access_mask < LANDLOCK_MASK_ACCESS_FS);
+	BUILD_BUG_ON(net_access_mask < LANDLOCK_MASK_ACCESS_NET);
 }

 /**
@@ -179,6 +189,11 @@ static int insert_rule(struct landlock_ruleset *const ruleset,
 		object_data = (uintptr_t)object_ptr;
 		root = &ruleset->root_inode;
 		break;
+	case LANDLOCK_RULE_NET_SERVICE:
+		if (WARN_ON_ONCE(object_ptr))
+			return -EINVAL;
+		root = &ruleset->root_net_port;
+		break;
 	default:
 		WARN_ON_ONCE(1);
 		return -EINVAL;
@@ -232,6 +247,15 @@ static int insert_rule(struct landlock_ruleset *const ruleset,
 					&ruleset->root_inode);
 			free_rule(this, rule_type);
 			break;
+		case LANDLOCK_RULE_NET_SERVICE:
+			new_rule = create_rule(NULL, object_data, &this->layers,
+					       this->num_layers, &(*layers)[0]);
+			if (IS_ERR(new_rule))
+				return PTR_ERR(new_rule);
+			rb_replace_node(&this->node, &new_rule->node,
+					&ruleset->root_net_port);
+			free_rule(this, rule_type);
+			break;
 		}
 		return 0;
 	}
@@ -249,6 +273,15 @@ static int insert_rule(struct landlock_ruleset *const ruleset,
 		rb_insert_color(&new_rule->node, &ruleset->root_inode);
 		ruleset->num_rules++;
 		break;
+	case LANDLOCK_RULE_NET_SERVICE:
+		new_rule = create_rule(NULL, object_data, layers, num_layers,
+				       NULL);
+		if (IS_ERR(new_rule))
+			return PTR_ERR(new_rule);
+		rb_link_node(&new_rule->node, parent_node, walker_node);
+		rb_insert_color(&new_rule->node, &ruleset->root_net_port);
+		ruleset->num_rules++;
+		break;
 	}
 	return 0;
 }
@@ -309,6 +342,9 @@ static int tree_merge(struct landlock_ruleset *const src,
 	case LANDLOCK_RULE_PATH_BENEATH:
 		src_root = &src->root_inode;
 		break;
+	case LANDLOCK_RULE_NET_SERVICE:
+		src_root = &src->root_net_port;
+		break;
 	default:
 		return -EINVAL;
 	}
@@ -335,6 +371,11 @@ static int tree_merge(struct landlock_ruleset *const src,
 					  rule_type, &layers,
 					  ARRAY_SIZE(layers));
 			break;
+		case LANDLOCK_RULE_NET_SERVICE:
+			err = insert_rule(dst, NULL, walker_rule->object.data,
+					  rule_type, &layers,
+					  ARRAY_SIZE(layers));
+			break;
 		}
 		if (err)
 			return err;
@@ -370,6 +411,10 @@ static int merge_ruleset(struct landlock_ruleset *const dst,
 	err = tree_merge(src, dst, LANDLOCK_RULE_PATH_BENEATH);
 	if (err)
 		goto out_unlock;
+	/* Merges the @src network tree. */
+	err = tree_merge(src, dst, LANDLOCK_RULE_NET_SERVICE);
+	if (err)
+		goto out_unlock;

 out_unlock:
 	mutex_unlock(&src->lock);
@@ -389,10 +434,13 @@ static int tree_copy(struct landlock_ruleset *const parent,
 	case LANDLOCK_RULE_PATH_BENEATH:
 		parent_root = &parent->root_inode;
 		break;
+	case LANDLOCK_RULE_NET_SERVICE:
+		parent_root = &parent->root_net_port;
+		break;
 	default:
 		return -EINVAL;
 	}
-	/* Copies the @parent inode tree. */
+	/* Copies the @parent inode or network tree. */
 	rbtree_postorder_for_each_entry_safe(walker_rule, next_rule,
 					     parent_root, node) {
 		switch (rule_type) {
@@ -401,6 +449,11 @@ static int tree_copy(struct landlock_ruleset *const parent,
 					  rule_type, &walker_rule->layers,
 					  walker_rule->num_layers);
 			break;
+		case LANDLOCK_RULE_NET_SERVICE:
+			err = insert_rule(child, NULL, walker_rule->object.data,
+					  rule_type, &walker_rule->layers,
+					  walker_rule->num_layers);
+			break;
 		}
 		if (err)
 			return err;
@@ -423,6 +476,10 @@ static int inherit_ruleset(struct landlock_ruleset *const parent,

 	/* Copies the @parent inode tree. */
 	err = tree_copy(parent, child, LANDLOCK_RULE_PATH_BENEATH);
+	if (err)
+		goto out_unlock;
+	/* Copies the @parent network tree. */
+	err = tree_copy(parent, child, LANDLOCK_RULE_NET_SERVICE);
 	if (err)
 		goto out_unlock;

@@ -458,6 +515,9 @@ static void free_ruleset(struct landlock_ruleset *const ruleset)
 	rbtree_postorder_for_each_entry_safe(freeme, next, &ruleset->root_inode,
 					     node)
 		free_rule(freeme, LANDLOCK_RULE_PATH_BENEATH);
+	rbtree_postorder_for_each_entry_safe(freeme, next,
+					     &ruleset->root_net_port, node)
+		free_rule(freeme, LANDLOCK_RULE_NET_SERVICE);
 	put_hierarchy(ruleset->hierarchy);
 	kfree(ruleset);
 }
@@ -552,13 +612,13 @@ landlock_find_rule(const struct landlock_ruleset *const ruleset,
 {
 	const struct rb_node *node;

-	if (!object_data)
-		return NULL;
-
 	switch (rule_type) {
 	case LANDLOCK_RULE_PATH_BENEATH:
 		node = ruleset->root_inode.rb_node;
 		break;
+	case LANDLOCK_RULE_NET_SERVICE:
+		node = ruleset->root_net_port.rb_node;
+		break;
 	default:
 		WARN_ON_ONCE(1);
 		return NULL;
diff --git a/security/landlock/ruleset.h b/security/landlock/ruleset.h
index c1cf7cce2cb5..0cedfe65e326 100644
--- a/security/landlock/ruleset.h
+++ b/security/landlock/ruleset.h
@@ -101,6 +101,12 @@ struct landlock_ruleset {
 	 * tree is immutable until @usage reaches zero.
 	 */
 	struct rb_root root_inode;
+	/**
+	 * @root_net_port: Root of a red-black tree containing object nodes
+	 * for network port. Once a ruleset is tied to a process (i.e. as a domain),
+	 * this tree is immutable until @usage reaches zero.
+	 */
+	struct rb_root root_net_port;
 	/**
 	 * @hierarchy: Enables hierarchy identification even when a parent
 	 * domain vanishes.  This is needed for the ptrace protection.
@@ -156,7 +162,8 @@ struct landlock_ruleset {
 };

 struct landlock_ruleset *
-landlock_create_ruleset(const access_mask_t access_mask);
+landlock_create_ruleset(const access_mask_t access_mask_fs,
+			const access_mask_t access_mask_net);

 void landlock_put_ruleset(struct landlock_ruleset *const ruleset);
 void landlock_put_ruleset_deferred(struct landlock_ruleset *const ruleset);
@@ -183,9 +190,9 @@ static inline void landlock_get_ruleset(struct landlock_ruleset *const ruleset)
 /* A helper function to set a filesystem mask. */
 static inline void
 landlock_set_fs_access_mask(struct landlock_ruleset *ruleset,
-			    const access_mask_t access_maskset, u16 mask_level)
+			    const access_mask_t access_mask_fs, u16 mask_level)
 {
-	ruleset->access_masks[mask_level] = access_maskset;
+	ruleset->access_masks[mask_level] = access_mask_fs;
 }

 /* A helper function to get a filesystem mask. */
@@ -196,6 +203,24 @@ landlock_get_fs_access_mask(const struct landlock_ruleset *ruleset,
 	return (ruleset->access_masks[mask_level] & LANDLOCK_MASK_ACCESS_FS);
 }

+/* A helper function to set a network mask. */
+static inline void
+landlock_set_net_access_mask(struct landlock_ruleset *ruleset,
+			     const access_mask_t access_mask_net,
+			     u16 mask_level)
+{
+	ruleset->access_masks[mask_level] |=
+		(access_mask_net << LANDLOCK_MASK_SHIFT_NET);
+}
+
+/* A helper function to get a network mask. */
+static inline u32
+landlock_get_net_access_mask(const struct landlock_ruleset *ruleset,
+			     u16 mask_level)
+{
+	return (ruleset->access_masks[mask_level] >> LANDLOCK_MASK_SHIFT_NET);
+}
+
 access_mask_t get_handled_accesses(const struct landlock_ruleset *const domain,
 				   u16 rule_type, u16 num_access);

diff --git a/security/landlock/syscalls.c b/security/landlock/syscalls.c
index 246bc48deba3..72fa01ba9de7 100644
--- a/security/landlock/syscalls.c
+++ b/security/landlock/syscalls.c
@@ -189,8 +189,14 @@ SYSCALL_DEFINE3(landlock_create_ruleset,
 	    LANDLOCK_MASK_ACCESS_FS)
 		return -EINVAL;

+	/* Checks network content (and 32-bits cast). */
+	if ((ruleset_attr.handled_access_net | LANDLOCK_MASK_ACCESS_NET) !=
+	    LANDLOCK_MASK_ACCESS_NET)
+		return -EINVAL;
+
 	/* Checks arguments and transforms to kernel struct. */
-	ruleset = landlock_create_ruleset(ruleset_attr.handled_access_fs);
+	ruleset = landlock_create_ruleset(ruleset_attr.handled_access_fs,
+					  ruleset_attr.handled_access_net);
 	if (IS_ERR(ruleset))
 		return PTR_ERR(ruleset);

--
2.25.1


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v6 09/17] landlock: implements TCP network hooks
  2022-06-21  8:22 [PATCH v6 00/17] Network support for Landlock Konstantin Meskhidze
                   ` (7 preceding siblings ...)
  2022-06-21  8:23 ` [PATCH v6 08/17] landlock: adds support network rules Konstantin Meskhidze
@ 2022-06-21  8:23 ` Konstantin Meskhidze
  2022-06-21  8:23 ` [PATCH v6 10/17] seltests/landlock: moves helper function Konstantin Meskhidze
                   ` (8 subsequent siblings)
  17 siblings, 0 replies; 53+ messages in thread
From: Konstantin Meskhidze @ 2022-06-21  8:23 UTC (permalink / raw)
  To: mic
  Cc: willemdebruijn.kernel, linux-security-module, netdev,
	netfilter-devel, yusongping, anton.sirazetdinov

This patch adds support of socket_bind() and
socket_connect() hooks. It's possible to restrict
binding and connecting of TCP types of sockets
to particular ports. It's just basic idea of
how Landlock could support network confinement.

Signed-off-by: Konstantin Meskhidze <konstantin.meskhidze@huawei.com>
---

Changes since v5:
* Fixes some logic errors.
* Formats code with clang-format-14.

Changes since v4:
* Factors out CONFIG_INET into make file.
* Refactors check_socket_access().
* Adds helper get_port().
* Adds CONFIG_IPV6 in get_port(), hook_socket_bind/connect
functions to support AF_INET6 family.
* Adds AF_UNSPEC family support in hook_socket_bind/connect
functions.
* Refactors add_rule_net_service() and landlock_add_rule
syscall to support network rule inserting.
* Refactors init_layer_masks() to support network rules.

Changes since v3:
* Splits commit.
* Adds SECURITY_NETWORK in config.
* Adds IS_ENABLED(CONFIG_INET) if a kernel has no INET configuration.
* Adds hook_socket_bind and hook_socket_connect hooks.

---
 security/landlock/Kconfig    |   1 +
 security/landlock/Makefile   |   2 +
 security/landlock/net.c      | 155 +++++++++++++++++++++++++++++++++++
 security/landlock/net.h      |  26 ++++++
 security/landlock/ruleset.c  |  12 +++
 security/landlock/setup.c    |   2 +
 security/landlock/syscalls.c |  59 ++++++++++++-
 7 files changed, 254 insertions(+), 3 deletions(-)
 create mode 100644 security/landlock/net.c
 create mode 100644 security/landlock/net.h

diff --git a/security/landlock/Kconfig b/security/landlock/Kconfig
index 8e33c4e8ffb8..10c099097533 100644
--- a/security/landlock/Kconfig
+++ b/security/landlock/Kconfig
@@ -3,6 +3,7 @@
 config SECURITY_LANDLOCK
 	bool "Landlock support"
 	depends on SECURITY && !ARCH_EPHEMERAL_INODES
+	select SECURITY_NETWORK
 	select SECURITY_PATH
 	help
 	  Landlock is a sandboxing mechanism that enables processes to restrict
diff --git a/security/landlock/Makefile b/security/landlock/Makefile
index 7bbd2f413b3e..53d3c92ae22e 100644
--- a/security/landlock/Makefile
+++ b/security/landlock/Makefile
@@ -2,3 +2,5 @@ obj-$(CONFIG_SECURITY_LANDLOCK) := landlock.o

 landlock-y := setup.o syscalls.o object.o ruleset.o \
 	cred.o ptrace.o fs.o
+
+landlock-$(CONFIG_INET) += net.o
\ No newline at end of file
diff --git a/security/landlock/net.c b/security/landlock/net.c
new file mode 100644
index 000000000000..da63e4f1dca4
--- /dev/null
+++ b/security/landlock/net.c
@@ -0,0 +1,155 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Landlock LSM - Network management and hooks
+ *
+ * Copyright (C) 2022 Huawei Tech. Co., Ltd.
+ */
+
+#include <linux/in.h>
+#include <linux/net.h>
+#include <linux/socket.h>
+#include <net/ipv6.h>
+
+#include "cred.h"
+#include "limits.h"
+#include "net.h"
+
+int landlock_append_net_rule(struct landlock_ruleset *const ruleset, u16 port,
+			     u32 access_rights)
+{
+	int err;
+
+	/* Transforms relative access rights to absolute ones. */
+	access_rights |= LANDLOCK_MASK_ACCESS_NET &
+			 ~landlock_get_net_access_mask(ruleset, 0);
+
+	BUILD_BUG_ON(sizeof(port) > sizeof(uintptr_t));
+	mutex_lock(&ruleset->lock);
+	err = landlock_insert_rule(ruleset, NULL, port, access_rights,
+				   LANDLOCK_RULE_NET_SERVICE);
+	mutex_unlock(&ruleset->lock);
+
+	return err;
+}
+
+static int check_socket_access(const struct landlock_ruleset *const domain,
+			       u16 port, access_mask_t access_request)
+{
+	bool allowed = false;
+	layer_mask_t layer_masks[LANDLOCK_NUM_ACCESS_NET] = {};
+	const struct landlock_rule *rule;
+	access_mask_t handled_access;
+
+	if (WARN_ON_ONCE(!domain))
+		return 0;
+	if (WARN_ON_ONCE(domain->num_layers < 1))
+		return -EACCES;
+
+	rule = landlock_find_rule(domain, port, LANDLOCK_RULE_NET_SERVICE);
+
+	handled_access = init_layer_masks(domain, access_request, &layer_masks,
+					  sizeof(layer_masks),
+					  LANDLOCK_RULE_NET_SERVICE);
+	allowed = unmask_layers(rule, handled_access, &layer_masks,
+				ARRAY_SIZE(layer_masks));
+
+	return allowed ? 0 : -EACCES;
+}
+
+static u16 get_port(const struct sockaddr *const address)
+{
+	/* Gets port value in host byte order. */
+	switch (address->sa_family) {
+	case AF_UNSPEC:
+	case AF_INET: {
+		const struct sockaddr_in *const sockaddr =
+			(struct sockaddr_in *)address;
+		return ntohs(sockaddr->sin_port);
+	}
+#if IS_ENABLED(CONFIG_IPV6)
+	case AF_INET6: {
+		const struct sockaddr_in6 *const sockaddr_ip6 =
+			(struct sockaddr_in6 *)address;
+		return ntohs(sockaddr_ip6->sin6_port);
+	}
+#endif
+	}
+	WARN_ON_ONCE(1);
+	return 0;
+}
+
+static int hook_socket_bind(struct socket *sock, struct sockaddr *address,
+			    int addrlen)
+{
+	const struct landlock_ruleset *const dom =
+		landlock_get_current_domain();
+
+	if (!dom)
+		return 0;
+
+	/* Check if it's a TCP socket. */
+	if (sock->type != SOCK_STREAM)
+		return 0;
+
+	switch (address->sa_family) {
+	case AF_UNSPEC:
+	case AF_INET:
+#if IS_ENABLED(CONFIG_IPV6)
+	case AF_INET6:
+#endif
+		return check_socket_access(dom, get_port(address),
+					   LANDLOCK_ACCESS_NET_BIND_TCP);
+	default:
+		return 0;
+	}
+}
+
+static int hook_socket_connect(struct socket *sock, struct sockaddr *address,
+			       int addrlen)
+{
+	const struct landlock_ruleset *const dom =
+		landlock_get_current_domain();
+
+	if (!dom)
+		return 0;
+
+	/* Check if it's a TCP socket. */
+	if (sock->type != SOCK_STREAM)
+		return 0;
+
+	/* Check if the hook is AF_INET* socket's action. */
+	switch (address->sa_family) {
+	case AF_INET:
+#if IS_ENABLED(CONFIG_IPV6)
+	case AF_INET6:
+#endif
+		return check_socket_access(dom, get_port(address),
+					   LANDLOCK_ACCESS_NET_CONNECT_TCP);
+	case AF_UNSPEC: {
+		u16 i;
+		/*
+		 * If just in a layer a mask supports connect access,
+		 * the socket_connect() hook with AF_UNSPEC family flag
+		 * must be banned. This prevents from disconnecting already
+		 * connected sockets.
+		 */
+		for (i = 0; i < dom->num_layers; i++) {
+			if (landlock_get_net_access_mask(dom, i) &
+			    LANDLOCK_ACCESS_NET_CONNECT_TCP)
+				return -EACCES;
+		}
+	}
+	}
+	return 0;
+}
+
+static struct security_hook_list landlock_hooks[] __lsm_ro_after_init = {
+	LSM_HOOK_INIT(socket_bind, hook_socket_bind),
+	LSM_HOOK_INIT(socket_connect, hook_socket_connect),
+};
+
+__init void landlock_add_net_hooks(void)
+{
+	security_add_hooks(landlock_hooks, ARRAY_SIZE(landlock_hooks),
+			   LANDLOCK_NAME);
+}
diff --git a/security/landlock/net.h b/security/landlock/net.h
new file mode 100644
index 000000000000..7a79fb4bf3dd
--- /dev/null
+++ b/security/landlock/net.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Landlock LSM - Network management and hooks
+ *
+ * Copyright (C) 2022 Huawei Tech. Co., Ltd.
+ */
+
+#ifndef _SECURITY_LANDLOCK_NET_H
+#define _SECURITY_LANDLOCK_NET_H
+
+#include "common.h"
+#include "ruleset.h"
+#include "setup.h"
+
+#if IS_ENABLED(CONFIG_INET)
+__init void landlock_add_net_hooks(void);
+
+int landlock_append_net_rule(struct landlock_ruleset *const ruleset, u16 port,
+			     u32 access_hierarchy);
+#else /* IS_ENABLED(CONFIG_INET) */
+static inline void landlock_add_net_hooks(void)
+{
+}
+#endif /* IS_ENABLED(CONFIG_INET) */
+
+#endif /* _SECURITY_LANDLOCK_NET_H */
diff --git a/security/landlock/ruleset.c b/security/landlock/ruleset.c
index 6ca6373b3950..469811a77675 100644
--- a/security/landlock/ruleset.c
+++ b/security/landlock/ruleset.c
@@ -751,6 +751,18 @@ access_mask_t init_layer_masks(const struct landlock_ruleset *const domain,
 				}
 			}
 			break;
+		case LANDLOCK_RULE_NET_SERVICE:
+			for_each_set_bit(access_bit, &access_req,
+					 LANDLOCK_NUM_ACCESS_NET) {
+				if (landlock_get_net_access_mask(domain,
+								 layer_level) &
+				    BIT_ULL(access_bit)) {
+					(*layer_masks)[access_bit] |=
+						BIT_ULL(layer_level);
+					handled_accesses |= BIT_ULL(access_bit);
+				}
+			}
+			break;
 		default:
 			return 0;
 		}
diff --git a/security/landlock/setup.c b/security/landlock/setup.c
index f8e8e980454c..8059dc0b47d3 100644
--- a/security/landlock/setup.c
+++ b/security/landlock/setup.c
@@ -14,6 +14,7 @@
 #include "fs.h"
 #include "ptrace.h"
 #include "setup.h"
+#include "net.h"

 bool landlock_initialized __lsm_ro_after_init = false;

@@ -28,6 +29,7 @@ static int __init landlock_init(void)
 	landlock_add_cred_hooks();
 	landlock_add_ptrace_hooks();
 	landlock_add_fs_hooks();
+	landlock_add_net_hooks();
 	landlock_initialized = true;
 	pr_info("Up and running.\n");
 	return 0;
diff --git a/security/landlock/syscalls.c b/security/landlock/syscalls.c
index 72fa01ba9de7..5069fac2ecf6 100644
--- a/security/landlock/syscalls.c
+++ b/security/landlock/syscalls.c
@@ -29,6 +29,7 @@
 #include "cred.h"
 #include "fs.h"
 #include "limits.h"
+#include "net.h"
 #include "ruleset.h"
 #include "setup.h"

@@ -74,7 +75,8 @@ static void build_check_abi(void)
 {
 	struct landlock_ruleset_attr ruleset_attr;
 	struct landlock_path_beneath_attr path_beneath_attr;
-	size_t ruleset_size, path_beneath_size;
+	struct landlock_net_service_attr net_service_attr;
+	size_t ruleset_size, path_beneath_size, net_service_size;

 	/*
 	 * For each user space ABI structures, first checks that there is no
@@ -90,6 +92,11 @@ static void build_check_abi(void)
 	path_beneath_size += sizeof(path_beneath_attr.parent_fd);
 	BUILD_BUG_ON(sizeof(path_beneath_attr) != path_beneath_size);
 	BUILD_BUG_ON(sizeof(path_beneath_attr) != 12);
+
+	net_service_size = sizeof(net_service_attr.allowed_access);
+	net_service_size += sizeof(net_service_attr.port);
+	BUILD_BUG_ON(sizeof(net_service_attr) != net_service_size);
+	BUILD_BUG_ON(sizeof(net_service_attr) != 10);
 }

 /* Ruleset handling */
@@ -322,13 +329,54 @@ static int add_rule_path_beneath(struct landlock_ruleset *const ruleset,
 	return err;
 }

+static int add_rule_net_service(struct landlock_ruleset *ruleset,
+				const void *const rule_attr)
+{
+#if IS_ENABLED(CONFIG_INET)
+	struct landlock_net_service_attr net_service_attr;
+	int res;
+	u32 mask;
+
+	/* Copies raw user space buffer, only one type for now. */
+	res = copy_from_user(&net_service_attr, rule_attr,
+			     sizeof(net_service_attr));
+	if (res)
+		return -EFAULT;
+
+	/*
+	 * Informs about useless rule: empty allowed_access (i.e. deny rules)
+	 * are ignored by network actions.
+	 */
+	if (!net_service_attr.allowed_access)
+		return -ENOMSG;
+
+	/*
+	 * Checks that allowed_access matches the @ruleset constraints
+	 * (ruleset->access_masks[0] is automatically upgraded to 64-bits).
+	 */
+	mask = landlock_get_net_access_mask(ruleset, 0);
+	if ((net_service_attr.allowed_access | mask) != mask)
+		return -EINVAL;
+
+	/* Denies inserting a rule with port 0. */
+	if (net_service_attr.port == 0)
+		return -EINVAL;
+
+	/* Imports the new rule. */
+	return landlock_append_net_rule(ruleset, net_service_attr.port,
+					net_service_attr.allowed_access);
+#else /* IS_ENABLED(CONFIG_INET) */
+	return -EAFNOSUPPORT;
+#endif /* IS_ENABLED(CONFIG_INET) */
+}
+
 /**
  * sys_landlock_add_rule - Add a new rule to a ruleset
  *
  * @ruleset_fd: File descriptor tied to the ruleset that should be extended
  *		with the new rule.
- * @rule_type: Identify the structure type pointed to by @rule_attr (only
- *             LANDLOCK_RULE_PATH_BENEATH for now).
+ * @rule_type: Identify the structure type pointed to by @rule_attr:
+ *             LANDLOCK_RULE_PATH_BENEATH or LANDLOCK_RULE_NET_SERVICE.
  * @rule_attr: Pointer to a rule (only of type &struct
  *             landlock_path_beneath_attr for now).
  * @flags: Must be 0.
@@ -339,6 +387,8 @@ static int add_rule_path_beneath(struct landlock_ruleset *const ruleset,
  * Possible returned errors are:
  *
  * - EOPNOTSUPP: Landlock is supported by the kernel but disabled at boot time;
+ * - EAFNOSUPPORT: @rule_type is LANDLOCK_RULE_NET_SERVICE but TCP/IP is not
+ *   supported by the running kernel;
  * - EINVAL: @flags is not 0, or inconsistent access in the rule (i.e.
  *   &landlock_path_beneath_attr.allowed_access is not a subset of the rule's
  *   accesses);
@@ -374,6 +424,9 @@ SYSCALL_DEFINE4(landlock_add_rule, const int, ruleset_fd,
 	case LANDLOCK_RULE_PATH_BENEATH:
 		err = add_rule_path_beneath(ruleset, rule_attr);
 		break;
+	case LANDLOCK_RULE_NET_SERVICE:
+		err = add_rule_net_service(ruleset, rule_attr);
+		break;
 	default:
 		err = -EINVAL;
 		break;
--
2.25.1


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v6 10/17] seltests/landlock: moves helper function
  2022-06-21  8:22 [PATCH v6 00/17] Network support for Landlock Konstantin Meskhidze
                   ` (8 preceding siblings ...)
  2022-06-21  8:23 ` [PATCH v6 09/17] landlock: implements TCP network hooks Konstantin Meskhidze
@ 2022-06-21  8:23 ` Konstantin Meskhidze
  2022-06-21  8:23 ` [PATCH v6 11/17] seltests/landlock: adds tests for bind() hooks Konstantin Meskhidze
                   ` (7 subsequent siblings)
  17 siblings, 0 replies; 53+ messages in thread
From: Konstantin Meskhidze @ 2022-06-21  8:23 UTC (permalink / raw)
  To: mic
  Cc: willemdebruijn.kernel, linux-security-module, netdev,
	netfilter-devel, yusongping, anton.sirazetdinov

This commit moves enforce_ruleset() helper
function to common.h so that to be used
both by filesystem tests and network ones.

Signed-off-by: Konstantin Meskhidze <konstantin.meskhidze@huawei.com>
---

Changes since v5:
* Splits commit.
* Moves enforce_ruleset helper into common.h
* Formats code with clang-format-14.

---
 tools/testing/selftests/landlock/common.h  | 10 ++++++++++
 tools/testing/selftests/landlock/fs_test.c | 10 ----------
 2 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/tools/testing/selftests/landlock/common.h b/tools/testing/selftests/landlock/common.h
index 7ba18eb23783..48870afb054b 100644
--- a/tools/testing/selftests/landlock/common.h
+++ b/tools/testing/selftests/landlock/common.h
@@ -187,3 +187,13 @@ clear_cap(struct __test_metadata *const _metadata, const cap_value_t caps)
 {
 	_effective_cap(_metadata, caps, CAP_CLEAR);
 }
+
+__attribute__((__unused__)) static void
+enforce_ruleset(struct __test_metadata *const _metadata, const int ruleset_fd)
+{
+	ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0));
+	ASSERT_EQ(0, landlock_restrict_self(ruleset_fd, 0))
+	{
+		TH_LOG("Failed to enforce ruleset: %s", strerror(errno));
+	}
+}
diff --git a/tools/testing/selftests/landlock/fs_test.c b/tools/testing/selftests/landlock/fs_test.c
index 21a2ce8fa739..036dd6f8f9ea 100644
--- a/tools/testing/selftests/landlock/fs_test.c
+++ b/tools/testing/selftests/landlock/fs_test.c
@@ -551,16 +551,6 @@ static int create_ruleset(struct __test_metadata *const _metadata,
 	return ruleset_fd;
 }

-static void enforce_ruleset(struct __test_metadata *const _metadata,
-			    const int ruleset_fd)
-{
-	ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0));
-	ASSERT_EQ(0, landlock_restrict_self(ruleset_fd, 0))
-	{
-		TH_LOG("Failed to enforce ruleset: %s", strerror(errno));
-	}
-}
-
 TEST_F_FORK(layout1, proc_nsfs)
 {
 	const struct rule rules[] = {
--
2.25.1


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v6 11/17] seltests/landlock: adds tests for bind() hooks
  2022-06-21  8:22 [PATCH v6 00/17] Network support for Landlock Konstantin Meskhidze
                   ` (9 preceding siblings ...)
  2022-06-21  8:23 ` [PATCH v6 10/17] seltests/landlock: moves helper function Konstantin Meskhidze
@ 2022-06-21  8:23 ` Konstantin Meskhidze
  2022-07-28 13:24   ` Mickaël Salaün
  2022-06-21  8:23 ` [PATCH v6 12/17] seltests/landlock: adds tests for connect() hooks Konstantin Meskhidze
                   ` (6 subsequent siblings)
  17 siblings, 1 reply; 53+ messages in thread
From: Konstantin Meskhidze @ 2022-06-21  8:23 UTC (permalink / raw)
  To: mic
  Cc: willemdebruijn.kernel, linux-security-module, netdev,
	netfilter-devel, yusongping, anton.sirazetdinov

Adds selftests for bind() socket action.
The first is with no landlock restrictions:
    - bind without restrictions for ip4;
    - bind without restrictions for ip6;
The second ones is with mixed landlock rules:
    - bind with restrictions for ip4;
    - bind with restrictions for ip6;

Signed-off-by: Konstantin Meskhidze <konstantin.meskhidze@huawei.com>
---

Changes since v5:
* Splits commit.
* Adds local address 127.0.0.1.
* Adds FIXTURE_VARIANT and FIXTURE_VARIANT_ADD
helpers to support both ip4 and ip6 family tests and
shorten the code.
* Adds create_socket_variant() and bind_variant() helpers.
* Gets rid of reuse_addr variable in create_socket_variant.
* Formats code with clang-format-14.

Changes since v4:
* Adds port[MAX_SOCKET_NUM], struct sockaddr_in addr4
and struct sockaddr_in addr6 in FIXTURE.
* Refactors FIXTURE_SETUP:
    - initializing self->port, self->addr4 and self->addr6.
    - adding network namespace.
* Refactors code with self->port, self->addr4 and
self->addr6 variables.
* Adds selftests for IP6 family:
    - bind_no_restrictions_ip6.
    - bind_with_restrictions_ip6.
* Refactors selftests/landlock/config
* Moves enforce_ruleset() into common.h

Changes since v3:
* Split commit.
* Add helper create_socket.
* Add FIXTURE_SETUP.

---
 tools/testing/selftests/landlock/config     |   4 +
 tools/testing/selftests/landlock/net_test.c | 180 ++++++++++++++++++++
 2 files changed, 184 insertions(+)
 create mode 100644 tools/testing/selftests/landlock/net_test.c

diff --git a/tools/testing/selftests/landlock/config b/tools/testing/selftests/landlock/config
index 0f0a65287bac..71f7e9a8a64c 100644
--- a/tools/testing/selftests/landlock/config
+++ b/tools/testing/selftests/landlock/config
@@ -1,3 +1,7 @@
+CONFIG_INET=y
+CONFIG_IPV6=y
+CONFIG_NET=y
+CONFIG_NET_NS=y
 CONFIG_OVERLAY_FS=y
 CONFIG_SECURITY_LANDLOCK=y
 CONFIG_SECURITY_PATH=y
diff --git a/tools/testing/selftests/landlock/net_test.c b/tools/testing/selftests/landlock/net_test.c
new file mode 100644
index 000000000000..a0e02b6bd79f
--- /dev/null
+++ b/tools/testing/selftests/landlock/net_test.c
@@ -0,0 +1,180 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Landlock tests - Network
+ *
+ * Copyright (C) 2022 Huawei Tech. Co., Ltd.
+ */
+
+#define _GNU_SOURCE
+#include <arpa/inet.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/landlock.h>
+#include <netinet/in.h>
+#include <sched.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#include "common.h"
+
+#define MAX_SOCKET_NUM 10
+
+#define SOCK_PORT_START 3470
+#define SOCK_PORT_ADD 10
+
+#define IP_ADDRESS "127.0.0.1"
+
+FIXTURE(socket)
+{
+	uint port[MAX_SOCKET_NUM];
+	struct sockaddr_in addr4[MAX_SOCKET_NUM];
+	struct sockaddr_in6 addr6[MAX_SOCKET_NUM];
+};
+
+FIXTURE_VARIANT(socket)
+{
+	const bool is_ipv4;
+};
+
+/* clang-format off */
+FIXTURE_VARIANT_ADD(socket, ipv4) {
+	/* clang-format on */
+	.is_ipv4 = true,
+};
+
+/* clang-format off */
+FIXTURE_VARIANT_ADD(socket, ipv6) {
+	/* clang-format on */
+	.is_ipv4 = false,
+};
+
+static int create_socket_variant(const FIXTURE_VARIANT(socket) * const variant,
+				 const int type)
+{
+	if (variant->is_ipv4)
+		return socket(AF_INET, type | SOCK_CLOEXEC, 0);
+	else
+		return socket(AF_INET6, type | SOCK_CLOEXEC, 0);
+}
+
+static int bind_variant(const FIXTURE_VARIANT(socket) * const variant,
+			const int sockfd,
+			const FIXTURE_DATA(socket) * const self,
+			const size_t index)
+{
+	if (variant->is_ipv4)
+		return bind(sockfd, &self->addr4[index],
+			    sizeof(self->addr4[index]));
+	else
+		return bind(sockfd, &self->addr6[index],
+			    sizeof(self->addr6[index]));
+}
+
+FIXTURE_SETUP(socket)
+{
+	int i;
+	/* Creates IP4 socket addresses. */
+	for (i = 0; i < MAX_SOCKET_NUM; i++) {
+		self->port[i] = SOCK_PORT_START + SOCK_PORT_ADD * i;
+		self->addr4[i].sin_family = AF_INET;
+		self->addr4[i].sin_port = htons(self->port[i]);
+		self->addr4[i].sin_addr.s_addr = inet_addr(IP_ADDRESS);
+		memset(&(self->addr4[i].sin_zero), '\0', 8);
+	}
+
+	/* Creates IP6 socket addresses. */
+	for (i = 0; i < MAX_SOCKET_NUM; i++) {
+		self->port[i] = SOCK_PORT_START + SOCK_PORT_ADD * i;
+		self->addr6[i].sin6_family = AF_INET6;
+		self->addr6[i].sin6_port = htons(self->port[i]);
+		inet_pton(AF_INET6, IP_ADDRESS, &(self->addr6[i].sin6_addr));
+	}
+
+	set_cap(_metadata, CAP_SYS_ADMIN);
+	ASSERT_EQ(0, unshare(CLONE_NEWNET));
+	ASSERT_EQ(0, system("ip link set dev lo up"));
+	clear_cap(_metadata, CAP_SYS_ADMIN);
+}
+
+FIXTURE_TEARDOWN(socket)
+{
+}
+
+TEST_F(socket, bind_no_restrictions)
+{
+	int sockfd;
+
+	sockfd = create_socket_variant(variant, SOCK_STREAM);
+	ASSERT_LE(0, sockfd);
+
+	/* Binds a socket to port[0]. */
+	ASSERT_EQ(0, bind_variant(variant, sockfd, self, 0));
+
+	ASSERT_EQ(0, close(sockfd));
+}
+
+TEST_F(socket, bind_with_restrictions)
+{
+	int sockfd;
+
+	struct landlock_ruleset_attr ruleset_attr = {
+		.handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP |
+				      LANDLOCK_ACCESS_NET_CONNECT_TCP,
+	};
+	struct landlock_net_service_attr net_service_1 = {
+		.allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP |
+				  LANDLOCK_ACCESS_NET_CONNECT_TCP,
+		.port = self->port[0],
+	};
+	struct landlock_net_service_attr net_service_2 = {
+		.allowed_access = LANDLOCK_ACCESS_NET_CONNECT_TCP,
+		.port = self->port[1],
+	};
+	struct landlock_net_service_attr net_service_3 = {
+		.allowed_access = 0,
+		.port = self->port[2],
+	};
+
+	const int ruleset_fd =
+		landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
+	ASSERT_LE(0, ruleset_fd);
+
+	/* Allows connect and bind operations to the port[0] socket. */
+	ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_SERVICE,
+				       &net_service_1, 0));
+	/* Allows connect and deny bind operations to the port[1] socket. */
+	ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_SERVICE,
+				       &net_service_2, 0));
+	/* Empty allowed_access (i.e. deny rules) are ignored in network actions
+	 * for port[2] socket.
+	 */
+	ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_SERVICE,
+					&net_service_3, 0));
+	ASSERT_EQ(ENOMSG, errno);
+
+	/* Enforces the ruleset. */
+	enforce_ruleset(_metadata, ruleset_fd);
+
+	sockfd = create_socket_variant(variant, SOCK_STREAM);
+	ASSERT_LE(0, sockfd);
+	/* Binds a socket to port[0]. */
+	ASSERT_EQ(0, bind_variant(variant, sockfd, self, 0));
+
+	/* Close bounded socket. */
+	ASSERT_EQ(0, close(sockfd));
+
+	sockfd = create_socket_variant(variant, SOCK_STREAM);
+	ASSERT_LE(0, sockfd);
+	/* Binds a socket to port[1]. */
+	ASSERT_EQ(-1, bind_variant(variant, sockfd, self, 1));
+	ASSERT_EQ(EACCES, errno);
+
+	sockfd = create_socket_variant(variant, SOCK_STREAM);
+	ASSERT_LE(0, sockfd);
+	/* Binds a socket to port[2]. */
+	ASSERT_EQ(-1, bind_variant(variant, sockfd, self, 2));
+	ASSERT_EQ(EACCES, errno);
+}
+TEST_HARNESS_MAIN
--
2.25.1


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v6 12/17] seltests/landlock: adds tests for connect() hooks
  2022-06-21  8:22 [PATCH v6 00/17] Network support for Landlock Konstantin Meskhidze
                   ` (10 preceding siblings ...)
  2022-06-21  8:23 ` [PATCH v6 11/17] seltests/landlock: adds tests for bind() hooks Konstantin Meskhidze
@ 2022-06-21  8:23 ` Konstantin Meskhidze
  2022-06-21  8:23 ` [PATCH v6 13/17] seltests/landlock: adds AF_UNSPEC family test Konstantin Meskhidze
                   ` (5 subsequent siblings)
  17 siblings, 0 replies; 53+ messages in thread
From: Konstantin Meskhidze @ 2022-06-21  8:23 UTC (permalink / raw)
  To: mic
  Cc: willemdebruijn.kernel, linux-security-module, netdev,
	netfilter-devel, yusongping, anton.sirazetdinov

Adds selftests for connect socket action.
The first are with no landlock restrictions:
    - connect without restrictions for ip4;
    - connect without restrictions for ip6;
The second ones are with mixed landlock rules:
    - connect with restrictions ip4;
    - connect with restrictions ip6;

Signed-off-by: Konstantin Meskhidze <konstantin.meskhidze@huawei.com>
---

Changes since v5:
* Adds connect_variant() helper.
* Formats code with clang-format-14.

Changes since v4:
* Adds selftests for IP6 family:
    - connect_no_restrictions_ip6.
    - connect_with_restrictions_ip6.
* Refactors code with self->port, self->addr4 and
self->addr6 variables.

Changes since v3:
* Split commit.

---
 tools/testing/selftests/landlock/net_test.c | 174 ++++++++++++++++++++
 1 file changed, 174 insertions(+)

diff --git a/tools/testing/selftests/landlock/net_test.c b/tools/testing/selftests/landlock/net_test.c
index a0e02b6bd79f..ce6fd51a922d 100644
--- a/tools/testing/selftests/landlock/net_test.c
+++ b/tools/testing/selftests/landlock/net_test.c
@@ -26,6 +26,9 @@

 #define IP_ADDRESS "127.0.0.1"

+/* Number pending connections queue to be hold */
+#define BACKLOG 10
+
 FIXTURE(socket)
 {
 	uint port[MAX_SOCKET_NUM];
@@ -72,6 +75,19 @@ static int bind_variant(const FIXTURE_VARIANT(socket) * const variant,
 			    sizeof(self->addr6[index]));
 }

+static int connect_variant(const FIXTURE_VARIANT(socket) * const variant,
+			   const int sockfd,
+			   const FIXTURE_DATA(socket) * const self,
+			   const size_t index)
+{
+	if (variant->is_ipv4)
+		return connect(sockfd, &self->addr4[index],
+			       sizeof(self->addr4[index]));
+	else
+		return connect(sockfd, &self->addr6[index],
+			       sizeof(self->addr6[index]));
+}
+
 FIXTURE_SETUP(socket)
 {
 	int i;
@@ -177,4 +193,162 @@ TEST_F(socket, bind_with_restrictions)
 	ASSERT_EQ(-1, bind_variant(variant, sockfd, self, 2));
 	ASSERT_EQ(EACCES, errno);
 }
+
+TEST_F(socket, connect_no_restrictions)
+{
+	int sockfd, new_fd;
+	pid_t child;
+	int status;
+
+	/* Creates a server socket. */
+	sockfd = create_socket_variant(variant, SOCK_STREAM);
+	ASSERT_LE(0, sockfd);
+
+	/* Binds a socket to port[0]. */
+	ASSERT_EQ(0, bind_variant(variant, sockfd, self, 0));
+
+	/* Makes listening socket. */
+	ASSERT_EQ(0, listen(sockfd, BACKLOG));
+
+	child = fork();
+	ASSERT_LE(0, child);
+	if (child == 0) {
+		int child_sockfd;
+
+		/* Closes listening socket for the child. */
+		ASSERT_EQ(0, close(sockfd));
+		/* Create a stream client socket. */
+		child_sockfd = create_socket_variant(variant, SOCK_STREAM);
+		ASSERT_LE(0, child_sockfd);
+
+		/* Makes connection to the listening socket with port[0]. */
+		ASSERT_EQ(0, connect_variant(variant, child_sockfd, self, 0));
+		_exit(_metadata->passed ? EXIT_SUCCESS : EXIT_FAILURE);
+		return;
+	}
+	/* Accepts connection from the child. */
+	new_fd = accept(sockfd, NULL, 0);
+	ASSERT_LE(0, new_fd);
+
+	/* Closes connection. */
+	ASSERT_EQ(0, close(new_fd));
+
+	/* Closes listening socket for the parent. */
+	ASSERT_EQ(0, close(sockfd));
+
+	ASSERT_EQ(child, waitpid(child, &status, 0));
+	ASSERT_EQ(1, WIFEXITED(status));
+	ASSERT_EQ(EXIT_SUCCESS, WEXITSTATUS(status));
+}
+
+TEST_F(socket, connect_with_restrictions)
+{
+	int new_fd;
+	int sockfd_1, sockfd_2;
+	pid_t child_1, child_2;
+	int status;
+
+	struct landlock_ruleset_attr ruleset_attr = {
+		.handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP |
+				      LANDLOCK_ACCESS_NET_CONNECT_TCP,
+	};
+	struct landlock_net_service_attr net_service_1 = {
+		.allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP |
+				  LANDLOCK_ACCESS_NET_CONNECT_TCP,
+		.port = self->port[0],
+	};
+	struct landlock_net_service_attr net_service_2 = {
+		.allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP,
+		.port = self->port[1],
+	};
+
+	const int ruleset_fd =
+		landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
+	ASSERT_LE(0, ruleset_fd);
+
+	/* Allows connect and bind operations to the port[0] socket. */
+	ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_SERVICE,
+				       &net_service_1, 0));
+	/* Allows connect and deny bind operations to the port[1] socket. */
+	ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_SERVICE,
+				       &net_service_2, 0));
+
+	/* Enforces the ruleset. */
+	enforce_ruleset(_metadata, ruleset_fd);
+
+	/* Creates a server socket 1. */
+	sockfd_1 = create_socket_variant(variant, SOCK_STREAM);
+	ASSERT_LE(0, sockfd_1);
+
+	/* Binds the socket 1 to address with port[0]. */
+	ASSERT_EQ(0, bind_variant(variant, sockfd_1, self, 0));
+
+	/* Makes listening socket 1. */
+	ASSERT_EQ(0, listen(sockfd_1, BACKLOG));
+
+	child_1 = fork();
+	ASSERT_LE(0, child_1);
+	if (child_1 == 0) {
+		int child_sockfd;
+
+		/* Closes listening socket for the child. */
+		ASSERT_EQ(0, close(sockfd_1));
+		/* Creates a stream client socket. */
+		child_sockfd = create_socket_variant(variant, SOCK_STREAM);
+		ASSERT_LE(0, child_sockfd);
+
+		/* Makes connection to the listening socket with port[0]. */
+		ASSERT_EQ(0, connect_variant(variant, child_sockfd, self, 0));
+		_exit(_metadata->passed ? EXIT_SUCCESS : EXIT_FAILURE);
+		return;
+	}
+	/* Accepts connection from the child 1. */
+	new_fd = accept(sockfd_1, NULL, 0);
+	ASSERT_LE(0, new_fd);
+
+	/* Closes connection. */
+	ASSERT_EQ(0, close(new_fd));
+
+	/* Closes listening socket 1 for the parent. */
+	ASSERT_EQ(0, close(sockfd_1));
+
+	ASSERT_EQ(child_1, waitpid(child_1, &status, 0));
+	ASSERT_EQ(1, WIFEXITED(status));
+	ASSERT_EQ(EXIT_SUCCESS, WEXITSTATUS(status));
+
+	/* Creates a server socket 2. */
+	sockfd_2 = create_socket_variant(variant, SOCK_STREAM);
+	ASSERT_LE(0, sockfd_2);
+
+	/* Binds the socket 2 to address with port[1]. */
+	ASSERT_EQ(0, bind_variant(variant, sockfd_2, self, 1));
+
+	/* Makes listening socket 2. */
+	ASSERT_EQ(0, listen(sockfd_2, BACKLOG));
+
+	child_2 = fork();
+	ASSERT_LE(0, child_2);
+	if (child_2 == 0) {
+		int child_sockfd;
+
+		/* Closes listening socket for the child. */
+		ASSERT_EQ(0, close(sockfd_2));
+		/* Creates a stream client socket. */
+		child_sockfd = create_socket_variant(variant, SOCK_STREAM);
+		ASSERT_LE(0, child_sockfd);
+
+		/* Makes connection to the listening socket with port[1]. */
+		ASSERT_EQ(-1, connect_variant(variant, child_sockfd, self, 1));
+		ASSERT_EQ(EACCES, errno);
+		_exit(_metadata->passed ? EXIT_SUCCESS : EXIT_FAILURE);
+		return;
+	}
+
+	/* Closes listening socket 2 for the parent. */
+	ASSERT_EQ(0, close(sockfd_2));
+
+	ASSERT_EQ(child_2, waitpid(child_2, &status, 0));
+	ASSERT_EQ(1, WIFEXITED(status));
+	ASSERT_EQ(EXIT_SUCCESS, WEXITSTATUS(status));
+}
 TEST_HARNESS_MAIN
--
2.25.1


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v6 13/17] seltests/landlock: adds AF_UNSPEC family test
  2022-06-21  8:22 [PATCH v6 00/17] Network support for Landlock Konstantin Meskhidze
                   ` (11 preceding siblings ...)
  2022-06-21  8:23 ` [PATCH v6 12/17] seltests/landlock: adds tests for connect() hooks Konstantin Meskhidze
@ 2022-06-21  8:23 ` Konstantin Meskhidze
  2022-06-21  8:23 ` [PATCH v6 14/17] seltests/landlock: adds rules overlapping test Konstantin Meskhidze
                   ` (4 subsequent siblings)
  17 siblings, 0 replies; 53+ messages in thread
From: Konstantin Meskhidze @ 2022-06-21  8:23 UTC (permalink / raw)
  To: mic
  Cc: willemdebruijn.kernel, linux-security-module, netdev,
	netfilter-devel, yusongping, anton.sirazetdinov

Adds two selftests for connect() action with
AF_UNSPEC family flag.
The one is with no landlock restrictions
allows to disconnect already connected socket
with connect(..., AF_UNSPEC, ...):
    - connect_afunspec_no_restictions;
The second one refuses landlocked process
to disconnect already connected socket:
    - connect_afunspec_with_restictions;

Signed-off-by: Konstantin Meskhidze <konstantin.meskhidze@huawei.com>
---

Changes since v5:
* Formats code with clang-format-14.

Changes since v4:
* Refactors code with self->port, self->addr4 variables.
* Adds bind() hook check for with AF_UNSPEC family.

Changes since v3:
* Adds connect_afunspec_no_restictions test.
* Adds connect_afunspec_with_restictions test.

---
 tools/testing/selftests/landlock/net_test.c | 113 ++++++++++++++++++++
 1 file changed, 113 insertions(+)

diff --git a/tools/testing/selftests/landlock/net_test.c b/tools/testing/selftests/landlock/net_test.c
index ce6fd51a922d..c5fe4284c38f 100644
--- a/tools/testing/selftests/landlock/net_test.c
+++ b/tools/testing/selftests/landlock/net_test.c
@@ -351,4 +351,117 @@ TEST_F(socket, connect_with_restrictions)
 	ASSERT_EQ(1, WIFEXITED(status));
 	ASSERT_EQ(EXIT_SUCCESS, WEXITSTATUS(status));
 }
+
+TEST_F(socket, connect_afunspec_no_restictions)
+{
+	int sockfd;
+	pid_t child;
+	int status;
+
+	/* Creates a server socket 1. */
+	sockfd = create_socket_variant(variant, SOCK_STREAM);
+	ASSERT_LE(0, sockfd);
+
+	/* Binds the socket 1 to address with port[0]. */
+	ASSERT_EQ(0, bind_variant(variant, sockfd, self, 0));
+
+	/* Makes connection to the socket with port[0]. */
+	ASSERT_EQ(0, connect_variant(variant, sockfd, self, 0));
+
+	child = fork();
+	ASSERT_LE(0, child);
+	if (child == 0) {
+		struct sockaddr addr_unspec = { .sa_family = AF_UNSPEC };
+
+		/* Child tries to disconnect already connected socket. */
+		ASSERT_EQ(0, connect(sockfd, (struct sockaddr *)&addr_unspec,
+				     sizeof(addr_unspec)));
+		_exit(_metadata->passed ? EXIT_SUCCESS : EXIT_FAILURE);
+		return;
+	}
+	/* Closes listening socket 1 for the parent. */
+	ASSERT_EQ(0, close(sockfd));
+
+	ASSERT_EQ(child, waitpid(child, &status, 0));
+	ASSERT_EQ(1, WIFEXITED(status));
+	ASSERT_EQ(EXIT_SUCCESS, WEXITSTATUS(status));
+}
+
+TEST_F(socket, connect_afunspec_with_restictions)
+{
+	int sockfd;
+	pid_t child;
+	int status;
+
+	struct landlock_ruleset_attr ruleset_attr_1 = {
+		.handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP,
+	};
+	struct landlock_net_service_attr net_service_1 = {
+		.allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP,
+
+		.port = self->port[0],
+	};
+
+	struct landlock_ruleset_attr ruleset_attr_2 = {
+		.handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP |
+				      LANDLOCK_ACCESS_NET_CONNECT_TCP,
+	};
+	struct landlock_net_service_attr net_service_2 = {
+		.allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP |
+				  LANDLOCK_ACCESS_NET_CONNECT_TCP,
+
+		.port = self->port[0],
+	};
+
+	const int ruleset_fd_1 = landlock_create_ruleset(
+		&ruleset_attr_1, sizeof(ruleset_attr_1), 0);
+	ASSERT_LE(0, ruleset_fd_1);
+
+	/* Allows bind operations to the port[0] socket. */
+	ASSERT_EQ(0, landlock_add_rule(ruleset_fd_1, LANDLOCK_RULE_NET_SERVICE,
+				       &net_service_1, 0));
+
+	/* Enforces the ruleset. */
+	enforce_ruleset(_metadata, ruleset_fd_1);
+
+	/* Creates a server socket 1. */
+	sockfd = create_socket_variant(variant, SOCK_STREAM);
+	ASSERT_LE(0, sockfd);
+
+	/* Binds the socket 1 to address with port[0]. */
+	ASSERT_EQ(0, bind_variant(variant, sockfd, self, 0));
+
+	/* Makes connection to socket with port[0]. */
+	ASSERT_EQ(0, connect_variant(variant, sockfd, self, 0));
+
+	const int ruleset_fd_2 = landlock_create_ruleset(
+		&ruleset_attr_2, sizeof(ruleset_attr_2), 0);
+	ASSERT_LE(0, ruleset_fd_2);
+
+	/* Allows connect and bind operations to the port[0] socket. */
+	ASSERT_EQ(0, landlock_add_rule(ruleset_fd_2, LANDLOCK_RULE_NET_SERVICE,
+				       &net_service_2, 0));
+
+	/* Enforces the ruleset. */
+	enforce_ruleset(_metadata, ruleset_fd_2);
+
+	child = fork();
+	ASSERT_LE(0, child);
+	if (child == 0) {
+		struct sockaddr addr_unspec = { .sa_family = AF_UNSPEC };
+
+		/* Child tries to disconnect already connected socket. */
+		ASSERT_EQ(-1, connect(sockfd, (struct sockaddr *)&addr_unspec,
+				      sizeof(addr_unspec)));
+		ASSERT_EQ(EACCES, errno);
+		_exit(_metadata->passed ? EXIT_SUCCESS : EXIT_FAILURE);
+		return;
+	}
+	/* Closes listening socket 1 for the parent. */
+	ASSERT_EQ(0, close(sockfd));
+
+	ASSERT_EQ(child, waitpid(child, &status, 0));
+	ASSERT_EQ(1, WIFEXITED(status));
+	ASSERT_EQ(EXIT_SUCCESS, WEXITSTATUS(status));
+}
 TEST_HARNESS_MAIN
--
2.25.1


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v6 14/17] seltests/landlock: adds rules overlapping test
  2022-06-21  8:22 [PATCH v6 00/17] Network support for Landlock Konstantin Meskhidze
                   ` (12 preceding siblings ...)
  2022-06-21  8:23 ` [PATCH v6 13/17] seltests/landlock: adds AF_UNSPEC family test Konstantin Meskhidze
@ 2022-06-21  8:23 ` Konstantin Meskhidze
  2022-06-21  8:23 ` [PATCH v6 15/17] seltests/landlock: adds ruleset expanding test Konstantin Meskhidze
                   ` (3 subsequent siblings)
  17 siblings, 0 replies; 53+ messages in thread
From: Konstantin Meskhidze @ 2022-06-21  8:23 UTC (permalink / raw)
  To: mic
  Cc: willemdebruijn.kernel, linux-security-module, netdev,
	netfilter-devel, yusongping, anton.sirazetdinov

This patch adds overlapping rules for one port.
First rule adds just bind() access right for a port.
The second one adds both bind() and connect()
access rights for the same port.

Signed-off-by: Konstantin Meskhidze <konstantin.meskhidze@huawei.com>
---

Changes since v5:
* Formats code with clang-format-14.

Changes since v4:
* Refactors code with self->port, self->addr4 variables.

Changes since v3:
* Adds ruleset_overlap test.

---
 tools/testing/selftests/landlock/net_test.c | 89 +++++++++++++++++++++
 1 file changed, 89 insertions(+)

diff --git a/tools/testing/selftests/landlock/net_test.c b/tools/testing/selftests/landlock/net_test.c
index c5fe4284c38f..18ffd36f959c 100644
--- a/tools/testing/selftests/landlock/net_test.c
+++ b/tools/testing/selftests/landlock/net_test.c
@@ -464,4 +464,93 @@ TEST_F(socket, connect_afunspec_with_restictions)
 	ASSERT_EQ(1, WIFEXITED(status));
 	ASSERT_EQ(EXIT_SUCCESS, WEXITSTATUS(status));
 }
+
+TEST_F(socket, ruleset_overlap)
+{
+	int sockfd;
+	int one = 1;
+
+	struct landlock_ruleset_attr ruleset_attr = {
+		.handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP |
+				      LANDLOCK_ACCESS_NET_CONNECT_TCP,
+	};
+	struct landlock_net_service_attr net_service_1 = {
+		.allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP,
+
+		.port = self->port[0],
+	};
+
+	struct landlock_net_service_attr net_service_2 = {
+		.allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP |
+				  LANDLOCK_ACCESS_NET_CONNECT_TCP,
+
+		.port = self->port[0],
+	};
+
+	int ruleset_fd =
+		landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
+	ASSERT_LE(0, ruleset_fd);
+
+	/* Allows bind operations to the port[0] socket. */
+	ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_SERVICE,
+				       &net_service_1, 0));
+	/* Allows connect and bind operations to the port[0] socket. */
+	ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_SERVICE,
+				       &net_service_2, 0));
+
+	/* Enforces the ruleset. */
+	enforce_ruleset(_metadata, ruleset_fd);
+
+	/* Creates a server socket. */
+	sockfd = create_socket_variant(variant, SOCK_STREAM);
+	ASSERT_LE(0, sockfd);
+	/* Allows to reuse of local address. */
+	ASSERT_EQ(0, setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &one,
+				sizeof(one)));
+
+	/* Binds the socket to address with port[0]. */
+	ASSERT_EQ(0, bind_variant(variant, sockfd, self, 0));
+
+	/* Makes connection to socket with port[0]. */
+	ASSERT_EQ(0, connect_variant(variant, sockfd, self, 0));
+
+	/* Closes socket. */
+	ASSERT_EQ(0, close(sockfd));
+
+	/* Creates another ruleset layer. */
+	ruleset_fd =
+		landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
+	ASSERT_LE(0, ruleset_fd);
+
+	/*
+	 * Allows bind operations to the port[0] socket in
+	 * the new ruleset layer.
+	 */
+	ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_SERVICE,
+				       &net_service_1, 0));
+
+	/* Enforces the new ruleset. */
+	enforce_ruleset(_metadata, ruleset_fd);
+
+	/* Creates a server socket. */
+	sockfd = create_socket_variant(variant, SOCK_STREAM);
+	ASSERT_LE(0, sockfd);
+	/* Allows to reuse of local address. */
+	ASSERT_EQ(0, setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &one,
+				sizeof(one)));
+
+	/* Binds the socket to address with port[0]. */
+	ASSERT_EQ(0, bind_variant(variant, sockfd, self, 0));
+
+	/*
+	 * Forbids to connect the socket to address with port[0],
+	 * cause just one ruleset layer has connect() access rule.
+	 */
+	ASSERT_EQ(-1, connect_variant(variant, sockfd, self, 0));
+	ASSERT_EQ(EACCES, errno);
+
+	/* Closes socket. */
+	ASSERT_EQ(0, close(sockfd));
+}
+
 TEST_HARNESS_MAIN
--
2.25.1


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v6 15/17] seltests/landlock: adds ruleset expanding test
  2022-06-21  8:22 [PATCH v6 00/17] Network support for Landlock Konstantin Meskhidze
                   ` (13 preceding siblings ...)
  2022-06-21  8:23 ` [PATCH v6 14/17] seltests/landlock: adds rules overlapping test Konstantin Meskhidze
@ 2022-06-21  8:23 ` Konstantin Meskhidze
  2022-06-21  8:23 ` [PATCH v6 16/17] seltests/landlock: adds invalid input data test Konstantin Meskhidze
                   ` (2 subsequent siblings)
  17 siblings, 0 replies; 53+ messages in thread
From: Konstantin Meskhidze @ 2022-06-21  8:23 UTC (permalink / raw)
  To: mic
  Cc: willemdebruijn.kernel, linux-security-module, netdev,
	netfilter-devel, yusongping, anton.sirazetdinov

This patch adds expanding rulesets in which
rules are gradually added one by one, restricting
sockets' connections.

Signed-off-by: Konstantin Meskhidze <konstantin.meskhidze@huawei.com>
---

Changes since v5:
* Formats code with clang-format-14.

Changes since v4:
* Refactors code with self->port, self->addr4 variables.

Changes since v3:
* Adds ruleset_expanding test.

---
 tools/testing/selftests/landlock/net_test.c | 166 ++++++++++++++++++++
 1 file changed, 166 insertions(+)

diff --git a/tools/testing/selftests/landlock/net_test.c b/tools/testing/selftests/landlock/net_test.c
index 18ffd36f959c..a9cb47836a21 100644
--- a/tools/testing/selftests/landlock/net_test.c
+++ b/tools/testing/selftests/landlock/net_test.c
@@ -553,4 +553,170 @@ TEST_F(socket, ruleset_overlap)
 	ASSERT_EQ(0, close(sockfd));
 }

+TEST_F(socket, ruleset_expanding)
+{
+	int sockfd_1, sockfd_2;
+	int one = 1;
+
+	struct landlock_ruleset_attr ruleset_attr_1 = {
+		.handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP,
+	};
+	struct landlock_net_service_attr net_service_1 = {
+		.allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP,
+
+		.port = self->port[0],
+	};
+
+	const int ruleset_fd_1 = landlock_create_ruleset(
+		&ruleset_attr_1, sizeof(ruleset_attr_1), 0);
+	ASSERT_LE(0, ruleset_fd_1);
+
+	/* Adds rule to port[0] socket. */
+	ASSERT_EQ(0, landlock_add_rule(ruleset_fd_1, LANDLOCK_RULE_NET_SERVICE,
+				       &net_service_1, 0));
+
+	/* Enforces the ruleset. */
+	enforce_ruleset(_metadata, ruleset_fd_1);
+	ASSERT_EQ(0, close(ruleset_fd_1));
+
+	/* Creates a socket 1. */
+	sockfd_1 = create_socket_variant(variant, SOCK_STREAM);
+	ASSERT_LE(0, sockfd_1);
+	/* Allows to reuse of local address. */
+	ASSERT_EQ(0, setsockopt(sockfd_1, SOL_SOCKET, SO_REUSEADDR, &one,
+				sizeof(one)));
+
+	/* Binds the socket 1 to address with port[0]. */
+	ASSERT_EQ(0, bind_variant(variant, sockfd_1, self, 0));
+
+	/* Makes connection to socket 1 with port[0]. */
+	ASSERT_EQ(0, connect_variant(variant, sockfd_1, self, 0));
+
+	/* Closes socket 1. */
+	ASSERT_EQ(0, close(sockfd_1));
+
+	/* Creates a socket 2. */
+	sockfd_2 = create_socket_variant(variant, SOCK_STREAM);
+	ASSERT_LE(0, sockfd_2);
+	/* Allows to reuse of local address. */
+	ASSERT_EQ(0, setsockopt(sockfd_2, SOL_SOCKET, SO_REUSEADDR, &one,
+				sizeof(one)));
+
+	/*
+	 * Forbids to bind the socket 2 to address with port[1],
+	 * cause there is no rule with bind() access for port[1].
+	 */
+	ASSERT_EQ(-1, bind_variant(variant, sockfd_2, self, 1));
+	ASSERT_EQ(EACCES, errno);
+
+	/* Expands network mask. */
+	struct landlock_ruleset_attr ruleset_attr_2 = {
+		.handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP |
+				      LANDLOCK_ACCESS_NET_CONNECT_TCP,
+	};
+
+	/* Adds connect() access to port[0]. */
+	struct landlock_net_service_attr net_service_2 = {
+		.allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP |
+				  LANDLOCK_ACCESS_NET_CONNECT_TCP,
+
+		.port = self->port[0],
+	};
+	/* Adds bind() access to port[1]. */
+	struct landlock_net_service_attr net_service_3 = {
+		.allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP,
+
+		.port = self->port[1],
+	};
+
+	const int ruleset_fd_2 = landlock_create_ruleset(
+		&ruleset_attr_2, sizeof(ruleset_attr_2), 0);
+	ASSERT_LE(0, ruleset_fd_2);
+
+	/* Adds rule to port[0] socket. */
+	ASSERT_EQ(0, landlock_add_rule(ruleset_fd_2, LANDLOCK_RULE_NET_SERVICE,
+				       &net_service_2, 0));
+	/* Adds rule to port[1] socket. */
+	ASSERT_EQ(0, landlock_add_rule(ruleset_fd_2, LANDLOCK_RULE_NET_SERVICE,
+				       &net_service_3, 0));
+
+	/* Enforces the ruleset. */
+	enforce_ruleset(_metadata, ruleset_fd_2);
+	ASSERT_EQ(0, close(ruleset_fd_2));
+
+	/* Creates a socket 1. */
+	sockfd_1 = create_socket_variant(variant, SOCK_STREAM);
+	ASSERT_LE(0, sockfd_1);
+	/* Allows to reuse of local address. */
+	ASSERT_EQ(0, setsockopt(sockfd_1, SOL_SOCKET, SO_REUSEADDR, &one,
+				sizeof(one)));
+
+	/* Binds the socket 1 to address with port[0]. */
+	ASSERT_EQ(0, bind_variant(variant, sockfd_1, self, 0));
+
+	/* Makes connection to socket 1 with port[0]. */
+	ASSERT_EQ(0, connect_variant(variant, sockfd_1, self, 0));
+
+	/* Closes socket 1. */
+	ASSERT_EQ(0, close(sockfd_1));
+
+	/* Creates a socket 2. */
+	sockfd_2 = create_socket_variant(variant, SOCK_STREAM);
+	ASSERT_LE(0, sockfd_2);
+	/* Allows to reuse of local address. */
+	ASSERT_EQ(0, setsockopt(sockfd_2, SOL_SOCKET, SO_REUSEADDR, &one,
+				sizeof(one)));
+
+	/*
+	 * Forbids to bind the socket 2 to address with port[1],
+	 * cause just one layer has bind() access rule.
+	 */
+	ASSERT_EQ(-1, bind_variant(variant, sockfd_1, self, 1));
+	ASSERT_EQ(EACCES, errno);
+
+	/* Expands network mask. */
+	struct landlock_ruleset_attr ruleset_attr_3 = {
+		.handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP |
+				      LANDLOCK_ACCESS_NET_CONNECT_TCP,
+	};
+
+	/* Restricts connect() access to port[0]. */
+	struct landlock_net_service_attr net_service_4 = {
+		.allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP,
+
+		.port = self->port[0],
+	};
+
+	const int ruleset_fd_3 = landlock_create_ruleset(
+		&ruleset_attr_3, sizeof(ruleset_attr_3), 0);
+	ASSERT_LE(0, ruleset_fd_3);
+
+	/* Adds rule to port[0] socket. */
+	ASSERT_EQ(0, landlock_add_rule(ruleset_fd_3, LANDLOCK_RULE_NET_SERVICE,
+				       &net_service_4, 0));
+
+	/* Enforces the ruleset. */
+	enforce_ruleset(_metadata, ruleset_fd_3);
+	ASSERT_EQ(0, close(ruleset_fd_3));
+
+	/* Creates a socket 1. */
+	sockfd_1 = create_socket_variant(variant, SOCK_STREAM);
+	ASSERT_LE(0, sockfd_1);
+	/* Allows to reuse of local address. */
+	ASSERT_EQ(0, setsockopt(sockfd_1, SOL_SOCKET, SO_REUSEADDR, &one,
+				sizeof(one)));
+
+	/* Binds the socket 1 to address with port[0]. */
+	ASSERT_EQ(0, bind_variant(variant, sockfd_1, self, 0));
+
+	/*
+	 * Forbids to connect the socket 1 to address with port[0],
+	 * cause just one layer has connect() access rule.
+	 */
+	ASSERT_EQ(-1, connect_variant(variant, sockfd_1, self, 0));
+	ASSERT_EQ(EACCES, errno);
+
+	/* Closes socket 1. */
+	ASSERT_EQ(0, close(sockfd_1));
+}
 TEST_HARNESS_MAIN
--
2.25.1


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v6 16/17] seltests/landlock: adds invalid input data test
  2022-06-21  8:22 [PATCH v6 00/17] Network support for Landlock Konstantin Meskhidze
                   ` (14 preceding siblings ...)
  2022-06-21  8:23 ` [PATCH v6 15/17] seltests/landlock: adds ruleset expanding test Konstantin Meskhidze
@ 2022-06-21  8:23 ` Konstantin Meskhidze
  2022-06-21  8:23 ` [PATCH v6 17/17] samples/landlock: adds network demo Konstantin Meskhidze
  2022-07-26 17:43 ` [PATCH v6 00/17] Network support for Landlock Mickaël Salaün
  17 siblings, 0 replies; 53+ messages in thread
From: Konstantin Meskhidze @ 2022-06-21  8:23 UTC (permalink / raw)
  To: mic
  Cc: willemdebruijn.kernel, linux-security-module, netdev,
	netfilter-devel, yusongping, anton.sirazetdinov

This patch adds rules with invalid user space
supplied data:
    - unhandled allowed access;
    - zero port value;
    - zero access value;

Signed-off-by: Konstantin Meskhidze <konstantin.meskhidze@huawei.com>
---

Changes since v5:
* Formats code with clang-format-14.

Changes since v4:
* Refactors code with self->port variable.

Changes since v3:
* Adds inval test.

---
 tools/testing/selftests/landlock/net_test.c | 52 +++++++++++++++++++++
 1 file changed, 52 insertions(+)

diff --git a/tools/testing/selftests/landlock/net_test.c b/tools/testing/selftests/landlock/net_test.c
index a9cb47836a21..ade834ab6497 100644
--- a/tools/testing/selftests/landlock/net_test.c
+++ b/tools/testing/selftests/landlock/net_test.c
@@ -719,4 +719,56 @@ TEST_F(socket, ruleset_expanding)
 	/* Closes socket 1. */
 	ASSERT_EQ(0, close(sockfd_1));
 }
+
+TEST_F(socket, inval)
+{
+	struct landlock_ruleset_attr ruleset_attr = {
+		.handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP
+	};
+	struct landlock_net_service_attr net_service_1 = {
+		.allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP |
+				  LANDLOCK_ACCESS_NET_CONNECT_TCP,
+		.port = self->port[0],
+	};
+	struct landlock_net_service_attr net_service_2 = {
+		.allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP,
+		.port = 0,
+	};
+	struct landlock_net_service_attr net_service_3 = {
+		.allowed_access = 0,
+		.port = self->port[1],
+	};
+	struct landlock_net_service_attr net_service_4 = {
+		.allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP,
+		.port = self->port[2],
+	};
+
+	/* Gets ruleset. */
+	const int ruleset_fd =
+		landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
+	ASSERT_LE(0, ruleset_fd);
+
+	/* Checks unhandled allowed_access. */
+	ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_SERVICE,
+					&net_service_1, 0));
+	ASSERT_EQ(EINVAL, errno);
+
+	/* Checks zero port value. */
+	ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_SERVICE,
+					&net_service_2, 0));
+	ASSERT_EQ(EINVAL, errno);
+
+	/* Checks zero access value. */
+	ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_SERVICE,
+					&net_service_3, 0));
+	ASSERT_EQ(ENOMSG, errno);
+
+	/* Adds with legitimate values. */
+	ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_SERVICE,
+				       &net_service_4, 0));
+
+	/* Enforces the ruleset. */
+	enforce_ruleset(_metadata, ruleset_fd);
+	ASSERT_EQ(0, close(ruleset_fd));
+}
 TEST_HARNESS_MAIN
--
2.25.1


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v6 17/17] samples/landlock: adds network demo
  2022-06-21  8:22 [PATCH v6 00/17] Network support for Landlock Konstantin Meskhidze
                   ` (15 preceding siblings ...)
  2022-06-21  8:23 ` [PATCH v6 16/17] seltests/landlock: adds invalid input data test Konstantin Meskhidze
@ 2022-06-21  8:23 ` Konstantin Meskhidze
  2022-07-27 20:26   ` Mickaël Salaün
  2022-07-26 17:43 ` [PATCH v6 00/17] Network support for Landlock Mickaël Salaün
  17 siblings, 1 reply; 53+ messages in thread
From: Konstantin Meskhidze @ 2022-06-21  8:23 UTC (permalink / raw)
  To: mic
  Cc: willemdebruijn.kernel, linux-security-module, netdev,
	netfilter-devel, yusongping, anton.sirazetdinov

This commit adds network demo. It's possible to
allow a sandoxer to bind/connect to a list of
particular ports restricting networks actions to
the rest of ports.

Signed-off-by: Konstantin Meskhidze <konstantin.meskhidze@huawei.com>
---

Changes since v5:
* Makes network ports sandboxing optional.
* Fixes some logic errors.
* Formats code with clang-format-14.

Changes since v4:
* Adds ENV_TCP_BIND_NAME "LL_TCP_BIND" and
ENV_TCP_CONNECT_NAME "LL_TCP_CONNECT" variables
to insert TCP ports.
* Renames populate_ruleset() to populate_ruleset_fs().
* Adds populate_ruleset_net() and parse_port_num() helpers.
* Refactors main() to support network sandboxing.

---
 samples/landlock/sandboxer.c | 118 +++++++++++++++++++++++++++++++----
 1 file changed, 107 insertions(+), 11 deletions(-)

diff --git a/samples/landlock/sandboxer.c b/samples/landlock/sandboxer.c
index 3e404e51ec64..0606c676fded 100644
--- a/samples/landlock/sandboxer.c
+++ b/samples/landlock/sandboxer.c
@@ -51,6 +51,8 @@ static inline int landlock_restrict_self(const int ruleset_fd,

 #define ENV_FS_RO_NAME "LL_FS_RO"
 #define ENV_FS_RW_NAME "LL_FS_RW"
+#define ENV_TCP_BIND_NAME "LL_TCP_BIND"
+#define ENV_TCP_CONNECT_NAME "LL_TCP_CONNECT"
 #define ENV_PATH_TOKEN ":"

 static int parse_path(char *env_path, const char ***const path_list)
@@ -71,6 +73,20 @@ static int parse_path(char *env_path, const char ***const path_list)
 	return num_paths;
 }

+static int parse_port_num(char *env_port)
+{
+	int i, num_ports = 0;
+
+	if (env_port) {
+		num_ports++;
+		for (i = 0; env_port[i]; i++) {
+			if (env_port[i] == ENV_PATH_TOKEN[0])
+				num_ports++;
+		}
+	}
+	return num_ports;
+}
+
 /* clang-format off */

 #define ACCESS_FILE ( \
@@ -80,8 +96,8 @@ static int parse_path(char *env_path, const char ***const path_list)

 /* clang-format on */

-static int populate_ruleset(const char *const env_var, const int ruleset_fd,
-			    const __u64 allowed_access)
+static int populate_ruleset_fs(const char *const env_var, const int ruleset_fd,
+			       const __u64 allowed_access)
 {
 	int num_paths, i, ret = 1;
 	char *env_path_name;
@@ -142,6 +158,48 @@ static int populate_ruleset(const char *const env_var, const int ruleset_fd,
 	return ret;
 }

+static int populate_ruleset_net(const char *const env_var, const int ruleset_fd,
+				const __u64 allowed_access)
+{
+	int num_ports, i, ret = 1;
+	char *env_port_name;
+	struct landlock_net_service_attr net_service = {
+		.allowed_access = 0,
+		.port = 0,
+	};
+
+	env_port_name = getenv(env_var);
+	if (!env_port_name) {
+		ret = 0;
+		goto out_free_name;
+	}
+	env_port_name = strdup(env_port_name);
+	unsetenv(env_var);
+	num_ports = parse_port_num(env_port_name);
+
+	if (num_ports == 1 && (strtok(env_port_name, ENV_PATH_TOKEN) == NULL)) {
+		ret = 0;
+		goto out_free_name;
+	}
+
+	for (i = 0; i < num_ports; i++) {
+		net_service.allowed_access = allowed_access;
+		net_service.port = atoi(strsep(&env_port_name, ENV_PATH_TOKEN));
+		if (landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_SERVICE,
+				      &net_service, 0)) {
+			fprintf(stderr,
+				"Failed to update the ruleset with port \"%d\": %s\n",
+				net_service.port, strerror(errno));
+			goto out_free_name;
+		}
+	}
+	ret = 0;
+
+out_free_name:
+	free(env_port_name);
+	return ret;
+}
+
 /* clang-format off */

 #define ACCESS_FS_ROUGHLY_READ ( \
@@ -172,32 +230,50 @@ int main(const int argc, char *const argv[], char *const *const envp)
 	const char *cmd_path;
 	char *const *cmd_argv;
 	int ruleset_fd, abi;
+	char *env_port_name;
 	__u64 access_fs_ro = ACCESS_FS_ROUGHLY_READ,
-	      access_fs_rw = ACCESS_FS_ROUGHLY_READ | ACCESS_FS_ROUGHLY_WRITE;
+	      access_fs_rw = ACCESS_FS_ROUGHLY_READ | ACCESS_FS_ROUGHLY_WRITE,
+	      access_net_tcp = 0;
 	struct landlock_ruleset_attr ruleset_attr = {
 		.handled_access_fs = access_fs_rw,
+		.handled_access_net = access_net_tcp,
 	};

 	if (argc < 2) {
 		fprintf(stderr,
-			"usage: %s=\"...\" %s=\"...\" %s <cmd> [args]...\n\n",
-			ENV_FS_RO_NAME, ENV_FS_RW_NAME, argv[0]);
+			"usage: %s=\"...\" %s=\"...\" %s=\"...\" %s=\"...\"%s "
+			"<cmd> [args]...\n\n",
+			ENV_FS_RO_NAME, ENV_FS_RW_NAME, ENV_TCP_BIND_NAME,
+			ENV_TCP_CONNECT_NAME, argv[0]);
 		fprintf(stderr,
 			"Launch a command in a restricted environment.\n\n");
-		fprintf(stderr, "Environment variables containing paths, "
-				"each separated by a colon:\n");
+		fprintf(stderr,
+			"Environment variables containing paths and ports "
+			"each separated by a colon:\n");
 		fprintf(stderr,
 			"* %s: list of paths allowed to be used in a read-only way.\n",
 			ENV_FS_RO_NAME);
 		fprintf(stderr,
-			"* %s: list of paths allowed to be used in a read-write way.\n",
+			"* %s: list of paths allowed to be used in a read-write way.\n\n",
 			ENV_FS_RW_NAME);
+		fprintf(stderr,
+			"Environment variables containing ports are optional "
+			"and could be skipped.\n");
+		fprintf(stderr,
+			"* %s: list of ports allowed to bind (server).\n",
+			ENV_TCP_BIND_NAME);
+		fprintf(stderr,
+			"* %s: list of ports allowed to connect (client).\n",
+			ENV_TCP_CONNECT_NAME);
 		fprintf(stderr,
 			"\nexample:\n"
 			"%s=\"/bin:/lib:/usr:/proc:/etc:/dev/urandom\" "
 			"%s=\"/dev/null:/dev/full:/dev/zero:/dev/pts:/tmp\" "
+			"%s=\"9418\" "
+			"%s=\"80:443\" "
 			"%s bash -i\n",
-			ENV_FS_RO_NAME, ENV_FS_RW_NAME, argv[0]);
+			ENV_FS_RO_NAME, ENV_FS_RW_NAME, ENV_TCP_BIND_NAME,
+			ENV_TCP_CONNECT_NAME, argv[0]);
 		return 1;
 	}

@@ -232,16 +308,36 @@ int main(const int argc, char *const argv[], char *const *const envp)
 		access_fs_rw &= ~ACCESS_ABI_2;
 	}

+	/* Adds optionally network bind() support. */
+	env_port_name = getenv(ENV_TCP_BIND_NAME);
+	if (env_port_name) {
+		access_net_tcp |= LANDLOCK_ACCESS_NET_BIND_TCP;
+	}
+	/* Adds optionally network connect() support. */
+	env_port_name = getenv(ENV_TCP_CONNECT_NAME);
+	if (env_port_name) {
+		access_net_tcp |= LANDLOCK_ACCESS_NET_CONNECT_TCP;
+	}
+	ruleset_attr.handled_access_net = access_net_tcp;
+
 	ruleset_fd =
 		landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
 	if (ruleset_fd < 0) {
 		perror("Failed to create a ruleset");
 		return 1;
 	}
-	if (populate_ruleset(ENV_FS_RO_NAME, ruleset_fd, access_fs_ro)) {
+	if (populate_ruleset_fs(ENV_FS_RO_NAME, ruleset_fd, access_fs_ro)) {
+		goto err_close_ruleset;
+	}
+	if (populate_ruleset_fs(ENV_FS_RW_NAME, ruleset_fd, access_fs_rw)) {
+		goto err_close_ruleset;
+	}
+	if (populate_ruleset_net(ENV_TCP_BIND_NAME, ruleset_fd,
+				 LANDLOCK_ACCESS_NET_BIND_TCP)) {
 		goto err_close_ruleset;
 	}
-	if (populate_ruleset(ENV_FS_RW_NAME, ruleset_fd, access_fs_rw)) {
+	if (populate_ruleset_net(ENV_TCP_CONNECT_NAME, ruleset_fd,
+				 LANDLOCK_ACCESS_NET_CONNECT_TCP)) {
 		goto err_close_ruleset;
 	}
 	if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
--
2.25.1


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 01/17] landlock: renames access mask
  2022-06-21  8:22 ` [PATCH v6 01/17] landlock: renames access mask Konstantin Meskhidze
@ 2022-07-01 17:08   ` Mickaël Salaün
  2022-07-04  9:23     ` Konstantin Meskhidze (A)
  2022-07-05 11:29     ` Konstantin Meskhidze (A)
  0 siblings, 2 replies; 53+ messages in thread
From: Mickaël Salaün @ 2022-07-01 17:08 UTC (permalink / raw)
  To: Konstantin Meskhidze
  Cc: willemdebruijn.kernel, linux-security-module, netdev,
	netfilter-devel, yusongping, anton.sirazetdinov


On 21/06/2022 10:22, Konstantin Meskhidze wrote:
> To support network type rules,
> this modification extends and renames
> ruleset's access masks.
> This patch adds filesystem helper functions
> to set and get filesystem mask. Also the
> modification adds a helper structure
> landlock_access_mask to support managing
> multiple access mask.

Please use a text-width of 72 columns for all commit messages. You can 
also split them into paragraphs.

> 
> Signed-off-by: Konstantin Meskhidze <konstantin.meskhidze@huawei.com>
> ---
> 
> Changes since v5:
> * Changes access_mask_t to u32.
> * Formats code with clang-format-14.
> 
> Changes since v4:
> * Deletes struct landlock_access_mask.
> 
> Changes since v3:
> * Splits commit.
> * Adds get_mask, set_mask helpers for filesystem.
> * Adds new struct landlock_access_mask.
> 
> ---
>   security/landlock/fs.c       |  7 ++++---
>   security/landlock/ruleset.c  | 18 +++++++++---------
>   security/landlock/ruleset.h  | 25 ++++++++++++++++++++-----
>   security/landlock/syscalls.c |  7 ++++---
>   4 files changed, 37 insertions(+), 20 deletions(-)
> 
> diff --git a/security/landlock/fs.c b/security/landlock/fs.c
> index ec5a6247cd3e..e6da08ed99d1 100644
> --- a/security/landlock/fs.c
> +++ b/security/landlock/fs.c
> @@ -167,7 +167,8 @@ int landlock_append_fs_rule(struct landlock_ruleset *const ruleset,
>   		return -EINVAL;
> 
>   	/* Transforms relative access rights to absolute ones. */
> -	access_rights |= LANDLOCK_MASK_ACCESS_FS & ~ruleset->fs_access_masks[0];
> +	access_rights |= LANDLOCK_MASK_ACCESS_FS &
> +			 ~landlock_get_fs_access_mask(ruleset, 0);
>   	object = get_inode_object(d_backing_inode(path->dentry));
>   	if (IS_ERR(object))
>   		return PTR_ERR(object);
> @@ -286,7 +287,7 @@ get_handled_accesses(const struct landlock_ruleset *const domain)
> 
>   		for (layer_level = 0; layer_level < domain->num_layers;
>   		     layer_level++) {
> -			if (domain->fs_access_masks[layer_level] &
> +			if (landlock_get_fs_access_mask(domain, layer_level) &
>   			    BIT_ULL(access_bit)) {
>   				access_dom |= BIT_ULL(access_bit);
>   				break;
> @@ -316,7 +317,7 @@ init_layer_masks(const struct landlock_ruleset *const domain,
> 
>   		for_each_set_bit(access_bit, &access_req,
>   				 ARRAY_SIZE(*layer_masks)) {
> -			if (domain->fs_access_masks[layer_level] &
> +			if (landlock_get_fs_access_mask(domain, layer_level) &
>   			    BIT_ULL(access_bit)) {
>   				(*layer_masks)[access_bit] |=
>   					BIT_ULL(layer_level);
> diff --git a/security/landlock/ruleset.c b/security/landlock/ruleset.c
> index 996484f98bfd..a3fd58d01f09 100644
> --- a/security/landlock/ruleset.c
> +++ b/security/landlock/ruleset.c
> @@ -29,7 +29,7 @@ static struct landlock_ruleset *create_ruleset(const u32 num_layers)
>   	struct landlock_ruleset *new_ruleset;
> 
>   	new_ruleset =
> -		kzalloc(struct_size(new_ruleset, fs_access_masks, num_layers),
> +		kzalloc(struct_size(new_ruleset, access_masks, num_layers),
>   			GFP_KERNEL_ACCOUNT);
>   	if (!new_ruleset)
>   		return ERR_PTR(-ENOMEM);
> @@ -40,22 +40,22 @@ static struct landlock_ruleset *create_ruleset(const u32 num_layers)
>   	/*
>   	 * hierarchy = NULL
>   	 * num_rules = 0
> -	 * fs_access_masks[] = 0
> +	 * access_masks[] = 0
>   	 */
>   	return new_ruleset;
>   }
> 
>   struct landlock_ruleset *
> -landlock_create_ruleset(const access_mask_t fs_access_mask)
> +landlock_create_ruleset(const access_mask_t access_mask)
>   {
>   	struct landlock_ruleset *new_ruleset;
> 
>   	/* Informs about useless ruleset. */
> -	if (!fs_access_mask)
> +	if (!access_mask)
>   		return ERR_PTR(-ENOMSG);
>   	new_ruleset = create_ruleset(1);
>   	if (!IS_ERR(new_ruleset))
> -		new_ruleset->fs_access_masks[0] = fs_access_mask;
> +		landlock_set_fs_access_mask(new_ruleset, access_mask, 0);
>   	return new_ruleset;
>   }
> 
> @@ -117,7 +117,7 @@ static void build_check_ruleset(void)
>   		.num_rules = ~0,
>   		.num_layers = ~0,
>   	};
> -	typeof(ruleset.fs_access_masks[0]) fs_access_mask = ~0;
> +	typeof(ruleset.access_masks[0]) fs_access_mask = ~0;
> 
>   	BUILD_BUG_ON(ruleset.num_rules < LANDLOCK_MAX_NUM_RULES);
>   	BUILD_BUG_ON(ruleset.num_layers < LANDLOCK_MAX_NUM_LAYERS);
> @@ -281,7 +281,7 @@ static int merge_ruleset(struct landlock_ruleset *const dst,
>   		err = -EINVAL;
>   		goto out_unlock;
>   	}
> -	dst->fs_access_masks[dst->num_layers - 1] = src->fs_access_masks[0];
> +	dst->access_masks[dst->num_layers - 1] = src->access_masks[0];
> 
>   	/* Merges the @src tree. */
>   	rbtree_postorder_for_each_entry_safe(walker_rule, next_rule, &src->root,
> @@ -340,8 +340,8 @@ static int inherit_ruleset(struct landlock_ruleset *const parent,
>   		goto out_unlock;
>   	}
>   	/* Copies the parent layer stack and leaves a space for the new layer. */
> -	memcpy(child->fs_access_masks, parent->fs_access_masks,
> -	       flex_array_size(parent, fs_access_masks, parent->num_layers));
> +	memcpy(child->access_masks, parent->access_masks,
> +	       flex_array_size(parent, access_masks, parent->num_layers));
> 
>   	if (WARN_ON_ONCE(!parent->hierarchy)) {
>   		err = -EINVAL;
> diff --git a/security/landlock/ruleset.h b/security/landlock/ruleset.h
> index d43231b783e4..bd7ab39859bf 100644
> --- a/security/landlock/ruleset.h
> +++ b/security/landlock/ruleset.h
> @@ -19,7 +19,7 @@
>   #include "limits.h"
>   #include "object.h"
> 
> -typedef u16 access_mask_t;
> +typedef u32 access_mask_t;
>   /* Makes sure all filesystem access rights can be stored. */
>   static_assert(BITS_PER_TYPE(access_mask_t) >= LANDLOCK_NUM_ACCESS_FS);
>   /* Makes sure for_each_set_bit() and for_each_clear_bit() calls are OK. */
> @@ -110,7 +110,7 @@ struct landlock_ruleset {
>   		 * section.  This is only used by
>   		 * landlock_put_ruleset_deferred() when @usage reaches zero.
>   		 * The fields @lock, @usage, @num_rules, @num_layers and
> -		 * @fs_access_masks are then unused.
> +		 * @access_masks are then unused.
>   		 */
>   		struct work_struct work_free;
>   		struct {
> @@ -137,7 +137,7 @@ struct landlock_ruleset {
>   			 */
>   			u32 num_layers;
>   			/**
> -			 * @fs_access_masks: Contains the subset of filesystem
> +			 * @access_masks: Contains the subset of filesystem
>   			 * actions that are restricted by a ruleset.  A domain
>   			 * saves all layers of merged rulesets in a stack
>   			 * (FAM), starting from the first layer to the last
> @@ -148,13 +148,13 @@ struct landlock_ruleset {
>   			 * layers are set once and never changed for the
>   			 * lifetime of the ruleset.
>   			 */
> -			access_mask_t fs_access_masks[];
> +			access_mask_t access_masks[];
>   		};
>   	};
>   };
> 
>   struct landlock_ruleset *
> -landlock_create_ruleset(const access_mask_t fs_access_mask);
> +landlock_create_ruleset(const access_mask_t access_mask);
> 
>   void landlock_put_ruleset(struct landlock_ruleset *const ruleset);
>   void landlock_put_ruleset_deferred(struct landlock_ruleset *const ruleset);
> @@ -177,4 +177,19 @@ static inline void landlock_get_ruleset(struct landlock_ruleset *const ruleset)
>   		refcount_inc(&ruleset->usage);
>   }
> 
> +/* A helper function to set a filesystem mask. */
> +static inline void
> +landlock_set_fs_access_mask(struct landlock_ruleset *ruleset,
> +			    const access_mask_t access_maskset, u16 mask_level)
> +{
> +	ruleset->access_masks[mask_level] = access_maskset;
> +}
> +
> +/* A helper function to get a filesystem mask. */
> +static inline u32

You need to use access_mask_t everywhere, including here.

> +landlock_get_fs_access_mask(const struct landlock_ruleset *ruleset,
> +			    u16 mask_level)
> +{
> +	return ruleset->access_masks[mask_level];
> +}
>   #endif /* _SECURITY_LANDLOCK_RULESET_H */
> diff --git a/security/landlock/syscalls.c b/security/landlock/syscalls.c
> index 735a0865ea11..5836736ce9d7 100644
> --- a/security/landlock/syscalls.c
> +++ b/security/landlock/syscalls.c
> @@ -346,10 +346,11 @@ SYSCALL_DEFINE4(landlock_add_rule, const int, ruleset_fd,
>   	}
>   	/*
>   	 * Checks that allowed_access matches the @ruleset constraints
> -	 * (ruleset->fs_access_masks[0] is automatically upgraded to 64-bits).
> +	 * (ruleset->access_masks[0] is automatically upgraded to 64-bits).
>   	 */
> -	if ((path_beneath_attr.allowed_access | ruleset->fs_access_masks[0]) !=
> -	    ruleset->fs_access_masks[0]) {
> +	if ((path_beneath_attr.allowed_access |
> +	     landlock_get_fs_access_mask(ruleset, 0)) !=
> +	    landlock_get_fs_access_mask(ruleset, 0)) {
>   		err = -EINVAL;
>   		goto out_put_ruleset;
>   	}
> --
> 2.25.1
> 

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 01/17] landlock: renames access mask
  2022-07-01 17:08   ` Mickaël Salaün
@ 2022-07-04  9:23     ` Konstantin Meskhidze (A)
  2022-07-05 11:29     ` Konstantin Meskhidze (A)
  1 sibling, 0 replies; 53+ messages in thread
From: Konstantin Meskhidze (A) @ 2022-07-04  9:23 UTC (permalink / raw)
  To: Mickaël Salaün
  Cc: willemdebruijn.kernel, linux-security-module, netdev,
	netfilter-devel, yusongping, anton.sirazetdinov



7/1/2022 8:08 PM, Mickaël Salaün пишет:
> 
> On 21/06/2022 10:22, Konstantin Meskhidze wrote:
>> To support network type rules,
>> this modification extends and renames
>> ruleset's access masks.
>> This patch adds filesystem helper functions
>> to set and get filesystem mask. Also the
>> modification adds a helper structure
>> landlock_access_mask to support managing
>> multiple access mask.
> 
> Please use a text-width of 72 columns for all commit messages. You can
> also split them into paragraphs.
> 
   Ok. I will rewrite all commits' messages. Thanks.
>> 
>> Signed-off-by: Konstantin Meskhidze <konstantin.meskhidze@huawei.com>
>> ---
>> 
>> Changes since v5:
>> * Changes access_mask_t to u32.
>> * Formats code with clang-format-14.
>> 
>> Changes since v4:
>> * Deletes struct landlock_access_mask.
>> 
>> Changes since v3:
>> * Splits commit.
>> * Adds get_mask, set_mask helpers for filesystem.
>> * Adds new struct landlock_access_mask.
>> 
>> ---
>>   security/landlock/fs.c       |  7 ++++---
>>   security/landlock/ruleset.c  | 18 +++++++++---------
>>   security/landlock/ruleset.h  | 25 ++++++++++++++++++++-----
>>   security/landlock/syscalls.c |  7 ++++---
>>   4 files changed, 37 insertions(+), 20 deletions(-)
>> 
>> diff --git a/security/landlock/fs.c b/security/landlock/fs.c
>> index ec5a6247cd3e..e6da08ed99d1 100644
>> --- a/security/landlock/fs.c
>> +++ b/security/landlock/fs.c
>> @@ -167,7 +167,8 @@ int landlock_append_fs_rule(struct landlock_ruleset *const ruleset,
>>   		return -EINVAL;
>> 
>>   	/* Transforms relative access rights to absolute ones. */
>> -	access_rights |= LANDLOCK_MASK_ACCESS_FS & ~ruleset->fs_access_masks[0];
>> +	access_rights |= LANDLOCK_MASK_ACCESS_FS &
>> +			 ~landlock_get_fs_access_mask(ruleset, 0);
>>   	object = get_inode_object(d_backing_inode(path->dentry));
>>   	if (IS_ERR(object))
>>   		return PTR_ERR(object);
>> @@ -286,7 +287,7 @@ get_handled_accesses(const struct landlock_ruleset *const domain)
>> 
>>   		for (layer_level = 0; layer_level < domain->num_layers;
>>   		     layer_level++) {
>> -			if (domain->fs_access_masks[layer_level] &
>> +			if (landlock_get_fs_access_mask(domain, layer_level) &
>>   			    BIT_ULL(access_bit)) {
>>   				access_dom |= BIT_ULL(access_bit);
>>   				break;
>> @@ -316,7 +317,7 @@ init_layer_masks(const struct landlock_ruleset *const domain,
>> 
>>   		for_each_set_bit(access_bit, &access_req,
>>   				 ARRAY_SIZE(*layer_masks)) {
>> -			if (domain->fs_access_masks[layer_level] &
>> +			if (landlock_get_fs_access_mask(domain, layer_level) &
>>   			    BIT_ULL(access_bit)) {
>>   				(*layer_masks)[access_bit] |=
>>   					BIT_ULL(layer_level);
>> diff --git a/security/landlock/ruleset.c b/security/landlock/ruleset.c
>> index 996484f98bfd..a3fd58d01f09 100644
>> --- a/security/landlock/ruleset.c
>> +++ b/security/landlock/ruleset.c
>> @@ -29,7 +29,7 @@ static struct landlock_ruleset *create_ruleset(const u32 num_layers)
>>   	struct landlock_ruleset *new_ruleset;
>> 
>>   	new_ruleset =
>> -		kzalloc(struct_size(new_ruleset, fs_access_masks, num_layers),
>> +		kzalloc(struct_size(new_ruleset, access_masks, num_layers),
>>   			GFP_KERNEL_ACCOUNT);
>>   	if (!new_ruleset)
>>   		return ERR_PTR(-ENOMEM);
>> @@ -40,22 +40,22 @@ static struct landlock_ruleset *create_ruleset(const u32 num_layers)
>>   	/*
>>   	 * hierarchy = NULL
>>   	 * num_rules = 0
>> -	 * fs_access_masks[] = 0
>> +	 * access_masks[] = 0
>>   	 */
>>   	return new_ruleset;
>>   }
>> 
>>   struct landlock_ruleset *
>> -landlock_create_ruleset(const access_mask_t fs_access_mask)
>> +landlock_create_ruleset(const access_mask_t access_mask)
>>   {
>>   	struct landlock_ruleset *new_ruleset;
>> 
>>   	/* Informs about useless ruleset. */
>> -	if (!fs_access_mask)
>> +	if (!access_mask)
>>   		return ERR_PTR(-ENOMSG);
>>   	new_ruleset = create_ruleset(1);
>>   	if (!IS_ERR(new_ruleset))
>> -		new_ruleset->fs_access_masks[0] = fs_access_mask;
>> +		landlock_set_fs_access_mask(new_ruleset, access_mask, 0);
>>   	return new_ruleset;
>>   }
>> 
>> @@ -117,7 +117,7 @@ static void build_check_ruleset(void)
>>   		.num_rules = ~0,
>>   		.num_layers = ~0,
>>   	};
>> -	typeof(ruleset.fs_access_masks[0]) fs_access_mask = ~0;
>> +	typeof(ruleset.access_masks[0]) fs_access_mask = ~0;
>> 
>>   	BUILD_BUG_ON(ruleset.num_rules < LANDLOCK_MAX_NUM_RULES);
>>   	BUILD_BUG_ON(ruleset.num_layers < LANDLOCK_MAX_NUM_LAYERS);
>> @@ -281,7 +281,7 @@ static int merge_ruleset(struct landlock_ruleset *const dst,
>>   		err = -EINVAL;
>>   		goto out_unlock;
>>   	}
>> -	dst->fs_access_masks[dst->num_layers - 1] = src->fs_access_masks[0];
>> +	dst->access_masks[dst->num_layers - 1] = src->access_masks[0];
>> 
>>   	/* Merges the @src tree. */
>>   	rbtree_postorder_for_each_entry_safe(walker_rule, next_rule, &src->root,
>> @@ -340,8 +340,8 @@ static int inherit_ruleset(struct landlock_ruleset *const parent,
>>   		goto out_unlock;
>>   	}
>>   	/* Copies the parent layer stack and leaves a space for the new layer. */
>> -	memcpy(child->fs_access_masks, parent->fs_access_masks,
>> -	       flex_array_size(parent, fs_access_masks, parent->num_layers));
>> +	memcpy(child->access_masks, parent->access_masks,
>> +	       flex_array_size(parent, access_masks, parent->num_layers));
>> 
>>   	if (WARN_ON_ONCE(!parent->hierarchy)) {
>>   		err = -EINVAL;
>> diff --git a/security/landlock/ruleset.h b/security/landlock/ruleset.h
>> index d43231b783e4..bd7ab39859bf 100644
>> --- a/security/landlock/ruleset.h
>> +++ b/security/landlock/ruleset.h
>> @@ -19,7 +19,7 @@
>>   #include "limits.h"
>>   #include "object.h"
>> 
>> -typedef u16 access_mask_t;
>> +typedef u32 access_mask_t;
>>   /* Makes sure all filesystem access rights can be stored. */
>>   static_assert(BITS_PER_TYPE(access_mask_t) >= LANDLOCK_NUM_ACCESS_FS);
>>   /* Makes sure for_each_set_bit() and for_each_clear_bit() calls are OK. */
>> @@ -110,7 +110,7 @@ struct landlock_ruleset {
>>   		 * section.  This is only used by
>>   		 * landlock_put_ruleset_deferred() when @usage reaches zero.
>>   		 * The fields @lock, @usage, @num_rules, @num_layers and
>> -		 * @fs_access_masks are then unused.
>> +		 * @access_masks are then unused.
>>   		 */
>>   		struct work_struct work_free;
>>   		struct {
>> @@ -137,7 +137,7 @@ struct landlock_ruleset {
>>   			 */
>>   			u32 num_layers;
>>   			/**
>> -			 * @fs_access_masks: Contains the subset of filesystem
>> +			 * @access_masks: Contains the subset of filesystem
>>   			 * actions that are restricted by a ruleset.  A domain
>>   			 * saves all layers of merged rulesets in a stack
>>   			 * (FAM), starting from the first layer to the last
>> @@ -148,13 +148,13 @@ struct landlock_ruleset {
>>   			 * layers are set once and never changed for the
>>   			 * lifetime of the ruleset.
>>   			 */
>> -			access_mask_t fs_access_masks[];
>> +			access_mask_t access_masks[];
>>   		};
>>   	};
>>   };
>> 
>>   struct landlock_ruleset *
>> -landlock_create_ruleset(const access_mask_t fs_access_mask);
>> +landlock_create_ruleset(const access_mask_t access_mask);
>> 
>>   void landlock_put_ruleset(struct landlock_ruleset *const ruleset);
>>   void landlock_put_ruleset_deferred(struct landlock_ruleset *const ruleset);
>> @@ -177,4 +177,19 @@ static inline void landlock_get_ruleset(struct landlock_ruleset *const ruleset)
>>   		refcount_inc(&ruleset->usage);
>>   }
>> 
>> +/* A helper function to set a filesystem mask. */
>> +static inline void
>> +landlock_set_fs_access_mask(struct landlock_ruleset *ruleset,
>> +			    const access_mask_t access_maskset, u16 mask_level)
>> +{
>> +	ruleset->access_masks[mask_level] = access_maskset;
>> +}
>> +
>> +/* A helper function to get a filesystem mask. */
>> +static inline u32
> 
> You need to use access_mask_t everywhere, including here.
> 
   I got it. Will fix it. Thanks.

>> +landlock_get_fs_access_mask(const struct landlock_ruleset *ruleset,
>> +			    u16 mask_level)
>> +{
>> +	return ruleset->access_masks[mask_level];
>> +}
>>   #endif /* _SECURITY_LANDLOCK_RULESET_H */
>> diff --git a/security/landlock/syscalls.c b/security/landlock/syscalls.c
>> index 735a0865ea11..5836736ce9d7 100644
>> --- a/security/landlock/syscalls.c
>> +++ b/security/landlock/syscalls.c
>> @@ -346,10 +346,11 @@ SYSCALL_DEFINE4(landlock_add_rule, const int, ruleset_fd,
>>   	}
>>   	/*
>>   	 * Checks that allowed_access matches the @ruleset constraints
>> -	 * (ruleset->fs_access_masks[0] is automatically upgraded to 64-bits).
>> +	 * (ruleset->access_masks[0] is automatically upgraded to 64-bits).
>>   	 */
>> -	if ((path_beneath_attr.allowed_access | ruleset->fs_access_masks[0]) !=
>> -	    ruleset->fs_access_masks[0]) {
>> +	if ((path_beneath_attr.allowed_access |
>> +	     landlock_get_fs_access_mask(ruleset, 0)) !=
>> +	    landlock_get_fs_access_mask(ruleset, 0)) {
>>   		err = -EINVAL;
>>   		goto out_put_ruleset;
>>   	}
>> --
>> 2.25.1
>> 
> .

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 01/17] landlock: renames access mask
  2022-07-01 17:08   ` Mickaël Salaün
  2022-07-04  9:23     ` Konstantin Meskhidze (A)
@ 2022-07-05 11:29     ` Konstantin Meskhidze (A)
  2022-07-05 13:26       ` Mickaël Salaün
  1 sibling, 1 reply; 53+ messages in thread
From: Konstantin Meskhidze (A) @ 2022-07-05 11:29 UTC (permalink / raw)
  To: Mickaël Salaün
  Cc: willemdebruijn.kernel, linux-security-module, netdev,
	netfilter-devel, yusongping, anton.sirazetdinov



7/1/2022 8:08 PM, Mickaël Salaün пишет:
> 
> On 21/06/2022 10:22, Konstantin Meskhidze wrote:
>> To support network type rules,
>> this modification extends and renames
>> ruleset's access masks.
>> This patch adds filesystem helper functions
>> to set and get filesystem mask. Also the
>> modification adds a helper structure
>> landlock_access_mask to support managing
>> multiple access mask.
> 
> Please use a text-width of 72 columns for all commit messages. You can
> also split them into paragraphs.
> 
   By the way, are you going to review the rest patches?
>> 
>> Signed-off-by: Konstantin Meskhidze <konstantin.meskhidze@huawei.com>
>> ---
>> 
>> Changes since v5:
>> * Changes access_mask_t to u32.
>> * Formats code with clang-format-14.
>> 
>> Changes since v4:
>> * Deletes struct landlock_access_mask.
>> 
>> Changes since v3:
>> * Splits commit.
>> * Adds get_mask, set_mask helpers for filesystem.
>> * Adds new struct landlock_access_mask.
>> 
>> ---
>>   security/landlock/fs.c       |  7 ++++---
>>   security/landlock/ruleset.c  | 18 +++++++++---------
>>   security/landlock/ruleset.h  | 25 ++++++++++++++++++++-----
>>   security/landlock/syscalls.c |  7 ++++---
>>   4 files changed, 37 insertions(+), 20 deletions(-)
>> 
>> diff --git a/security/landlock/fs.c b/security/landlock/fs.c
>> index ec5a6247cd3e..e6da08ed99d1 100644
>> --- a/security/landlock/fs.c
>> +++ b/security/landlock/fs.c
>> @@ -167,7 +167,8 @@ int landlock_append_fs_rule(struct landlock_ruleset *const ruleset,
>>   		return -EINVAL;
>> 
>>   	/* Transforms relative access rights to absolute ones. */
>> -	access_rights |= LANDLOCK_MASK_ACCESS_FS & ~ruleset->fs_access_masks[0];
>> +	access_rights |= LANDLOCK_MASK_ACCESS_FS &
>> +			 ~landlock_get_fs_access_mask(ruleset, 0);
>>   	object = get_inode_object(d_backing_inode(path->dentry));
>>   	if (IS_ERR(object))
>>   		return PTR_ERR(object);
>> @@ -286,7 +287,7 @@ get_handled_accesses(const struct landlock_ruleset *const domain)
>> 
>>   		for (layer_level = 0; layer_level < domain->num_layers;
>>   		     layer_level++) {
>> -			if (domain->fs_access_masks[layer_level] &
>> +			if (landlock_get_fs_access_mask(domain, layer_level) &
>>   			    BIT_ULL(access_bit)) {
>>   				access_dom |= BIT_ULL(access_bit);
>>   				break;
>> @@ -316,7 +317,7 @@ init_layer_masks(const struct landlock_ruleset *const domain,
>> 
>>   		for_each_set_bit(access_bit, &access_req,
>>   				 ARRAY_SIZE(*layer_masks)) {
>> -			if (domain->fs_access_masks[layer_level] &
>> +			if (landlock_get_fs_access_mask(domain, layer_level) &
>>   			    BIT_ULL(access_bit)) {
>>   				(*layer_masks)[access_bit] |=
>>   					BIT_ULL(layer_level);
>> diff --git a/security/landlock/ruleset.c b/security/landlock/ruleset.c
>> index 996484f98bfd..a3fd58d01f09 100644
>> --- a/security/landlock/ruleset.c
>> +++ b/security/landlock/ruleset.c
>> @@ -29,7 +29,7 @@ static struct landlock_ruleset *create_ruleset(const u32 num_layers)
>>   	struct landlock_ruleset *new_ruleset;
>> 
>>   	new_ruleset =
>> -		kzalloc(struct_size(new_ruleset, fs_access_masks, num_layers),
>> +		kzalloc(struct_size(new_ruleset, access_masks, num_layers),
>>   			GFP_KERNEL_ACCOUNT);
>>   	if (!new_ruleset)
>>   		return ERR_PTR(-ENOMEM);
>> @@ -40,22 +40,22 @@ static struct landlock_ruleset *create_ruleset(const u32 num_layers)
>>   	/*
>>   	 * hierarchy = NULL
>>   	 * num_rules = 0
>> -	 * fs_access_masks[] = 0
>> +	 * access_masks[] = 0
>>   	 */
>>   	return new_ruleset;
>>   }
>> 
>>   struct landlock_ruleset *
>> -landlock_create_ruleset(const access_mask_t fs_access_mask)
>> +landlock_create_ruleset(const access_mask_t access_mask)
>>   {
>>   	struct landlock_ruleset *new_ruleset;
>> 
>>   	/* Informs about useless ruleset. */
>> -	if (!fs_access_mask)
>> +	if (!access_mask)
>>   		return ERR_PTR(-ENOMSG);
>>   	new_ruleset = create_ruleset(1);
>>   	if (!IS_ERR(new_ruleset))
>> -		new_ruleset->fs_access_masks[0] = fs_access_mask;
>> +		landlock_set_fs_access_mask(new_ruleset, access_mask, 0);
>>   	return new_ruleset;
>>   }
>> 
>> @@ -117,7 +117,7 @@ static void build_check_ruleset(void)
>>   		.num_rules = ~0,
>>   		.num_layers = ~0,
>>   	};
>> -	typeof(ruleset.fs_access_masks[0]) fs_access_mask = ~0;
>> +	typeof(ruleset.access_masks[0]) fs_access_mask = ~0;
>> 
>>   	BUILD_BUG_ON(ruleset.num_rules < LANDLOCK_MAX_NUM_RULES);
>>   	BUILD_BUG_ON(ruleset.num_layers < LANDLOCK_MAX_NUM_LAYERS);
>> @@ -281,7 +281,7 @@ static int merge_ruleset(struct landlock_ruleset *const dst,
>>   		err = -EINVAL;
>>   		goto out_unlock;
>>   	}
>> -	dst->fs_access_masks[dst->num_layers - 1] = src->fs_access_masks[0];
>> +	dst->access_masks[dst->num_layers - 1] = src->access_masks[0];
>> 
>>   	/* Merges the @src tree. */
>>   	rbtree_postorder_for_each_entry_safe(walker_rule, next_rule, &src->root,
>> @@ -340,8 +340,8 @@ static int inherit_ruleset(struct landlock_ruleset *const parent,
>>   		goto out_unlock;
>>   	}
>>   	/* Copies the parent layer stack and leaves a space for the new layer. */
>> -	memcpy(child->fs_access_masks, parent->fs_access_masks,
>> -	       flex_array_size(parent, fs_access_masks, parent->num_layers));
>> +	memcpy(child->access_masks, parent->access_masks,
>> +	       flex_array_size(parent, access_masks, parent->num_layers));
>> 
>>   	if (WARN_ON_ONCE(!parent->hierarchy)) {
>>   		err = -EINVAL;
>> diff --git a/security/landlock/ruleset.h b/security/landlock/ruleset.h
>> index d43231b783e4..bd7ab39859bf 100644
>> --- a/security/landlock/ruleset.h
>> +++ b/security/landlock/ruleset.h
>> @@ -19,7 +19,7 @@
>>   #include "limits.h"
>>   #include "object.h"
>> 
>> -typedef u16 access_mask_t;
>> +typedef u32 access_mask_t;
>>   /* Makes sure all filesystem access rights can be stored. */
>>   static_assert(BITS_PER_TYPE(access_mask_t) >= LANDLOCK_NUM_ACCESS_FS);
>>   /* Makes sure for_each_set_bit() and for_each_clear_bit() calls are OK. */
>> @@ -110,7 +110,7 @@ struct landlock_ruleset {
>>   		 * section.  This is only used by
>>   		 * landlock_put_ruleset_deferred() when @usage reaches zero.
>>   		 * The fields @lock, @usage, @num_rules, @num_layers and
>> -		 * @fs_access_masks are then unused.
>> +		 * @access_masks are then unused.
>>   		 */
>>   		struct work_struct work_free;
>>   		struct {
>> @@ -137,7 +137,7 @@ struct landlock_ruleset {
>>   			 */
>>   			u32 num_layers;
>>   			/**
>> -			 * @fs_access_masks: Contains the subset of filesystem
>> +			 * @access_masks: Contains the subset of filesystem
>>   			 * actions that are restricted by a ruleset.  A domain
>>   			 * saves all layers of merged rulesets in a stack
>>   			 * (FAM), starting from the first layer to the last
>> @@ -148,13 +148,13 @@ struct landlock_ruleset {
>>   			 * layers are set once and never changed for the
>>   			 * lifetime of the ruleset.
>>   			 */
>> -			access_mask_t fs_access_masks[];
>> +			access_mask_t access_masks[];
>>   		};
>>   	};
>>   };
>> 
>>   struct landlock_ruleset *
>> -landlock_create_ruleset(const access_mask_t fs_access_mask);
>> +landlock_create_ruleset(const access_mask_t access_mask);
>> 
>>   void landlock_put_ruleset(struct landlock_ruleset *const ruleset);
>>   void landlock_put_ruleset_deferred(struct landlock_ruleset *const ruleset);
>> @@ -177,4 +177,19 @@ static inline void landlock_get_ruleset(struct landlock_ruleset *const ruleset)
>>   		refcount_inc(&ruleset->usage);
>>   }
>> 
>> +/* A helper function to set a filesystem mask. */
>> +static inline void
>> +landlock_set_fs_access_mask(struct landlock_ruleset *ruleset,
>> +			    const access_mask_t access_maskset, u16 mask_level)
>> +{
>> +	ruleset->access_masks[mask_level] = access_maskset;
>> +}
>> +
>> +/* A helper function to get a filesystem mask. */
>> +static inline u32
> 
> You need to use access_mask_t everywhere, including here.
> 
>> +landlock_get_fs_access_mask(const struct landlock_ruleset *ruleset,
>> +			    u16 mask_level)
>> +{
>> +	return ruleset->access_masks[mask_level];
>> +}
>>   #endif /* _SECURITY_LANDLOCK_RULESET_H */
>> diff --git a/security/landlock/syscalls.c b/security/landlock/syscalls.c
>> index 735a0865ea11..5836736ce9d7 100644
>> --- a/security/landlock/syscalls.c
>> +++ b/security/landlock/syscalls.c
>> @@ -346,10 +346,11 @@ SYSCALL_DEFINE4(landlock_add_rule, const int, ruleset_fd,
>>   	}
>>   	/*
>>   	 * Checks that allowed_access matches the @ruleset constraints
>> -	 * (ruleset->fs_access_masks[0] is automatically upgraded to 64-bits).
>> +	 * (ruleset->access_masks[0] is automatically upgraded to 64-bits).
>>   	 */
>> -	if ((path_beneath_attr.allowed_access | ruleset->fs_access_masks[0]) !=
>> -	    ruleset->fs_access_masks[0]) {
>> +	if ((path_beneath_attr.allowed_access |
>> +	     landlock_get_fs_access_mask(ruleset, 0)) !=
>> +	    landlock_get_fs_access_mask(ruleset, 0)) {
>>   		err = -EINVAL;
>>   		goto out_put_ruleset;
>>   	}
>> --
>> 2.25.1
>> 
> .

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 01/17] landlock: renames access mask
  2022-07-05 11:29     ` Konstantin Meskhidze (A)
@ 2022-07-05 13:26       ` Mickaël Salaün
  2022-07-08 12:56         ` Konstantin Meskhidze (A)
  0 siblings, 1 reply; 53+ messages in thread
From: Mickaël Salaün @ 2022-07-05 13:26 UTC (permalink / raw)
  To: Konstantin Meskhidze
  Cc: willemdebruijn.kernel, linux-security-module, netdev,
	netfilter-devel, yusongping, anton.sirazetdinov

On 2022-07-05T13:29:04.000+02:00, Konstantin Meskhidze (A) <konstantin.meskhidze@huawei.com> wrote:
>  7/1/2022 8:08 PM, Mickaël Salaün пишет:
> 
> >    
> >  On 21/06/2022 10:22, Konstantin Meskhidze wrote:
> > 
> > >    To support network type rules,
> > >  this modification extends and renames
> > >  ruleset's access masks.
> > >  This patch adds filesystem helper functions
> > >  to set and get filesystem mask. Also the
> > >  modification adds a helper structure
> > >  landlock_access_mask to support managing
> > >  multiple access mask.
> >   
> >  Please use a text-width of 72 columns for all commit messages. You can
> >  also split them into paragraphs.
> >  
>     By the way, are you going to review the rest patches?

Yes, of course, I'm busy right now but I'll send more reviews by the end of the week.

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 02/17] landlock: refactors landlock_find/insert_rule
  2022-06-21  8:22 ` [PATCH v6 02/17] landlock: refactors landlock_find/insert_rule Konstantin Meskhidze
@ 2022-07-07 16:44   ` Mickaël Salaün
  2022-07-08 12:53     ` Konstantin Meskhidze (A)
  2022-07-08 13:10     ` Konstantin Meskhidze (A)
  2022-07-07 16:46   ` Mickaël Salaün
  1 sibling, 2 replies; 53+ messages in thread
From: Mickaël Salaün @ 2022-07-07 16:44 UTC (permalink / raw)
  To: Konstantin Meskhidze
  Cc: willemdebruijn.kernel, linux-security-module, netdev,
	netfilter-devel, yusongping, anton.sirazetdinov


On 21/06/2022 10:22, Konstantin Meskhidze wrote:
> Adds a new object union to support a socket port
> rule type. Refactors landlock_insert_rule() and
> landlock_find_rule() to support coming network
> modifications. Now adding or searching a rule
> in a ruleset depends on a rule_type argument
> provided in refactored functions mentioned above.
> 
> Signed-off-by: Konstantin Meskhidze <konstantin.meskhidze@huawei.com>
> ---
> 
> Changes since v5:
> * Formats code with clang-format-14.
> 
> Changes since v4:
> * Refactors insert_rule() and create_rule() functions by deleting
> rule_type from their arguments list, it helps to reduce useless code.
> 
> Changes since v3:
> * Splits commit.
> * Refactors landlock_insert_rule and landlock_find_rule functions.
> * Rename new_ruleset->root_inode.
> 
> ---
>   security/landlock/fs.c      |   7 ++-
>   security/landlock/ruleset.c | 105 ++++++++++++++++++++++++++----------
>   security/landlock/ruleset.h |  27 +++++-----
>   3 files changed, 96 insertions(+), 43 deletions(-)
> 
> diff --git a/security/landlock/fs.c b/security/landlock/fs.c
> index e6da08ed99d1..46aedc2a05a8 100644
> --- a/security/landlock/fs.c
> +++ b/security/landlock/fs.c
> @@ -173,7 +173,8 @@ int landlock_append_fs_rule(struct landlock_ruleset *const ruleset,
>   	if (IS_ERR(object))
>   		return PTR_ERR(object);
>   	mutex_lock(&ruleset->lock);
> -	err = landlock_insert_rule(ruleset, object, access_rights);
> +	err = landlock_insert_rule(ruleset, object, 0, access_rights,
> +				   LANDLOCK_RULE_PATH_BENEATH);
>   	mutex_unlock(&ruleset->lock);
>   	/*
>   	 * No need to check for an error because landlock_insert_rule()
> @@ -204,7 +205,9 @@ find_rule(const struct landlock_ruleset *const domain,
>   	inode = d_backing_inode(dentry);
>   	rcu_read_lock();
>   	rule = landlock_find_rule(
> -		domain, rcu_dereference(landlock_inode(inode)->object));
> +		domain,
> +		(uintptr_t)rcu_dereference(landlock_inode(inode)->object),
> +		LANDLOCK_RULE_PATH_BENEATH);
>   	rcu_read_unlock();
>   	return rule;
>   }
> diff --git a/security/landlock/ruleset.c b/security/landlock/ruleset.c
> index a3fd58d01f09..5f13f8a12aee 100644
> --- a/security/landlock/ruleset.c
> +++ b/security/landlock/ruleset.c
> @@ -35,7 +35,7 @@ static struct landlock_ruleset *create_ruleset(const u32 num_layers)
>   		return ERR_PTR(-ENOMEM);
>   	refcount_set(&new_ruleset->usage, 1);
>   	mutex_init(&new_ruleset->lock);
> -	new_ruleset->root = RB_ROOT;
> +	new_ruleset->root_inode = RB_ROOT;
>   	new_ruleset->num_layers = num_layers;
>   	/*
>   	 * hierarchy = NULL
> @@ -69,7 +69,8 @@ static void build_check_rule(void)
>   }
> 
>   static struct landlock_rule *
> -create_rule(struct landlock_object *const object,
> +create_rule(struct landlock_object *const object_ptr,
> +	    const uintptr_t object_data,
>   	    const struct landlock_layer (*const layers)[], const u32 num_layers,
>   	    const struct landlock_layer *const new_layer)
>   {
> @@ -90,8 +91,15 @@ create_rule(struct landlock_object *const object,
>   	if (!new_rule)
>   		return ERR_PTR(-ENOMEM);
>   	RB_CLEAR_NODE(&new_rule->node);
> -	landlock_get_object(object);
> -	new_rule->object = object;
> +
> +	if (object_ptr) {
> +		landlock_get_object(object_ptr);
> +		new_rule->object.ptr = object_ptr;
> +	} else if (object_ptr && object_data) {

Something is wrong with this second check: else + object_ptr?


> +		WARN_ON_ONCE(1);
> +		return ERR_PTR(-EINVAL);
> +	}
> +
>   	new_rule->num_layers = new_num_layers;
>   	/* Copies the original layer stack. */
>   	memcpy(new_rule->layers, layers,
> @@ -107,7 +115,7 @@ static void free_rule(struct landlock_rule *const rule)
>   	might_sleep();
>   	if (!rule)
>   		return;
> -	landlock_put_object(rule->object);
> +	landlock_put_object(rule->object.ptr);
>   	kfree(rule);
>   }
> 
> @@ -143,26 +151,42 @@ static void build_check_ruleset(void)
>    * access rights.
>    */
>   static int insert_rule(struct landlock_ruleset *const ruleset,
> -		       struct landlock_object *const object,
> +		       struct landlock_object *const object_ptr,
> +		       uintptr_t object_data, u16 rule_type,

Use landlock_rule_type instead of u16, everywhere. It was part of my 
review/patch two versions ago (with other things), please take them into 
account: 
https://lore.kernel.org/r/92d498f0-c598-7413-6b7c-d19c5aec6cab@digikod.net


>   		       const struct landlock_layer (*const layers)[],
>   		       size_t num_layers)
>   {
>   	struct rb_node **walker_node;
>   	struct rb_node *parent_node = NULL;
>   	struct landlock_rule *new_rule;
> +	struct rb_root *root;
> 
>   	might_sleep();
>   	lockdep_assert_held(&ruleset->lock);
> -	if (WARN_ON_ONCE(!object || !layers))
> +	if (WARN_ON_ONCE(!layers))
>   		return -ENOENT;
> -	walker_node = &(ruleset->root.rb_node);
> +	if (WARN_ON_ONCE(object_ptr && object_data))
> +		return -EINVAL;
> +	/* Chooses rb_tree structure depending on a rule type. */
> +	switch (rule_type) {
> +	case LANDLOCK_RULE_PATH_BENEATH:
> +		if (WARN_ON_ONCE(!object_ptr))
> +			return -ENOENT;
> +		object_data = (uintptr_t)object_ptr;
> +		root = &ruleset->root_inode;
> +		break;
> +	default:
> +		WARN_ON_ONCE(1);
> +		return -EINVAL;
> +	}
> +	walker_node = &root->rb_node;
>   	while (*walker_node) {
>   		struct landlock_rule *const this =
>   			rb_entry(*walker_node, struct landlock_rule, node);
> 
> -		if (this->object != object) {
> +		if (this->object.data != object_data) {
>   			parent_node = *walker_node;
> -			if (this->object < object)
> +			if (this->object.data < object_data)
>   				walker_node = &((*walker_node)->rb_right);
>   			else
>   				walker_node = &((*walker_node)->rb_left);
> @@ -194,11 +218,16 @@ static int insert_rule(struct landlock_ruleset *const ruleset,
>   		 * Intersects access rights when it is a merge between a
>   		 * ruleset and a domain.
>   		 */
> -		new_rule = create_rule(object, &this->layers, this->num_layers,
> -				       &(*layers)[0]);
> +		switch (rule_type) {
> +		case LANDLOCK_RULE_PATH_BENEATH:
> +			new_rule = create_rule(object_ptr, 0, &this->layers,
> +					       this->num_layers, &(*layers)[0]);
> +			break;
> +		}
>   		if (IS_ERR(new_rule))
>   			return PTR_ERR(new_rule);
> -		rb_replace_node(&this->node, &new_rule->node, &ruleset->root);
> +		rb_replace_node(&this->node, &new_rule->node,
> +				&ruleset->root_inode);
>   		free_rule(this);
>   		return 0;
>   	}
> @@ -207,11 +236,15 @@ static int insert_rule(struct landlock_ruleset *const ruleset,
>   	build_check_ruleset();
>   	if (ruleset->num_rules >= LANDLOCK_MAX_NUM_RULES)
>   		return -E2BIG;
> -	new_rule = create_rule(object, layers, num_layers, NULL);
> +	switch (rule_type) {
> +	case LANDLOCK_RULE_PATH_BENEATH:
> +		new_rule = create_rule(object_ptr, 0, layers, num_layers, NULL);
> +		break;
> +	}
>   	if (IS_ERR(new_rule))
>   		return PTR_ERR(new_rule);
>   	rb_link_node(&new_rule->node, parent_node, walker_node);
> -	rb_insert_color(&new_rule->node, &ruleset->root);
> +	rb_insert_color(&new_rule->node, &ruleset->root_inode);
>   	ruleset->num_rules++;
>   	return 0;
>   }
> @@ -229,8 +262,9 @@ static void build_check_layer(void)
> 
>   /* @ruleset must be locked by the caller. */
>   int landlock_insert_rule(struct landlock_ruleset *const ruleset,
> -			 struct landlock_object *const object,
> -			 const access_mask_t access)
> +			 struct landlock_object *const object_ptr,
> +			 const uintptr_t object_data,
> +			 const access_mask_t access, const u16 rule_type)
>   {
>   	struct landlock_layer layers[] = { {
>   		.access = access,
> @@ -239,7 +273,8 @@ int landlock_insert_rule(struct landlock_ruleset *const ruleset,
>   	} };
> 
>   	build_check_layer();
> -	return insert_rule(ruleset, object, &layers, ARRAY_SIZE(layers));
> +	return insert_rule(ruleset, object_ptr, object_data, rule_type, &layers,
> +			   ARRAY_SIZE(layers));
>   }
> 
>   static inline void get_hierarchy(struct landlock_hierarchy *const hierarchy)
> @@ -284,8 +319,8 @@ static int merge_ruleset(struct landlock_ruleset *const dst,
>   	dst->access_masks[dst->num_layers - 1] = src->access_masks[0];
> 
>   	/* Merges the @src tree. */
> -	rbtree_postorder_for_each_entry_safe(walker_rule, next_rule, &src->root,
> -					     node) {
> +	rbtree_postorder_for_each_entry_safe(walker_rule, next_rule,
> +					     &src->root_inode, node) {
>   		struct landlock_layer layers[] = { {
>   			.level = dst->num_layers,
>   		} };
> @@ -299,7 +334,8 @@ static int merge_ruleset(struct landlock_ruleset *const dst,
>   			goto out_unlock;
>   		}
>   		layers[0].access = walker_rule->layers[0].access;
> -		err = insert_rule(dst, walker_rule->object, &layers,
> +		err = insert_rule(dst, walker_rule->object.ptr, 0,
> +				  LANDLOCK_RULE_PATH_BENEATH, &layers,
>   				  ARRAY_SIZE(layers));
>   		if (err)
>   			goto out_unlock;
> @@ -327,8 +363,9 @@ static int inherit_ruleset(struct landlock_ruleset *const parent,
> 
>   	/* Copies the @parent tree. */
>   	rbtree_postorder_for_each_entry_safe(walker_rule, next_rule,
> -					     &parent->root, node) {
> -		err = insert_rule(child, walker_rule->object,
> +					     &parent->root_inode, node) {
> +		err = insert_rule(child, walker_rule->object.ptr, 0,
> +				  LANDLOCK_RULE_PATH_BENEATH,
>   				  &walker_rule->layers,
>   				  walker_rule->num_layers);
>   		if (err)
> @@ -361,7 +398,8 @@ static void free_ruleset(struct landlock_ruleset *const ruleset)
>   	struct landlock_rule *freeme, *next;
> 
>   	might_sleep();
> -	rbtree_postorder_for_each_entry_safe(freeme, next, &ruleset->root, node)
> +	rbtree_postorder_for_each_entry_safe(freeme, next, &ruleset->root_inode,
> +					     node)
>   		free_rule(freeme);
>   	put_hierarchy(ruleset->hierarchy);
>   	kfree(ruleset);
> @@ -453,20 +491,29 @@ landlock_merge_ruleset(struct landlock_ruleset *const parent,
>    */
>   const struct landlock_rule *
>   landlock_find_rule(const struct landlock_ruleset *const ruleset,
> -		   const struct landlock_object *const object)
> +		   const uintptr_t object_data, const u16 rule_type)
>   {
>   	const struct rb_node *node;
> 
> -	if (!object)
> +	if (!object_data)
>   		return NULL;
> -	node = ruleset->root.rb_node;
> +
> +	switch (rule_type) {
> +	case LANDLOCK_RULE_PATH_BENEATH:
> +		node = ruleset->root_inode.rb_node;
> +		break;
> +	default:
> +		WARN_ON_ONCE(1);
> +		return NULL;
> +	}
> +
>   	while (node) {
>   		struct landlock_rule *this =
>   			rb_entry(node, struct landlock_rule, node);
> 
> -		if (this->object == object)
> +		if (this->object.data == object_data)
>   			return this;
> -		if (this->object < object)
> +		if (this->object.data < object_data)
>   			node = node->rb_right;
>   		else
>   			node = node->rb_left;
> diff --git a/security/landlock/ruleset.h b/security/landlock/ruleset.h
> index bd7ab39859bf..a22d132c32a7 100644
> --- a/security/landlock/ruleset.h
> +++ b/security/landlock/ruleset.h
> @@ -53,15 +53,17 @@ struct landlock_rule {
>   	 */
>   	struct rb_node node;
>   	/**
> -	 * @object: Pointer to identify a kernel object (e.g. an inode).  This
> -	 * is used as a key for this ruleset element.  This pointer is set once
> -	 * and never modified.  It always points to an allocated object because
> -	 * each rule increments the refcount of its object.
> -	 */
> -	struct landlock_object *object;
> -	/**
> -	 * @num_layers: Number of entries in @layers.
> +	 * @object: A union to identify either a kernel object (e.g. an inode) or
> +	 * a raw data value (e.g. a network socket port). This is used as a key
> +	 * for this ruleset element. This pointer/@object.ptr/ is set once and
> +	 * never modified. It always points to an allocated object because each
> +	 * rule increments the refcount of its object (for inodes).;
>   	 */
> +	union {
> +		struct landlock_object *ptr;
> +		uintptr_t data;
> +	} object;
> +
>   	u32 num_layers;
>   	/**
>   	 * @layers: Stack of layers, from the latest to the newest, implemented
> @@ -98,7 +100,7 @@ struct landlock_ruleset {
>   	 * nodes.  Once a ruleset is tied to a process (i.e. as a domain), this
>   	 * tree is immutable until @usage reaches zero.
>   	 */
> -	struct rb_root root;
> +	struct rb_root root_inode;
>   	/**
>   	 * @hierarchy: Enables hierarchy identification even when a parent
>   	 * domain vanishes.  This is needed for the ptrace protection.
> @@ -160,8 +162,9 @@ void landlock_put_ruleset(struct landlock_ruleset *const ruleset);
>   void landlock_put_ruleset_deferred(struct landlock_ruleset *const ruleset);
> 
>   int landlock_insert_rule(struct landlock_ruleset *const ruleset,
> -			 struct landlock_object *const object,
> -			 const access_mask_t access);
> +			 struct landlock_object *const object_ptr,
> +			 const uintptr_t object_data,
> +			 const access_mask_t access, const u16 rule_type);
> 
>   struct landlock_ruleset *
>   landlock_merge_ruleset(struct landlock_ruleset *const parent,
> @@ -169,7 +172,7 @@ landlock_merge_ruleset(struct landlock_ruleset *const parent,
> 
>   const struct landlock_rule *
>   landlock_find_rule(const struct landlock_ruleset *const ruleset,
> -		   const struct landlock_object *const object);
> +		   const uintptr_t object_data, const u16 rule_type);
> 
>   static inline void landlock_get_ruleset(struct landlock_ruleset *const ruleset)
>   {
> --
> 2.25.1
> 

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 02/17] landlock: refactors landlock_find/insert_rule
  2022-06-21  8:22 ` [PATCH v6 02/17] landlock: refactors landlock_find/insert_rule Konstantin Meskhidze
  2022-07-07 16:44   ` Mickaël Salaün
@ 2022-07-07 16:46   ` Mickaël Salaün
  2022-07-08 12:54     ` Konstantin Meskhidze (A)
  1 sibling, 1 reply; 53+ messages in thread
From: Mickaël Salaün @ 2022-07-07 16:46 UTC (permalink / raw)
  To: Konstantin Meskhidze
  Cc: willemdebruijn.kernel, linux-security-module, netdev,
	netfilter-devel, yusongping, anton.sirazetdinov



On 21/06/2022 10:22, Konstantin Meskhidze wrote:
> Adds a new object union to support a socket port
> rule type. Refactors landlock_insert_rule() and
> landlock_find_rule() to support coming network
> modifications. Now adding or searching a rule
> in a ruleset depends on a rule_type argument
> provided in refactored functions mentioned above.
> 
> Signed-off-by: Konstantin Meskhidze <konstantin.meskhidze@huawei.com>
> ---
> 
> Changes since v5:
> * Formats code with clang-format-14.
> 
> Changes since v4:
> * Refactors insert_rule() and create_rule() functions by deleting
> rule_type from their arguments list, it helps to reduce useless code.
> 
> Changes since v3:
> * Splits commit.
> * Refactors landlock_insert_rule and landlock_find_rule functions.
> * Rename new_ruleset->root_inode.
> 
> ---
>   security/landlock/fs.c      |   7 ++-
>   security/landlock/ruleset.c | 105 ++++++++++++++++++++++++++----------
>   security/landlock/ruleset.h |  27 +++++-----
>   3 files changed, 96 insertions(+), 43 deletions(-)

[...]

> diff --git a/security/landlock/ruleset.h b/security/landlock/ruleset.h
> index bd7ab39859bf..a22d132c32a7 100644
> --- a/security/landlock/ruleset.h
> +++ b/security/landlock/ruleset.h
> @@ -53,15 +53,17 @@ struct landlock_rule {
>   	 */
>   	struct rb_node node;
>   	/**
> -	 * @object: Pointer to identify a kernel object (e.g. an inode).  This
> -	 * is used as a key for this ruleset element.  This pointer is set once
> -	 * and never modified.  It always points to an allocated object because
> -	 * each rule increments the refcount of its object.
> -	 */
> -	struct landlock_object *object;
> -	/**
> -	 * @num_layers: Number of entries in @layers.
> +	 * @object: A union to identify either a kernel object (e.g. an inode) or
> +	 * a raw data value (e.g. a network socket port). This is used as a key
> +	 * for this ruleset element. This pointer/@object.ptr/ is set once and
> +	 * never modified. It always points to an allocated object because each
> +	 * rule increments the refcount of its object (for inodes).;

Extra ";"

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 02/17] landlock: refactors landlock_find/insert_rule
  2022-07-07 16:44   ` Mickaël Salaün
@ 2022-07-08 12:53     ` Konstantin Meskhidze (A)
  2022-07-08 13:56       ` Mickaël Salaün
  2022-07-08 13:10     ` Konstantin Meskhidze (A)
  1 sibling, 1 reply; 53+ messages in thread
From: Konstantin Meskhidze (A) @ 2022-07-08 12:53 UTC (permalink / raw)
  To: Mickaël Salaün
  Cc: willemdebruijn.kernel, linux-security-module, netdev,
	netfilter-devel, yusongping, anton.sirazetdinov



7/7/2022 7:44 PM, Mickaël Salaün пишет:
> 
> On 21/06/2022 10:22, Konstantin Meskhidze wrote:
>> Adds a new object union to support a socket port
>> rule type. Refactors landlock_insert_rule() and
>> landlock_find_rule() to support coming network
>> modifications. Now adding or searching a rule
>> in a ruleset depends on a rule_type argument
>> provided in refactored functions mentioned above.
>> 
>> Signed-off-by: Konstantin Meskhidze <konstantin.meskhidze@huawei.com>
>> ---
>> 
>> Changes since v5:
>> * Formats code with clang-format-14.
>> 
>> Changes since v4:
>> * Refactors insert_rule() and create_rule() functions by deleting
>> rule_type from their arguments list, it helps to reduce useless code.
>> 
>> Changes since v3:
>> * Splits commit.
>> * Refactors landlock_insert_rule and landlock_find_rule functions.
>> * Rename new_ruleset->root_inode.
>> 
>> ---
>>   security/landlock/fs.c      |   7 ++-
>>   security/landlock/ruleset.c | 105 ++++++++++++++++++++++++++----------
>>   security/landlock/ruleset.h |  27 +++++-----
>>   3 files changed, 96 insertions(+), 43 deletions(-)
>> 
>> diff --git a/security/landlock/fs.c b/security/landlock/fs.c
>> index e6da08ed99d1..46aedc2a05a8 100644
>> --- a/security/landlock/fs.c
>> +++ b/security/landlock/fs.c
>> @@ -173,7 +173,8 @@ int landlock_append_fs_rule(struct landlock_ruleset *const ruleset,
>>   	if (IS_ERR(object))
>>   		return PTR_ERR(object);
>>   	mutex_lock(&ruleset->lock);
>> -	err = landlock_insert_rule(ruleset, object, access_rights);
>> +	err = landlock_insert_rule(ruleset, object, 0, access_rights,
>> +				   LANDLOCK_RULE_PATH_BENEATH);
>>   	mutex_unlock(&ruleset->lock);
>>   	/*
>>   	 * No need to check for an error because landlock_insert_rule()
>> @@ -204,7 +205,9 @@ find_rule(const struct landlock_ruleset *const domain,
>>   	inode = d_backing_inode(dentry);
>>   	rcu_read_lock();
>>   	rule = landlock_find_rule(
>> -		domain, rcu_dereference(landlock_inode(inode)->object));
>> +		domain,
>> +		(uintptr_t)rcu_dereference(landlock_inode(inode)->object),
>> +		LANDLOCK_RULE_PATH_BENEATH);
>>   	rcu_read_unlock();
>>   	return rule;
>>   }
>> diff --git a/security/landlock/ruleset.c b/security/landlock/ruleset.c
>> index a3fd58d01f09..5f13f8a12aee 100644
>> --- a/security/landlock/ruleset.c
>> +++ b/security/landlock/ruleset.c
>> @@ -35,7 +35,7 @@ static struct landlock_ruleset *create_ruleset(const u32 num_layers)
>>   		return ERR_PTR(-ENOMEM);
>>   	refcount_set(&new_ruleset->usage, 1);
>>   	mutex_init(&new_ruleset->lock);
>> -	new_ruleset->root = RB_ROOT;
>> +	new_ruleset->root_inode = RB_ROOT;
>>   	new_ruleset->num_layers = num_layers;
>>   	/*
>>   	 * hierarchy = NULL
>> @@ -69,7 +69,8 @@ static void build_check_rule(void)
>>   }
>> 
>>   static struct landlock_rule *
>> -create_rule(struct landlock_object *const object,
>> +create_rule(struct landlock_object *const object_ptr,
>> +	    const uintptr_t object_data,
>>   	    const struct landlock_layer (*const layers)[], const u32 num_layers,
>>   	    const struct landlock_layer *const new_layer)
>>   {
>> @@ -90,8 +91,15 @@ create_rule(struct landlock_object *const object,
>>   	if (!new_rule)
>>   		return ERR_PTR(-ENOMEM);
>>   	RB_CLEAR_NODE(&new_rule->node);
>> -	landlock_get_object(object);
>> -	new_rule->object = object;
>> +
>> +	if (object_ptr) {
>> +		landlock_get_object(object_ptr);
>> +		new_rule->object.ptr = object_ptr;
>> +	} else if (object_ptr && object_data) {
> 
> Something is wrong with this second check: else + object_ptr?

It was your suggestion to use it like this:
" ....You can also add a WARN_ON_ONCE(object_ptr && object_data)."

Please check it here:
https://lore.kernel.org/linux-security-module/bc44f11f-0eaa-a5f6-c5dc-1d36570f1be1@digikod.net/

> 
> 
>> +		WARN_ON_ONCE(1);
>> +		return ERR_PTR(-EINVAL);
>> +	}
>> +
>>   	new_rule->num_layers = new_num_layers;
>>   	/* Copies the original layer stack. */
>>   	memcpy(new_rule->layers, layers,
>> @@ -107,7 +115,7 @@ static void free_rule(struct landlock_rule *const rule)
>>   	might_sleep();
>>   	if (!rule)
>>   		return;
>> -	landlock_put_object(rule->object);
>> +	landlock_put_object(rule->object.ptr);
>>   	kfree(rule);
>>   }
>> 
>> @@ -143,26 +151,42 @@ static void build_check_ruleset(void)
>>    * access rights.
>>    */
>>   static int insert_rule(struct landlock_ruleset *const ruleset,
>> -		       struct landlock_object *const object,
>> +		       struct landlock_object *const object_ptr,
>> +		       uintptr_t object_data, u16 rule_type,
> 
> Use landlock_rule_type instead of u16, everywhere. It was part of my
> review/patch two versions ago (with other things), please take them into
> account:
> https://lore.kernel.org/r/92d498f0-c598-7413-6b7c-d19c5aec6cab@digikod.net
> 
  Ok. Thanks for the reminder.
> 
>>   		       const struct landlock_layer (*const layers)[],
>>   		       size_t num_layers)
>>   {
>>   	struct rb_node **walker_node;
>>   	struct rb_node *parent_node = NULL;
>>   	struct landlock_rule *new_rule;
>> +	struct rb_root *root;
>> 
>>   	might_sleep();
>>   	lockdep_assert_held(&ruleset->lock);
>> -	if (WARN_ON_ONCE(!object || !layers))
>> +	if (WARN_ON_ONCE(!layers))
>>   		return -ENOENT;
>> -	walker_node = &(ruleset->root.rb_node);
>> +	if (WARN_ON_ONCE(object_ptr && object_data))
>> +		return -EINVAL;
>> +	/* Chooses rb_tree structure depending on a rule type. */
>> +	switch (rule_type) {
>> +	case LANDLOCK_RULE_PATH_BENEATH:
>> +		if (WARN_ON_ONCE(!object_ptr))
>> +			return -ENOENT;
>> +		object_data = (uintptr_t)object_ptr;
>> +		root = &ruleset->root_inode;
>> +		break;
>> +	default:
>> +		WARN_ON_ONCE(1);
>> +		return -EINVAL;
>> +	}
>> +	walker_node = &root->rb_node;
>>   	while (*walker_node) {
>>   		struct landlock_rule *const this =
>>   			rb_entry(*walker_node, struct landlock_rule, node);
>> 
>> -		if (this->object != object) {
>> +		if (this->object.data != object_data) {
>>   			parent_node = *walker_node;
>> -			if (this->object < object)
>> +			if (this->object.data < object_data)
>>   				walker_node = &((*walker_node)->rb_right);
>>   			else
>>   				walker_node = &((*walker_node)->rb_left);
>> @@ -194,11 +218,16 @@ static int insert_rule(struct landlock_ruleset *const ruleset,
>>   		 * Intersects access rights when it is a merge between a
>>   		 * ruleset and a domain.
>>   		 */
>> -		new_rule = create_rule(object, &this->layers, this->num_layers,
>> -				       &(*layers)[0]);
>> +		switch (rule_type) {
>> +		case LANDLOCK_RULE_PATH_BENEATH:
>> +			new_rule = create_rule(object_ptr, 0, &this->layers,
>> +					       this->num_layers, &(*layers)[0]);
>> +			break;
>> +		}
>>   		if (IS_ERR(new_rule))
>>   			return PTR_ERR(new_rule);
>> -		rb_replace_node(&this->node, &new_rule->node, &ruleset->root);
>> +		rb_replace_node(&this->node, &new_rule->node,
>> +				&ruleset->root_inode);
>>   		free_rule(this);
>>   		return 0;
>>   	}
>> @@ -207,11 +236,15 @@ static int insert_rule(struct landlock_ruleset *const ruleset,
>>   	build_check_ruleset();
>>   	if (ruleset->num_rules >= LANDLOCK_MAX_NUM_RULES)
>>   		return -E2BIG;
>> -	new_rule = create_rule(object, layers, num_layers, NULL);
>> +	switch (rule_type) {
>> +	case LANDLOCK_RULE_PATH_BENEATH:
>> +		new_rule = create_rule(object_ptr, 0, layers, num_layers, NULL);
>> +		break;
>> +	}
>>   	if (IS_ERR(new_rule))
>>   		return PTR_ERR(new_rule);
>>   	rb_link_node(&new_rule->node, parent_node, walker_node);
>> -	rb_insert_color(&new_rule->node, &ruleset->root);
>> +	rb_insert_color(&new_rule->node, &ruleset->root_inode);
>>   	ruleset->num_rules++;
>>   	return 0;
>>   }
>> @@ -229,8 +262,9 @@ static void build_check_layer(void)
>> 
>>   /* @ruleset must be locked by the caller. */
>>   int landlock_insert_rule(struct landlock_ruleset *const ruleset,
>> -			 struct landlock_object *const object,
>> -			 const access_mask_t access)
>> +			 struct landlock_object *const object_ptr,
>> +			 const uintptr_t object_data,
>> +			 const access_mask_t access, const u16 rule_type)
>>   {
>>   	struct landlock_layer layers[] = { {
>>   		.access = access,
>> @@ -239,7 +273,8 @@ int landlock_insert_rule(struct landlock_ruleset *const ruleset,
>>   	} };
>> 
>>   	build_check_layer();
>> -	return insert_rule(ruleset, object, &layers, ARRAY_SIZE(layers));
>> +	return insert_rule(ruleset, object_ptr, object_data, rule_type, &layers,
>> +			   ARRAY_SIZE(layers));
>>   }
>> 
>>   static inline void get_hierarchy(struct landlock_hierarchy *const hierarchy)
>> @@ -284,8 +319,8 @@ static int merge_ruleset(struct landlock_ruleset *const dst,
>>   	dst->access_masks[dst->num_layers - 1] = src->access_masks[0];
>> 
>>   	/* Merges the @src tree. */
>> -	rbtree_postorder_for_each_entry_safe(walker_rule, next_rule, &src->root,
>> -					     node) {
>> +	rbtree_postorder_for_each_entry_safe(walker_rule, next_rule,
>> +					     &src->root_inode, node) {
>>   		struct landlock_layer layers[] = { {
>>   			.level = dst->num_layers,
>>   		} };
>> @@ -299,7 +334,8 @@ static int merge_ruleset(struct landlock_ruleset *const dst,
>>   			goto out_unlock;
>>   		}
>>   		layers[0].access = walker_rule->layers[0].access;
>> -		err = insert_rule(dst, walker_rule->object, &layers,
>> +		err = insert_rule(dst, walker_rule->object.ptr, 0,
>> +				  LANDLOCK_RULE_PATH_BENEATH, &layers,
>>   				  ARRAY_SIZE(layers));
>>   		if (err)
>>   			goto out_unlock;
>> @@ -327,8 +363,9 @@ static int inherit_ruleset(struct landlock_ruleset *const parent,
>> 
>>   	/* Copies the @parent tree. */
>>   	rbtree_postorder_for_each_entry_safe(walker_rule, next_rule,
>> -					     &parent->root, node) {
>> -		err = insert_rule(child, walker_rule->object,
>> +					     &parent->root_inode, node) {
>> +		err = insert_rule(child, walker_rule->object.ptr, 0,
>> +				  LANDLOCK_RULE_PATH_BENEATH,
>>   				  &walker_rule->layers,
>>   				  walker_rule->num_layers);
>>   		if (err)
>> @@ -361,7 +398,8 @@ static void free_ruleset(struct landlock_ruleset *const ruleset)
>>   	struct landlock_rule *freeme, *next;
>> 
>>   	might_sleep();
>> -	rbtree_postorder_for_each_entry_safe(freeme, next, &ruleset->root, node)
>> +	rbtree_postorder_for_each_entry_safe(freeme, next, &ruleset->root_inode,
>> +					     node)
>>   		free_rule(freeme);
>>   	put_hierarchy(ruleset->hierarchy);
>>   	kfree(ruleset);
>> @@ -453,20 +491,29 @@ landlock_merge_ruleset(struct landlock_ruleset *const parent,
>>    */
>>   const struct landlock_rule *
>>   landlock_find_rule(const struct landlock_ruleset *const ruleset,
>> -		   const struct landlock_object *const object)
>> +		   const uintptr_t object_data, const u16 rule_type)
>>   {
>>   	const struct rb_node *node;
>> 
>> -	if (!object)
>> +	if (!object_data)
>>   		return NULL;
>> -	node = ruleset->root.rb_node;
>> +
>> +	switch (rule_type) {
>> +	case LANDLOCK_RULE_PATH_BENEATH:
>> +		node = ruleset->root_inode.rb_node;
>> +		break;
>> +	default:
>> +		WARN_ON_ONCE(1);
>> +		return NULL;
>> +	}
>> +
>>   	while (node) {
>>   		struct landlock_rule *this =
>>   			rb_entry(node, struct landlock_rule, node);
>> 
>> -		if (this->object == object)
>> +		if (this->object.data == object_data)
>>   			return this;
>> -		if (this->object < object)
>> +		if (this->object.data < object_data)
>>   			node = node->rb_right;
>>   		else
>>   			node = node->rb_left;
>> diff --git a/security/landlock/ruleset.h b/security/landlock/ruleset.h
>> index bd7ab39859bf..a22d132c32a7 100644
>> --- a/security/landlock/ruleset.h
>> +++ b/security/landlock/ruleset.h
>> @@ -53,15 +53,17 @@ struct landlock_rule {
>>   	 */
>>   	struct rb_node node;
>>   	/**
>> -	 * @object: Pointer to identify a kernel object (e.g. an inode).  This
>> -	 * is used as a key for this ruleset element.  This pointer is set once
>> -	 * and never modified.  It always points to an allocated object because
>> -	 * each rule increments the refcount of its object.
>> -	 */
>> -	struct landlock_object *object;
>> -	/**
>> -	 * @num_layers: Number of entries in @layers.
>> +	 * @object: A union to identify either a kernel object (e.g. an inode) or
>> +	 * a raw data value (e.g. a network socket port). This is used as a key
>> +	 * for this ruleset element. This pointer/@object.ptr/ is set once and
>> +	 * never modified. It always points to an allocated object because each
>> +	 * rule increments the refcount of its object (for inodes).;
>>   	 */
>> +	union {
>> +		struct landlock_object *ptr;
>> +		uintptr_t data;
>> +	} object;
>> +
>>   	u32 num_layers;
>>   	/**
>>   	 * @layers: Stack of layers, from the latest to the newest, implemented
>> @@ -98,7 +100,7 @@ struct landlock_ruleset {
>>   	 * nodes.  Once a ruleset is tied to a process (i.e. as a domain), this
>>   	 * tree is immutable until @usage reaches zero.
>>   	 */
>> -	struct rb_root root;
>> +	struct rb_root root_inode;
>>   	/**
>>   	 * @hierarchy: Enables hierarchy identification even when a parent
>>   	 * domain vanishes.  This is needed for the ptrace protection.
>> @@ -160,8 +162,9 @@ void landlock_put_ruleset(struct landlock_ruleset *const ruleset);
>>   void landlock_put_ruleset_deferred(struct landlock_ruleset *const ruleset);
>> 
>>   int landlock_insert_rule(struct landlock_ruleset *const ruleset,
>> -			 struct landlock_object *const object,
>> -			 const access_mask_t access);
>> +			 struct landlock_object *const object_ptr,
>> +			 const uintptr_t object_data,
>> +			 const access_mask_t access, const u16 rule_type);
>> 
>>   struct landlock_ruleset *
>>   landlock_merge_ruleset(struct landlock_ruleset *const parent,
>> @@ -169,7 +172,7 @@ landlock_merge_ruleset(struct landlock_ruleset *const parent,
>> 
>>   const struct landlock_rule *
>>   landlock_find_rule(const struct landlock_ruleset *const ruleset,
>> -		   const struct landlock_object *const object);
>> +		   const uintptr_t object_data, const u16 rule_type);
>> 
>>   static inline void landlock_get_ruleset(struct landlock_ruleset *const ruleset)
>>   {
>> --
>> 2.25.1
>> 
> .

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 02/17] landlock: refactors landlock_find/insert_rule
  2022-07-07 16:46   ` Mickaël Salaün
@ 2022-07-08 12:54     ` Konstantin Meskhidze (A)
  0 siblings, 0 replies; 53+ messages in thread
From: Konstantin Meskhidze (A) @ 2022-07-08 12:54 UTC (permalink / raw)
  To: Mickaël Salaün
  Cc: willemdebruijn.kernel, linux-security-module, netdev,
	netfilter-devel, yusongping, anton.sirazetdinov



7/7/2022 7:46 PM, Mickaël Salaün пишет:
> 
> 
> On 21/06/2022 10:22, Konstantin Meskhidze wrote:
>> Adds a new object union to support a socket port
>> rule type. Refactors landlock_insert_rule() and
>> landlock_find_rule() to support coming network
>> modifications. Now adding or searching a rule
>> in a ruleset depends on a rule_type argument
>> provided in refactored functions mentioned above.
>> 
>> Signed-off-by: Konstantin Meskhidze <konstantin.meskhidze@huawei.com>
>> ---
>> 
>> Changes since v5:
>> * Formats code with clang-format-14.
>> 
>> Changes since v4:
>> * Refactors insert_rule() and create_rule() functions by deleting
>> rule_type from their arguments list, it helps to reduce useless code.
>> 
>> Changes since v3:
>> * Splits commit.
>> * Refactors landlock_insert_rule and landlock_find_rule functions.
>> * Rename new_ruleset->root_inode.
>> 
>> ---
>>   security/landlock/fs.c      |   7 ++-
>>   security/landlock/ruleset.c | 105 ++++++++++++++++++++++++++----------
>>   security/landlock/ruleset.h |  27 +++++-----
>>   3 files changed, 96 insertions(+), 43 deletions(-)
> 
> [...]
> 
>> diff --git a/security/landlock/ruleset.h b/security/landlock/ruleset.h
>> index bd7ab39859bf..a22d132c32a7 100644
>> --- a/security/landlock/ruleset.h
>> +++ b/security/landlock/ruleset.h
>> @@ -53,15 +53,17 @@ struct landlock_rule {
>>   	 */
>>   	struct rb_node node;
>>   	/**
>> -	 * @object: Pointer to identify a kernel object (e.g. an inode).  This
>> -	 * is used as a key for this ruleset element.  This pointer is set once
>> -	 * and never modified.  It always points to an allocated object because
>> -	 * each rule increments the refcount of its object.
>> -	 */
>> -	struct landlock_object *object;
>> -	/**
>> -	 * @num_layers: Number of entries in @layers.
>> +	 * @object: A union to identify either a kernel object (e.g. an inode) or
>> +	 * a raw data value (e.g. a network socket port). This is used as a key
>> +	 * for this ruleset element. This pointer/@object.ptr/ is set once and
>> +	 * never modified. It always points to an allocated object because each
>> +	 * rule increments the refcount of its object (for inodes).;
> 
> Extra ";"

  Yep. It's a silly typo. Thanks.
  Will be removed.
> .

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 01/17] landlock: renames access mask
  2022-07-05 13:26       ` Mickaël Salaün
@ 2022-07-08 12:56         ` Konstantin Meskhidze (A)
  0 siblings, 0 replies; 53+ messages in thread
From: Konstantin Meskhidze (A) @ 2022-07-08 12:56 UTC (permalink / raw)
  To: Mickaël Salaün
  Cc: willemdebruijn.kernel, linux-security-module, netdev,
	netfilter-devel, yusongping, anton.sirazetdinov



7/5/2022 4:26 PM, Mickaël Salaün пишет:
> On 2022-07-05T13:29:04.000+02:00, Konstantin Meskhidze (A) <konstantin.meskhidze@huawei.com> wrote:
>>  7/1/2022 8:08 PM, Mickaël Salaün пишет:
>> 
>> >    
>> >  On 21/06/2022 10:22, Konstantin Meskhidze wrote:
>> > 
>> > >    To support network type rules,
>> > >  this modification extends and renames
>> > >  ruleset's access masks.
>> > >  This patch adds filesystem helper functions
>> > >  to set and get filesystem mask. Also the
>> > >  modification adds a helper structure
>> > >  landlock_access_mask to support managing
>> > >  multiple access mask.
>> >   
>> >  Please use a text-width of 72 columns for all commit messages. You can
>> >  also split them into paragraphs.
>> >  
>>     By the way, are you going to review the rest patches?
> 
> Yes, of course, I'm busy right now but I'll send more reviews by the end of the week.

   Thanks. Take your time.
> .

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 02/17] landlock: refactors landlock_find/insert_rule
  2022-07-07 16:44   ` Mickaël Salaün
  2022-07-08 12:53     ` Konstantin Meskhidze (A)
@ 2022-07-08 13:10     ` Konstantin Meskhidze (A)
  2022-07-08 13:59       ` Mickaël Salaün
  1 sibling, 1 reply; 53+ messages in thread
From: Konstantin Meskhidze (A) @ 2022-07-08 13:10 UTC (permalink / raw)
  To: Mickaël Salaün
  Cc: willemdebruijn.kernel, linux-security-module, netdev,
	netfilter-devel, yusongping, anton.sirazetdinov



7/7/2022 7:44 PM, Mickaël Salaün пишет:
> 
> On 21/06/2022 10:22, Konstantin Meskhidze wrote:
>> Adds a new object union to support a socket port
>> rule type. Refactors landlock_insert_rule() and
>> landlock_find_rule() to support coming network
>> modifications. Now adding or searching a rule
>> in a ruleset depends on a rule_type argument
>> provided in refactored functions mentioned above.
>> 
>> Signed-off-by: Konstantin Meskhidze <konstantin.meskhidze@huawei.com>
>> ---
>> 
>> Changes since v5:
>> * Formats code with clang-format-14.
>> 
>> Changes since v4:
>> * Refactors insert_rule() and create_rule() functions by deleting
>> rule_type from their arguments list, it helps to reduce useless code.
>> 
>> Changes since v3:
>> * Splits commit.
>> * Refactors landlock_insert_rule and landlock_find_rule functions.
>> * Rename new_ruleset->root_inode.
>> 
>> ---
>>   security/landlock/fs.c      |   7 ++-
>>   security/landlock/ruleset.c | 105 ++++++++++++++++++++++++++----------
>>   security/landlock/ruleset.h |  27 +++++-----
>>   3 files changed, 96 insertions(+), 43 deletions(-)
>> 
>> diff --git a/security/landlock/fs.c b/security/landlock/fs.c
>> index e6da08ed99d1..46aedc2a05a8 100644
>> --- a/security/landlock/fs.c
>> +++ b/security/landlock/fs.c
>> @@ -173,7 +173,8 @@ int landlock_append_fs_rule(struct landlock_ruleset *const ruleset,
>>   	if (IS_ERR(object))
>>   		return PTR_ERR(object);
>>   	mutex_lock(&ruleset->lock);
>> -	err = landlock_insert_rule(ruleset, object, access_rights);
>> +	err = landlock_insert_rule(ruleset, object, 0, access_rights,
>> +				   LANDLOCK_RULE_PATH_BENEATH);
>>   	mutex_unlock(&ruleset->lock);
>>   	/*
>>   	 * No need to check for an error because landlock_insert_rule()
>> @@ -204,7 +205,9 @@ find_rule(const struct landlock_ruleset *const domain,
>>   	inode = d_backing_inode(dentry);
>>   	rcu_read_lock();
>>   	rule = landlock_find_rule(
>> -		domain, rcu_dereference(landlock_inode(inode)->object));
>> +		domain,
>> +		(uintptr_t)rcu_dereference(landlock_inode(inode)->object),
>> +		LANDLOCK_RULE_PATH_BENEATH);
>>   	rcu_read_unlock();
>>   	return rule;
>>   }
>> diff --git a/security/landlock/ruleset.c b/security/landlock/ruleset.c
>> index a3fd58d01f09..5f13f8a12aee 100644
>> --- a/security/landlock/ruleset.c
>> +++ b/security/landlock/ruleset.c
>> @@ -35,7 +35,7 @@ static struct landlock_ruleset *create_ruleset(const u32 num_layers)
>>   		return ERR_PTR(-ENOMEM);
>>   	refcount_set(&new_ruleset->usage, 1);
>>   	mutex_init(&new_ruleset->lock);
>> -	new_ruleset->root = RB_ROOT;
>> +	new_ruleset->root_inode = RB_ROOT;
>>   	new_ruleset->num_layers = num_layers;
>>   	/*
>>   	 * hierarchy = NULL
>> @@ -69,7 +69,8 @@ static void build_check_rule(void)
>>   }
>> 
>>   static struct landlock_rule *
>> -create_rule(struct landlock_object *const object,
>> +create_rule(struct landlock_object *const object_ptr,
>> +	    const uintptr_t object_data,
>>   	    const struct landlock_layer (*const layers)[], const u32 num_layers,
>>   	    const struct landlock_layer *const new_layer)
>>   {
>> @@ -90,8 +91,15 @@ create_rule(struct landlock_object *const object,
>>   	if (!new_rule)
>>   		return ERR_PTR(-ENOMEM);
>>   	RB_CLEAR_NODE(&new_rule->node);
>> -	landlock_get_object(object);
>> -	new_rule->object = object;
>> +
>> +	if (object_ptr) {
>> +		landlock_get_object(object_ptr);
>> +		new_rule->object.ptr = object_ptr;
>> +	} else if (object_ptr && object_data) {
> 
> Something is wrong with this second check: else + object_ptr?

  Sorry. Do you mean logical error here? I got your point.
  You are right!

  I think it must be refactored like this:

	if (object_ptr && !object_data) {
		landlock_get_object(object_ptr);
		new_rule->object.ptr = object_ptr;
	} else if (object_ptr && object_data) {
		...
	}
Plus, I will add a test for this case.

> 
> 
>> +		WARN_ON_ONCE(1);
>> +		return ERR_PTR(-EINVAL);
>> +	}
>> +
>>   	new_rule->num_layers = new_num_layers;
>>   	/* Copies the original layer stack. */
>>   	memcpy(new_rule->layers, layers,
>> @@ -107,7 +115,7 @@ static void free_rule(struct landlock_rule *const rule)
>>   	might_sleep();
>>   	if (!rule)
>>   		return;
>> -	landlock_put_object(rule->object);
>> +	landlock_put_object(rule->object.ptr);
>>   	kfree(rule);
>>   }
>> 
>> @@ -143,26 +151,42 @@ static void build_check_ruleset(void)
>>    * access rights.
>>    */
>>   static int insert_rule(struct landlock_ruleset *const ruleset,
>> -		       struct landlock_object *const object,
>> +		       struct landlock_object *const object_ptr,
>> +		       uintptr_t object_data, u16 rule_type,
> 
> Use landlock_rule_type instead of u16, everywhere. It was part of my
> review/patch two versions ago (with other things), please take them into
> account:
> https://lore.kernel.org/r/92d498f0-c598-7413-6b7c-d19c5aec6cab@digikod.net
> 
> 
>>   		       const struct landlock_layer (*const layers)[],
>>   		       size_t num_layers)
>>   {
>>   	struct rb_node **walker_node;
>>   	struct rb_node *parent_node = NULL;
>>   	struct landlock_rule *new_rule;
>> +	struct rb_root *root;
>> 
>>   	might_sleep();
>>   	lockdep_assert_held(&ruleset->lock);
>> -	if (WARN_ON_ONCE(!object || !layers))
>> +	if (WARN_ON_ONCE(!layers))
>>   		return -ENOENT;
>> -	walker_node = &(ruleset->root.rb_node);
>> +	if (WARN_ON_ONCE(object_ptr && object_data))
>> +		return -EINVAL;
>> +	/* Chooses rb_tree structure depending on a rule type. */
>> +	switch (rule_type) {
>> +	case LANDLOCK_RULE_PATH_BENEATH:
>> +		if (WARN_ON_ONCE(!object_ptr))
>> +			return -ENOENT;
>> +		object_data = (uintptr_t)object_ptr;
>> +		root = &ruleset->root_inode;
>> +		break;
>> +	default:
>> +		WARN_ON_ONCE(1);
>> +		return -EINVAL;
>> +	}
>> +	walker_node = &root->rb_node;
>>   	while (*walker_node) {
>>   		struct landlock_rule *const this =
>>   			rb_entry(*walker_node, struct landlock_rule, node);
>> 
>> -		if (this->object != object) {
>> +		if (this->object.data != object_data) {
>>   			parent_node = *walker_node;
>> -			if (this->object < object)
>> +			if (this->object.data < object_data)
>>   				walker_node = &((*walker_node)->rb_right);
>>   			else
>>   				walker_node = &((*walker_node)->rb_left);
>> @@ -194,11 +218,16 @@ static int insert_rule(struct landlock_ruleset *const ruleset,
>>   		 * Intersects access rights when it is a merge between a
>>   		 * ruleset and a domain.
>>   		 */
>> -		new_rule = create_rule(object, &this->layers, this->num_layers,
>> -				       &(*layers)[0]);
>> +		switch (rule_type) {
>> +		case LANDLOCK_RULE_PATH_BENEATH:
>> +			new_rule = create_rule(object_ptr, 0, &this->layers,
>> +					       this->num_layers, &(*layers)[0]);
>> +			break;
>> +		}
>>   		if (IS_ERR(new_rule))
>>   			return PTR_ERR(new_rule);
>> -		rb_replace_node(&this->node, &new_rule->node, &ruleset->root);
>> +		rb_replace_node(&this->node, &new_rule->node,
>> +				&ruleset->root_inode);
>>   		free_rule(this);
>>   		return 0;
>>   	}
>> @@ -207,11 +236,15 @@ static int insert_rule(struct landlock_ruleset *const ruleset,
>>   	build_check_ruleset();
>>   	if (ruleset->num_rules >= LANDLOCK_MAX_NUM_RULES)
>>   		return -E2BIG;
>> -	new_rule = create_rule(object, layers, num_layers, NULL);
>> +	switch (rule_type) {
>> +	case LANDLOCK_RULE_PATH_BENEATH:
>> +		new_rule = create_rule(object_ptr, 0, layers, num_layers, NULL);
>> +		break;
>> +	}
>>   	if (IS_ERR(new_rule))
>>   		return PTR_ERR(new_rule);
>>   	rb_link_node(&new_rule->node, parent_node, walker_node);
>> -	rb_insert_color(&new_rule->node, &ruleset->root);
>> +	rb_insert_color(&new_rule->node, &ruleset->root_inode);
>>   	ruleset->num_rules++;
>>   	return 0;
>>   }
>> @@ -229,8 +262,9 @@ static void build_check_layer(void)
>> 
>>   /* @ruleset must be locked by the caller. */
>>   int landlock_insert_rule(struct landlock_ruleset *const ruleset,
>> -			 struct landlock_object *const object,
>> -			 const access_mask_t access)
>> +			 struct landlock_object *const object_ptr,
>> +			 const uintptr_t object_data,
>> +			 const access_mask_t access, const u16 rule_type)
>>   {
>>   	struct landlock_layer layers[] = { {
>>   		.access = access,
>> @@ -239,7 +273,8 @@ int landlock_insert_rule(struct landlock_ruleset *const ruleset,
>>   	} };
>> 
>>   	build_check_layer();
>> -	return insert_rule(ruleset, object, &layers, ARRAY_SIZE(layers));
>> +	return insert_rule(ruleset, object_ptr, object_data, rule_type, &layers,
>> +			   ARRAY_SIZE(layers));
>>   }
>> 
>>   static inline void get_hierarchy(struct landlock_hierarchy *const hierarchy)
>> @@ -284,8 +319,8 @@ static int merge_ruleset(struct landlock_ruleset *const dst,
>>   	dst->access_masks[dst->num_layers - 1] = src->access_masks[0];
>> 
>>   	/* Merges the @src tree. */
>> -	rbtree_postorder_for_each_entry_safe(walker_rule, next_rule, &src->root,
>> -					     node) {
>> +	rbtree_postorder_for_each_entry_safe(walker_rule, next_rule,
>> +					     &src->root_inode, node) {
>>   		struct landlock_layer layers[] = { {
>>   			.level = dst->num_layers,
>>   		} };
>> @@ -299,7 +334,8 @@ static int merge_ruleset(struct landlock_ruleset *const dst,
>>   			goto out_unlock;
>>   		}
>>   		layers[0].access = walker_rule->layers[0].access;
>> -		err = insert_rule(dst, walker_rule->object, &layers,
>> +		err = insert_rule(dst, walker_rule->object.ptr, 0,
>> +				  LANDLOCK_RULE_PATH_BENEATH, &layers,
>>   				  ARRAY_SIZE(layers));
>>   		if (err)
>>   			goto out_unlock;
>> @@ -327,8 +363,9 @@ static int inherit_ruleset(struct landlock_ruleset *const parent,
>> 
>>   	/* Copies the @parent tree. */
>>   	rbtree_postorder_for_each_entry_safe(walker_rule, next_rule,
>> -					     &parent->root, node) {
>> -		err = insert_rule(child, walker_rule->object,
>> +					     &parent->root_inode, node) {
>> +		err = insert_rule(child, walker_rule->object.ptr, 0,
>> +				  LANDLOCK_RULE_PATH_BENEATH,
>>   				  &walker_rule->layers,
>>   				  walker_rule->num_layers);
>>   		if (err)
>> @@ -361,7 +398,8 @@ static void free_ruleset(struct landlock_ruleset *const ruleset)
>>   	struct landlock_rule *freeme, *next;
>> 
>>   	might_sleep();
>> -	rbtree_postorder_for_each_entry_safe(freeme, next, &ruleset->root, node)
>> +	rbtree_postorder_for_each_entry_safe(freeme, next, &ruleset->root_inode,
>> +					     node)
>>   		free_rule(freeme);
>>   	put_hierarchy(ruleset->hierarchy);
>>   	kfree(ruleset);
>> @@ -453,20 +491,29 @@ landlock_merge_ruleset(struct landlock_ruleset *const parent,
>>    */
>>   const struct landlock_rule *
>>   landlock_find_rule(const struct landlock_ruleset *const ruleset,
>> -		   const struct landlock_object *const object)
>> +		   const uintptr_t object_data, const u16 rule_type)
>>   {
>>   	const struct rb_node *node;
>> 
>> -	if (!object)
>> +	if (!object_data)
>>   		return NULL;
>> -	node = ruleset->root.rb_node;
>> +
>> +	switch (rule_type) {
>> +	case LANDLOCK_RULE_PATH_BENEATH:
>> +		node = ruleset->root_inode.rb_node;
>> +		break;
>> +	default:
>> +		WARN_ON_ONCE(1);
>> +		return NULL;
>> +	}
>> +
>>   	while (node) {
>>   		struct landlock_rule *this =
>>   			rb_entry(node, struct landlock_rule, node);
>> 
>> -		if (this->object == object)
>> +		if (this->object.data == object_data)
>>   			return this;
>> -		if (this->object < object)
>> +		if (this->object.data < object_data)
>>   			node = node->rb_right;
>>   		else
>>   			node = node->rb_left;
>> diff --git a/security/landlock/ruleset.h b/security/landlock/ruleset.h
>> index bd7ab39859bf..a22d132c32a7 100644
>> --- a/security/landlock/ruleset.h
>> +++ b/security/landlock/ruleset.h
>> @@ -53,15 +53,17 @@ struct landlock_rule {
>>   	 */
>>   	struct rb_node node;
>>   	/**
>> -	 * @object: Pointer to identify a kernel object (e.g. an inode).  This
>> -	 * is used as a key for this ruleset element.  This pointer is set once
>> -	 * and never modified.  It always points to an allocated object because
>> -	 * each rule increments the refcount of its object.
>> -	 */
>> -	struct landlock_object *object;
>> -	/**
>> -	 * @num_layers: Number of entries in @layers.
>> +	 * @object: A union to identify either a kernel object (e.g. an inode) or
>> +	 * a raw data value (e.g. a network socket port). This is used as a key
>> +	 * for this ruleset element. This pointer/@object.ptr/ is set once and
>> +	 * never modified. It always points to an allocated object because each
>> +	 * rule increments the refcount of its object (for inodes).;
>>   	 */
>> +	union {
>> +		struct landlock_object *ptr;
>> +		uintptr_t data;
>> +	} object;
>> +
>>   	u32 num_layers;
>>   	/**
>>   	 * @layers: Stack of layers, from the latest to the newest, implemented
>> @@ -98,7 +100,7 @@ struct landlock_ruleset {
>>   	 * nodes.  Once a ruleset is tied to a process (i.e. as a domain), this
>>   	 * tree is immutable until @usage reaches zero.
>>   	 */
>> -	struct rb_root root;
>> +	struct rb_root root_inode;
>>   	/**
>>   	 * @hierarchy: Enables hierarchy identification even when a parent
>>   	 * domain vanishes.  This is needed for the ptrace protection.
>> @@ -160,8 +162,9 @@ void landlock_put_ruleset(struct landlock_ruleset *const ruleset);
>>   void landlock_put_ruleset_deferred(struct landlock_ruleset *const ruleset);
>> 
>>   int landlock_insert_rule(struct landlock_ruleset *const ruleset,
>> -			 struct landlock_object *const object,
>> -			 const access_mask_t access);
>> +			 struct landlock_object *const object_ptr,
>> +			 const uintptr_t object_data,
>> +			 const access_mask_t access, const u16 rule_type);
>> 
>>   struct landlock_ruleset *
>>   landlock_merge_ruleset(struct landlock_ruleset *const parent,
>> @@ -169,7 +172,7 @@ landlock_merge_ruleset(struct landlock_ruleset *const parent,
>> 
>>   const struct landlock_rule *
>>   landlock_find_rule(const struct landlock_ruleset *const ruleset,
>> -		   const struct landlock_object *const object);
>> +		   const uintptr_t object_data, const u16 rule_type);
>> 
>>   static inline void landlock_get_ruleset(struct landlock_ruleset *const ruleset)
>>   {
>> --
>> 2.25.1
>> 
> .

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 02/17] landlock: refactors landlock_find/insert_rule
  2022-07-08 12:53     ` Konstantin Meskhidze (A)
@ 2022-07-08 13:56       ` Mickaël Salaün
  2022-07-08 14:14         ` Konstantin Meskhidze (A)
  2022-07-08 14:20         ` Konstantin Meskhidze (A)
  0 siblings, 2 replies; 53+ messages in thread
From: Mickaël Salaün @ 2022-07-08 13:56 UTC (permalink / raw)
  To: Konstantin Meskhidze (A)
  Cc: willemdebruijn.kernel, linux-security-module, netdev,
	netfilter-devel, yusongping, anton.sirazetdinov


On 08/07/2022 14:53, Konstantin Meskhidze (A) wrote:
> 
> 
> 7/7/2022 7:44 PM, Mickaël Salaün пишет:
>>
>> On 21/06/2022 10:22, Konstantin Meskhidze wrote:
>>> Adds a new object union to support a socket port
>>> rule type. Refactors landlock_insert_rule() and
>>> landlock_find_rule() to support coming network
>>> modifications. Now adding or searching a rule
>>> in a ruleset depends on a rule_type argument
>>> provided in refactored functions mentioned above.
>>>
>>> Signed-off-by: Konstantin Meskhidze <konstantin.meskhidze@huawei.com>
>>> ---
>>>
>>> Changes since v5:
>>> * Formats code with clang-format-14.
>>>
>>> Changes since v4:
>>> * Refactors insert_rule() and create_rule() functions by deleting
>>> rule_type from their arguments list, it helps to reduce useless code.
>>>
>>> Changes since v3:
>>> * Splits commit.
>>> * Refactors landlock_insert_rule and landlock_find_rule functions.
>>> * Rename new_ruleset->root_inode.
>>>
>>> ---
>>>   security/landlock/fs.c      |   7 ++-
>>>   security/landlock/ruleset.c | 105 ++++++++++++++++++++++++++----------
>>>   security/landlock/ruleset.h |  27 +++++-----
>>>   3 files changed, 96 insertions(+), 43 deletions(-)
>>>
>>> diff --git a/security/landlock/fs.c b/security/landlock/fs.c
>>> index e6da08ed99d1..46aedc2a05a8 100644
>>> --- a/security/landlock/fs.c
>>> +++ b/security/landlock/fs.c
>>> @@ -173,7 +173,8 @@ int landlock_append_fs_rule(struct 
>>> landlock_ruleset *const ruleset,
>>>       if (IS_ERR(object))
>>>           return PTR_ERR(object);
>>>       mutex_lock(&ruleset->lock);
>>> -    err = landlock_insert_rule(ruleset, object, access_rights);
>>> +    err = landlock_insert_rule(ruleset, object, 0, access_rights,
>>> +                   LANDLOCK_RULE_PATH_BENEATH);
>>>       mutex_unlock(&ruleset->lock);
>>>       /*
>>>        * No need to check for an error because landlock_insert_rule()
>>> @@ -204,7 +205,9 @@ find_rule(const struct landlock_ruleset *const 
>>> domain,
>>>       inode = d_backing_inode(dentry);
>>>       rcu_read_lock();
>>>       rule = landlock_find_rule(
>>> -        domain, rcu_dereference(landlock_inode(inode)->object));
>>> +        domain,
>>> +        (uintptr_t)rcu_dereference(landlock_inode(inode)->object),
>>> +        LANDLOCK_RULE_PATH_BENEATH);
>>>       rcu_read_unlock();
>>>       return rule;
>>>   }
>>> diff --git a/security/landlock/ruleset.c b/security/landlock/ruleset.c
>>> index a3fd58d01f09..5f13f8a12aee 100644
>>> --- a/security/landlock/ruleset.c
>>> +++ b/security/landlock/ruleset.c
>>> @@ -35,7 +35,7 @@ static struct landlock_ruleset 
>>> *create_ruleset(const u32 num_layers)
>>>           return ERR_PTR(-ENOMEM);
>>>       refcount_set(&new_ruleset->usage, 1);
>>>       mutex_init(&new_ruleset->lock);
>>> -    new_ruleset->root = RB_ROOT;
>>> +    new_ruleset->root_inode = RB_ROOT;
>>>       new_ruleset->num_layers = num_layers;
>>>       /*
>>>        * hierarchy = NULL
>>> @@ -69,7 +69,8 @@ static void build_check_rule(void)
>>>   }
>>>
>>>   static struct landlock_rule *
>>> -create_rule(struct landlock_object *const object,
>>> +create_rule(struct landlock_object *const object_ptr,
>>> +        const uintptr_t object_data,
>>>           const struct landlock_layer (*const layers)[], const u32 
>>> num_layers,
>>>           const struct landlock_layer *const new_layer)
>>>   {
>>> @@ -90,8 +91,15 @@ create_rule(struct landlock_object *const object,
>>>       if (!new_rule)
>>>           return ERR_PTR(-ENOMEM);
>>>       RB_CLEAR_NODE(&new_rule->node);
>>> -    landlock_get_object(object);
>>> -    new_rule->object = object;
>>> +
>>> +    if (object_ptr) {
>>> +        landlock_get_object(object_ptr);
>>> +        new_rule->object.ptr = object_ptr;
>>> +    } else if (object_ptr && object_data) {
>>
>> Something is wrong with this second check: else + object_ptr?
> 
> It was your suggestion to use it like this:
> " ....You can also add a WARN_ON_ONCE(object_ptr && object_data)."
> 
> Please check it here:
> https://lore.kernel.org/linux-security-module/bc44f11f-0eaa-a5f6-c5dc-1d36570f1be1@digikod.net/ 

Yes, but the error is in the "else", you should write:
if (WARN_ON_ONCE(object_ptr && object_data))
	return ERR_PTR(-EINVAL);

…and this should be before the `if (object_ptr) {` line (to avoid 
erronous landlock_get_object() call), just after the `if (!new_rule)` check.

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 02/17] landlock: refactors landlock_find/insert_rule
  2022-07-08 13:10     ` Konstantin Meskhidze (A)
@ 2022-07-08 13:59       ` Mickaël Salaün
  2022-07-08 14:14         ` Konstantin Meskhidze (A)
  0 siblings, 1 reply; 53+ messages in thread
From: Mickaël Salaün @ 2022-07-08 13:59 UTC (permalink / raw)
  To: Konstantin Meskhidze (A)
  Cc: willemdebruijn.kernel, linux-security-module, netdev,
	netfilter-devel, yusongping, anton.sirazetdinov


On 08/07/2022 15:10, Konstantin Meskhidze (A) wrote:
> 
> 
> 7/7/2022 7:44 PM, Mickaël Salaün пишет:
>>
>> On 21/06/2022 10:22, Konstantin Meskhidze wrote:
>>> Adds a new object union to support a socket port
>>> rule type. Refactors landlock_insert_rule() and
>>> landlock_find_rule() to support coming network
>>> modifications. Now adding or searching a rule
>>> in a ruleset depends on a rule_type argument
>>> provided in refactored functions mentioned above.
>>>
>>> Signed-off-by: Konstantin Meskhidze <konstantin.meskhidze@huawei.com>
>>> ---
>>>
>>> Changes since v5:
>>> * Formats code with clang-format-14.
>>>
>>> Changes since v4:
>>> * Refactors insert_rule() and create_rule() functions by deleting
>>> rule_type from their arguments list, it helps to reduce useless code.
>>>
>>> Changes since v3:
>>> * Splits commit.
>>> * Refactors landlock_insert_rule and landlock_find_rule functions.
>>> * Rename new_ruleset->root_inode.
>>>
>>> ---
>>>   security/landlock/fs.c      |   7 ++-
>>>   security/landlock/ruleset.c | 105 ++++++++++++++++++++++++++----------
>>>   security/landlock/ruleset.h |  27 +++++-----
>>>   3 files changed, 96 insertions(+), 43 deletions(-)
>>>
>>> diff --git a/security/landlock/fs.c b/security/landlock/fs.c
>>> index e6da08ed99d1..46aedc2a05a8 100644
>>> --- a/security/landlock/fs.c
>>> +++ b/security/landlock/fs.c
>>> @@ -173,7 +173,8 @@ int landlock_append_fs_rule(struct 
>>> landlock_ruleset *const ruleset,
>>>       if (IS_ERR(object))
>>>           return PTR_ERR(object);
>>>       mutex_lock(&ruleset->lock);
>>> -    err = landlock_insert_rule(ruleset, object, access_rights);
>>> +    err = landlock_insert_rule(ruleset, object, 0, access_rights,
>>> +                   LANDLOCK_RULE_PATH_BENEATH);
>>>       mutex_unlock(&ruleset->lock);
>>>       /*
>>>        * No need to check for an error because landlock_insert_rule()
>>> @@ -204,7 +205,9 @@ find_rule(const struct landlock_ruleset *const 
>>> domain,
>>>       inode = d_backing_inode(dentry);
>>>       rcu_read_lock();
>>>       rule = landlock_find_rule(
>>> -        domain, rcu_dereference(landlock_inode(inode)->object));
>>> +        domain,
>>> +        (uintptr_t)rcu_dereference(landlock_inode(inode)->object),
>>> +        LANDLOCK_RULE_PATH_BENEATH);
>>>       rcu_read_unlock();
>>>       return rule;
>>>   }
>>> diff --git a/security/landlock/ruleset.c b/security/landlock/ruleset.c
>>> index a3fd58d01f09..5f13f8a12aee 100644
>>> --- a/security/landlock/ruleset.c
>>> +++ b/security/landlock/ruleset.c
>>> @@ -35,7 +35,7 @@ static struct landlock_ruleset 
>>> *create_ruleset(const u32 num_layers)
>>>           return ERR_PTR(-ENOMEM);
>>>       refcount_set(&new_ruleset->usage, 1);
>>>       mutex_init(&new_ruleset->lock);
>>> -    new_ruleset->root = RB_ROOT;
>>> +    new_ruleset->root_inode = RB_ROOT;
>>>       new_ruleset->num_layers = num_layers;
>>>       /*
>>>        * hierarchy = NULL
>>> @@ -69,7 +69,8 @@ static void build_check_rule(void)
>>>   }
>>>
>>>   static struct landlock_rule *
>>> -create_rule(struct landlock_object *const object,
>>> +create_rule(struct landlock_object *const object_ptr,
>>> +        const uintptr_t object_data,
>>>           const struct landlock_layer (*const layers)[], const u32 
>>> num_layers,
>>>           const struct landlock_layer *const new_layer)
>>>   {
>>> @@ -90,8 +91,15 @@ create_rule(struct landlock_object *const object,
>>>       if (!new_rule)
>>>           return ERR_PTR(-ENOMEM);
>>>       RB_CLEAR_NODE(&new_rule->node);
>>> -    landlock_get_object(object);
>>> -    new_rule->object = object;
>>> +
>>> +    if (object_ptr) {
>>> +        landlock_get_object(object_ptr);
>>> +        new_rule->object.ptr = object_ptr;
>>> +    } else if (object_ptr && object_data) {
>>
>> Something is wrong with this second check: else + object_ptr?
> 
>   Sorry. Do you mean logical error here? I got your point.
>   You are right!
> 
>   I think it must be refactored like this:
> 
>      if (object_ptr && !object_data) {
>          landlock_get_object(object_ptr);
>          new_rule->object.ptr = object_ptr;
>      } else if (object_ptr && object_data) {
>          ...
>      }

There is indeed a logical error but this doesn't fix everything. Please 
include my previous suggestion instead.


> Plus, I will add a test for this case.

That would be great but I don't think this code is reachable from user 
space. I think that would require kunit but I may be missing something. 
How would you test this?

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 02/17] landlock: refactors landlock_find/insert_rule
  2022-07-08 13:59       ` Mickaël Salaün
@ 2022-07-08 14:14         ` Konstantin Meskhidze (A)
  2022-07-08 14:35           ` Mickaël Salaün
  0 siblings, 1 reply; 53+ messages in thread
From: Konstantin Meskhidze (A) @ 2022-07-08 14:14 UTC (permalink / raw)
  To: Mickaël Salaün
  Cc: willemdebruijn.kernel, linux-security-module, netdev,
	netfilter-devel, yusongping, anton.sirazetdinov



7/8/2022 4:59 PM, Mickaël Salaün пишет:
> 
> On 08/07/2022 15:10, Konstantin Meskhidze (A) wrote:
>> 
>> 
>> 7/7/2022 7:44 PM, Mickaël Salaün пишет:
>>>
>>> On 21/06/2022 10:22, Konstantin Meskhidze wrote:
>>>> Adds a new object union to support a socket port
>>>> rule type. Refactors landlock_insert_rule() and
>>>> landlock_find_rule() to support coming network
>>>> modifications. Now adding or searching a rule
>>>> in a ruleset depends on a rule_type argument
>>>> provided in refactored functions mentioned above.
>>>>
>>>> Signed-off-by: Konstantin Meskhidze <konstantin.meskhidze@huawei.com>
>>>> ---
>>>>
>>>> Changes since v5:
>>>> * Formats code with clang-format-14.
>>>>
>>>> Changes since v4:
>>>> * Refactors insert_rule() and create_rule() functions by deleting
>>>> rule_type from their arguments list, it helps to reduce useless code.
>>>>
>>>> Changes since v3:
>>>> * Splits commit.
>>>> * Refactors landlock_insert_rule and landlock_find_rule functions.
>>>> * Rename new_ruleset->root_inode.
>>>>
>>>> ---
>>>>   security/landlock/fs.c      |   7 ++-
>>>>   security/landlock/ruleset.c | 105 ++++++++++++++++++++++++++----------
>>>>   security/landlock/ruleset.h |  27 +++++-----
>>>>   3 files changed, 96 insertions(+), 43 deletions(-)
>>>>
>>>> diff --git a/security/landlock/fs.c b/security/landlock/fs.c
>>>> index e6da08ed99d1..46aedc2a05a8 100644
>>>> --- a/security/landlock/fs.c
>>>> +++ b/security/landlock/fs.c
>>>> @@ -173,7 +173,8 @@ int landlock_append_fs_rule(struct 
>>>> landlock_ruleset *const ruleset,
>>>>       if (IS_ERR(object))
>>>>           return PTR_ERR(object);
>>>>       mutex_lock(&ruleset->lock);
>>>> -    err = landlock_insert_rule(ruleset, object, access_rights);
>>>> +    err = landlock_insert_rule(ruleset, object, 0, access_rights,
>>>> +                   LANDLOCK_RULE_PATH_BENEATH);
>>>>       mutex_unlock(&ruleset->lock);
>>>>       /*
>>>>        * No need to check for an error because landlock_insert_rule()
>>>> @@ -204,7 +205,9 @@ find_rule(const struct landlock_ruleset *const 
>>>> domain,
>>>>       inode = d_backing_inode(dentry);
>>>>       rcu_read_lock();
>>>>       rule = landlock_find_rule(
>>>> -        domain, rcu_dereference(landlock_inode(inode)->object));
>>>> +        domain,
>>>> +        (uintptr_t)rcu_dereference(landlock_inode(inode)->object),
>>>> +        LANDLOCK_RULE_PATH_BENEATH);
>>>>       rcu_read_unlock();
>>>>       return rule;
>>>>   }
>>>> diff --git a/security/landlock/ruleset.c b/security/landlock/ruleset.c
>>>> index a3fd58d01f09..5f13f8a12aee 100644
>>>> --- a/security/landlock/ruleset.c
>>>> +++ b/security/landlock/ruleset.c
>>>> @@ -35,7 +35,7 @@ static struct landlock_ruleset 
>>>> *create_ruleset(const u32 num_layers)
>>>>           return ERR_PTR(-ENOMEM);
>>>>       refcount_set(&new_ruleset->usage, 1);
>>>>       mutex_init(&new_ruleset->lock);
>>>> -    new_ruleset->root = RB_ROOT;
>>>> +    new_ruleset->root_inode = RB_ROOT;
>>>>       new_ruleset->num_layers = num_layers;
>>>>       /*
>>>>        * hierarchy = NULL
>>>> @@ -69,7 +69,8 @@ static void build_check_rule(void)
>>>>   }
>>>>
>>>>   static struct landlock_rule *
>>>> -create_rule(struct landlock_object *const object,
>>>> +create_rule(struct landlock_object *const object_ptr,
>>>> +        const uintptr_t object_data,
>>>>           const struct landlock_layer (*const layers)[], const u32 
>>>> num_layers,
>>>>           const struct landlock_layer *const new_layer)
>>>>   {
>>>> @@ -90,8 +91,15 @@ create_rule(struct landlock_object *const object,
>>>>       if (!new_rule)
>>>>           return ERR_PTR(-ENOMEM);
>>>>       RB_CLEAR_NODE(&new_rule->node);
>>>> -    landlock_get_object(object);
>>>> -    new_rule->object = object;
>>>> +
>>>> +    if (object_ptr) {
>>>> +        landlock_get_object(object_ptr);
>>>> +        new_rule->object.ptr = object_ptr;
>>>> +    } else if (object_ptr && object_data) {
>>>
>>> Something is wrong with this second check: else + object_ptr?
>> 
>>   Sorry. Do you mean logical error here? I got your point.
>>   You are right!
>> 
>>   I think it must be refactored like this:
>> 
>>      if (object_ptr && !object_data) {
>>          landlock_get_object(object_ptr);
>>          new_rule->object.ptr = object_ptr;
>>      } else if (object_ptr && object_data) {
>>          ...
>>      }
> 
> There is indeed a logical error but this doesn't fix everything. Please
> include my previous suggestion instead.
> 
    By the way, in the next commits I have fixed this logic error.
Anyway I will refactor this one also. Thanks.
> 
>> Plus, I will add a test for this case.
> 
> That would be great but I don't think this code is reachable from user
> space. I think that would require kunit but I may be missing something.
> How would you test this?

You are correct. I checked it. It's impossible to reach this line from 
userpace (insert both object_ptr and object_data). But create_rule() 
must be used carefuly by other developers (if any in future). Do you 
think if its possible to have some internal kernel tests that could 
handle this issue?
> .

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 02/17] landlock: refactors landlock_find/insert_rule
  2022-07-08 13:56       ` Mickaël Salaün
@ 2022-07-08 14:14         ` Konstantin Meskhidze (A)
  2022-07-08 14:20         ` Konstantin Meskhidze (A)
  1 sibling, 0 replies; 53+ messages in thread
From: Konstantin Meskhidze (A) @ 2022-07-08 14:14 UTC (permalink / raw)
  To: Mickaël Salaün
  Cc: willemdebruijn.kernel, linux-security-module, netdev,
	netfilter-devel, yusongping, anton.sirazetdinov



7/8/2022 4:56 PM, Mickaël Salaün пишет:
> 
> On 08/07/2022 14:53, Konstantin Meskhidze (A) wrote:
>> 
>> 
>> 7/7/2022 7:44 PM, Mickaël Salaün пишет:
>>>
>>> On 21/06/2022 10:22, Konstantin Meskhidze wrote:
>>>> Adds a new object union to support a socket port
>>>> rule type. Refactors landlock_insert_rule() and
>>>> landlock_find_rule() to support coming network
>>>> modifications. Now adding or searching a rule
>>>> in a ruleset depends on a rule_type argument
>>>> provided in refactored functions mentioned above.
>>>>
>>>> Signed-off-by: Konstantin Meskhidze <konstantin.meskhidze@huawei.com>
>>>> ---
>>>>
>>>> Changes since v5:
>>>> * Formats code with clang-format-14.
>>>>
>>>> Changes since v4:
>>>> * Refactors insert_rule() and create_rule() functions by deleting
>>>> rule_type from their arguments list, it helps to reduce useless code.
>>>>
>>>> Changes since v3:
>>>> * Splits commit.
>>>> * Refactors landlock_insert_rule and landlock_find_rule functions.
>>>> * Rename new_ruleset->root_inode.
>>>>
>>>> ---
>>>>   security/landlock/fs.c      |   7 ++-
>>>>   security/landlock/ruleset.c | 105 ++++++++++++++++++++++++++----------
>>>>   security/landlock/ruleset.h |  27 +++++-----
>>>>   3 files changed, 96 insertions(+), 43 deletions(-)
>>>>
>>>> diff --git a/security/landlock/fs.c b/security/landlock/fs.c
>>>> index e6da08ed99d1..46aedc2a05a8 100644
>>>> --- a/security/landlock/fs.c
>>>> +++ b/security/landlock/fs.c
>>>> @@ -173,7 +173,8 @@ int landlock_append_fs_rule(struct 
>>>> landlock_ruleset *const ruleset,
>>>>       if (IS_ERR(object))
>>>>           return PTR_ERR(object);
>>>>       mutex_lock(&ruleset->lock);
>>>> -    err = landlock_insert_rule(ruleset, object, access_rights);
>>>> +    err = landlock_insert_rule(ruleset, object, 0, access_rights,
>>>> +                   LANDLOCK_RULE_PATH_BENEATH);
>>>>       mutex_unlock(&ruleset->lock);
>>>>       /*
>>>>        * No need to check for an error because landlock_insert_rule()
>>>> @@ -204,7 +205,9 @@ find_rule(const struct landlock_ruleset *const 
>>>> domain,
>>>>       inode = d_backing_inode(dentry);
>>>>       rcu_read_lock();
>>>>       rule = landlock_find_rule(
>>>> -        domain, rcu_dereference(landlock_inode(inode)->object));
>>>> +        domain,
>>>> +        (uintptr_t)rcu_dereference(landlock_inode(inode)->object),
>>>> +        LANDLOCK_RULE_PATH_BENEATH);
>>>>       rcu_read_unlock();
>>>>       return rule;
>>>>   }
>>>> diff --git a/security/landlock/ruleset.c b/security/landlock/ruleset.c
>>>> index a3fd58d01f09..5f13f8a12aee 100644
>>>> --- a/security/landlock/ruleset.c
>>>> +++ b/security/landlock/ruleset.c
>>>> @@ -35,7 +35,7 @@ static struct landlock_ruleset 
>>>> *create_ruleset(const u32 num_layers)
>>>>           return ERR_PTR(-ENOMEM);
>>>>       refcount_set(&new_ruleset->usage, 1);
>>>>       mutex_init(&new_ruleset->lock);
>>>> -    new_ruleset->root = RB_ROOT;
>>>> +    new_ruleset->root_inode = RB_ROOT;
>>>>       new_ruleset->num_layers = num_layers;
>>>>       /*
>>>>        * hierarchy = NULL
>>>> @@ -69,7 +69,8 @@ static void build_check_rule(void)
>>>>   }
>>>>
>>>>   static struct landlock_rule *
>>>> -create_rule(struct landlock_object *const object,
>>>> +create_rule(struct landlock_object *const object_ptr,
>>>> +        const uintptr_t object_data,
>>>>           const struct landlock_layer (*const layers)[], const u32 
>>>> num_layers,
>>>>           const struct landlock_layer *const new_layer)
>>>>   {
>>>> @@ -90,8 +91,15 @@ create_rule(struct landlock_object *const object,
>>>>       if (!new_rule)
>>>>           return ERR_PTR(-ENOMEM);
>>>>       RB_CLEAR_NODE(&new_rule->node);
>>>> -    landlock_get_object(object);
>>>> -    new_rule->object = object;
>>>> +
>>>> +    if (object_ptr) {
>>>> +        landlock_get_object(object_ptr);
>>>> +        new_rule->object.ptr = object_ptr;
>>>> +    } else if (object_ptr && object_data) {
>>>
>>> Something is wrong with this second check: else + object_ptr?
>> 
>> It was your suggestion to use it like this:
>> " ....You can also add a WARN_ON_ONCE(object_ptr && object_data)."
>> 
>> Please check it here:
>> https://lore.kernel.org/linux-security-module/bc44f11f-0eaa-a5f6-c5dc-1d36570f1be1@digikod.net/ 
> 
> Yes, but the error is in the "else", you should write:
> if (WARN_ON_ONCE(object_ptr && object_data))
> 	return ERR_PTR(-EINVAL);
> 
> …and this should be before the `if (object_ptr) {` line (to avoid
> erronous landlock_get_object() call), just after the `if (!new_rule)` check.

  By the way, in the next commits I have fixed this logic error.
Anyway I will refactor this one also. Thanks.
> .

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 02/17] landlock: refactors landlock_find/insert_rule
  2022-07-08 13:56       ` Mickaël Salaün
  2022-07-08 14:14         ` Konstantin Meskhidze (A)
@ 2022-07-08 14:20         ` Konstantin Meskhidze (A)
  2022-07-08 16:57           ` Mickaël Salaün
  1 sibling, 1 reply; 53+ messages in thread
From: Konstantin Meskhidze (A) @ 2022-07-08 14:20 UTC (permalink / raw)
  To: Mickaël Salaün
  Cc: willemdebruijn.kernel, linux-security-module, netdev,
	netfilter-devel, yusongping, anton.sirazetdinov



7/8/2022 4:56 PM, Mickaël Salaün пишет:
> 
> On 08/07/2022 14:53, Konstantin Meskhidze (A) wrote:
>> 
>> 
>> 7/7/2022 7:44 PM, Mickaël Salaün пишет:
>>>
>>> On 21/06/2022 10:22, Konstantin Meskhidze wrote:
>>>> Adds a new object union to support a socket port
>>>> rule type. Refactors landlock_insert_rule() and
>>>> landlock_find_rule() to support coming network
>>>> modifications. Now adding or searching a rule
>>>> in a ruleset depends on a rule_type argument
>>>> provided in refactored functions mentioned above.
>>>>
>>>> Signed-off-by: Konstantin Meskhidze <konstantin.meskhidze@huawei.com>
>>>> ---
>>>>
>>>> Changes since v5:
>>>> * Formats code with clang-format-14.
>>>>
>>>> Changes since v4:
>>>> * Refactors insert_rule() and create_rule() functions by deleting
>>>> rule_type from their arguments list, it helps to reduce useless code.
>>>>
>>>> Changes since v3:
>>>> * Splits commit.
>>>> * Refactors landlock_insert_rule and landlock_find_rule functions.
>>>> * Rename new_ruleset->root_inode.
>>>>
>>>> ---
>>>>   security/landlock/fs.c      |   7 ++-
>>>>   security/landlock/ruleset.c | 105 ++++++++++++++++++++++++++----------
>>>>   security/landlock/ruleset.h |  27 +++++-----
>>>>   3 files changed, 96 insertions(+), 43 deletions(-)
>>>>
>>>> diff --git a/security/landlock/fs.c b/security/landlock/fs.c
>>>> index e6da08ed99d1..46aedc2a05a8 100644
>>>> --- a/security/landlock/fs.c
>>>> +++ b/security/landlock/fs.c
>>>> @@ -173,7 +173,8 @@ int landlock_append_fs_rule(struct 
>>>> landlock_ruleset *const ruleset,
>>>>       if (IS_ERR(object))
>>>>           return PTR_ERR(object);
>>>>       mutex_lock(&ruleset->lock);
>>>> -    err = landlock_insert_rule(ruleset, object, access_rights);
>>>> +    err = landlock_insert_rule(ruleset, object, 0, access_rights,
>>>> +                   LANDLOCK_RULE_PATH_BENEATH);
>>>>       mutex_unlock(&ruleset->lock);
>>>>       /*
>>>>        * No need to check for an error because landlock_insert_rule()
>>>> @@ -204,7 +205,9 @@ find_rule(const struct landlock_ruleset *const 
>>>> domain,
>>>>       inode = d_backing_inode(dentry);
>>>>       rcu_read_lock();
>>>>       rule = landlock_find_rule(
>>>> -        domain, rcu_dereference(landlock_inode(inode)->object));
>>>> +        domain,
>>>> +        (uintptr_t)rcu_dereference(landlock_inode(inode)->object),
>>>> +        LANDLOCK_RULE_PATH_BENEATH);
>>>>       rcu_read_unlock();
>>>>       return rule;
>>>>   }
>>>> diff --git a/security/landlock/ruleset.c b/security/landlock/ruleset.c
>>>> index a3fd58d01f09..5f13f8a12aee 100644
>>>> --- a/security/landlock/ruleset.c
>>>> +++ b/security/landlock/ruleset.c
>>>> @@ -35,7 +35,7 @@ static struct landlock_ruleset 
>>>> *create_ruleset(const u32 num_layers)
>>>>           return ERR_PTR(-ENOMEM);
>>>>       refcount_set(&new_ruleset->usage, 1);
>>>>       mutex_init(&new_ruleset->lock);
>>>> -    new_ruleset->root = RB_ROOT;
>>>> +    new_ruleset->root_inode = RB_ROOT;
>>>>       new_ruleset->num_layers = num_layers;
>>>>       /*
>>>>        * hierarchy = NULL
>>>> @@ -69,7 +69,8 @@ static void build_check_rule(void)
>>>>   }
>>>>
>>>>   static struct landlock_rule *
>>>> -create_rule(struct landlock_object *const object,
>>>> +create_rule(struct landlock_object *const object_ptr,
>>>> +        const uintptr_t object_data,
>>>>           const struct landlock_layer (*const layers)[], const u32 
>>>> num_layers,
>>>>           const struct landlock_layer *const new_layer)
>>>>   {
>>>> @@ -90,8 +91,15 @@ create_rule(struct landlock_object *const object,
>>>>       if (!new_rule)
>>>>           return ERR_PTR(-ENOMEM);
>>>>       RB_CLEAR_NODE(&new_rule->node);
>>>> -    landlock_get_object(object);
>>>> -    new_rule->object = object;
>>>> +
>>>> +    if (object_ptr) {
>>>> +        landlock_get_object(object_ptr);
>>>> +        new_rule->object.ptr = object_ptr;
>>>> +    } else if (object_ptr && object_data) {
>>>
>>> Something is wrong with this second check: else + object_ptr?
>> 
>> It was your suggestion to use it like this:
>> " ....You can also add a WARN_ON_ONCE(object_ptr && object_data)."
>> 
>> Please check it here:
>> https://lore.kernel.org/linux-security-module/bc44f11f-0eaa-a5f6-c5dc-1d36570f1be1@digikod.net/ 
> 
> Yes, but the error is in the "else", you should write:
> if (WARN_ON_ONCE(object_ptr && object_data))
> 	return ERR_PTR(-EINVAL);
> 
> …and this should be before the `if (object_ptr) {` line (to avoid
> erronous landlock_get_object() call), just after the `if (!new_rule)` check.

   Maybe we could delete this check here cause we have it in the upper 
insert_rule() function??

...
	if (WARN_ON_ONCE(!layers))
		return -ENOENT;
------>	if (WARN_ON_ONCE(object_ptr && object_data))
		return -EINVAL;
	/* Chooses rb_tree structure depending on a rule type. */
	switch (rule_type) {
	case LANDLOCK_RULE_PATH_BENEATH:
		if (WARN_ON_ONCE(!object_ptr))
			return -ENOENT;
		object_data = (uintptr_t)object_ptr;
		root = &ruleset->root_inode;
		break;
	default:
		WARN_ON_ONCE(1);
		return -EINVAL;
	}
...

This is double check here. What do you think?
> .

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 02/17] landlock: refactors landlock_find/insert_rule
  2022-07-08 14:14         ` Konstantin Meskhidze (A)
@ 2022-07-08 14:35           ` Mickaël Salaün
  2022-07-11 14:05             ` Konstantin Meskhidze (A)
  0 siblings, 1 reply; 53+ messages in thread
From: Mickaël Salaün @ 2022-07-08 14:35 UTC (permalink / raw)
  To: Konstantin Meskhidze (A)
  Cc: willemdebruijn.kernel, linux-security-module, netdev,
	netfilter-devel, yusongping, anton.sirazetdinov


On 08/07/2022 16:14, Konstantin Meskhidze (A) wrote:
> 
> 
> 7/8/2022 4:59 PM, Mickaël Salaün пишет:
>>
>> On 08/07/2022 15:10, Konstantin Meskhidze (A) wrote:
>>>
>>>
>>> 7/7/2022 7:44 PM, Mickaël Salaün пишет:
>>>>
>>>> On 21/06/2022 10:22, Konstantin Meskhidze wrote:
>>>>> Adds a new object union to support a socket port
>>>>> rule type. Refactors landlock_insert_rule() and
>>>>> landlock_find_rule() to support coming network
>>>>> modifications. Now adding or searching a rule
>>>>> in a ruleset depends on a rule_type argument
>>>>> provided in refactored functions mentioned above.
>>>>>
>>>>> Signed-off-by: Konstantin Meskhidze <konstantin.meskhidze@huawei.com>
>>>>> ---
>>>>>
>>>>> Changes since v5:
>>>>> * Formats code with clang-format-14.
>>>>>
>>>>> Changes since v4:
>>>>> * Refactors insert_rule() and create_rule() functions by deleting
>>>>> rule_type from their arguments list, it helps to reduce useless code.
>>>>>
>>>>> Changes since v3:
>>>>> * Splits commit.
>>>>> * Refactors landlock_insert_rule and landlock_find_rule functions.
>>>>> * Rename new_ruleset->root_inode.
>>>>>
>>>>> ---
>>>>>   security/landlock/fs.c      |   7 ++-
>>>>>   security/landlock/ruleset.c | 105 
>>>>> ++++++++++++++++++++++++++----------
>>>>>   security/landlock/ruleset.h |  27 +++++-----
>>>>>   3 files changed, 96 insertions(+), 43 deletions(-)
>>>>>
>>>>> diff --git a/security/landlock/fs.c b/security/landlock/fs.c
>>>>> index e6da08ed99d1..46aedc2a05a8 100644
>>>>> --- a/security/landlock/fs.c
>>>>> +++ b/security/landlock/fs.c
>>>>> @@ -173,7 +173,8 @@ int landlock_append_fs_rule(struct 
>>>>> landlock_ruleset *const ruleset,
>>>>>       if (IS_ERR(object))
>>>>>           return PTR_ERR(object);
>>>>>       mutex_lock(&ruleset->lock);
>>>>> -    err = landlock_insert_rule(ruleset, object, access_rights);
>>>>> +    err = landlock_insert_rule(ruleset, object, 0, access_rights,
>>>>> +                   LANDLOCK_RULE_PATH_BENEATH);
>>>>>       mutex_unlock(&ruleset->lock);
>>>>>       /*
>>>>>        * No need to check for an error because landlock_insert_rule()
>>>>> @@ -204,7 +205,9 @@ find_rule(const struct landlock_ruleset *const 
>>>>> domain,
>>>>>       inode = d_backing_inode(dentry);
>>>>>       rcu_read_lock();
>>>>>       rule = landlock_find_rule(
>>>>> -        domain, rcu_dereference(landlock_inode(inode)->object));
>>>>> +        domain,
>>>>> +        (uintptr_t)rcu_dereference(landlock_inode(inode)->object),
>>>>> +        LANDLOCK_RULE_PATH_BENEATH);
>>>>>       rcu_read_unlock();
>>>>>       return rule;
>>>>>   }
>>>>> diff --git a/security/landlock/ruleset.c b/security/landlock/ruleset.c
>>>>> index a3fd58d01f09..5f13f8a12aee 100644
>>>>> --- a/security/landlock/ruleset.c
>>>>> +++ b/security/landlock/ruleset.c
>>>>> @@ -35,7 +35,7 @@ static struct landlock_ruleset 
>>>>> *create_ruleset(const u32 num_layers)
>>>>>           return ERR_PTR(-ENOMEM);
>>>>>       refcount_set(&new_ruleset->usage, 1);
>>>>>       mutex_init(&new_ruleset->lock);
>>>>> -    new_ruleset->root = RB_ROOT;
>>>>> +    new_ruleset->root_inode = RB_ROOT;
>>>>>       new_ruleset->num_layers = num_layers;
>>>>>       /*
>>>>>        * hierarchy = NULL
>>>>> @@ -69,7 +69,8 @@ static void build_check_rule(void)
>>>>>   }
>>>>>
>>>>>   static struct landlock_rule *
>>>>> -create_rule(struct landlock_object *const object,
>>>>> +create_rule(struct landlock_object *const object_ptr,
>>>>> +        const uintptr_t object_data,
>>>>>           const struct landlock_layer (*const layers)[], const u32 
>>>>> num_layers,
>>>>>           const struct landlock_layer *const new_layer)
>>>>>   {
>>>>> @@ -90,8 +91,15 @@ create_rule(struct landlock_object *const object,
>>>>>       if (!new_rule)
>>>>>           return ERR_PTR(-ENOMEM);
>>>>>       RB_CLEAR_NODE(&new_rule->node);
>>>>> -    landlock_get_object(object);
>>>>> -    new_rule->object = object;
>>>>> +
>>>>> +    if (object_ptr) {
>>>>> +        landlock_get_object(object_ptr);
>>>>> +        new_rule->object.ptr = object_ptr;
>>>>> +    } else if (object_ptr && object_data) {
>>>>
>>>> Something is wrong with this second check: else + object_ptr?
>>>
>>>   Sorry. Do you mean logical error here? I got your point.
>>>   You are right!
>>>
>>>   I think it must be refactored like this:
>>>
>>>      if (object_ptr && !object_data) {
>>>          landlock_get_object(object_ptr);
>>>          new_rule->object.ptr = object_ptr;
>>>      } else if (object_ptr && object_data) {
>>>          ...
>>>      }
>>
>> There is indeed a logical error but this doesn't fix everything. Please
>> include my previous suggestion instead.
>>
>     By the way, in the next commits I have fixed this logic error.
> Anyway I will refactor this one also. Thanks.
>>
>>> Plus, I will add a test for this case.
>>
>> That would be great but I don't think this code is reachable from user
>> space. I think that would require kunit but I may be missing something.
>> How would you test this?
> 
> You are correct. I checked it. It's impossible to reach this line from 
> userpace (insert both object_ptr and object_data). But create_rule() 
> must be used carefuly by other developers (if any in future). Do you 
> think if its possible to have some internal kernel tests that could 
> handle this issue?

We can use kunit tests for such kernel functions, but in this case I'm 
not sure what could be tested. I started working on bringing kunit tests 
to Landlock but it's not ready yet. Please list all non-userspace tests 
you can think about.

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 02/17] landlock: refactors landlock_find/insert_rule
  2022-07-08 14:20         ` Konstantin Meskhidze (A)
@ 2022-07-08 16:57           ` Mickaël Salaün
  2022-07-11  8:16             ` Konstantin Meskhidze (A)
  0 siblings, 1 reply; 53+ messages in thread
From: Mickaël Salaün @ 2022-07-08 16:57 UTC (permalink / raw)
  To: Konstantin Meskhidze (A)
  Cc: willemdebruijn.kernel, linux-security-module, netdev,
	netfilter-devel, yusongping, anton.sirazetdinov


On 08/07/2022 16:20, Konstantin Meskhidze (A) wrote:
> 
> 
> 7/8/2022 4:56 PM, Mickaël Salaün пишет:
>>
>> On 08/07/2022 14:53, Konstantin Meskhidze (A) wrote:
>>>
>>>
>>> 7/7/2022 7:44 PM, Mickaël Salaün пишет:
>>>>
>>>> On 21/06/2022 10:22, Konstantin Meskhidze wrote:
>>>>> Adds a new object union to support a socket port
>>>>> rule type. Refactors landlock_insert_rule() and
>>>>> landlock_find_rule() to support coming network
>>>>> modifications. Now adding or searching a rule
>>>>> in a ruleset depends on a rule_type argument
>>>>> provided in refactored functions mentioned above.
>>>>>
>>>>> Signed-off-by: Konstantin Meskhidze <konstantin.meskhidze@huawei.com>
>>>>> ---
>>>>>
>>>>> Changes since v5:
>>>>> * Formats code with clang-format-14.
>>>>>
>>>>> Changes since v4:
>>>>> * Refactors insert_rule() and create_rule() functions by deleting
>>>>> rule_type from their arguments list, it helps to reduce useless code.
>>>>>
>>>>> Changes since v3:
>>>>> * Splits commit.
>>>>> * Refactors landlock_insert_rule and landlock_find_rule functions.
>>>>> * Rename new_ruleset->root_inode.
>>>>>
>>>>> ---
>>>>>   security/landlock/fs.c      |   7 ++-
>>>>>   security/landlock/ruleset.c | 105 
>>>>> ++++++++++++++++++++++++++----------
>>>>>   security/landlock/ruleset.h |  27 +++++-----
>>>>>   3 files changed, 96 insertions(+), 43 deletions(-)
>>>>>
>>>>> diff --git a/security/landlock/fs.c b/security/landlock/fs.c
>>>>> index e6da08ed99d1..46aedc2a05a8 100644
>>>>> --- a/security/landlock/fs.c
>>>>> +++ b/security/landlock/fs.c
>>>>> @@ -173,7 +173,8 @@ int landlock_append_fs_rule(struct 
>>>>> landlock_ruleset *const ruleset,
>>>>>       if (IS_ERR(object))
>>>>>           return PTR_ERR(object);
>>>>>       mutex_lock(&ruleset->lock);
>>>>> -    err = landlock_insert_rule(ruleset, object, access_rights);
>>>>> +    err = landlock_insert_rule(ruleset, object, 0, access_rights,
>>>>> +                   LANDLOCK_RULE_PATH_BENEATH);
>>>>>       mutex_unlock(&ruleset->lock);
>>>>>       /*
>>>>>        * No need to check for an error because landlock_insert_rule()
>>>>> @@ -204,7 +205,9 @@ find_rule(const struct landlock_ruleset *const 
>>>>> domain,
>>>>>       inode = d_backing_inode(dentry);
>>>>>       rcu_read_lock();
>>>>>       rule = landlock_find_rule(
>>>>> -        domain, rcu_dereference(landlock_inode(inode)->object));
>>>>> +        domain,
>>>>> +        (uintptr_t)rcu_dereference(landlock_inode(inode)->object),
>>>>> +        LANDLOCK_RULE_PATH_BENEATH);
>>>>>       rcu_read_unlock();
>>>>>       return rule;
>>>>>   }
>>>>> diff --git a/security/landlock/ruleset.c b/security/landlock/ruleset.c
>>>>> index a3fd58d01f09..5f13f8a12aee 100644
>>>>> --- a/security/landlock/ruleset.c
>>>>> +++ b/security/landlock/ruleset.c
>>>>> @@ -35,7 +35,7 @@ static struct landlock_ruleset 
>>>>> *create_ruleset(const u32 num_layers)
>>>>>           return ERR_PTR(-ENOMEM);
>>>>>       refcount_set(&new_ruleset->usage, 1);
>>>>>       mutex_init(&new_ruleset->lock);
>>>>> -    new_ruleset->root = RB_ROOT;
>>>>> +    new_ruleset->root_inode = RB_ROOT;
>>>>>       new_ruleset->num_layers = num_layers;
>>>>>       /*
>>>>>        * hierarchy = NULL
>>>>> @@ -69,7 +69,8 @@ static void build_check_rule(void)
>>>>>   }
>>>>>
>>>>>   static struct landlock_rule *
>>>>> -create_rule(struct landlock_object *const object,
>>>>> +create_rule(struct landlock_object *const object_ptr,
>>>>> +        const uintptr_t object_data,
>>>>>           const struct landlock_layer (*const layers)[], const u32 
>>>>> num_layers,
>>>>>           const struct landlock_layer *const new_layer)
>>>>>   {
>>>>> @@ -90,8 +91,15 @@ create_rule(struct landlock_object *const object,
>>>>>       if (!new_rule)
>>>>>           return ERR_PTR(-ENOMEM);
>>>>>       RB_CLEAR_NODE(&new_rule->node);
>>>>> -    landlock_get_object(object);
>>>>> -    new_rule->object = object;
>>>>> +
>>>>> +    if (object_ptr) {
>>>>> +        landlock_get_object(object_ptr);
>>>>> +        new_rule->object.ptr = object_ptr;
>>>>> +    } else if (object_ptr && object_data) {
>>>>
>>>> Something is wrong with this second check: else + object_ptr?
>>>
>>> It was your suggestion to use it like this:
>>> " ....You can also add a WARN_ON_ONCE(object_ptr && object_data)."
>>>
>>> Please check it here:
>>> https://lore.kernel.org/linux-security-module/bc44f11f-0eaa-a5f6-c5dc-1d36570f1be1@digikod.net/ 
>>
>>
>> Yes, but the error is in the "else", you should write:
>> if (WARN_ON_ONCE(object_ptr && object_data))
>>     return ERR_PTR(-EINVAL);
>>
>> …and this should be before the `if (object_ptr) {` line (to avoid
>> erronous landlock_get_object() call), just after the `if (!new_rule)` 
>> check.
> 
>    Maybe we could delete this check here cause we have it in the upper 
> insert_rule() function??
> 
> ...
>      if (WARN_ON_ONCE(!layers))
>          return -ENOENT;
> ------>    if (WARN_ON_ONCE(object_ptr && object_data))
>          return -EINVAL;
>      /* Chooses rb_tree structure depending on a rule type. */
>      switch (rule_type) {
>      case LANDLOCK_RULE_PATH_BENEATH:
>          if (WARN_ON_ONCE(!object_ptr))
>              return -ENOENT;
>          object_data = (uintptr_t)object_ptr;
>          root = &ruleset->root_inode;
>          break;
>      default:
>          WARN_ON_ONCE(1);
>          return -EINVAL;
>      }
> ...
> 
> This is double check here. What do you think?

This check is indeed done twice, and for now create_rule() is only 
called from insert_rule(), but I prefer to keep it in both location to 
not get bitten in the future were it could be called from other 
locations. The compiler may be smart enough to remove the redundant 
checks though.

I'll send a patch to improve this part.

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 02/17] landlock: refactors landlock_find/insert_rule
  2022-07-08 16:57           ` Mickaël Salaün
@ 2022-07-11  8:16             ` Konstantin Meskhidze (A)
  0 siblings, 0 replies; 53+ messages in thread
From: Konstantin Meskhidze (A) @ 2022-07-11  8:16 UTC (permalink / raw)
  To: Mickaël Salaün
  Cc: willemdebruijn.kernel, linux-security-module, netdev,
	netfilter-devel, yusongping, anton.sirazetdinov



7/8/2022 7:57 PM, Mickaël Salaün пишет:
> 
> On 08/07/2022 16:20, Konstantin Meskhidze (A) wrote:
>> 
>> 
>> 7/8/2022 4:56 PM, Mickaël Salaün пишет:
>>>
>>> On 08/07/2022 14:53, Konstantin Meskhidze (A) wrote:
>>>>
>>>>
>>>> 7/7/2022 7:44 PM, Mickaël Salaün пишет:
>>>>>
>>>>> On 21/06/2022 10:22, Konstantin Meskhidze wrote:
>>>>>> Adds a new object union to support a socket port
>>>>>> rule type. Refactors landlock_insert_rule() and
>>>>>> landlock_find_rule() to support coming network
>>>>>> modifications. Now adding or searching a rule
>>>>>> in a ruleset depends on a rule_type argument
>>>>>> provided in refactored functions mentioned above.
>>>>>>
>>>>>> Signed-off-by: Konstantin Meskhidze <konstantin.meskhidze@huawei.com>
>>>>>> ---
>>>>>>
>>>>>> Changes since v5:
>>>>>> * Formats code with clang-format-14.
>>>>>>
>>>>>> Changes since v4:
>>>>>> * Refactors insert_rule() and create_rule() functions by deleting
>>>>>> rule_type from their arguments list, it helps to reduce useless code.
>>>>>>
>>>>>> Changes since v3:
>>>>>> * Splits commit.
>>>>>> * Refactors landlock_insert_rule and landlock_find_rule functions.
>>>>>> * Rename new_ruleset->root_inode.
>>>>>>
>>>>>> ---
>>>>>>   security/landlock/fs.c      |   7 ++-
>>>>>>   security/landlock/ruleset.c | 105 
>>>>>> ++++++++++++++++++++++++++----------
>>>>>>   security/landlock/ruleset.h |  27 +++++-----
>>>>>>   3 files changed, 96 insertions(+), 43 deletions(-)
>>>>>>
>>>>>> diff --git a/security/landlock/fs.c b/security/landlock/fs.c
>>>>>> index e6da08ed99d1..46aedc2a05a8 100644
>>>>>> --- a/security/landlock/fs.c
>>>>>> +++ b/security/landlock/fs.c
>>>>>> @@ -173,7 +173,8 @@ int landlock_append_fs_rule(struct 
>>>>>> landlock_ruleset *const ruleset,
>>>>>>       if (IS_ERR(object))
>>>>>>           return PTR_ERR(object);
>>>>>>       mutex_lock(&ruleset->lock);
>>>>>> -    err = landlock_insert_rule(ruleset, object, access_rights);
>>>>>> +    err = landlock_insert_rule(ruleset, object, 0, access_rights,
>>>>>> +                   LANDLOCK_RULE_PATH_BENEATH);
>>>>>>       mutex_unlock(&ruleset->lock);
>>>>>>       /*
>>>>>>        * No need to check for an error because landlock_insert_rule()
>>>>>> @@ -204,7 +205,9 @@ find_rule(const struct landlock_ruleset *const 
>>>>>> domain,
>>>>>>       inode = d_backing_inode(dentry);
>>>>>>       rcu_read_lock();
>>>>>>       rule = landlock_find_rule(
>>>>>> -        domain, rcu_dereference(landlock_inode(inode)->object));
>>>>>> +        domain,
>>>>>> +        (uintptr_t)rcu_dereference(landlock_inode(inode)->object),
>>>>>> +        LANDLOCK_RULE_PATH_BENEATH);
>>>>>>       rcu_read_unlock();
>>>>>>       return rule;
>>>>>>   }
>>>>>> diff --git a/security/landlock/ruleset.c b/security/landlock/ruleset.c
>>>>>> index a3fd58d01f09..5f13f8a12aee 100644
>>>>>> --- a/security/landlock/ruleset.c
>>>>>> +++ b/security/landlock/ruleset.c
>>>>>> @@ -35,7 +35,7 @@ static struct landlock_ruleset 
>>>>>> *create_ruleset(const u32 num_layers)
>>>>>>           return ERR_PTR(-ENOMEM);
>>>>>>       refcount_set(&new_ruleset->usage, 1);
>>>>>>       mutex_init(&new_ruleset->lock);
>>>>>> -    new_ruleset->root = RB_ROOT;
>>>>>> +    new_ruleset->root_inode = RB_ROOT;
>>>>>>       new_ruleset->num_layers = num_layers;
>>>>>>       /*
>>>>>>        * hierarchy = NULL
>>>>>> @@ -69,7 +69,8 @@ static void build_check_rule(void)
>>>>>>   }
>>>>>>
>>>>>>   static struct landlock_rule *
>>>>>> -create_rule(struct landlock_object *const object,
>>>>>> +create_rule(struct landlock_object *const object_ptr,
>>>>>> +        const uintptr_t object_data,
>>>>>>           const struct landlock_layer (*const layers)[], const u32 
>>>>>> num_layers,
>>>>>>           const struct landlock_layer *const new_layer)
>>>>>>   {
>>>>>> @@ -90,8 +91,15 @@ create_rule(struct landlock_object *const object,
>>>>>>       if (!new_rule)
>>>>>>           return ERR_PTR(-ENOMEM);
>>>>>>       RB_CLEAR_NODE(&new_rule->node);
>>>>>> -    landlock_get_object(object);
>>>>>> -    new_rule->object = object;
>>>>>> +
>>>>>> +    if (object_ptr) {
>>>>>> +        landlock_get_object(object_ptr);
>>>>>> +        new_rule->object.ptr = object_ptr;
>>>>>> +    } else if (object_ptr && object_data) {
>>>>>
>>>>> Something is wrong with this second check: else + object_ptr?
>>>>
>>>> It was your suggestion to use it like this:
>>>> " ....You can also add a WARN_ON_ONCE(object_ptr && object_data)."
>>>>
>>>> Please check it here:
>>>> https://lore.kernel.org/linux-security-module/bc44f11f-0eaa-a5f6-c5dc-1d36570f1be1@digikod.net/ 
>>>
>>>
>>> Yes, but the error is in the "else", you should write:
>>> if (WARN_ON_ONCE(object_ptr && object_data))
>>>     return ERR_PTR(-EINVAL);
>>>
>>> …and this should be before the `if (object_ptr) {` line (to avoid
>>> erronous landlock_get_object() call), just after the `if (!new_rule)` 
>>> check.

     Ok. I got it.
>> 
>>    Maybe we could delete this check here cause we have it in the upper 
>> insert_rule() function??
>> 
>> ...
>>      if (WARN_ON_ONCE(!layers))
>>          return -ENOENT;
>> ------>    if (WARN_ON_ONCE(object_ptr && object_data))
>>          return -EINVAL;
>>      /* Chooses rb_tree structure depending on a rule type. */
>>      switch (rule_type) {
>>      case LANDLOCK_RULE_PATH_BENEATH:
>>          if (WARN_ON_ONCE(!object_ptr))
>>              return -ENOENT;
>>          object_data = (uintptr_t)object_ptr;
>>          root = &ruleset->root_inode;
>>          break;
>>      default:
>>          WARN_ON_ONCE(1);
>>          return -EINVAL;
>>      }
>> ...
>> 
>> This is double check here. What do you think?
> 
> This check is indeed done twice, and for now create_rule() is only
> called from insert_rule(), but I prefer to keep it in both location to
> not get bitten in the future were it could be called from other
> locations. The compiler may be smart enough to remove the redundant
> checks though.
> 
> I'll send a patch to improve this part.

  Ok. thanks!!!
> .

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 02/17] landlock: refactors landlock_find/insert_rule
  2022-07-08 14:35           ` Mickaël Salaün
@ 2022-07-11 14:05             ` Konstantin Meskhidze (A)
  2022-07-28 14:48               ` Mickaël Salaün
  0 siblings, 1 reply; 53+ messages in thread
From: Konstantin Meskhidze (A) @ 2022-07-11 14:05 UTC (permalink / raw)
  To: Mickaël Salaün
  Cc: willemdebruijn.kernel, linux-security-module, netdev,
	netfilter-devel, yusongping, anton.sirazetdinov



7/8/2022 5:35 PM, Mickaël Salaün пишет:
> 
> On 08/07/2022 16:14, Konstantin Meskhidze (A) wrote:
>> 
>> 
>> 7/8/2022 4:59 PM, Mickaël Salaün пишет:
>>>
>>> On 08/07/2022 15:10, Konstantin Meskhidze (A) wrote:
>>>>
>>>>
>>>> 7/7/2022 7:44 PM, Mickaël Salaün пишет:
>>>>>
>>>>> On 21/06/2022 10:22, Konstantin Meskhidze wrote:
>>>>>> Adds a new object union to support a socket port
>>>>>> rule type. Refactors landlock_insert_rule() and
>>>>>> landlock_find_rule() to support coming network
>>>>>> modifications. Now adding or searching a rule
>>>>>> in a ruleset depends on a rule_type argument
>>>>>> provided in refactored functions mentioned above.
>>>>>>
>>>>>> Signed-off-by: Konstantin Meskhidze <konstantin.meskhidze@huawei.com>
>>>>>> ---
>>>>>>
>>>>>> Changes since v5:
>>>>>> * Formats code with clang-format-14.
>>>>>>
>>>>>> Changes since v4:
>>>>>> * Refactors insert_rule() and create_rule() functions by deleting
>>>>>> rule_type from their arguments list, it helps to reduce useless code.
>>>>>>
>>>>>> Changes since v3:
>>>>>> * Splits commit.
>>>>>> * Refactors landlock_insert_rule and landlock_find_rule functions.
>>>>>> * Rename new_ruleset->root_inode.
>>>>>>
>>>>>> ---
>>>>>>   security/landlock/fs.c      |   7 ++-
>>>>>>   security/landlock/ruleset.c | 105 
>>>>>> ++++++++++++++++++++++++++----------
>>>>>>   security/landlock/ruleset.h |  27 +++++-----
>>>>>>   3 files changed, 96 insertions(+), 43 deletions(-)
>>>>>>
>>>>>> diff --git a/security/landlock/fs.c b/security/landlock/fs.c
>>>>>> index e6da08ed99d1..46aedc2a05a8 100644
>>>>>> --- a/security/landlock/fs.c
>>>>>> +++ b/security/landlock/fs.c
>>>>>> @@ -173,7 +173,8 @@ int landlock_append_fs_rule(struct 
>>>>>> landlock_ruleset *const ruleset,
>>>>>>       if (IS_ERR(object))
>>>>>>           return PTR_ERR(object);
>>>>>>       mutex_lock(&ruleset->lock);
>>>>>> -    err = landlock_insert_rule(ruleset, object, access_rights);
>>>>>> +    err = landlock_insert_rule(ruleset, object, 0, access_rights,
>>>>>> +                   LANDLOCK_RULE_PATH_BENEATH);
>>>>>>       mutex_unlock(&ruleset->lock);
>>>>>>       /*
>>>>>>        * No need to check for an error because landlock_insert_rule()
>>>>>> @@ -204,7 +205,9 @@ find_rule(const struct landlock_ruleset *const 
>>>>>> domain,
>>>>>>       inode = d_backing_inode(dentry);
>>>>>>       rcu_read_lock();
>>>>>>       rule = landlock_find_rule(
>>>>>> -        domain, rcu_dereference(landlock_inode(inode)->object));
>>>>>> +        domain,
>>>>>> +        (uintptr_t)rcu_dereference(landlock_inode(inode)->object),
>>>>>> +        LANDLOCK_RULE_PATH_BENEATH);
>>>>>>       rcu_read_unlock();
>>>>>>       return rule;
>>>>>>   }
>>>>>> diff --git a/security/landlock/ruleset.c b/security/landlock/ruleset.c
>>>>>> index a3fd58d01f09..5f13f8a12aee 100644
>>>>>> --- a/security/landlock/ruleset.c
>>>>>> +++ b/security/landlock/ruleset.c
>>>>>> @@ -35,7 +35,7 @@ static struct landlock_ruleset 
>>>>>> *create_ruleset(const u32 num_layers)
>>>>>>           return ERR_PTR(-ENOMEM);
>>>>>>       refcount_set(&new_ruleset->usage, 1);
>>>>>>       mutex_init(&new_ruleset->lock);
>>>>>> -    new_ruleset->root = RB_ROOT;
>>>>>> +    new_ruleset->root_inode = RB_ROOT;
>>>>>>       new_ruleset->num_layers = num_layers;
>>>>>>       /*
>>>>>>        * hierarchy = NULL
>>>>>> @@ -69,7 +69,8 @@ static void build_check_rule(void)
>>>>>>   }
>>>>>>
>>>>>>   static struct landlock_rule *
>>>>>> -create_rule(struct landlock_object *const object,
>>>>>> +create_rule(struct landlock_object *const object_ptr,
>>>>>> +        const uintptr_t object_data,
>>>>>>           const struct landlock_layer (*const layers)[], const u32 
>>>>>> num_layers,
>>>>>>           const struct landlock_layer *const new_layer)
>>>>>>   {
>>>>>> @@ -90,8 +91,15 @@ create_rule(struct landlock_object *const object,
>>>>>>       if (!new_rule)
>>>>>>           return ERR_PTR(-ENOMEM);
>>>>>>       RB_CLEAR_NODE(&new_rule->node);
>>>>>> -    landlock_get_object(object);
>>>>>> -    new_rule->object = object;
>>>>>> +
>>>>>> +    if (object_ptr) {
>>>>>> +        landlock_get_object(object_ptr);
>>>>>> +        new_rule->object.ptr = object_ptr;
>>>>>> +    } else if (object_ptr && object_data) {
>>>>>
>>>>> Something is wrong with this second check: else + object_ptr?
>>>>
>>>>   Sorry. Do you mean logical error here? I got your point.
>>>>   You are right!
>>>>
>>>>   I think it must be refactored like this:
>>>>
>>>>      if (object_ptr && !object_data) {
>>>>          landlock_get_object(object_ptr);
>>>>          new_rule->object.ptr = object_ptr;
>>>>      } else if (object_ptr && object_data) {
>>>>          ...
>>>>      }
>>>
>>> There is indeed a logical error but this doesn't fix everything. Please
>>> include my previous suggestion instead.
>>>
>>     By the way, in the next commits I have fixed this logic error.
>> Anyway I will refactor this one also. Thanks.
>>>
>>>> Plus, I will add a test for this case.
>>>
>>> That would be great but I don't think this code is reachable from user
>>> space. I think that would require kunit but I may be missing something.
>>> How would you test this?
>> 
>> You are correct. I checked it. It's impossible to reach this line from 
>> userpace (insert both object_ptr and object_data). But create_rule() 
>> must be used carefuly by other developers (if any in future). Do you 
>> think if its possible to have some internal kernel tests that could 
>> handle this issue?
> 
> We can use kunit tests for such kernel functions, but in this case I'm
> not sure what could be tested. I started working on bringing kunit tests
> to Landlock but it's not ready yet. Please list all non-userspace tests
> you can think about.

  I'm thinking about ones that we can't reach from the userspace.
  I analyzed test coverage logs finding lines that are untouched by the 
userspace tests.
  Let's discus this list:

	1. create_rule():  - insert both  object_ptr and object_data.

	2. insert_rule():  - insert both  object_ptr and object_data.
			   - insert NULL (*const layers).
			   - insert layers[0].level != 0.
			   - insert num_layers != 1.
			   - insert default rule_type.
	
	3. tree_merge():   - insert default rule_type.
			   - insert walker_rule->num_layers != 1.
			   - insert walker_rule->layers[0].level != 0.
	
	4. tree_copy():    - insert default rule_type.
	
	5. merge_ruleset:  - insert !dst || !dst->hierarchy.
			   - insert src->num_layers != 1 ||
                                     dst->num_layers < 1.

	6. inherit_ruleset(): - insert child->num_layers <=
				   parent->num_layers.
  			      - insert parent->hierarchy = NULL.

	7. landlock_merge_ruleset(): - insert ruleset = NULL.
				     - insert parent = ruleset

	8. landlock_find_rule(): - insert default rule_type.

  Please your opinion?
> .

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 00/17] Network support for Landlock
  2022-06-21  8:22 [PATCH v6 00/17] Network support for Landlock Konstantin Meskhidze
                   ` (16 preceding siblings ...)
  2022-06-21  8:23 ` [PATCH v6 17/17] samples/landlock: adds network demo Konstantin Meskhidze
@ 2022-07-26 17:43 ` Mickaël Salaün
  2022-07-27 19:54   ` Mickaël Salaün
  2022-07-27 20:21   ` Mickaël Salaün
  17 siblings, 2 replies; 53+ messages in thread
From: Mickaël Salaün @ 2022-07-26 17:43 UTC (permalink / raw)
  To: Konstantin Meskhidze
  Cc: willemdebruijn.kernel, linux-security-module, netdev,
	netfilter-devel, yusongping, anton.sirazetdinov


On 21/06/2022 10:22, Konstantin Meskhidze wrote:
> Hi,
> This is a new V6 patch related to Landlock LSM network confinement.
> It is based on the latest landlock-wip branch on top of v5.19-rc2:
> https://git.kernel.org/pub/scm/linux/kernel/git/mic/linux.git/log/?h=landlock-wip
> 
> It brings refactoring of previous patch version V5:
>      - Fixes some logic errors and typos.
>      - Adds additional FIXTURE_VARIANT and FIXTURE_VARIANT_ADD helpers
>      to support both ip4 and ip6 families and shorten seltests' code.
>      - Makes TCP sockets confinement support optional in sandboxer demo.
>      - Formats the code with clang-format-14
> 
> All test were run in QEMU evironment and compiled with
>   -static flag.
>   1. network_test: 18/18 tests passed.
>   2. base_test: 7/7 tests passed.
>   3. fs_test: 59/59 tests passed.
>   4. ptrace_test: 8/8 tests passed.
> 
> Still have issue with base_test were compiled without -static flag
> (landlock-wip branch without network support)
> 1. base_test: 6/7 tests passed.
>   Error:
>   #  RUN           global.inconsistent_attr ...
>   # base_test.c:54:inconsistent_attr:Expected ENOMSG (42) == errno (22)
>   # inconsistent_attr: Test terminated by assertion
>   #          FAIL  global.inconsistent_attr
> not ok 1 global.inconsistent_attr
> 
> LCOV - code coverage report:
>              Hit  Total  Coverage
> Lines:      952  1010    94.3 %
> Functions:  79   82      96.3 %
> 
> Previous versions:
> v5: https://lore.kernel.org/linux-security-module/20220516152038.39594-1-konstantin.meskhidze@huawei.com
> v4: https://lore.kernel.org/linux-security-module/20220309134459.6448-1-konstantin.meskhidze@huawei.com/
> v3: https://lore.kernel.org/linux-security-module/20220124080215.265538-1-konstantin.meskhidze@huawei.com/
> v2: https://lore.kernel.org/linux-security-module/20211228115212.703084-1-konstantin.meskhidze@huawei.com/
> v1: https://lore.kernel.org/linux-security-module/20211210072123.386713-1-konstantin.meskhidze@huawei.com/
> 
> Konstantin Meskhidze (17):
>    landlock: renames access mask
>    landlock: refactors landlock_find/insert_rule
>    landlock: refactors merge and inherit functions
>    landlock: moves helper functions
>    landlock: refactors helper functions
>    landlock: refactors landlock_add_rule syscall
>    landlock: user space API network support
>    landlock: adds support network rules
>    landlock: implements TCP network hooks
>    seltests/landlock: moves helper function
>    seltests/landlock: adds tests for bind() hooks
>    seltests/landlock: adds tests for connect() hooks
>    seltests/landlock: adds AF_UNSPEC family test
>    seltests/landlock: adds rules overlapping test
>    seltests/landlock: adds ruleset expanding test
>    seltests/landlock: adds invalid input data test
>    samples/landlock: adds network demo
> 
>   include/uapi/linux/landlock.h               |  49 ++
>   samples/landlock/sandboxer.c                | 118 ++-
>   security/landlock/Kconfig                   |   1 +
>   security/landlock/Makefile                  |   2 +
>   security/landlock/fs.c                      | 162 +---
>   security/landlock/limits.h                  |   8 +-
>   security/landlock/net.c                     | 155 ++++
>   security/landlock/net.h                     |  26 +
>   security/landlock/ruleset.c                 | 448 +++++++++--
>   security/landlock/ruleset.h                 |  91 ++-
>   security/landlock/setup.c                   |   2 +
>   security/landlock/syscalls.c                | 168 +++--
>   tools/testing/selftests/landlock/common.h   |  10 +
>   tools/testing/selftests/landlock/config     |   4 +
>   tools/testing/selftests/landlock/fs_test.c  |  10 -
>   tools/testing/selftests/landlock/net_test.c | 774 ++++++++++++++++++++
>   16 files changed, 1737 insertions(+), 291 deletions(-)
>   create mode 100644 security/landlock/net.c
>   create mode 100644 security/landlock/net.h
>   create mode 100644 tools/testing/selftests/landlock/net_test.c
> 
> --
> 2.25.1
> 

I did a thorough review of all the code. I found that the main issue 
with this version is that we stick to the layers limit whereas it is 
only relevant for filesystem hierarchies. You'll find in the following 
patch miscellaneous fixes and improvement, with some TODOs to get rid of 
this layer limit. We'll need a test to check that too. You'll need to 
integrate this diff into your patches though.


* Add union landlock_key, enum landlock_key_type, and struct
   landlock_id.  Refactor ruleset functions with them and improve
   switch/cases: create_rule(), get_root(), free_rule(),
   landlock_find_rule() and init_layer_masks().  This avoids key
   object/pointer and data inconsistencies and enables to safely remove
   the related checks in create_rule().
* Remove masks_size attribute from init_layer_masks().
* Rename landlock_rule.object to landlock_rule.key
* Rename tree_merge to merge_tree (and reorder arguments), and tree_copy
   to inherit_tree.  This is more consistent with their caller:
   merge_ruleset and inherit_ruleset.
* Fix landlock_set_fs_access_mask() and constify similar helpers'
   arguments.
* Fix add_rule_path_beneath() and add_rule_net_service() rule_attr
   argument type.
* Update copyright.
* Add TODOs to implement unlimited layers of network policies and
   simplify the code.
---
  security/landlock/fs.c       |  39 ++--
  security/landlock/limits.h   |   2 +
  security/landlock/net.c      |  22 ++-
  security/landlock/net.h      |   2 +-
  security/landlock/ruleset.c  | 358 ++++++++++++++++-------------------
  security/landlock/ruleset.h  |  60 ++++--
  security/landlock/syscalls.c |   4 +-
  7 files changed, 242 insertions(+), 245 deletions(-)

diff --git a/security/landlock/fs.c b/security/landlock/fs.c
index 10f6c67f5c3b..7198bb8a7dac 100644
--- a/security/landlock/fs.c
+++ b/security/landlock/fs.c
@@ -157,7 +157,9 @@ int landlock_append_fs_rule(struct landlock_ruleset 
*const ruleset,
  			    access_mask_t access_rights)
  {
  	int err;
-	struct landlock_object *object;
+	struct landlock_id id = {
+		.type = LANDLOCK_KEY_INODE,
+	};

  	/* Files only get access rights that make sense. */
  	if (!d_is_dir(path->dentry) &&
@@ -169,18 +171,17 @@ int landlock_append_fs_rule(struct 
landlock_ruleset *const ruleset,
  	/* Transforms relative access rights to absolute ones. */
  	access_rights |= LANDLOCK_MASK_ACCESS_FS &
  			 ~landlock_get_fs_access_mask(ruleset, 0);
-	object = get_inode_object(d_backing_inode(path->dentry));
-	if (IS_ERR(object))
-		return PTR_ERR(object);
+	id.key.object = get_inode_object(d_backing_inode(path->dentry));
+	if (IS_ERR(id.key.object))
+		return PTR_ERR(id.key.object);
  	mutex_lock(&ruleset->lock);
-	err = landlock_insert_rule(ruleset, object, 0, access_rights,
-				   LANDLOCK_RULE_PATH_BENEATH);
+	err = landlock_insert_rule(ruleset, id, access_rights);
  	mutex_unlock(&ruleset->lock);
  	/*
  	 * No need to check for an error because landlock_insert_rule()
  	 * increments the refcount for the new object if needed.
  	 */
-	landlock_put_object(object);
+	landlock_put_object(id.key.object);
  	return err;
  }

@@ -197,6 +198,9 @@ find_rule(const struct landlock_ruleset *const domain,
  {
  	const struct landlock_rule *rule;
  	const struct inode *inode;
+	struct landlock_id id = {
+		.type = LANDLOCK_KEY_INODE,
+	};

  	/* Ignores nonexistent leafs. */
  	if (d_is_negative(dentry))
@@ -204,10 +208,8 @@ find_rule(const struct landlock_ruleset *const domain,

  	inode = d_backing_inode(dentry);
  	rcu_read_lock();
-	rule = landlock_find_rule(
-		domain,
-		(uintptr_t)rcu_dereference(landlock_inode(inode)->object),
-		LANDLOCK_RULE_PATH_BENEATH);
+	id.key.object = rcu_dereference(landlock_inode(inode)->object);
+	rule = landlock_find_rule(domain, id);
  	rcu_read_unlock();
  	return rule;
  }
@@ -416,8 +418,7 @@ static int check_access_path_dual(
  		unmask_layers(find_rule(domain, dentry_child1),
  			      init_layer_masks(domain, LANDLOCK_MASK_ACCESS_FS,
  					       &_layer_masks_child1,
-					       sizeof(_layer_masks_child1),
-					       LANDLOCK_RULE_PATH_BENEATH),
+					       LANDLOCK_KEY_INODE),
  			      &_layer_masks_child1,
  			      ARRAY_SIZE(_layer_masks_child1));
  		layer_masks_child1 = &_layer_masks_child1;
@@ -427,8 +428,7 @@ static int check_access_path_dual(
  		unmask_layers(find_rule(domain, dentry_child2),
  			      init_layer_masks(domain, LANDLOCK_MASK_ACCESS_FS,
  					       &_layer_masks_child2,
-					       sizeof(_layer_masks_child2),
-					       LANDLOCK_RULE_PATH_BENEATH),
+					       LANDLOCK_KEY_INODE),
  			      &_layer_masks_child2,
  			      ARRAY_SIZE(_layer_masks_child2));
  		layer_masks_child2 = &_layer_masks_child2;
@@ -548,8 +548,7 @@ static inline int check_access_path(const struct 
landlock_ruleset *const domain,
  	layer_mask_t layer_masks[LANDLOCK_NUM_ACCESS_FS] = {};

  	access_request = init_layer_masks(domain, access_request, &layer_masks,
-					  sizeof(layer_masks),
-					  LANDLOCK_RULE_PATH_BENEATH);
+					  LANDLOCK_KEY_INODE);
  	return check_access_path_dual(domain, path, access_request,
  				      &layer_masks, NULL, 0, NULL, NULL);
  }
@@ -633,8 +632,7 @@ static bool collect_domain_accesses(
  		return true;

  	access_dom = init_layer_masks(domain, LANDLOCK_MASK_ACCESS_FS,
-				      layer_masks_dom, sizeof(*layer_masks_dom),
-				      LANDLOCK_RULE_PATH_BENEATH);
+				      layer_masks_dom, LANDLOCK_KEY_INODE);

  	dget(dir);
  	while (true) {
@@ -759,8 +757,7 @@ static int current_check_refer_path(struct dentry 
*const old_dentry,
  		 */
  		access_request_parent1 = init_layer_masks(
  			dom, access_request_parent1 | access_request_parent2,
-			&layer_masks_parent1, sizeof(layer_masks_parent1),
-			LANDLOCK_RULE_PATH_BENEATH);
+			&layer_masks_parent1, LANDLOCK_KEY_INODE);
  		return check_access_path_dual(dom, new_dir,
  					      access_request_parent1,
  					      &layer_masks_parent1, NULL, 0,
diff --git a/security/landlock/limits.h b/security/landlock/limits.h
index 23694bf05cb7..660335258466 100644
--- a/security/landlock/limits.h
+++ b/security/landlock/limits.h
@@ -25,6 +25,8 @@
  #define LANDLOCK_LAST_ACCESS_NET	LANDLOCK_ACCESS_NET_CONNECT_TCP
  #define LANDLOCK_MASK_ACCESS_NET	((LANDLOCK_LAST_ACCESS_NET << 1) - 1)
  #define LANDLOCK_NUM_ACCESS_NET	 
__const_hweight64(LANDLOCK_MASK_ACCESS_NET)
+// TODO: LANDLOCK_MASK_SHIFT_NET will not be useful with the new
+// ruleset->net_access_mask
  #define LANDLOCK_MASK_SHIFT_NET		16

  #define LANDLOCK_RULE_TYPE_NUM		LANDLOCK_RULE_NET_SERVICE
diff --git a/security/landlock/net.c b/security/landlock/net.c
index da63e4f1dca4..0d249ad619bf 100644
--- a/security/landlock/net.c
+++ b/security/landlock/net.c
@@ -2,7 +2,8 @@
  /*
   * Landlock LSM - Network management and hooks
   *
- * Copyright (C) 2022 Huawei Tech. Co., Ltd.
+ * Copyright © 2022 Huawei Tech. Co., Ltd.
+ * Copyright © 2022 Microsoft Corporation
   */

  #include <linux/in.h>
@@ -18,15 +19,18 @@ int landlock_append_net_rule(struct landlock_ruleset 
*const ruleset, u16 port,
  			     u32 access_rights)
  {
  	int err;
+	const struct landlock_id id = {
+		.key.data = port,
+		.type = LANDLOCK_KEY_NET_PORT,
+	};
+	BUILD_BUG_ON(sizeof(port) > sizeof(id.key.data));

  	/* Transforms relative access rights to absolute ones. */
  	access_rights |= LANDLOCK_MASK_ACCESS_NET &
  			 ~landlock_get_net_access_mask(ruleset, 0);

-	BUILD_BUG_ON(sizeof(port) > sizeof(uintptr_t));
  	mutex_lock(&ruleset->lock);
-	err = landlock_insert_rule(ruleset, NULL, port, access_rights,
-				   LANDLOCK_RULE_NET_SERVICE);
+	err = landlock_insert_rule(ruleset, id, access_rights);
  	mutex_unlock(&ruleset->lock);

  	return err;
@@ -39,17 +43,19 @@ static int check_socket_access(const struct 
landlock_ruleset *const domain,
  	layer_mask_t layer_masks[LANDLOCK_NUM_ACCESS_NET] = {};
  	const struct landlock_rule *rule;
  	access_mask_t handled_access;
+	const struct landlock_id id = {
+		.key.data = port,
+		.type = LANDLOCK_KEY_NET_PORT,
+	};

  	if (WARN_ON_ONCE(!domain))
  		return 0;
  	if (WARN_ON_ONCE(domain->num_layers < 1))
  		return -EACCES;

-	rule = landlock_find_rule(domain, port, LANDLOCK_RULE_NET_SERVICE);
-
+	rule = landlock_find_rule(domain, id);
  	handled_access = init_layer_masks(domain, access_request, &layer_masks,
-					  sizeof(layer_masks),
-					  LANDLOCK_RULE_NET_SERVICE);
+					  LANDLOCK_KEY_NET_PORT);
  	allowed = unmask_layers(rule, handled_access, &layer_masks,
  				ARRAY_SIZE(layer_masks));

diff --git a/security/landlock/net.h b/security/landlock/net.h
index 7a79fb4bf3dd..2c63a8f1b258 100644
--- a/security/landlock/net.h
+++ b/security/landlock/net.h
@@ -2,7 +2,7 @@
  /*
   * Landlock LSM - Network management and hooks
   *
- * Copyright (C) 2022 Huawei Tech. Co., Ltd.
+ * Copyright © 2022 Huawei Tech. Co., Ltd.
   */

  #ifndef _SECURITY_LANDLOCK_NET_H
diff --git a/security/landlock/ruleset.c b/security/landlock/ruleset.c
index 469811a77675..e7555b16069a 100644
--- a/security/landlock/ruleset.c
+++ b/security/landlock/ruleset.c
@@ -74,9 +74,20 @@ static void build_check_rule(void)
  	BUILD_BUG_ON(rule.num_layers < LANDLOCK_MAX_NUM_LAYERS);
  }

+static inline bool is_object_pointer(const enum landlock_key_type key_type)
+{
+	switch (key_type) {
+	case LANDLOCK_KEY_INODE:
+		return true;
+	case LANDLOCK_KEY_NET_PORT:
+		return false;
+	}
+	WARN_ON_ONCE(1);
+	return false;
+}
+
  static struct landlock_rule *
-create_rule(struct landlock_object *const object_ptr,
-	    const uintptr_t object_data,
+create_rule(const struct landlock_id id,
  	    const struct landlock_layer (*const layers)[], const u32 num_layers,
  	    const struct landlock_layer *const new_layer)
  {
@@ -97,17 +108,13 @@ create_rule(struct landlock_object *const object_ptr,
  	if (!new_rule)
  		return ERR_PTR(-ENOMEM);
  	RB_CLEAR_NODE(&new_rule->node);
-
-	if (object_ptr && !object_data) {
-		landlock_get_object(object_ptr);
-		new_rule->object.ptr = object_ptr;
-	} else if (object_data && !object_ptr) {
-		new_rule->object.data = object_data;
-	} else if (object_ptr && object_data) {
-		WARN_ON_ONCE(1);
-		return ERR_PTR(-EINVAL);
+	if (is_object_pointer(id.type)) {
+		/* This should be catched by insert_rule(). */
+		WARN_ON_ONCE(!id.key.object);
+		landlock_get_object(id.key.object);
  	}

+	new_rule->key = id.key;
  	new_rule->num_layers = new_num_layers;
  	/* Copies the original layer stack. */
  	memcpy(new_rule->layers, layers,
@@ -118,16 +125,32 @@ create_rule(struct landlock_object *const object_ptr,
  	return new_rule;
  }

-static void free_rule(struct landlock_rule *const rule, const u16 
rule_type)
+static inline struct rb_root *get_root(struct landlock_ruleset *const 
ruleset,
+				       const enum landlock_key_type key_type)
+{
+	struct rb_root *root = NULL;
+
+	switch (key_type) {
+	case LANDLOCK_KEY_INODE:
+		root = &ruleset->root_inode;
+		break;
+	case LANDLOCK_KEY_NET_PORT:
+		root = &ruleset->root_net_port;
+		break;
+	}
+	if (WARN_ON_ONCE(!root))
+		return ERR_PTR(-EINVAL);
+	return root;
+}
+
+static void free_rule(struct landlock_rule *const rule,
+		      const enum landlock_key_type key_type)
  {
  	might_sleep();
  	if (!rule)
  		return;
-	switch (rule_type) {
-	case LANDLOCK_RULE_PATH_BENEATH:
-		landlock_put_object(rule->object.ptr);
-		break;
-	}
+	if (is_object_pointer(key_type))
+		landlock_put_object(rule->key.object);
  	kfree(rule);
  }

@@ -150,8 +173,8 @@ static void build_check_ruleset(void)
   * insert_rule - Create and insert a rule in a ruleset
   *
   * @ruleset: The ruleset to be updated.
- * @object: The object to build the new rule with.  The underlying kernel
- *          object must be held by the caller.
+ * @id: The ID to build the new rule with.  The underlying kernel 
object, if
+ *      any, must be held by the caller.
   * @layers: One or multiple layers to be copied into the new rule.
   * @num_layers: The number of @layers entries.
   *
@@ -165,10 +188,9 @@ static void build_check_ruleset(void)
   * access rights.
   */
  static int insert_rule(struct landlock_ruleset *const ruleset,
-		       struct landlock_object *const object_ptr,
-		       uintptr_t object_data, u16 rule_type,
+		       const struct landlock_id id,
  		       const struct landlock_layer (*const layers)[],
-		       size_t num_layers)
+		       const size_t num_layers)
  {
  	struct rb_node **walker_node;
  	struct rb_node *parent_node = NULL;
@@ -179,33 +201,24 @@ static int insert_rule(struct landlock_ruleset 
*const ruleset,
  	lockdep_assert_held(&ruleset->lock);
  	if (WARN_ON_ONCE(!layers))
  		return -ENOENT;
-	if (WARN_ON_ONCE(object_ptr && object_data))
-		return -EINVAL;
-	/* Chooses rb_tree structure depending on a rule type. */
-	switch (rule_type) {
-	case LANDLOCK_RULE_PATH_BENEATH:
-		if (WARN_ON_ONCE(!object_ptr))
+
+	if (is_object_pointer(id.type)) {
+		if (WARN_ON_ONCE(!id.key.object))
  			return -ENOENT;
-		object_data = (uintptr_t)object_ptr;
-		root = &ruleset->root_inode;
-		break;
-	case LANDLOCK_RULE_NET_SERVICE:
-		if (WARN_ON_ONCE(object_ptr))
-			return -EINVAL;
-		root = &ruleset->root_net_port;
-		break;
-	default:
-		WARN_ON_ONCE(1);
-		return -EINVAL;
  	}
+
+	root = get_root(ruleset, id.type);
+	if (IS_ERR(root))
+		return PTR_ERR(root);
+
  	walker_node = &root->rb_node;
  	while (*walker_node) {
  		struct landlock_rule *const this =
  			rb_entry(*walker_node, struct landlock_rule, node);

-		if (this->object.data != object_data) {
+		if (this->key.data != id.key.data) {
  			parent_node = *walker_node;
-			if (this->object.data < object_data)
+			if (this->key.data < id.key.data)
  				walker_node = &((*walker_node)->rb_right);
  			else
  				walker_node = &((*walker_node)->rb_left);
@@ -237,52 +250,27 @@ static int insert_rule(struct landlock_ruleset 
*const ruleset,
  		 * Intersects access rights when it is a merge between a
  		 * ruleset and a domain.
  		 */
-		switch (rule_type) {
-		case LANDLOCK_RULE_PATH_BENEATH:
-			new_rule = create_rule(object_ptr, 0, &this->layers,
-					       this->num_layers, &(*layers)[0]);
-			if (IS_ERR(new_rule))
-				return PTR_ERR(new_rule);
-			rb_replace_node(&this->node, &new_rule->node,
-					&ruleset->root_inode);
-			free_rule(this, rule_type);
-			break;
-		case LANDLOCK_RULE_NET_SERVICE:
-			new_rule = create_rule(NULL, object_data, &this->layers,
-					       this->num_layers, &(*layers)[0]);
-			if (IS_ERR(new_rule))
-				return PTR_ERR(new_rule);
-			rb_replace_node(&this->node, &new_rule->node,
-					&ruleset->root_net_port);
-			free_rule(this, rule_type);
-			break;
-		}
+		// TODO: Don't create a new rule but AND accesses (of the first
+		// and only layer) if !is_object_pointer(id.type)
+		new_rule = create_rule(id, &this->layers, this->num_layers,
+				       &(*layers)[0]);
+		if (IS_ERR(new_rule))
+			return PTR_ERR(new_rule);
+		rb_replace_node(&this->node, &new_rule->node, root);
+		free_rule(this, id.type);
  		return 0;
  	}

-	/* There is no match for @object. */
+	/* There is no match for @id. */
  	build_check_ruleset();
  	if (ruleset->num_rules >= LANDLOCK_MAX_NUM_RULES)
  		return -E2BIG;
-	switch (rule_type) {
-	case LANDLOCK_RULE_PATH_BENEATH:
-		new_rule = create_rule(object_ptr, 0, layers, num_layers, NULL);
-		if (IS_ERR(new_rule))
-			return PTR_ERR(new_rule);
-		rb_link_node(&new_rule->node, parent_node, walker_node);
-		rb_insert_color(&new_rule->node, &ruleset->root_inode);
-		ruleset->num_rules++;
-		break;
-	case LANDLOCK_RULE_NET_SERVICE:
-		new_rule = create_rule(NULL, object_data, layers, num_layers,
-				       NULL);
-		if (IS_ERR(new_rule))
-			return PTR_ERR(new_rule);
-		rb_link_node(&new_rule->node, parent_node, walker_node);
-		rb_insert_color(&new_rule->node, &ruleset->root_net_port);
-		ruleset->num_rules++;
-		break;
-	}
+	new_rule = create_rule(id, layers, num_layers, NULL);
+	if (IS_ERR(new_rule))
+		return PTR_ERR(new_rule);
+	rb_link_node(&new_rule->node, parent_node, walker_node);
+	rb_insert_color(&new_rule->node, root);
+	ruleset->num_rules++;
  	return 0;
  }

@@ -299,9 +287,8 @@ static void build_check_layer(void)

  /* @ruleset must be locked by the caller. */
  int landlock_insert_rule(struct landlock_ruleset *const ruleset,
-			 struct landlock_object *const object_ptr,
-			 const uintptr_t object_data,
-			 const access_mask_t access, const u16 rule_type)
+			 const struct landlock_id id,
+			 const access_mask_t access)
  {
  	struct landlock_layer layers[] = { {
  		.access = access,
@@ -310,8 +297,7 @@ int landlock_insert_rule(struct landlock_ruleset 
*const ruleset,
  	} };

  	build_check_layer();
-	return insert_rule(ruleset, object_ptr, object_data, rule_type, &layers,
-			   ARRAY_SIZE(layers));
+	return insert_rule(ruleset, id, &layers, ARRAY_SIZE(layers));
  }

  static inline void get_hierarchy(struct landlock_hierarchy *const 
hierarchy)
@@ -330,53 +316,37 @@ static void put_hierarchy(struct 
landlock_hierarchy *hierarchy)
  	}
  }

-static int tree_merge(struct landlock_ruleset *const src,
-		      struct landlock_ruleset *const dst, u16 rule_type)
+static int merge_tree(struct landlock_ruleset *const dst,
+		      struct landlock_ruleset *const src,
+		      const enum landlock_key_type key_type)
  {
  	struct landlock_rule *walker_rule, *next_rule;
  	struct rb_root *src_root;
  	int err = 0;

-	/* Chooses rb_tree structure depending on a rule type. */
-	switch (rule_type) {
-	case LANDLOCK_RULE_PATH_BENEATH:
-		src_root = &src->root_inode;
-		break;
-	case LANDLOCK_RULE_NET_SERVICE:
-		src_root = &src->root_net_port;
-		break;
-	default:
-		return -EINVAL;
-	}
+	src_root = get_root(src, key_type);
+	if (IS_ERR(src_root))
+		return PTR_ERR(src_root);
+
  	/* Merges the @src tree. */
  	rbtree_postorder_for_each_entry_safe(walker_rule, next_rule, src_root,
  					     node) {
  		struct landlock_layer layers[] = { {
+			// TODO: Set level to 1 if !is_object_pointer(key_type).
  			.level = dst->num_layers,
  		} };
+		const struct landlock_id id = {
+			.key = walker_rule->key,
+			.type = key_type,
+		};

-		if (WARN_ON_ONCE(walker_rule->num_layers != 1)) {
-			err = -EINVAL;
-			return err;
-		}
-		if (WARN_ON_ONCE(walker_rule->layers[0].level != 0)) {
-			err = -EINVAL;
-			return err;
-		}
+		if (WARN_ON_ONCE(walker_rule->num_layers != 1))
+			return -EINVAL;
+		if (WARN_ON_ONCE(walker_rule->layers[0].level != 0))
+			return -EINVAL;
  		layers[0].access = walker_rule->layers[0].access;

-		switch (rule_type) {
-		case LANDLOCK_RULE_PATH_BENEATH:
-			err = insert_rule(dst, walker_rule->object.ptr, 0,
-					  rule_type, &layers,
-					  ARRAY_SIZE(layers));
-			break;
-		case LANDLOCK_RULE_NET_SERVICE:
-			err = insert_rule(dst, NULL, walker_rule->object.data,
-					  rule_type, &layers,
-					  ARRAY_SIZE(layers));
-			break;
-		}
+		err = insert_rule(dst, id, &layers, ARRAY_SIZE(layers));
  		if (err)
  			return err;
  	}
@@ -408,11 +378,12 @@ static int merge_ruleset(struct landlock_ruleset 
*const dst,
  	dst->access_masks[dst->num_layers - 1] = src->access_masks[0];

  	/* Merges the @src inode tree. */
-	err = tree_merge(src, dst, LANDLOCK_RULE_PATH_BENEATH);
+	err = merge_tree(dst, src, LANDLOCK_KEY_INODE);
  	if (err)
  		goto out_unlock;
-	/* Merges the @src network tree. */
-	err = tree_merge(src, dst, LANDLOCK_RULE_NET_SERVICE);
+
+	/* Merges the @src network port tree. */
+	err = merge_tree(dst, src, LANDLOCK_KEY_NET_PORT);
  	if (err)
  		goto out_unlock;

@@ -422,39 +393,28 @@ static int merge_ruleset(struct landlock_ruleset 
*const dst,
  	return err;
  }

-static int tree_copy(struct landlock_ruleset *const parent,
-		     struct landlock_ruleset *const child, u16 rule_type)
+static int inherit_tree(struct landlock_ruleset *const parent,
+			struct landlock_ruleset *const child,
+			const enum landlock_key_type key_type)
  {
  	struct landlock_rule *walker_rule, *next_rule;
  	struct rb_root *parent_root;
  	int err = 0;

-	/* Chooses rb_tree structure depending on a rule type. */
-	switch (rule_type) {
-	case LANDLOCK_RULE_PATH_BENEATH:
-		parent_root = &parent->root_inode;
-		break;
-	case LANDLOCK_RULE_NET_SERVICE:
-		parent_root = &parent->root_net_port;
-		break;
-	default:
-		return -EINVAL;
-	}
+	parent_root = get_root(parent, key_type);
+	if (IS_ERR(parent_root))
+		return PTR_ERR(parent_root);
+
  	/* Copies the @parent inode or network tree. */
  	rbtree_postorder_for_each_entry_safe(walker_rule, next_rule,
  					     parent_root, node) {
-		switch (rule_type) {
-		case LANDLOCK_RULE_PATH_BENEATH:
-			err = insert_rule(child, walker_rule->object.ptr, 0,
-					  rule_type, &walker_rule->layers,
-					  walker_rule->num_layers);
-			break;
-		case LANDLOCK_RULE_NET_SERVICE:
-			err = insert_rule(child, NULL, walker_rule->object.data,
-					  rule_type, &walker_rule->layers,
-					  walker_rule->num_layers);
-			break;
-		}
+		const struct landlock_id id = {
+			.key = walker_rule->key,
+			.type = key_type,
+		};
+
+		err = insert_rule(child, id, &walker_rule->layers,
+				  walker_rule->num_layers);
  		if (err)
  			return err;
  	}
@@ -475,11 +435,12 @@ static int inherit_ruleset(struct landlock_ruleset 
*const parent,
  	mutex_lock_nested(&parent->lock, SINGLE_DEPTH_NESTING);

  	/* Copies the @parent inode tree. */
-	err = tree_copy(parent, child, LANDLOCK_RULE_PATH_BENEATH);
+	err = inherit_tree(parent, child, LANDLOCK_KEY_INODE);
  	if (err)
  		goto out_unlock;
-	/* Copies the @parent network tree. */
-	err = tree_copy(parent, child, LANDLOCK_RULE_NET_SERVICE);
+
+	/* Copies the @parent network port tree. */
+	err = inherit_tree(parent, child, LANDLOCK_KEY_NET_PORT);
  	if (err)
  		goto out_unlock;

@@ -514,10 +475,10 @@ static void free_ruleset(struct landlock_ruleset 
*const ruleset)
  	might_sleep();
  	rbtree_postorder_for_each_entry_safe(freeme, next, &ruleset->root_inode,
  					     node)
-		free_rule(freeme, LANDLOCK_RULE_PATH_BENEATH);
+		free_rule(freeme, LANDLOCK_KEY_INODE);
  	rbtree_postorder_for_each_entry_safe(freeme, next,
  					     &ruleset->root_net_port, node)
-		free_rule(freeme, LANDLOCK_RULE_NET_SERVICE);
+		free_rule(freeme, LANDLOCK_KEY_NET_PORT);
  	put_hierarchy(ruleset->hierarchy);
  	kfree(ruleset);
  }
@@ -570,6 +531,7 @@ landlock_merge_ruleset(struct landlock_ruleset 
*const parent,
  		if (parent->num_layers >= LANDLOCK_MAX_NUM_LAYERS)
  			return ERR_PTR(-E2BIG);
  		num_layers = parent->num_layers + 1;
+		// TODO: Don't increment num_layers if 
RB_EMPTY_ROOT(&ruleset->root_inode).
  	} else {
  		num_layers = 1;
  	}
@@ -608,29 +570,23 @@ landlock_merge_ruleset(struct landlock_ruleset 
*const parent,
   */
  const struct landlock_rule *
  landlock_find_rule(const struct landlock_ruleset *const ruleset,
-		   const uintptr_t object_data, const u16 rule_type)
+		   const struct landlock_id id)
  {
+	const struct rb_root *root;
  	const struct rb_node *node;

-	switch (rule_type) {
-	case LANDLOCK_RULE_PATH_BENEATH:
-		node = ruleset->root_inode.rb_node;
-		break;
-	case LANDLOCK_RULE_NET_SERVICE:
-		node = ruleset->root_net_port.rb_node;
-		break;
-	default:
-		WARN_ON_ONCE(1);
+	root = get_root((struct landlock_ruleset *)ruleset, id.type);
+	if (IS_ERR(root))
  		return NULL;
-	}
+	node = root->rb_node;

  	while (node) {
  		struct landlock_rule *this =
  			rb_entry(node, struct landlock_rule, node);

-		if (this->object.data == object_data)
+		if (this->key.data == id.key.data)
  			return this;
-		if (this->object.data < object_data)
+		if (this->key.data < id.key.data)
  			node = node->rb_right;
  		else
  			node = node->rb_left;
@@ -638,6 +594,8 @@ landlock_find_rule(const struct landlock_ruleset 
*const ruleset,
  	return NULL;
  }

+// XXX: If there is no use of this helper for net, then it should 
remains in fs.c
+// BTW, num_access is unused
  access_mask_t get_handled_accesses(const struct landlock_ruleset 
*const domain,
  				   u16 rule_type, u16 num_access)
  {
@@ -670,13 +628,15 @@ access_mask_t get_handled_accesses(const struct 
landlock_ruleset *const domain,
  /*
   * @layer_masks is read and may be updated according to the access 
request and
   * the matching rule.
+ * @masks_array_size must be equal to ARRAY_SIZE(*layer_masks).
   *
   * Returns true if the request is allowed (i.e. relevant layer masks 
for the
   * request are empty).
   */
  bool unmask_layers(const struct landlock_rule *const rule,
  		   const access_mask_t access_request,
-		   layer_mask_t (*const layer_masks)[], size_t masks_array_size)
+		   layer_mask_t (*const layer_masks)[],
+		   const size_t masks_array_size)
  {
  	size_t layer_level;

@@ -719,15 +679,43 @@ bool unmask_layers(const struct landlock_rule 
*const rule,
  	return false;
  }

+typedef access_mask_t
+get_access_mask_t(const struct landlock_ruleset *const ruleset,
+		  const u16 layer_level);
+
+/*
+ * @layer_masks must contain LANDLOCK_NUM_ACCESS_FS or 
LANDLOCK_NUM_ACCESS_NET
+ * elements according to @key_type.
+ */
  access_mask_t init_layer_masks(const struct landlock_ruleset *const 
domain,
  			       const access_mask_t access_request,
  			       layer_mask_t (*const layer_masks)[],
-			       size_t masks_size, u16 rule_type)
+			       const enum landlock_key_type key_type)
  {
  	access_mask_t handled_accesses = 0;
-	size_t layer_level;
+	size_t layer_level, num_access;
+	get_access_mask_t *get_access_mask;
+
+	switch (key_type) {
+	case LANDLOCK_KEY_INODE:
+		// XXX: landlock_get_fs_access_mask() should not be removed
+		// once we use ruleset->net_access_mask, and we can then
+		// replace the @key_type argument with num_access to make the
+		// code simpler.
+		get_access_mask = landlock_get_fs_access_mask;
+		num_access = LANDLOCK_NUM_ACCESS_FS;
+		break;
+	case LANDLOCK_KEY_NET_PORT:
+		get_access_mask = landlock_get_net_access_mask;
+		num_access = LANDLOCK_NUM_ACCESS_NET;
+		break;
+	default:
+		WARN_ON_ONCE(1);
+		return 0;
+	}

-	memset(layer_masks, 0, masks_size);
+	memset(layer_masks, 0,
+	       array_size(sizeof((*layer_masks)[0]), num_access));

  	/* An empty access request can happen because of O_WRONLY | O_RDWR. */
  	if (!access_request)
@@ -738,33 +726,13 @@ access_mask_t init_layer_masks(const struct 
landlock_ruleset *const domain,
  		const unsigned long access_req = access_request;
  		unsigned long access_bit;

-		switch (rule_type) {
-		case LANDLOCK_RULE_PATH_BENEATH:
-			for_each_set_bit(access_bit, &access_req,
-					 LANDLOCK_NUM_ACCESS_FS) {
-				if (landlock_get_fs_access_mask(domain,
-								layer_level) &
-				    BIT_ULL(access_bit)) {
-					(*layer_masks)[access_bit] |=
-						BIT_ULL(layer_level);
-					handled_accesses |= BIT_ULL(access_bit);
-				}
-			}
-			break;
-		case LANDLOCK_RULE_NET_SERVICE:
-			for_each_set_bit(access_bit, &access_req,
-					 LANDLOCK_NUM_ACCESS_NET) {
-				if (landlock_get_net_access_mask(domain,
-								 layer_level) &
-				    BIT_ULL(access_bit)) {
-					(*layer_masks)[access_bit] |=
-						BIT_ULL(layer_level);
-					handled_accesses |= BIT_ULL(access_bit);
-				}
+		for_each_set_bit(access_bit, &access_req, num_access) {
+			if (get_access_mask(domain, layer_level) &
+			    BIT_ULL(access_bit)) {
+				(*layer_masks)[access_bit] |=
+					BIT_ULL(layer_level);
+				handled_accesses |= BIT_ULL(access_bit);
  			}
-			break;
-		default:
-			return 0;
  		}
  	}
  	return handled_accesses;
diff --git a/security/landlock/ruleset.h b/security/landlock/ruleset.h
index 0cedfe65e326..59229be378d6 100644
--- a/security/landlock/ruleset.h
+++ b/security/landlock/ruleset.h
@@ -19,9 +19,12 @@
  #include "limits.h"
  #include "object.h"

+// TODO: get back to u16 thanks to ruleset->net_access_mask
  typedef u32 access_mask_t;
  /* Makes sure all filesystem access rights can be stored. */
  static_assert(BITS_PER_TYPE(access_mask_t) >= LANDLOCK_NUM_ACCESS_FS);
+/* Makes sure all network access rights can be stored. */
+static_assert(BITS_PER_TYPE(access_mask_t) >= LANDLOCK_NUM_ACCESS_NET);
  /* Makes sure for_each_set_bit() and for_each_clear_bit() calls are OK. */
  static_assert(sizeof(unsigned long) >= sizeof(access_mask_t));

@@ -44,6 +47,21 @@ struct landlock_layer {
  	access_mask_t access;
  };

+union landlock_key {
+	struct landlock_object *object;
+	uintptr_t data;
+};
+
+enum landlock_key_type {
+	LANDLOCK_KEY_INODE = 1,
+	LANDLOCK_KEY_NET_PORT = 2,
+};
+
+struct landlock_id {
+	union landlock_key key;
+	const enum landlock_key_type type;
+};
+
  /**
   * struct landlock_rule - Access rights tied to an object
   */
@@ -53,17 +71,16 @@ struct landlock_rule {
  	 */
  	struct rb_node node;
  	/**
-	 * @object: A union to identify either a kernel object (e.g. an inode) or
+	 * @key: A union to identify either a kernel object (e.g. an inode) or
  	 * a raw data value (e.g. a network socket port). This is used as a key
-	 * for this ruleset element. This pointer/@object.ptr/ is set once and
-	 * never modified. It always points to an allocated object because each
-	 * rule increments the refcount of its object (for inodes).;
+	 * for this ruleset element.  The pointer is set once and never
+	 * modified.  It always points to an allocated object because each rule
+	 * increments the refcount of its object.
+	 */
+	union landlock_key key;
+	/**
+	 * @num_layers: Number of entries in @layers.
  	 */
-	union {
-		struct landlock_object *ptr;
-		uintptr_t data;
-	} object;
-
  	u32 num_layers;
  	/**
  	 * @layers: Stack of layers, from the latest to the newest, implemented
@@ -117,8 +134,8 @@ struct landlock_ruleset {
  		 * @work_free: Enables to free a ruleset within a lockless
  		 * section.  This is only used by
  		 * landlock_put_ruleset_deferred() when @usage reaches zero.
-		 * The fields @lock, @usage, @num_rules, @num_layers and
-		 * @access_masks are then unused.
+		 * The fields @lock, @usage, @num_rules, @num_layers,
+		 * @net_access_mask and @access_masks are then unused.
  		 */
  		struct work_struct work_free;
  		struct {
@@ -144,6 +161,11 @@ struct landlock_ruleset {
  			 * non-merged ruleset (i.e. not a domain).
  			 */
  			u32 num_layers;
+			/**
+			 * TODO: net_access_mask: Contains the subset of network
+			 * actions that are restricted by a ruleset.
+			 */
+			access_mask_t net_access_mask;
  			/**
  			 * @access_masks: Contains the subset of filesystem
  			 * actions that are restricted by a ruleset.  A domain
@@ -156,6 +178,8 @@ struct landlock_ruleset {
  			 * layers are set once and never changed for the
  			 * lifetime of the ruleset.
  			 */
+			// TODO: rename (back) to fs_access_mask because layers
+			// are only useful for file hierarchies.
  			access_mask_t access_masks[];
  		};
  	};
@@ -169,9 +193,8 @@ void landlock_put_ruleset(struct landlock_ruleset 
*const ruleset);
  void landlock_put_ruleset_deferred(struct landlock_ruleset *const 
ruleset);

  int landlock_insert_rule(struct landlock_ruleset *const ruleset,
-			 struct landlock_object *const object_ptr,
-			 const uintptr_t object_data,
-			 const access_mask_t access, const u16 rule_type);
+			 const struct landlock_id id,
+			 const access_mask_t access);

  struct landlock_ruleset *
  landlock_merge_ruleset(struct landlock_ruleset *const parent,
@@ -179,7 +202,7 @@ landlock_merge_ruleset(struct landlock_ruleset 
*const parent,

  const struct landlock_rule *
  landlock_find_rule(const struct landlock_ruleset *const ruleset,
-		   const uintptr_t object_data, const u16 rule_type);
+		   const struct landlock_id id);

  static inline void landlock_get_ruleset(struct landlock_ruleset *const 
ruleset)
  {
@@ -187,6 +210,7 @@ static inline void landlock_get_ruleset(struct 
landlock_ruleset *const ruleset)
  		refcount_inc(&ruleset->usage);
  }

+// TODO: These helpers should not be required thanks to the new 
ruleset->net_access_mask.
  /* A helper function to set a filesystem mask. */
  static inline void
  landlock_set_fs_access_mask(struct landlock_ruleset *ruleset,
@@ -222,16 +246,16 @@ landlock_get_net_access_mask(const struct 
landlock_ruleset *ruleset,
  }

  access_mask_t get_handled_accesses(const struct landlock_ruleset 
*const domain,
-				   u16 rule_type, u16 num_access);
+				   const u16 rule_type, const u16 num_access);

  bool unmask_layers(const struct landlock_rule *const rule,
  		   const access_mask_t access_request,
  		   layer_mask_t (*const layer_masks)[],
-		   size_t masks_array_size);
+		   const size_t masks_array_size);

  access_mask_t init_layer_masks(const struct landlock_ruleset *const 
domain,
  			       const access_mask_t access_request,
  			       layer_mask_t (*const layer_masks)[],
-			       size_t masks_size, u16 rule_type);
+			       const enum landlock_key_type key_type);

  #endif /* _SECURITY_LANDLOCK_RULESET_H */
diff --git a/security/landlock/syscalls.c b/security/landlock/syscalls.c
index 5069fac2ecf6..880c2adec788 100644
--- a/security/landlock/syscalls.c
+++ b/security/landlock/syscalls.c
@@ -289,7 +289,7 @@ static int get_path_from_fd(const s32 fd, struct 
path *const path)
  }

  static int add_rule_path_beneath(struct landlock_ruleset *const ruleset,
-				 const void *const rule_attr)
+				 const void __user *const rule_attr)
  {
  	struct landlock_path_beneath_attr path_beneath_attr;
  	struct path path;
@@ -330,7 +330,7 @@ static int add_rule_path_beneath(struct 
landlock_ruleset *const ruleset,
  }

  static int add_rule_net_service(struct landlock_ruleset *ruleset,
-				const void *const rule_attr)
+				const void __user *const rule_attr)
  {
  #if IS_ENABLED(CONFIG_INET)
  	struct landlock_net_service_attr net_service_attr;

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 00/17] Network support for Landlock
  2022-07-26 17:43 ` [PATCH v6 00/17] Network support for Landlock Mickaël Salaün
@ 2022-07-27 19:54   ` Mickaël Salaün
  2022-07-28  9:19     ` Konstantin Meskhidze (A)
                       ` (2 more replies)
  2022-07-27 20:21   ` Mickaël Salaün
  1 sibling, 3 replies; 53+ messages in thread
From: Mickaël Salaün @ 2022-07-27 19:54 UTC (permalink / raw)
  To: Konstantin Meskhidze
  Cc: willemdebruijn.kernel, linux-security-module, netdev,
	netfilter-devel, yusongping, anton.sirazetdinov



On 26/07/2022 19:43, Mickaël Salaün wrote:
> 
> On 21/06/2022 10:22, Konstantin Meskhidze wrote:
>> Hi,
>> This is a new V6 patch related to Landlock LSM network confinement.
>> It is based on the latest landlock-wip branch on top of v5.19-rc2:
>> https://git.kernel.org/pub/scm/linux/kernel/git/mic/linux.git/log/?h=landlock-wip
>>
>> It brings refactoring of previous patch version V5:
>>      - Fixes some logic errors and typos.
>>      - Adds additional FIXTURE_VARIANT and FIXTURE_VARIANT_ADD helpers
>>      to support both ip4 and ip6 families and shorten seltests' code.
>>      - Makes TCP sockets confinement support optional in sandboxer demo.
>>      - Formats the code with clang-format-14
>>
>> All test were run in QEMU evironment and compiled with
>>   -static flag.
>>   1. network_test: 18/18 tests passed.
>>   2. base_test: 7/7 tests passed.
>>   3. fs_test: 59/59 tests passed.
>>   4. ptrace_test: 8/8 tests passed.
>>
>> Still have issue with base_test were compiled without -static flag
>> (landlock-wip branch without network support)
>> 1. base_test: 6/7 tests passed.
>>   Error:
>>   #  RUN           global.inconsistent_attr ...
>>   # base_test.c:54:inconsistent_attr:Expected ENOMSG (42) == errno (22)
>>   # inconsistent_attr: Test terminated by assertion
>>   #          FAIL  global.inconsistent_attr
>> not ok 1 global.inconsistent_attr
>>
>> LCOV - code coverage report:
>>              Hit  Total  Coverage
>> Lines:      952  1010    94.3 %
>> Functions:  79   82      96.3 %
>>
>> Previous versions:
>> v5: 
>> https://lore.kernel.org/linux-security-module/20220516152038.39594-1-konstantin.meskhidze@huawei.com
>> v4: 
>> https://lore.kernel.org/linux-security-module/20220309134459.6448-1-konstantin.meskhidze@huawei.com/
>> v3: 
>> https://lore.kernel.org/linux-security-module/20220124080215.265538-1-konstantin.meskhidze@huawei.com/
>> v2: 
>> https://lore.kernel.org/linux-security-module/20211228115212.703084-1-konstantin.meskhidze@huawei.com/
>> v1: 
>> https://lore.kernel.org/linux-security-module/20211210072123.386713-1-konstantin.meskhidze@huawei.com/
>>
>> Konstantin Meskhidze (17):
>>    landlock: renames access mask
>>    landlock: refactors landlock_find/insert_rule
>>    landlock: refactors merge and inherit functions
>>    landlock: moves helper functions
>>    landlock: refactors helper functions
>>    landlock: refactors landlock_add_rule syscall
>>    landlock: user space API network support
>>    landlock: adds support network rules
>>    landlock: implements TCP network hooks
>>    seltests/landlock: moves helper function
>>    seltests/landlock: adds tests for bind() hooks
>>    seltests/landlock: adds tests for connect() hooks
>>    seltests/landlock: adds AF_UNSPEC family test
>>    seltests/landlock: adds rules overlapping test
>>    seltests/landlock: adds ruleset expanding test
>>    seltests/landlock: adds invalid input data test
>>    samples/landlock: adds network demo
>>
>>   include/uapi/linux/landlock.h               |  49 ++
>>   samples/landlock/sandboxer.c                | 118 ++-
>>   security/landlock/Kconfig                   |   1 +
>>   security/landlock/Makefile                  |   2 +
>>   security/landlock/fs.c                      | 162 +---
>>   security/landlock/limits.h                  |   8 +-
>>   security/landlock/net.c                     | 155 ++++
>>   security/landlock/net.h                     |  26 +
>>   security/landlock/ruleset.c                 | 448 +++++++++--
>>   security/landlock/ruleset.h                 |  91 ++-
>>   security/landlock/setup.c                   |   2 +
>>   security/landlock/syscalls.c                | 168 +++--
>>   tools/testing/selftests/landlock/common.h   |  10 +
>>   tools/testing/selftests/landlock/config     |   4 +
>>   tools/testing/selftests/landlock/fs_test.c  |  10 -
>>   tools/testing/selftests/landlock/net_test.c | 774 ++++++++++++++++++++
>>   16 files changed, 1737 insertions(+), 291 deletions(-)
>>   create mode 100644 security/landlock/net.c
>>   create mode 100644 security/landlock/net.h
>>   create mode 100644 tools/testing/selftests/landlock/net_test.c
>>
>> -- 
>> 2.25.1
>>
> 
> I did a thorough review of all the code. I found that the main issue 
> with this version is that we stick to the layers limit whereas it is 
> only relevant for filesystem hierarchies. You'll find in the following 
> patch miscellaneous fixes and improvement, with some TODOs to get rid of 
> this layer limit. We'll need a test to check that too. You'll need to 
> integrate this diff into your patches though.

You can find the related patch here: 
https://git.kernel.org/mic/c/8f4104b3dc59e7f110c9b83cdf034d010a2d006f

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 00/17] Network support for Landlock
  2022-07-26 17:43 ` [PATCH v6 00/17] Network support for Landlock Mickaël Salaün
  2022-07-27 19:54   ` Mickaël Salaün
@ 2022-07-27 20:21   ` Mickaël Salaün
  2022-07-28  9:20     ` Konstantin Meskhidze (A)
  1 sibling, 1 reply; 53+ messages in thread
From: Mickaël Salaün @ 2022-07-27 20:21 UTC (permalink / raw)
  To: Konstantin Meskhidze
  Cc: willemdebruijn.kernel, linux-security-module, netdev,
	netfilter-devel, yusongping, anton.sirazetdinov


On 26/07/2022 19:43, Mickaël Salaün wrote:
> 
> On 21/06/2022 10:22, Konstantin Meskhidze wrote:
>> Hi,
>> This is a new V6 patch related to Landlock LSM network confinement.
>> It is based on the latest landlock-wip branch on top of v5.19-rc2:
>> https://git.kernel.org/pub/scm/linux/kernel/git/mic/linux.git/log/?h=landlock-wip
>>
>> It brings refactoring of previous patch version V5:
>>      - Fixes some logic errors and typos.
>>      - Adds additional FIXTURE_VARIANT and FIXTURE_VARIANT_ADD helpers
>>      to support both ip4 and ip6 families and shorten seltests' code.
>>      - Makes TCP sockets confinement support optional in sandboxer demo.
>>      - Formats the code with clang-format-14
>>
>> All test were run in QEMU evironment and compiled with
>>   -static flag.
>>   1. network_test: 18/18 tests passed.
>>   2. base_test: 7/7 tests passed.
>>   3. fs_test: 59/59 tests passed.
>>   4. ptrace_test: 8/8 tests passed.
>>
>> Still have issue with base_test were compiled without -static flag
>> (landlock-wip branch without network support)
>> 1. base_test: 6/7 tests passed.
>>   Error:
>>   #  RUN           global.inconsistent_attr ...
>>   # base_test.c:54:inconsistent_attr:Expected ENOMSG (42) == errno (22)
>>   # inconsistent_attr: Test terminated by assertion
>>   #          FAIL  global.inconsistent_attr
>> not ok 1 global.inconsistent_attr
>>
>> LCOV - code coverage report:
>>              Hit  Total  Coverage
>> Lines:      952  1010    94.3 %
>> Functions:  79   82      96.3 %
>>
>> Previous versions:
>> v5: 
>> https://lore.kernel.org/linux-security-module/20220516152038.39594-1-konstantin.meskhidze@huawei.com
>> v4: 
>> https://lore.kernel.org/linux-security-module/20220309134459.6448-1-konstantin.meskhidze@huawei.com/
>> v3: 
>> https://lore.kernel.org/linux-security-module/20220124080215.265538-1-konstantin.meskhidze@huawei.com/
>> v2: 
>> https://lore.kernel.org/linux-security-module/20211228115212.703084-1-konstantin.meskhidze@huawei.com/
>> v1: 
>> https://lore.kernel.org/linux-security-module/20211210072123.386713-1-konstantin.meskhidze@huawei.com/
>>
>> Konstantin Meskhidze (17):
>>    landlock: renames access mask
>>    landlock: refactors landlock_find/insert_rule
>>    landlock: refactors merge and inherit functions
>>    landlock: moves helper functions
>>    landlock: refactors helper functions
>>    landlock: refactors landlock_add_rule syscall
>>    landlock: user space API network support
>>    landlock: adds support network rules
>>    landlock: implements TCP network hooks
>>    seltests/landlock: moves helper function
>>    seltests/landlock: adds tests for bind() hooks
>>    seltests/landlock: adds tests for connect() hooks
>>    seltests/landlock: adds AF_UNSPEC family test
>>    seltests/landlock: adds rules overlapping test
>>    seltests/landlock: adds ruleset expanding test
>>    seltests/landlock: adds invalid input data test
>>    samples/landlock: adds network demo
>>
>>   include/uapi/linux/landlock.h               |  49 ++
>>   samples/landlock/sandboxer.c                | 118 ++-
>>   security/landlock/Kconfig                   |   1 +
>>   security/landlock/Makefile                  |   2 +
>>   security/landlock/fs.c                      | 162 +---
>>   security/landlock/limits.h                  |   8 +-
>>   security/landlock/net.c                     | 155 ++++
>>   security/landlock/net.h                     |  26 +
>>   security/landlock/ruleset.c                 | 448 +++++++++--
>>   security/landlock/ruleset.h                 |  91 ++-
>>   security/landlock/setup.c                   |   2 +
>>   security/landlock/syscalls.c                | 168 +++--
>>   tools/testing/selftests/landlock/common.h   |  10 +
>>   tools/testing/selftests/landlock/config     |   4 +
>>   tools/testing/selftests/landlock/fs_test.c  |  10 -
>>   tools/testing/selftests/landlock/net_test.c | 774 ++++++++++++++++++++
>>   16 files changed, 1737 insertions(+), 291 deletions(-)
>>   create mode 100644 security/landlock/net.c
>>   create mode 100644 security/landlock/net.h
>>   create mode 100644 tools/testing/selftests/landlock/net_test.c
>>
>> -- 
>> 2.25.1
>>
> 
> I did a thorough review of all the code. I found that the main issue 
> with this version is that we stick to the layers limit whereas it is 
> only relevant for filesystem hierarchies. You'll find in the following 
> patch miscellaneous fixes and improvement, with some TODOs to get rid of 
> this layer limit. We'll need a test to check that too. You'll need to 
> integrate this diff into your patches though.
> 
> 

[...]

> diff --git a/security/landlock/ruleset.c b/security/landlock/ruleset.c
> index 469811a77675..e7555b16069a 100644
> --- a/security/landlock/ruleset.c
> +++ b/security/landlock/ruleset.c

[...]

> @@ -719,15 +679,43 @@ bool unmask_layers(const struct landlock_rule 
> *const rule,
>       return false;
>   }
> 
> +typedef access_mask_t
> +get_access_mask_t(const struct landlock_ruleset *const ruleset,
> +          const u16 layer_level);
> +
> +/*
> + * @layer_masks must contain LANDLOCK_NUM_ACCESS_FS or 
> LANDLOCK_NUM_ACCESS_NET
> + * elements according to @key_type.
> + */
>   access_mask_t init_layer_masks(const struct landlock_ruleset *const 
> domain,
>                      const access_mask_t access_request,
>                      layer_mask_t (*const layer_masks)[],
> -                   size_t masks_size, u16 rule_type)
> +                   const enum landlock_key_type key_type)
>   {
>       access_mask_t handled_accesses = 0;
> -    size_t layer_level;
> +    size_t layer_level, num_access;
> +    get_access_mask_t *get_access_mask;
> +
> +    switch (key_type) {
> +    case LANDLOCK_KEY_INODE:
> +        // XXX: landlock_get_fs_access_mask() should not be removed

There is an extra "not", it should be: "landlock_get_fs_access_mask() 
and landlock_get_net_access_mask() should be removed".


> +        // once we use ruleset->net_access_mask, and we can then
> +        // replace the @key_type argument with num_access to make the
> +        // code simpler.
> +        get_access_mask = landlock_get_fs_access_mask;
> +        num_access = LANDLOCK_NUM_ACCESS_FS;
> +        break;
> +    case LANDLOCK_KEY_NET_PORT:
> +        get_access_mask = landlock_get_net_access_mask;
> +        num_access = LANDLOCK_NUM_ACCESS_NET;
> +        break;
> +    default:
> +        WARN_ON_ONCE(1);
> +        return 0;
> +    }

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 17/17] samples/landlock: adds network demo
  2022-06-21  8:23 ` [PATCH v6 17/17] samples/landlock: adds network demo Konstantin Meskhidze
@ 2022-07-27 20:26   ` Mickaël Salaün
  2022-07-28  9:21     ` Konstantin Meskhidze (A)
  0 siblings, 1 reply; 53+ messages in thread
From: Mickaël Salaün @ 2022-07-27 20:26 UTC (permalink / raw)
  To: Konstantin Meskhidze
  Cc: willemdebruijn.kernel, linux-security-module, netdev,
	netfilter-devel, yusongping, anton.sirazetdinov


On 21/06/2022 10:23, Konstantin Meskhidze wrote:
> This commit adds network demo. It's possible to
> allow a sandoxer to bind/connect to a list of
> particular ports restricting networks actions to
> the rest of ports.
> 
> Signed-off-by: Konstantin Meskhidze <konstantin.meskhidze@huawei.com>
> ---
> 
> Changes since v5:
> * Makes network ports sandboxing optional.
> * Fixes some logic errors.
> * Formats code with clang-format-14.
> 
> Changes since v4:
> * Adds ENV_TCP_BIND_NAME "LL_TCP_BIND" and
> ENV_TCP_CONNECT_NAME "LL_TCP_CONNECT" variables
> to insert TCP ports.
> * Renames populate_ruleset() to populate_ruleset_fs().
> * Adds populate_ruleset_net() and parse_port_num() helpers.
> * Refactors main() to support network sandboxing.
> 
> ---
>   samples/landlock/sandboxer.c | 118 +++++++++++++++++++++++++++++++----
>   1 file changed, 107 insertions(+), 11 deletions(-)
> 
> diff --git a/samples/landlock/sandboxer.c b/samples/landlock/sandboxer.c
> index 3e404e51ec64..0606c676fded 100644
> --- a/samples/landlock/sandboxer.c
> +++ b/samples/landlock/sandboxer.c


[...]

> @@ -232,16 +308,36 @@ int main(const int argc, char *const argv[], char *const *const envp)
>   		access_fs_rw &= ~ACCESS_ABI_2;

We need to check the ABI to make this sample work without a kernel 
supporting Landlock network access rights, and error out if the user 
explicitely asked for it anyway (with the environement variable).


>   	}
> 
> +	/* Adds optionally network bind() support. */
> +	env_port_name = getenv(ENV_TCP_BIND_NAME);
> +	if (env_port_name) {
> +		access_net_tcp |= LANDLOCK_ACCESS_NET_BIND_TCP;
> +	}
> +	/* Adds optionally network connect() support. */
> +	env_port_name = getenv(ENV_TCP_CONNECT_NAME);
> +	if (env_port_name) {
> +		access_net_tcp |= LANDLOCK_ACCESS_NET_CONNECT_TCP;
> +	}
> +	ruleset_attr.handled_access_net = access_net_tcp;
> +
>   	ruleset_fd =
>   		landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
>   	if (ruleset_fd < 0) {
>   		perror("Failed to create a ruleset");
>   		return 1;
>   	}
> -	if (populate_ruleset(ENV_FS_RO_NAME, ruleset_fd, access_fs_ro)) {
> +	if (populate_ruleset_fs(ENV_FS_RO_NAME, ruleset_fd, access_fs_ro)) {
> +		goto err_close_ruleset;
> +	}
> +	if (populate_ruleset_fs(ENV_FS_RW_NAME, ruleset_fd, access_fs_rw)) {
> +		goto err_close_ruleset;
> +	}
> +	if (populate_ruleset_net(ENV_TCP_BIND_NAME, ruleset_fd,
> +				 LANDLOCK_ACCESS_NET_BIND_TCP)) {
>   		goto err_close_ruleset;
>   	}
> -	if (populate_ruleset(ENV_FS_RW_NAME, ruleset_fd, access_fs_rw)) {
> +	if (populate_ruleset_net(ENV_TCP_CONNECT_NAME, ruleset_fd,
> +				 LANDLOCK_ACCESS_NET_CONNECT_TCP)) {
>   		goto err_close_ruleset;
>   	}
>   	if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
> --
> 2.25.1
> 

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 00/17] Network support for Landlock
  2022-07-27 19:54   ` Mickaël Salaün
@ 2022-07-28  9:19     ` Konstantin Meskhidze (A)
  2022-07-28  9:25     ` Konstantin Meskhidze (A)
  2022-07-28 13:17     ` Mickaël Salaün
  2 siblings, 0 replies; 53+ messages in thread
From: Konstantin Meskhidze (A) @ 2022-07-28  9:19 UTC (permalink / raw)
  To: Mickaël Salaün
  Cc: willemdebruijn.kernel, linux-security-module, netdev,
	netfilter-devel, yusongping, anton.sirazetdinov



7/27/2022 10:54 PM, Mickaël Salaün пишет:
> 
> 
> On 26/07/2022 19:43, Mickaël Salaün wrote:
>> 
>> On 21/06/2022 10:22, Konstantin Meskhidze wrote:
>>> Hi,
>>> This is a new V6 patch related to Landlock LSM network confinement.
>>> It is based on the latest landlock-wip branch on top of v5.19-rc2:
>>> https://git.kernel.org/pub/scm/linux/kernel/git/mic/linux.git/log/?h=landlock-wip
>>>
>>> It brings refactoring of previous patch version V5:
>>>      - Fixes some logic errors and typos.
>>>      - Adds additional FIXTURE_VARIANT and FIXTURE_VARIANT_ADD helpers
>>>      to support both ip4 and ip6 families and shorten seltests' code.
>>>      - Makes TCP sockets confinement support optional in sandboxer demo.
>>>      - Formats the code with clang-format-14
>>>
>>> All test were run in QEMU evironment and compiled with
>>>   -static flag.
>>>   1. network_test: 18/18 tests passed.
>>>   2. base_test: 7/7 tests passed.
>>>   3. fs_test: 59/59 tests passed.
>>>   4. ptrace_test: 8/8 tests passed.
>>>
>>> Still have issue with base_test were compiled without -static flag
>>> (landlock-wip branch without network support)
>>> 1. base_test: 6/7 tests passed.
>>>   Error:
>>>   #  RUN           global.inconsistent_attr ...
>>>   # base_test.c:54:inconsistent_attr:Expected ENOMSG (42) == errno (22)
>>>   # inconsistent_attr: Test terminated by assertion
>>>   #          FAIL  global.inconsistent_attr
>>> not ok 1 global.inconsistent_attr
>>>
>>> LCOV - code coverage report:
>>>              Hit  Total  Coverage
>>> Lines:      952  1010    94.3 %
>>> Functions:  79   82      96.3 %
>>>
>>> Previous versions:
>>> v5: 
>>> https://lore.kernel.org/linux-security-module/20220516152038.39594-1-konstantin.meskhidze@huawei.com
>>> v4: 
>>> https://lore.kernel.org/linux-security-module/20220309134459.6448-1-konstantin.meskhidze@huawei.com/
>>> v3: 
>>> https://lore.kernel.org/linux-security-module/20220124080215.265538-1-konstantin.meskhidze@huawei.com/
>>> v2: 
>>> https://lore.kernel.org/linux-security-module/20211228115212.703084-1-konstantin.meskhidze@huawei.com/
>>> v1: 
>>> https://lore.kernel.org/linux-security-module/20211210072123.386713-1-konstantin.meskhidze@huawei.com/
>>>
>>> Konstantin Meskhidze (17):
>>>    landlock: renames access mask
>>>    landlock: refactors landlock_find/insert_rule
>>>    landlock: refactors merge and inherit functions
>>>    landlock: moves helper functions
>>>    landlock: refactors helper functions
>>>    landlock: refactors landlock_add_rule syscall
>>>    landlock: user space API network support
>>>    landlock: adds support network rules
>>>    landlock: implements TCP network hooks
>>>    seltests/landlock: moves helper function
>>>    seltests/landlock: adds tests for bind() hooks
>>>    seltests/landlock: adds tests for connect() hooks
>>>    seltests/landlock: adds AF_UNSPEC family test
>>>    seltests/landlock: adds rules overlapping test
>>>    seltests/landlock: adds ruleset expanding test
>>>    seltests/landlock: adds invalid input data test
>>>    samples/landlock: adds network demo
>>>
>>>   include/uapi/linux/landlock.h               |  49 ++
>>>   samples/landlock/sandboxer.c                | 118 ++-
>>>   security/landlock/Kconfig                   |   1 +
>>>   security/landlock/Makefile                  |   2 +
>>>   security/landlock/fs.c                      | 162 +---
>>>   security/landlock/limits.h                  |   8 +-
>>>   security/landlock/net.c                     | 155 ++++
>>>   security/landlock/net.h                     |  26 +
>>>   security/landlock/ruleset.c                 | 448 +++++++++--
>>>   security/landlock/ruleset.h                 |  91 ++-
>>>   security/landlock/setup.c                   |   2 +
>>>   security/landlock/syscalls.c                | 168 +++--
>>>   tools/testing/selftests/landlock/common.h   |  10 +
>>>   tools/testing/selftests/landlock/config     |   4 +
>>>   tools/testing/selftests/landlock/fs_test.c  |  10 -
>>>   tools/testing/selftests/landlock/net_test.c | 774 ++++++++++++++++++++
>>>   16 files changed, 1737 insertions(+), 291 deletions(-)
>>>   create mode 100644 security/landlock/net.c
>>>   create mode 100644 security/landlock/net.h
>>>   create mode 100644 tools/testing/selftests/landlock/net_test.c
>>>
>>> -- 
>>> 2.25.1
>>>
>> 
>> I did a thorough review of all the code. I found that the main issue 
>> with this version is that we stick to the layers limit whereas it is 
>> only relevant for filesystem hierarchies. You'll find in the following 
>> patch miscellaneous fixes and improvement, with some TODOs to get rid of 
>> this layer limit. We'll need a test to check that too. You'll need to 
>> integrate this diff into your patches though.
> 
> You can find the related patch here:
> https://git.kernel.org/mic/c/8f4104b3dc59e7f110c9b83cdf034d010a2d006f

  Ok. Thank you.
  I will split your patch among my next V7 version.
> .

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 00/17] Network support for Landlock
  2022-07-27 20:21   ` Mickaël Salaün
@ 2022-07-28  9:20     ` Konstantin Meskhidze (A)
  0 siblings, 0 replies; 53+ messages in thread
From: Konstantin Meskhidze (A) @ 2022-07-28  9:20 UTC (permalink / raw)
  To: Mickaël Salaün
  Cc: willemdebruijn.kernel, linux-security-module, netdev,
	netfilter-devel, yusongping, anton.sirazetdinov



7/27/2022 11:21 PM, Mickaël Salaün пишет:
> 
> On 26/07/2022 19:43, Mickaël Salaün wrote:
>> 
>> On 21/06/2022 10:22, Konstantin Meskhidze wrote:
>>> Hi,
>>> This is a new V6 patch related to Landlock LSM network confinement.
>>> It is based on the latest landlock-wip branch on top of v5.19-rc2:
>>> https://git.kernel.org/pub/scm/linux/kernel/git/mic/linux.git/log/?h=landlock-wip
>>>
>>> It brings refactoring of previous patch version V5:
>>>      - Fixes some logic errors and typos.
>>>      - Adds additional FIXTURE_VARIANT and FIXTURE_VARIANT_ADD helpers
>>>      to support both ip4 and ip6 families and shorten seltests' code.
>>>      - Makes TCP sockets confinement support optional in sandboxer demo.
>>>      - Formats the code with clang-format-14
>>>
>>> All test were run in QEMU evironment and compiled with
>>>   -static flag.
>>>   1. network_test: 18/18 tests passed.
>>>   2. base_test: 7/7 tests passed.
>>>   3. fs_test: 59/59 tests passed.
>>>   4. ptrace_test: 8/8 tests passed.
>>>
>>> Still have issue with base_test were compiled without -static flag
>>> (landlock-wip branch without network support)
>>> 1. base_test: 6/7 tests passed.
>>>   Error:
>>>   #  RUN           global.inconsistent_attr ...
>>>   # base_test.c:54:inconsistent_attr:Expected ENOMSG (42) == errno (22)
>>>   # inconsistent_attr: Test terminated by assertion
>>>   #          FAIL  global.inconsistent_attr
>>> not ok 1 global.inconsistent_attr
>>>
>>> LCOV - code coverage report:
>>>              Hit  Total  Coverage
>>> Lines:      952  1010    94.3 %
>>> Functions:  79   82      96.3 %
>>>
>>> Previous versions:
>>> v5: 
>>> https://lore.kernel.org/linux-security-module/20220516152038.39594-1-konstantin.meskhidze@huawei.com
>>> v4: 
>>> https://lore.kernel.org/linux-security-module/20220309134459.6448-1-konstantin.meskhidze@huawei.com/
>>> v3: 
>>> https://lore.kernel.org/linux-security-module/20220124080215.265538-1-konstantin.meskhidze@huawei.com/
>>> v2: 
>>> https://lore.kernel.org/linux-security-module/20211228115212.703084-1-konstantin.meskhidze@huawei.com/
>>> v1: 
>>> https://lore.kernel.org/linux-security-module/20211210072123.386713-1-konstantin.meskhidze@huawei.com/
>>>
>>> Konstantin Meskhidze (17):
>>>    landlock: renames access mask
>>>    landlock: refactors landlock_find/insert_rule
>>>    landlock: refactors merge and inherit functions
>>>    landlock: moves helper functions
>>>    landlock: refactors helper functions
>>>    landlock: refactors landlock_add_rule syscall
>>>    landlock: user space API network support
>>>    landlock: adds support network rules
>>>    landlock: implements TCP network hooks
>>>    seltests/landlock: moves helper function
>>>    seltests/landlock: adds tests for bind() hooks
>>>    seltests/landlock: adds tests for connect() hooks
>>>    seltests/landlock: adds AF_UNSPEC family test
>>>    seltests/landlock: adds rules overlapping test
>>>    seltests/landlock: adds ruleset expanding test
>>>    seltests/landlock: adds invalid input data test
>>>    samples/landlock: adds network demo
>>>
>>>   include/uapi/linux/landlock.h               |  49 ++
>>>   samples/landlock/sandboxer.c                | 118 ++-
>>>   security/landlock/Kconfig                   |   1 +
>>>   security/landlock/Makefile                  |   2 +
>>>   security/landlock/fs.c                      | 162 +---
>>>   security/landlock/limits.h                  |   8 +-
>>>   security/landlock/net.c                     | 155 ++++
>>>   security/landlock/net.h                     |  26 +
>>>   security/landlock/ruleset.c                 | 448 +++++++++--
>>>   security/landlock/ruleset.h                 |  91 ++-
>>>   security/landlock/setup.c                   |   2 +
>>>   security/landlock/syscalls.c                | 168 +++--
>>>   tools/testing/selftests/landlock/common.h   |  10 +
>>>   tools/testing/selftests/landlock/config     |   4 +
>>>   tools/testing/selftests/landlock/fs_test.c  |  10 -
>>>   tools/testing/selftests/landlock/net_test.c | 774 ++++++++++++++++++++
>>>   16 files changed, 1737 insertions(+), 291 deletions(-)
>>>   create mode 100644 security/landlock/net.c
>>>   create mode 100644 security/landlock/net.h
>>>   create mode 100644 tools/testing/selftests/landlock/net_test.c
>>>
>>> -- 
>>> 2.25.1
>>>
>> 
>> I did a thorough review of all the code. I found that the main issue 
>> with this version is that we stick to the layers limit whereas it is 
>> only relevant for filesystem hierarchies. You'll find in the following 
>> patch miscellaneous fixes and improvement, with some TODOs to get rid of 
>> this layer limit. We'll need a test to check that too. You'll need to 
>> integrate this diff into your patches though.
>> 
>> 
> 
> [...]
> 
>> diff --git a/security/landlock/ruleset.c b/security/landlock/ruleset.c
>> index 469811a77675..e7555b16069a 100644
>> --- a/security/landlock/ruleset.c
>> +++ b/security/landlock/ruleset.c
> 
> [...]
> 
>> @@ -719,15 +679,43 @@ bool unmask_layers(const struct landlock_rule 
>> *const rule,
>>       return false;
>>   }
>> 
>> +typedef access_mask_t
>> +get_access_mask_t(const struct landlock_ruleset *const ruleset,
>> +          const u16 layer_level);
>> +
>> +/*
>> + * @layer_masks must contain LANDLOCK_NUM_ACCESS_FS or 
>> LANDLOCK_NUM_ACCESS_NET
>> + * elements according to @key_type.
>> + */
>>   access_mask_t init_layer_masks(const struct landlock_ruleset *const 
>> domain,
>>                      const access_mask_t access_request,
>>                      layer_mask_t (*const layer_masks)[],
>> -                   size_t masks_size, u16 rule_type)
>> +                   const enum landlock_key_type key_type)
>>   {
>>       access_mask_t handled_accesses = 0;
>> -    size_t layer_level;
>> +    size_t layer_level, num_access;
>> +    get_access_mask_t *get_access_mask;
>> +
>> +    switch (key_type) {
>> +    case LANDLOCK_KEY_INODE:
>> +        // XXX: landlock_get_fs_access_mask() should not be removed
> 
> There is an extra "not", it should be: "landlock_get_fs_access_mask()
> and landlock_get_net_access_mask() should be removed".
> 
   I got it. Will be fixed.
   Thank you!
> 
>> +        // once we use ruleset->net_access_mask, and we can then
>> +        // replace the @key_type argument with num_access to make the
>> +        // code simpler.
>> +        get_access_mask = landlock_get_fs_access_mask;
>> +        num_access = LANDLOCK_NUM_ACCESS_FS;
>> +        break;
>> +    case LANDLOCK_KEY_NET_PORT:
>> +        get_access_mask = landlock_get_net_access_mask;
>> +        num_access = LANDLOCK_NUM_ACCESS_NET;
>> +        break;
>> +    default:
>> +        WARN_ON_ONCE(1);
>> +        return 0;
>> +    }
> .

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 17/17] samples/landlock: adds network demo
  2022-07-27 20:26   ` Mickaël Salaün
@ 2022-07-28  9:21     ` Konstantin Meskhidze (A)
  0 siblings, 0 replies; 53+ messages in thread
From: Konstantin Meskhidze (A) @ 2022-07-28  9:21 UTC (permalink / raw)
  To: Mickaël Salaün
  Cc: willemdebruijn.kernel, linux-security-module, netdev,
	netfilter-devel, yusongping, anton.sirazetdinov



7/27/2022 11:26 PM, Mickaël Salaün пишет:
> 
> On 21/06/2022 10:23, Konstantin Meskhidze wrote:
>> This commit adds network demo. It's possible to
>> allow a sandoxer to bind/connect to a list of
>> particular ports restricting networks actions to
>> the rest of ports.
>> 
>> Signed-off-by: Konstantin Meskhidze <konstantin.meskhidze@huawei.com>
>> ---
>> 
>> Changes since v5:
>> * Makes network ports sandboxing optional.
>> * Fixes some logic errors.
>> * Formats code with clang-format-14.
>> 
>> Changes since v4:
>> * Adds ENV_TCP_BIND_NAME "LL_TCP_BIND" and
>> ENV_TCP_CONNECT_NAME "LL_TCP_CONNECT" variables
>> to insert TCP ports.
>> * Renames populate_ruleset() to populate_ruleset_fs().
>> * Adds populate_ruleset_net() and parse_port_num() helpers.
>> * Refactors main() to support network sandboxing.
>> 
>> ---
>>   samples/landlock/sandboxer.c | 118 +++++++++++++++++++++++++++++++----
>>   1 file changed, 107 insertions(+), 11 deletions(-)
>> 
>> diff --git a/samples/landlock/sandboxer.c b/samples/landlock/sandboxer.c
>> index 3e404e51ec64..0606c676fded 100644
>> --- a/samples/landlock/sandboxer.c
>> +++ b/samples/landlock/sandboxer.c
> 
> 
> [...]
> 
>> @@ -232,16 +308,36 @@ int main(const int argc, char *const argv[], char *const *const envp)
>>   		access_fs_rw &= ~ACCESS_ABI_2;
> 
> We need to check the ABI to make this sample work without a kernel
> supporting Landlock network access rights, and error out if the user
> explicitely asked for it anyway (with the environement variable).
> 
   Good point. Thanks for that.
   I will check it.
> 
>>   	}
>> 
>> +	/* Adds optionally network bind() support. */
>> +	env_port_name = getenv(ENV_TCP_BIND_NAME);
>> +	if (env_port_name) {
>> +		access_net_tcp |= LANDLOCK_ACCESS_NET_BIND_TCP;
>> +	}
>> +	/* Adds optionally network connect() support. */
>> +	env_port_name = getenv(ENV_TCP_CONNECT_NAME);
>> +	if (env_port_name) {
>> +		access_net_tcp |= LANDLOCK_ACCESS_NET_CONNECT_TCP;
>> +	}
>> +	ruleset_attr.handled_access_net = access_net_tcp;
>> +
>>   	ruleset_fd =
>>   		landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
>>   	if (ruleset_fd < 0) {
>>   		perror("Failed to create a ruleset");
>>   		return 1;
>>   	}
>> -	if (populate_ruleset(ENV_FS_RO_NAME, ruleset_fd, access_fs_ro)) {
>> +	if (populate_ruleset_fs(ENV_FS_RO_NAME, ruleset_fd, access_fs_ro)) {
>> +		goto err_close_ruleset;
>> +	}
>> +	if (populate_ruleset_fs(ENV_FS_RW_NAME, ruleset_fd, access_fs_rw)) {
>> +		goto err_close_ruleset;
>> +	}
>> +	if (populate_ruleset_net(ENV_TCP_BIND_NAME, ruleset_fd,
>> +				 LANDLOCK_ACCESS_NET_BIND_TCP)) {
>>   		goto err_close_ruleset;
>>   	}
>> -	if (populate_ruleset(ENV_FS_RW_NAME, ruleset_fd, access_fs_rw)) {
>> +	if (populate_ruleset_net(ENV_TCP_CONNECT_NAME, ruleset_fd,
>> +				 LANDLOCK_ACCESS_NET_CONNECT_TCP)) {
>>   		goto err_close_ruleset;
>>   	}
>>   	if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
>> --
>> 2.25.1
>> 
> .

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 00/17] Network support for Landlock
  2022-07-27 19:54   ` Mickaël Salaün
  2022-07-28  9:19     ` Konstantin Meskhidze (A)
@ 2022-07-28  9:25     ` Konstantin Meskhidze (A)
  2022-07-28 10:12       ` Mickaël Salaün
  2022-07-28 13:17     ` Mickaël Salaün
  2 siblings, 1 reply; 53+ messages in thread
From: Konstantin Meskhidze (A) @ 2022-07-28  9:25 UTC (permalink / raw)
  To: Mickaël Salaün
  Cc: willemdebruijn.kernel, linux-security-module, netdev,
	netfilter-devel, yusongping, anton.sirazetdinov



7/27/2022 10:54 PM, Mickaël Salaün пишет:
> 
> 
> On 26/07/2022 19:43, Mickaël Salaün wrote:
>> 
>> On 21/06/2022 10:22, Konstantin Meskhidze wrote:
>>> Hi,
>>> This is a new V6 patch related to Landlock LSM network confinement.
>>> It is based on the latest landlock-wip branch on top of v5.19-rc2:
>>> https://git.kernel.org/pub/scm/linux/kernel/git/mic/linux.git/log/?h=landlock-wip
>>>
>>> It brings refactoring of previous patch version V5:
>>>      - Fixes some logic errors and typos.
>>>      - Adds additional FIXTURE_VARIANT and FIXTURE_VARIANT_ADD helpers
>>>      to support both ip4 and ip6 families and shorten seltests' code.
>>>      - Makes TCP sockets confinement support optional in sandboxer demo.
>>>      - Formats the code with clang-format-14
>>>
>>> All test were run in QEMU evironment and compiled with
>>>   -static flag.
>>>   1. network_test: 18/18 tests passed.
>>>   2. base_test: 7/7 tests passed.
>>>   3. fs_test: 59/59 tests passed.
>>>   4. ptrace_test: 8/8 tests passed.
>>>
>>> Still have issue with base_test were compiled without -static flag
>>> (landlock-wip branch without network support)
>>> 1. base_test: 6/7 tests passed.
>>>   Error:
>>>   #  RUN           global.inconsistent_attr ...
>>>   # base_test.c:54:inconsistent_attr:Expected ENOMSG (42) == errno (22)
>>>   # inconsistent_attr: Test terminated by assertion
>>>   #          FAIL  global.inconsistent_attr
>>> not ok 1 global.inconsistent_attr
>>>
>>> LCOV - code coverage report:
>>>              Hit  Total  Coverage
>>> Lines:      952  1010    94.3 %
>>> Functions:  79   82      96.3 %
>>>
>>> Previous versions:
>>> v5: 
>>> https://lore.kernel.org/linux-security-module/20220516152038.39594-1-konstantin.meskhidze@huawei.com
>>> v4: 
>>> https://lore.kernel.org/linux-security-module/20220309134459.6448-1-konstantin.meskhidze@huawei.com/
>>> v3: 
>>> https://lore.kernel.org/linux-security-module/20220124080215.265538-1-konstantin.meskhidze@huawei.com/
>>> v2: 
>>> https://lore.kernel.org/linux-security-module/20211228115212.703084-1-konstantin.meskhidze@huawei.com/
>>> v1: 
>>> https://lore.kernel.org/linux-security-module/20211210072123.386713-1-konstantin.meskhidze@huawei.com/
>>>
>>> Konstantin Meskhidze (17):
>>>    landlock: renames access mask
>>>    landlock: refactors landlock_find/insert_rule
>>>    landlock: refactors merge and inherit functions
>>>    landlock: moves helper functions
>>>    landlock: refactors helper functions
>>>    landlock: refactors landlock_add_rule syscall
>>>    landlock: user space API network support
>>>    landlock: adds support network rules
>>>    landlock: implements TCP network hooks
>>>    seltests/landlock: moves helper function
>>>    seltests/landlock: adds tests for bind() hooks
>>>    seltests/landlock: adds tests for connect() hooks
>>>    seltests/landlock: adds AF_UNSPEC family test
>>>    seltests/landlock: adds rules overlapping test
>>>    seltests/landlock: adds ruleset expanding test
>>>    seltests/landlock: adds invalid input data test
>>>    samples/landlock: adds network demo
>>>
>>>   include/uapi/linux/landlock.h               |  49 ++
>>>   samples/landlock/sandboxer.c                | 118 ++-
>>>   security/landlock/Kconfig                   |   1 +
>>>   security/landlock/Makefile                  |   2 +
>>>   security/landlock/fs.c                      | 162 +---
>>>   security/landlock/limits.h                  |   8 +-
>>>   security/landlock/net.c                     | 155 ++++
>>>   security/landlock/net.h                     |  26 +
>>>   security/landlock/ruleset.c                 | 448 +++++++++--
>>>   security/landlock/ruleset.h                 |  91 ++-
>>>   security/landlock/setup.c                   |   2 +
>>>   security/landlock/syscalls.c                | 168 +++--
>>>   tools/testing/selftests/landlock/common.h   |  10 +
>>>   tools/testing/selftests/landlock/config     |   4 +
>>>   tools/testing/selftests/landlock/fs_test.c  |  10 -
>>>   tools/testing/selftests/landlock/net_test.c | 774 ++++++++++++++++++++
>>>   16 files changed, 1737 insertions(+), 291 deletions(-)
>>>   create mode 100644 security/landlock/net.c
>>>   create mode 100644 security/landlock/net.h
>>>   create mode 100644 tools/testing/selftests/landlock/net_test.c
>>>
>>> -- 
>>> 2.25.1
>>>
>> 
>> I did a thorough review of all the code. I found that the main issue 
>> with this version is that we stick to the layers limit whereas it is 
>> only relevant for filesystem hierarchies. You'll find in the following 
>> patch miscellaneous fixes and improvement, with some TODOs to get rid of 
>> this layer limit. We'll need a test to check that too. You'll need to 
>> integrate this diff into your patches though.
> 
> You can find the related patch here:
> https://git.kernel.org/mic/c/8f4104b3dc59e7f110c9b83cdf034d010a2d006f

  Is this patch based on your updated landlock-wip branch or it's still 
on Linux 5.19-rc2 version?
> .

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 00/17] Network support for Landlock
  2022-07-28  9:25     ` Konstantin Meskhidze (A)
@ 2022-07-28 10:12       ` Mickaël Salaün
  2022-07-28 11:27         ` Konstantin Meskhidze (A)
  0 siblings, 1 reply; 53+ messages in thread
From: Mickaël Salaün @ 2022-07-28 10:12 UTC (permalink / raw)
  To: Konstantin Meskhidze (A)
  Cc: willemdebruijn.kernel, linux-security-module, netdev,
	netfilter-devel, yusongping, anton.sirazetdinov



On 28/07/2022 11:25, Konstantin Meskhidze (A) wrote:
> 
> 
> 7/27/2022 10:54 PM, Mickaël Salaün пишет:
>>
>>
>> On 26/07/2022 19:43, Mickaël Salaün wrote:
>>>
>>> On 21/06/2022 10:22, Konstantin Meskhidze wrote:
>>>> Hi,
>>>> This is a new V6 patch related to Landlock LSM network confinement.
>>>> It is based on the latest landlock-wip branch on top of v5.19-rc2:
>>>> https://git.kernel.org/pub/scm/linux/kernel/git/mic/linux.git/log/?h=landlock-wip
>>>>
>>>> It brings refactoring of previous patch version V5:
>>>>      - Fixes some logic errors and typos.
>>>>      - Adds additional FIXTURE_VARIANT and FIXTURE_VARIANT_ADD helpers
>>>>      to support both ip4 and ip6 families and shorten seltests' code.
>>>>      - Makes TCP sockets confinement support optional in sandboxer 
>>>> demo.
>>>>      - Formats the code with clang-format-14
>>>>
>>>> All test were run in QEMU evironment and compiled with
>>>>   -static flag.
>>>>   1. network_test: 18/18 tests passed.
>>>>   2. base_test: 7/7 tests passed.
>>>>   3. fs_test: 59/59 tests passed.
>>>>   4. ptrace_test: 8/8 tests passed.
>>>>
>>>> Still have issue with base_test were compiled without -static flag
>>>> (landlock-wip branch without network support)
>>>> 1. base_test: 6/7 tests passed.
>>>>   Error:
>>>>   #  RUN           global.inconsistent_attr ...
>>>>   # base_test.c:54:inconsistent_attr:Expected ENOMSG (42) == errno (22)
>>>>   # inconsistent_attr: Test terminated by assertion
>>>>   #          FAIL  global.inconsistent_attr
>>>> not ok 1 global.inconsistent_attr
>>>>
>>>> LCOV - code coverage report:
>>>>              Hit  Total  Coverage
>>>> Lines:      952  1010    94.3 %
>>>> Functions:  79   82      96.3 %
>>>>
>>>> Previous versions:
>>>> v5: 
>>>> https://lore.kernel.org/linux-security-module/20220516152038.39594-1-konstantin.meskhidze@huawei.com
>>>> v4: 
>>>> https://lore.kernel.org/linux-security-module/20220309134459.6448-1-konstantin.meskhidze@huawei.com/
>>>> v3: 
>>>> https://lore.kernel.org/linux-security-module/20220124080215.265538-1-konstantin.meskhidze@huawei.com/
>>>> v2: 
>>>> https://lore.kernel.org/linux-security-module/20211228115212.703084-1-konstantin.meskhidze@huawei.com/
>>>> v1: 
>>>> https://lore.kernel.org/linux-security-module/20211210072123.386713-1-konstantin.meskhidze@huawei.com/
>>>>
>>>> Konstantin Meskhidze (17):
>>>>    landlock: renames access mask
>>>>    landlock: refactors landlock_find/insert_rule
>>>>    landlock: refactors merge and inherit functions
>>>>    landlock: moves helper functions
>>>>    landlock: refactors helper functions
>>>>    landlock: refactors landlock_add_rule syscall
>>>>    landlock: user space API network support
>>>>    landlock: adds support network rules
>>>>    landlock: implements TCP network hooks
>>>>    seltests/landlock: moves helper function
>>>>    seltests/landlock: adds tests for bind() hooks
>>>>    seltests/landlock: adds tests for connect() hooks
>>>>    seltests/landlock: adds AF_UNSPEC family test
>>>>    seltests/landlock: adds rules overlapping test
>>>>    seltests/landlock: adds ruleset expanding test
>>>>    seltests/landlock: adds invalid input data test
>>>>    samples/landlock: adds network demo
>>>>
>>>>   include/uapi/linux/landlock.h               |  49 ++
>>>>   samples/landlock/sandboxer.c                | 118 ++-
>>>>   security/landlock/Kconfig                   |   1 +
>>>>   security/landlock/Makefile                  |   2 +
>>>>   security/landlock/fs.c                      | 162 +---
>>>>   security/landlock/limits.h                  |   8 +-
>>>>   security/landlock/net.c                     | 155 ++++
>>>>   security/landlock/net.h                     |  26 +
>>>>   security/landlock/ruleset.c                 | 448 +++++++++--
>>>>   security/landlock/ruleset.h                 |  91 ++-
>>>>   security/landlock/setup.c                   |   2 +
>>>>   security/landlock/syscalls.c                | 168 +++--
>>>>   tools/testing/selftests/landlock/common.h   |  10 +
>>>>   tools/testing/selftests/landlock/config     |   4 +
>>>>   tools/testing/selftests/landlock/fs_test.c  |  10 -
>>>>   tools/testing/selftests/landlock/net_test.c | 774 
>>>> ++++++++++++++++++++
>>>>   16 files changed, 1737 insertions(+), 291 deletions(-)
>>>>   create mode 100644 security/landlock/net.c
>>>>   create mode 100644 security/landlock/net.h
>>>>   create mode 100644 tools/testing/selftests/landlock/net_test.c
>>>>
>>>> -- 
>>>> 2.25.1
>>>>
>>>
>>> I did a thorough review of all the code. I found that the main issue 
>>> with this version is that we stick to the layers limit whereas it is 
>>> only relevant for filesystem hierarchies. You'll find in the 
>>> following patch miscellaneous fixes and improvement, with some TODOs 
>>> to get rid of this layer limit. We'll need a test to check that too. 
>>> You'll need to integrate this diff into your patches though.
>>
>> You can find the related patch here:
>> https://git.kernel.org/mic/c/8f4104b3dc59e7f110c9b83cdf034d010a2d006f
> 
>   Is this patch based on your updated landlock-wip branch or it's still 
> on Linux 5.19-rc2 version?

It's based on v5.19-rc2 but it doesn't really matter. I removed the 
landlock-wip branch, which is not needed anymore. You can base your 
patches on Linus' master branch.

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 00/17] Network support for Landlock
  2022-07-28 10:12       ` Mickaël Salaün
@ 2022-07-28 11:27         ` Konstantin Meskhidze (A)
  0 siblings, 0 replies; 53+ messages in thread
From: Konstantin Meskhidze (A) @ 2022-07-28 11:27 UTC (permalink / raw)
  To: Mickaël Salaün
  Cc: willemdebruijn.kernel, linux-security-module, netdev,
	netfilter-devel, yusongping, anton.sirazetdinov



7/28/2022 1:12 PM, Mickaël Salaün пишет:
> 
> 
> On 28/07/2022 11:25, Konstantin Meskhidze (A) wrote:
>> 
>> 
>> 7/27/2022 10:54 PM, Mickaël Salaün пишет:
>>>
>>>
>>> On 26/07/2022 19:43, Mickaël Salaün wrote:
>>>>
>>>> On 21/06/2022 10:22, Konstantin Meskhidze wrote:
>>>>> Hi,
>>>>> This is a new V6 patch related to Landlock LSM network confinement.
>>>>> It is based on the latest landlock-wip branch on top of v5.19-rc2:
>>>>> https://git.kernel.org/pub/scm/linux/kernel/git/mic/linux.git/log/?h=landlock-wip
>>>>>
>>>>> It brings refactoring of previous patch version V5:
>>>>>      - Fixes some logic errors and typos.
>>>>>      - Adds additional FIXTURE_VARIANT and FIXTURE_VARIANT_ADD helpers
>>>>>      to support both ip4 and ip6 families and shorten seltests' code.
>>>>>      - Makes TCP sockets confinement support optional in sandboxer 
>>>>> demo.
>>>>>      - Formats the code with clang-format-14
>>>>>
>>>>> All test were run in QEMU evironment and compiled with
>>>>>   -static flag.
>>>>>   1. network_test: 18/18 tests passed.
>>>>>   2. base_test: 7/7 tests passed.
>>>>>   3. fs_test: 59/59 tests passed.
>>>>>   4. ptrace_test: 8/8 tests passed.
>>>>>
>>>>> Still have issue with base_test were compiled without -static flag
>>>>> (landlock-wip branch without network support)
>>>>> 1. base_test: 6/7 tests passed.
>>>>>   Error:
>>>>>   #  RUN           global.inconsistent_attr ...
>>>>>   # base_test.c:54:inconsistent_attr:Expected ENOMSG (42) == errno (22)
>>>>>   # inconsistent_attr: Test terminated by assertion
>>>>>   #          FAIL  global.inconsistent_attr
>>>>> not ok 1 global.inconsistent_attr
>>>>>
>>>>> LCOV - code coverage report:
>>>>>              Hit  Total  Coverage
>>>>> Lines:      952  1010    94.3 %
>>>>> Functions:  79   82      96.3 %
>>>>>
>>>>> Previous versions:
>>>>> v5: 
>>>>> https://lore.kernel.org/linux-security-module/20220516152038.39594-1-konstantin.meskhidze@huawei.com
>>>>> v4: 
>>>>> https://lore.kernel.org/linux-security-module/20220309134459.6448-1-konstantin.meskhidze@huawei.com/
>>>>> v3: 
>>>>> https://lore.kernel.org/linux-security-module/20220124080215.265538-1-konstantin.meskhidze@huawei.com/
>>>>> v2: 
>>>>> https://lore.kernel.org/linux-security-module/20211228115212.703084-1-konstantin.meskhidze@huawei.com/
>>>>> v1: 
>>>>> https://lore.kernel.org/linux-security-module/20211210072123.386713-1-konstantin.meskhidze@huawei.com/
>>>>>
>>>>> Konstantin Meskhidze (17):
>>>>>    landlock: renames access mask
>>>>>    landlock: refactors landlock_find/insert_rule
>>>>>    landlock: refactors merge and inherit functions
>>>>>    landlock: moves helper functions
>>>>>    landlock: refactors helper functions
>>>>>    landlock: refactors landlock_add_rule syscall
>>>>>    landlock: user space API network support
>>>>>    landlock: adds support network rules
>>>>>    landlock: implements TCP network hooks
>>>>>    seltests/landlock: moves helper function
>>>>>    seltests/landlock: adds tests for bind() hooks
>>>>>    seltests/landlock: adds tests for connect() hooks
>>>>>    seltests/landlock: adds AF_UNSPEC family test
>>>>>    seltests/landlock: adds rules overlapping test
>>>>>    seltests/landlock: adds ruleset expanding test
>>>>>    seltests/landlock: adds invalid input data test
>>>>>    samples/landlock: adds network demo
>>>>>
>>>>>   include/uapi/linux/landlock.h               |  49 ++
>>>>>   samples/landlock/sandboxer.c                | 118 ++-
>>>>>   security/landlock/Kconfig                   |   1 +
>>>>>   security/landlock/Makefile                  |   2 +
>>>>>   security/landlock/fs.c                      | 162 +---
>>>>>   security/landlock/limits.h                  |   8 +-
>>>>>   security/landlock/net.c                     | 155 ++++
>>>>>   security/landlock/net.h                     |  26 +
>>>>>   security/landlock/ruleset.c                 | 448 +++++++++--
>>>>>   security/landlock/ruleset.h                 |  91 ++-
>>>>>   security/landlock/setup.c                   |   2 +
>>>>>   security/landlock/syscalls.c                | 168 +++--
>>>>>   tools/testing/selftests/landlock/common.h   |  10 +
>>>>>   tools/testing/selftests/landlock/config     |   4 +
>>>>>   tools/testing/selftests/landlock/fs_test.c  |  10 -
>>>>>   tools/testing/selftests/landlock/net_test.c | 774 
>>>>> ++++++++++++++++++++
>>>>>   16 files changed, 1737 insertions(+), 291 deletions(-)
>>>>>   create mode 100644 security/landlock/net.c
>>>>>   create mode 100644 security/landlock/net.h
>>>>>   create mode 100644 tools/testing/selftests/landlock/net_test.c
>>>>>
>>>>> -- 
>>>>> 2.25.1
>>>>>
>>>>
>>>> I did a thorough review of all the code. I found that the main issue 
>>>> with this version is that we stick to the layers limit whereas it is 
>>>> only relevant for filesystem hierarchies. You'll find in the 
>>>> following patch miscellaneous fixes and improvement, with some TODOs 
>>>> to get rid of this layer limit. We'll need a test to check that too. 
>>>> You'll need to integrate this diff into your patches though.
>>>
>>> You can find the related patch here:
>>> https://git.kernel.org/mic/c/8f4104b3dc59e7f110c9b83cdf034d010a2d006f
>> 
>>   Is this patch based on your updated landlock-wip branch or it's still 
>> on Linux 5.19-rc2 version?
> 
> It's based on v5.19-rc2 but it doesn't really matter. I removed the
> landlock-wip branch, which is not needed anymore. You can base your
> patches on Linus' master branch.

   Ok. Thank you.
> .

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 00/17] Network support for Landlock
  2022-07-27 19:54   ` Mickaël Salaün
  2022-07-28  9:19     ` Konstantin Meskhidze (A)
  2022-07-28  9:25     ` Konstantin Meskhidze (A)
@ 2022-07-28 13:17     ` Mickaël Salaün
  2022-08-23  9:10       ` Konstantin Meskhidze (A)
  2022-08-27 13:30       ` Konstantin Meskhidze (A)
  2 siblings, 2 replies; 53+ messages in thread
From: Mickaël Salaün @ 2022-07-28 13:17 UTC (permalink / raw)
  To: Konstantin Meskhidze
  Cc: willemdebruijn.kernel, linux-security-module, netdev,
	netfilter-devel, yusongping, anton.sirazetdinov


On 27/07/2022 21:54, Mickaël Salaün wrote:
> 
> 
> On 26/07/2022 19:43, Mickaël Salaün wrote:
>>
>> On 21/06/2022 10:22, Konstantin Meskhidze wrote:
>>> Hi,
>>> This is a new V6 patch related to Landlock LSM network confinement.
>>> It is based on the latest landlock-wip branch on top of v5.19-rc2:
>>> https://git.kernel.org/pub/scm/linux/kernel/git/mic/linux.git/log/?h=landlock-wip
>>>
>>> It brings refactoring of previous patch version V5:
>>>       - Fixes some logic errors and typos.
>>>       - Adds additional FIXTURE_VARIANT and FIXTURE_VARIANT_ADD helpers
>>>       to support both ip4 and ip6 families and shorten seltests' code.
>>>       - Makes TCP sockets confinement support optional in sandboxer demo.
>>>       - Formats the code with clang-format-14
>>>
>>> All test were run in QEMU evironment and compiled with
>>>    -static flag.
>>>    1. network_test: 18/18 tests passed.
>>>    2. base_test: 7/7 tests passed.
>>>    3. fs_test: 59/59 tests passed.
>>>    4. ptrace_test: 8/8 tests passed.
>>>
>>> Still have issue with base_test were compiled without -static flag
>>> (landlock-wip branch without network support)
>>> 1. base_test: 6/7 tests passed.
>>>    Error:
>>>    #  RUN           global.inconsistent_attr ...
>>>    # base_test.c:54:inconsistent_attr:Expected ENOMSG (42) == errno (22)
>>>    # inconsistent_attr: Test terminated by assertion
>>>    #          FAIL  global.inconsistent_attr
>>> not ok 1 global.inconsistent_attr
>>>
>>> LCOV - code coverage report:
>>>               Hit  Total  Coverage
>>> Lines:      952  1010    94.3 %
>>> Functions:  79   82      96.3 %
>>>
>>> Previous versions:
>>> v5:
>>> https://lore.kernel.org/linux-security-module/20220516152038.39594-1-konstantin.meskhidze@huawei.com
>>> v4:
>>> https://lore.kernel.org/linux-security-module/20220309134459.6448-1-konstantin.meskhidze@huawei.com/
>>> v3:
>>> https://lore.kernel.org/linux-security-module/20220124080215.265538-1-konstantin.meskhidze@huawei.com/
>>> v2:
>>> https://lore.kernel.org/linux-security-module/20211228115212.703084-1-konstantin.meskhidze@huawei.com/
>>> v1:
>>> https://lore.kernel.org/linux-security-module/20211210072123.386713-1-konstantin.meskhidze@huawei.com/
>>>
>>> Konstantin Meskhidze (17):
>>>     landlock: renames access mask
>>>     landlock: refactors landlock_find/insert_rule
>>>     landlock: refactors merge and inherit functions
>>>     landlock: moves helper functions
>>>     landlock: refactors helper functions
>>>     landlock: refactors landlock_add_rule syscall
>>>     landlock: user space API network support
>>>     landlock: adds support network rules
>>>     landlock: implements TCP network hooks
>>>     seltests/landlock: moves helper function
>>>     seltests/landlock: adds tests for bind() hooks
>>>     seltests/landlock: adds tests for connect() hooks
>>>     seltests/landlock: adds AF_UNSPEC family test
>>>     seltests/landlock: adds rules overlapping test
>>>     seltests/landlock: adds ruleset expanding test
>>>     seltests/landlock: adds invalid input data test
>>>     samples/landlock: adds network demo
>>>
>>>    include/uapi/linux/landlock.h               |  49 ++
>>>    samples/landlock/sandboxer.c                | 118 ++-
>>>    security/landlock/Kconfig                   |   1 +
>>>    security/landlock/Makefile                  |   2 +
>>>    security/landlock/fs.c                      | 162 +---
>>>    security/landlock/limits.h                  |   8 +-
>>>    security/landlock/net.c                     | 155 ++++
>>>    security/landlock/net.h                     |  26 +
>>>    security/landlock/ruleset.c                 | 448 +++++++++--
>>>    security/landlock/ruleset.h                 |  91 ++-
>>>    security/landlock/setup.c                   |   2 +
>>>    security/landlock/syscalls.c                | 168 +++--
>>>    tools/testing/selftests/landlock/common.h   |  10 +
>>>    tools/testing/selftests/landlock/config     |   4 +
>>>    tools/testing/selftests/landlock/fs_test.c  |  10 -
>>>    tools/testing/selftests/landlock/net_test.c | 774 ++++++++++++++++++++
>>>    16 files changed, 1737 insertions(+), 291 deletions(-)
>>>    create mode 100644 security/landlock/net.c
>>>    create mode 100644 security/landlock/net.h
>>>    create mode 100644 tools/testing/selftests/landlock/net_test.c
>>>
>>> -- 
>>> 2.25.1
>>>
>>
>> I did a thorough review of all the code. I found that the main issue
>> with this version is that we stick to the layers limit whereas it is
>> only relevant for filesystem hierarchies. You'll find in the following
>> patch miscellaneous fixes and improvement, with some TODOs to get rid of
>> this layer limit. We'll need a test to check that too. You'll need to
>> integrate this diff into your patches though.
> 
> You can find the related patch here:
> https://git.kernel.org/mic/c/8f4104b3dc59e7f110c9b83cdf034d010a2d006f

Thinking more about the layer limit, I think you should keep your
changes and continue using ruleset.access_masks . Indeed, while it might
be a good thing to not be limited by the 16 layers, it would be an issue
with the upcoming audit feature, i.e. being able to point to the ruleset
responsible for a denied access. Here is a new patch (on top of the
other) to improve the current code:
https://git.kernel.org/mic/c/7d6cf40a6f81adf607ad3cc17aaa11e256beeea4


* Add a new access_masks_t for struct ruleset.  This is now u16 but
   would soon need to change to u32 (because of the upcoming
   LANDLOCK_ACCESS_FS_TRUNCATE).  Set back rules' access_masks_t to u16,
   it should be enough for a while.
* Rename LANDLOCK_MASK_SHIFT_NET to LANDLOCK_SHIFT_ACCESS_NET and use
   LANDLOCK_NUM_ACCESS_FS as value.
* Rename landlock_set_*_access_mask() to landlock_add_*_access_mask()
   because it OR values.
* Make landlock_add_*_access_mask() more resilient incorrect values.
* Rename some variable to make them more consistent with the rest of the
   code.
* Add and update kernel documentation.
* Remove unused code.
---
  security/landlock/limits.h  |   8 +-
  security/landlock/ruleset.c |  31 +++-----
  security/landlock/ruleset.h | 150 +++++++++++++++++++++---------------
  3 files changed, 105 insertions(+), 84 deletions(-)

diff --git a/security/landlock/limits.h b/security/landlock/limits.h
index 660335258466..e50a12c1b797 100644
--- a/security/landlock/limits.h
+++ b/security/landlock/limits.h
@@ -21,15 +21,13 @@
  #define LANDLOCK_LAST_ACCESS_FS		LANDLOCK_ACCESS_FS_REFER
  #define LANDLOCK_MASK_ACCESS_FS		((LANDLOCK_LAST_ACCESS_FS << 1) - 1)
  #define LANDLOCK_NUM_ACCESS_FS		__const_hweight64(LANDLOCK_MASK_ACCESS_FS)
+#define LANDLOCK_SHIFT_ACCESS_FS	0
  
  #define LANDLOCK_LAST_ACCESS_NET	LANDLOCK_ACCESS_NET_CONNECT_TCP
  #define LANDLOCK_MASK_ACCESS_NET	((LANDLOCK_LAST_ACCESS_NET << 1) - 1)
  #define LANDLOCK_NUM_ACCESS_NET		__const_hweight64(LANDLOCK_MASK_ACCESS_NET)
-// TODO: LANDLOCK_MASK_SHIFT_NET will not be useful with the new
-// ruleset->net_access_mask
-#define LANDLOCK_MASK_SHIFT_NET		16
-
-#define LANDLOCK_RULE_TYPE_NUM		LANDLOCK_RULE_NET_SERVICE
+#define LANDLOCK_SHIFT_ACCESS_NET	LANDLOCK_NUM_ACCESS_FS
  
  /* clang-format on */
+
  #endif /* _SECURITY_LANDLOCK_LIMITS_H */
diff --git a/security/landlock/ruleset.c b/security/landlock/ruleset.c
index e7555b16069a..1b3433ea4c61 100644
--- a/security/landlock/ruleset.c
+++ b/security/landlock/ruleset.c
@@ -47,21 +47,21 @@ static struct landlock_ruleset *create_ruleset(const u32 num_layers)
  }
  
  struct landlock_ruleset *
-landlock_create_ruleset(const access_mask_t access_mask_fs,
-			const access_mask_t access_mask_net)
+landlock_create_ruleset(const access_mask_t fs_access_mask,
+			const access_mask_t net_access_mask)
  {
  	struct landlock_ruleset *new_ruleset;
  
  	/* Informs about useless ruleset. */
-	if (!access_mask_fs && !access_mask_net)
+	if (!fs_access_mask && !net_access_mask)
  		return ERR_PTR(-ENOMSG);
  	new_ruleset = create_ruleset(1);
  	if (IS_ERR(new_ruleset))
  		return new_ruleset;
-	if (access_mask_fs)
-		landlock_set_fs_access_mask(new_ruleset, access_mask_fs, 0);
-	if (access_mask_net)
-		landlock_set_net_access_mask(new_ruleset, access_mask_net, 0);
+	if (fs_access_mask)
+		landlock_add_fs_access_mask(new_ruleset, fs_access_mask, 0);
+	if (net_access_mask)
+		landlock_add_net_access_mask(new_ruleset, net_access_mask, 0);
  	return new_ruleset;
  }
  
@@ -160,13 +160,14 @@ static void build_check_ruleset(void)
  		.num_rules = ~0,
  		.num_layers = ~0,
  	};
-	typeof(ruleset.access_masks[0]) fs_access_mask = ~0;
-	typeof(ruleset.access_masks[0]) net_access_mask = ~0;
+	typeof(ruleset.access_masks[0]) access_masks = ~0;
  
  	BUILD_BUG_ON(ruleset.num_rules < LANDLOCK_MAX_NUM_RULES);
  	BUILD_BUG_ON(ruleset.num_layers < LANDLOCK_MAX_NUM_LAYERS);
-	BUILD_BUG_ON(fs_access_mask < LANDLOCK_MASK_ACCESS_FS);
-	BUILD_BUG_ON(net_access_mask < LANDLOCK_MASK_ACCESS_NET);
+	BUILD_BUG_ON(access_masks <
+		     (LANDLOCK_MASK_ACCESS_FS << LANDLOCK_SHIFT_ACCESS_FS) +
+			     (LANDLOCK_MASK_ACCESS_NET
+			      << LANDLOCK_SHIFT_ACCESS_NET));
  }
  
  /**
@@ -250,8 +251,6 @@ static int insert_rule(struct landlock_ruleset *const ruleset,
  		 * Intersects access rights when it is a merge between a
  		 * ruleset and a domain.
  		 */
-		// TODO: Don't create a new rule but AND accesses (of the first
-		// and only layer) if !is_object_pointer(id.type)
  		new_rule = create_rule(id, &this->layers, this->num_layers,
  				       &(*layers)[0]);
  		if (IS_ERR(new_rule))
@@ -332,7 +331,6 @@ static int merge_tree(struct landlock_ruleset *const dst,
  	rbtree_postorder_for_each_entry_safe(walker_rule, next_rule, src_root,
  					     node) {
  		struct landlock_layer layers[] = { {
-			// TODO: Set level to 1 if !is_object_pointer(key_type).
  			.level = dst->num_layers,
  		} };
  		const struct landlock_id id = {
@@ -531,7 +529,6 @@ landlock_merge_ruleset(struct landlock_ruleset *const parent,
  		if (parent->num_layers >= LANDLOCK_MAX_NUM_LAYERS)
  			return ERR_PTR(-E2BIG);
  		num_layers = parent->num_layers + 1;
-		// TODO: Don't increment num_layers if RB_EMPTY_ROOT(&ruleset->root_inode).
  	} else {
  		num_layers = 1;
  	}
@@ -698,10 +695,6 @@ access_mask_t init_layer_masks(const struct landlock_ruleset *const domain,
  
  	switch (key_type) {
  	case LANDLOCK_KEY_INODE:
-		// XXX: landlock_get_fs_access_mask() should not be removed
-		// once we use ruleset->net_access_mask, and we can then
-		// replace the @key_type argument with num_access to make the
-		// code simpler.
  		get_access_mask = landlock_get_fs_access_mask;
  		num_access = LANDLOCK_NUM_ACCESS_FS;
  		break;
diff --git a/security/landlock/ruleset.h b/security/landlock/ruleset.h
index 59229be378d6..669de66094ed 100644
--- a/security/landlock/ruleset.h
+++ b/security/landlock/ruleset.h
@@ -19,8 +19,8 @@
  #include "limits.h"
  #include "object.h"
  
-// TODO: get back to u16 thanks to ruleset->net_access_mask
-typedef u32 access_mask_t;
+/* Rule access mask. */
+typedef u16 access_mask_t;
  /* Makes sure all filesystem access rights can be stored. */
  static_assert(BITS_PER_TYPE(access_mask_t) >= LANDLOCK_NUM_ACCESS_FS);
  /* Makes sure all network access rights can be stored. */
@@ -28,6 +28,12 @@ static_assert(BITS_PER_TYPE(access_mask_t) >= LANDLOCK_NUM_ACCESS_NET);
  /* Makes sure for_each_set_bit() and for_each_clear_bit() calls are OK. */
  static_assert(sizeof(unsigned long) >= sizeof(access_mask_t));
  
+/* Ruleset access masks. */
+typedef u16 access_masks_t;
+/* Makes sure all ruleset access rights can be stored. */
+static_assert(BITS_PER_TYPE(access_masks_t) >=
+	      LANDLOCK_NUM_ACCESS_FS + LANDLOCK_NUM_ACCESS_NET);
+
  typedef u16 layer_mask_t;
  /* Makes sure all layers can be checked. */
  static_assert(BITS_PER_TYPE(layer_mask_t) >= LANDLOCK_MAX_NUM_LAYERS);
@@ -47,16 +53,33 @@ struct landlock_layer {
  	access_mask_t access;
  };
  
+/**
+ * union landlock_key - Key of a ruleset's red-black tree
+ */
  union landlock_key {
  	struct landlock_object *object;
  	uintptr_t data;
  };
  
+/**
+ * enum landlock_key_type - Type of &union landlock_key
+ */
  enum landlock_key_type {
+	/**
+	 * @LANDLOCK_KEY_INODE: Type of &landlock_ruleset.root_inode's node
+	 * keys.
+	 */
  	LANDLOCK_KEY_INODE = 1,
+	/**
+	 * @LANDLOCK_KEY_NET_PORT: Type of &landlock_ruleset.root_net_port's
+	 * node keys.
+	 */
  	LANDLOCK_KEY_NET_PORT = 2,
  };
  
+/**
+ * struct landlock_id - Unique rule identifier for a ruleset
+ */
  struct landlock_id {
  	union landlock_key key;
  	const enum landlock_key_type type;
@@ -113,15 +136,17 @@ struct landlock_hierarchy {
   */
  struct landlock_ruleset {
  	/**
-	 * @root: Root of a red-black tree containing &struct landlock_rule
-	 * nodes.  Once a ruleset is tied to a process (i.e. as a domain), this
-	 * tree is immutable until @usage reaches zero.
+	 * @root_inode: Root of a red-black tree containing &struct
+	 * landlock_rule nodes with inode object.  Once a ruleset is tied to a
+	 * process (i.e. as a domain), this tree is immutable until @usage
+	 * reaches zero.
  	 */
  	struct rb_root root_inode;
  	/**
-	 * @root_net_port: Root of a red-black tree containing object nodes
-	 * for network port. Once a ruleset is tied to a process (i.e. as a domain),
-	 * this tree is immutable until @usage reaches zero.
+	 * @root_net_port: Root of a red-black tree containing &struct
+	 * landlock_rule nodes with network port. Once a ruleset is tied to a
+	 * process (i.e. as a domain), this tree is immutable until @usage
+	 * reaches zero.
  	 */
  	struct rb_root root_net_port;
  	/**
@@ -162,32 +187,25 @@ struct landlock_ruleset {
  			 */
  			u32 num_layers;
  			/**
-			 * TODO: net_access_mask: Contains the subset of network
-			 * actions that are restricted by a ruleset.
-			 */
-			access_mask_t net_access_mask;
-			/**
-			 * @access_masks: Contains the subset of filesystem
-			 * actions that are restricted by a ruleset.  A domain
-			 * saves all layers of merged rulesets in a stack
-			 * (FAM), starting from the first layer to the last
-			 * one.  These layers are used when merging rulesets,
-			 * for user space backward compatibility (i.e.
-			 * future-proof), and to properly handle merged
+			 * @access_masks: Contains the subset of filesystem and
+			 * network actions that are restricted by a ruleset.
+			 * A domain saves all layers of merged rulesets in a
+			 * stack (FAM), starting from the first layer to the
+			 * last one.  These layers are used when merging
+			 * rulesets, for user space backward compatibility
+			 * (i.e. future-proof), and to properly handle merged
  			 * rulesets without overlapping access rights.  These
  			 * layers are set once and never changed for the
  			 * lifetime of the ruleset.
  			 */
-			// TODO: rename (back) to fs_access_mask because layers
-			// are only useful for file hierarchies.
-			access_mask_t access_masks[];
+			access_masks_t access_masks[];
  		};
  	};
  };
  
  struct landlock_ruleset *
-landlock_create_ruleset(const access_mask_t access_mask_fs,
-			const access_mask_t access_mask_net);
+landlock_create_ruleset(const access_mask_t fs_access_mask,
+			const access_mask_t net_access_mask);
  
  void landlock_put_ruleset(struct landlock_ruleset *const ruleset);
  void landlock_put_ruleset_deferred(struct landlock_ruleset *const ruleset);
@@ -210,41 +228,7 @@ static inline void landlock_get_ruleset(struct landlock_ruleset *const ruleset)
  		refcount_inc(&ruleset->usage);
  }
  
-// TODO: These helpers should not be required thanks to the new ruleset->net_access_mask.
-/* A helper function to set a filesystem mask. */
-static inline void
-landlock_set_fs_access_mask(struct landlock_ruleset *ruleset,
-			    const access_mask_t access_mask_fs, u16 mask_level)
-{
-	ruleset->access_masks[mask_level] = access_mask_fs;
-}
-
-/* A helper function to get a filesystem mask. */
-static inline u32
-landlock_get_fs_access_mask(const struct landlock_ruleset *ruleset,
-			    u16 mask_level)
-{
-	return (ruleset->access_masks[mask_level] & LANDLOCK_MASK_ACCESS_FS);
-}
-
-/* A helper function to set a network mask. */
-static inline void
-landlock_set_net_access_mask(struct landlock_ruleset *ruleset,
-			     const access_mask_t access_mask_net,
-			     u16 mask_level)
-{
-	ruleset->access_masks[mask_level] |=
-		(access_mask_net << LANDLOCK_MASK_SHIFT_NET);
-}
-
-/* A helper function to get a network mask. */
-static inline u32
-landlock_get_net_access_mask(const struct landlock_ruleset *ruleset,
-			     u16 mask_level)
-{
-	return (ruleset->access_masks[mask_level] >> LANDLOCK_MASK_SHIFT_NET);
-}
-
+// TODO: Remove if only relevant for fs.c
  access_mask_t get_handled_accesses(const struct landlock_ruleset *const domain,
  				   const u16 rule_type, const u16 num_access);
  
@@ -258,4 +242,50 @@ access_mask_t init_layer_masks(const struct landlock_ruleset *const domain,
  			       layer_mask_t (*const layer_masks)[],
  			       const enum landlock_key_type key_type);
  
+static inline void
+landlock_add_fs_access_mask(struct landlock_ruleset *const ruleset,
+			    const access_mask_t fs_access_mask,
+			    const u16 layer_level)
+{
+	access_mask_t fs_mask = fs_access_mask & LANDLOCK_MASK_ACCESS_FS;
+
+	/* Should already be checked in sys_landlock_create_ruleset(). */
+	WARN_ON_ONCE(fs_access_mask != fs_mask);
+	// TODO: Add tests to check "|=" and not "="
+	ruleset->access_masks[layer_level] |=
+		(fs_mask << LANDLOCK_SHIFT_ACCESS_FS);
+}
+
+static inline void
+landlock_add_net_access_mask(struct landlock_ruleset *const ruleset,
+			     const access_mask_t net_access_mask,
+			     const u16 layer_level)
+{
+	access_mask_t net_mask = net_access_mask & LANDLOCK_MASK_ACCESS_NET;
+
+	/* Should already be checked in sys_landlock_create_ruleset(). */
+	WARN_ON_ONCE(net_access_mask != net_mask);
+	// TODO: Add tests to check "|=" and not "="
+	ruleset->access_masks[layer_level] |=
+		(net_mask << LANDLOCK_SHIFT_ACCESS_NET);
+}
+
+static inline access_mask_t
+landlock_get_fs_access_mask(const struct landlock_ruleset *const ruleset,
+			    const u16 layer_level)
+{
+	return (ruleset->access_masks[layer_level] >>
+		LANDLOCK_SHIFT_ACCESS_FS) &
+	       LANDLOCK_MASK_ACCESS_FS;
+}
+
+static inline access_mask_t
+landlock_get_net_access_mask(const struct landlock_ruleset *const ruleset,
+			     const u16 layer_level)
+{
+	return (ruleset->access_masks[layer_level] >>
+		LANDLOCK_SHIFT_ACCESS_NET) &
+	       LANDLOCK_MASK_ACCESS_NET;
+}
+
  #endif /* _SECURITY_LANDLOCK_RULESET_H */

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 11/17] seltests/landlock: adds tests for bind() hooks
  2022-06-21  8:23 ` [PATCH v6 11/17] seltests/landlock: adds tests for bind() hooks Konstantin Meskhidze
@ 2022-07-28 13:24   ` Mickaël Salaün
  0 siblings, 0 replies; 53+ messages in thread
From: Mickaël Salaün @ 2022-07-28 13:24 UTC (permalink / raw)
  To: Konstantin Meskhidze
  Cc: willemdebruijn.kernel, linux-security-module, netdev,
	netfilter-devel, yusongping, anton.sirazetdinov


On 21/06/2022 10:23, Konstantin Meskhidze wrote:
> Adds selftests for bind() socket action.
> The first is with no landlock restrictions:
>      - bind without restrictions for ip4;
>      - bind without restrictions for ip6;
> The second ones is with mixed landlock rules:
>      - bind with restrictions for ip4;
>      - bind with restrictions for ip6;
> 
> Signed-off-by: Konstantin Meskhidze <konstantin.meskhidze@huawei.com>
> ---
> 
> Changes since v5:
> * Splits commit.
> * Adds local address 127.0.0.1.
> * Adds FIXTURE_VARIANT and FIXTURE_VARIANT_ADD
> helpers to support both ip4 and ip6 family tests and
> shorten the code.
> * Adds create_socket_variant() and bind_variant() helpers.
> * Gets rid of reuse_addr variable in create_socket_variant.
> * Formats code with clang-format-14.

It seems that a formatting pass is missing for FIXTURE_VARIANT().

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 02/17] landlock: refactors landlock_find/insert_rule
  2022-07-11 14:05             ` Konstantin Meskhidze (A)
@ 2022-07-28 14:48               ` Mickaël Salaün
  0 siblings, 0 replies; 53+ messages in thread
From: Mickaël Salaün @ 2022-07-28 14:48 UTC (permalink / raw)
  To: Konstantin Meskhidze (A)
  Cc: willemdebruijn.kernel, linux-security-module, netdev,
	netfilter-devel, yusongping, anton.sirazetdinov


On 11/07/2022 16:05, Konstantin Meskhidze (A) wrote:
> 
> 
> 7/8/2022 5:35 PM, Mickaël Salaün пишет:
>>
>> On 08/07/2022 16:14, Konstantin Meskhidze (A) wrote:
>>>
>>>
>>> 7/8/2022 4:59 PM, Mickaël Salaün пишет:
>>>>
>>>> On 08/07/2022 15:10, Konstantin Meskhidze (A) wrote:
>>>>>
>>>>>
>>>>> 7/7/2022 7:44 PM, Mickaël Salaün пишет:
>>>>>>
>>>>>> On 21/06/2022 10:22, Konstantin Meskhidze wrote:
>>>>>>> Adds a new object union to support a socket port
>>>>>>> rule type. Refactors landlock_insert_rule() and
>>>>>>> landlock_find_rule() to support coming network
>>>>>>> modifications. Now adding or searching a rule
>>>>>>> in a ruleset depends on a rule_type argument
>>>>>>> provided in refactored functions mentioned above.
>>>>>>>
>>>>>>> Signed-off-by: Konstantin Meskhidze <konstantin.meskhidze@huawei.com>
>>>>>>> ---
>>>>>>>
>>>>>>> Changes since v5:
>>>>>>> * Formats code with clang-format-14.
>>>>>>>
>>>>>>> Changes since v4:
>>>>>>> * Refactors insert_rule() and create_rule() functions by deleting
>>>>>>> rule_type from their arguments list, it helps to reduce useless code.
>>>>>>>
>>>>>>> Changes since v3:
>>>>>>> * Splits commit.
>>>>>>> * Refactors landlock_insert_rule and landlock_find_rule functions.
>>>>>>> * Rename new_ruleset->root_inode.
>>>>>>>
>>>>>>> ---
>>>>>>>    security/landlock/fs.c      |   7 ++-
>>>>>>>    security/landlock/ruleset.c | 105
>>>>>>> ++++++++++++++++++++++++++----------
>>>>>>>    security/landlock/ruleset.h |  27 +++++-----
>>>>>>>    3 files changed, 96 insertions(+), 43 deletions(-)
>>>>>>>
>>>>>>> diff --git a/security/landlock/fs.c b/security/landlock/fs.c
>>>>>>> index e6da08ed99d1..46aedc2a05a8 100644
>>>>>>> --- a/security/landlock/fs.c
>>>>>>> +++ b/security/landlock/fs.c
>>>>>>> @@ -173,7 +173,8 @@ int landlock_append_fs_rule(struct
>>>>>>> landlock_ruleset *const ruleset,
>>>>>>>        if (IS_ERR(object))
>>>>>>>            return PTR_ERR(object);
>>>>>>>        mutex_lock(&ruleset->lock);
>>>>>>> -    err = landlock_insert_rule(ruleset, object, access_rights);
>>>>>>> +    err = landlock_insert_rule(ruleset, object, 0, access_rights,
>>>>>>> +                   LANDLOCK_RULE_PATH_BENEATH);
>>>>>>>        mutex_unlock(&ruleset->lock);
>>>>>>>        /*
>>>>>>>         * No need to check for an error because landlock_insert_rule()
>>>>>>> @@ -204,7 +205,9 @@ find_rule(const struct landlock_ruleset *const
>>>>>>> domain,
>>>>>>>        inode = d_backing_inode(dentry);
>>>>>>>        rcu_read_lock();
>>>>>>>        rule = landlock_find_rule(
>>>>>>> -        domain, rcu_dereference(landlock_inode(inode)->object));
>>>>>>> +        domain,
>>>>>>> +        (uintptr_t)rcu_dereference(landlock_inode(inode)->object),
>>>>>>> +        LANDLOCK_RULE_PATH_BENEATH);
>>>>>>>        rcu_read_unlock();
>>>>>>>        return rule;
>>>>>>>    }
>>>>>>> diff --git a/security/landlock/ruleset.c b/security/landlock/ruleset.c
>>>>>>> index a3fd58d01f09..5f13f8a12aee 100644
>>>>>>> --- a/security/landlock/ruleset.c
>>>>>>> +++ b/security/landlock/ruleset.c
>>>>>>> @@ -35,7 +35,7 @@ static struct landlock_ruleset
>>>>>>> *create_ruleset(const u32 num_layers)
>>>>>>>            return ERR_PTR(-ENOMEM);
>>>>>>>        refcount_set(&new_ruleset->usage, 1);
>>>>>>>        mutex_init(&new_ruleset->lock);
>>>>>>> -    new_ruleset->root = RB_ROOT;
>>>>>>> +    new_ruleset->root_inode = RB_ROOT;
>>>>>>>        new_ruleset->num_layers = num_layers;
>>>>>>>        /*
>>>>>>>         * hierarchy = NULL
>>>>>>> @@ -69,7 +69,8 @@ static void build_check_rule(void)
>>>>>>>    }
>>>>>>>
>>>>>>>    static struct landlock_rule *
>>>>>>> -create_rule(struct landlock_object *const object,
>>>>>>> +create_rule(struct landlock_object *const object_ptr,
>>>>>>> +        const uintptr_t object_data,
>>>>>>>            const struct landlock_layer (*const layers)[], const u32
>>>>>>> num_layers,
>>>>>>>            const struct landlock_layer *const new_layer)
>>>>>>>    {
>>>>>>> @@ -90,8 +91,15 @@ create_rule(struct landlock_object *const object,
>>>>>>>        if (!new_rule)
>>>>>>>            return ERR_PTR(-ENOMEM);
>>>>>>>        RB_CLEAR_NODE(&new_rule->node);
>>>>>>> -    landlock_get_object(object);
>>>>>>> -    new_rule->object = object;
>>>>>>> +
>>>>>>> +    if (object_ptr) {
>>>>>>> +        landlock_get_object(object_ptr);
>>>>>>> +        new_rule->object.ptr = object_ptr;
>>>>>>> +    } else if (object_ptr && object_data) {
>>>>>>
>>>>>> Something is wrong with this second check: else + object_ptr?
>>>>>
>>>>>    Sorry. Do you mean logical error here? I got your point.
>>>>>    You are right!
>>>>>
>>>>>    I think it must be refactored like this:
>>>>>
>>>>>       if (object_ptr && !object_data) {
>>>>>           landlock_get_object(object_ptr);
>>>>>           new_rule->object.ptr = object_ptr;
>>>>>       } else if (object_ptr && object_data) {
>>>>>           ...
>>>>>       }
>>>>
>>>> There is indeed a logical error but this doesn't fix everything. Please
>>>> include my previous suggestion instead.
>>>>
>>>      By the way, in the next commits I have fixed this logic error.
>>> Anyway I will refactor this one also. Thanks.
>>>>
>>>>> Plus, I will add a test for this case.
>>>>
>>>> That would be great but I don't think this code is reachable from user
>>>> space. I think that would require kunit but I may be missing something.
>>>> How would you test this?
>>>
>>> You are correct. I checked it. It's impossible to reach this line from
>>> userpace (insert both object_ptr and object_data). But create_rule()
>>> must be used carefuly by other developers (if any in future). Do you
>>> think if its possible to have some internal kernel tests that could
>>> handle this issue?
>>
>> We can use kunit tests for such kernel functions, but in this case I'm
>> not sure what could be tested. I started working on bringing kunit tests
>> to Landlock but it's not ready yet. Please list all non-userspace tests
>> you can think about.
> 
>    I'm thinking about ones that we can't reach from the userspace.

Right, some lines cannot be reached by user space because they are logically
not possible but safety checks in case of unexpected kernel code modification
(which, unfortunately, cannot be done at build time).


>    I analyzed test coverage logs finding lines that are untouched by the
> userspace tests.
>    Let's discus this list:
> 
> 	1. create_rule():  - insert both  object_ptr and object_data.

This check is gone with my last patch.

> 
> 	2. insert_rule():  - insert both  object_ptr and object_data.

This check is gone with my last patch.


> 			   - insert NULL (*const layers).
> 			   - insert layers[0].level != 0.
> 			   - insert num_layers != 1.
> 			   - insert default rule_type.
> 	
> 	3. tree_merge():   - insert default rule_type.
> 			   - insert walker_rule->num_layers != 1.
> 			   - insert walker_rule->layers[0].level != 0.
> 	
> 	4. tree_copy():    - insert default rule_type.
> 	
> 	5. merge_ruleset:  - insert !dst || !dst->hierarchy.
> 			   - insert src->num_layers != 1 ||
>                                       dst->num_layers < 1.
> 
> 	6. inherit_ruleset(): - insert child->num_layers <=
> 				   parent->num_layers.
>    			      - insert parent->hierarchy = NULL.
> 
> 	7. landlock_merge_ruleset(): - insert ruleset = NULL.
> 				     - insert parent = ruleset
> 
> 	8. landlock_find_rule(): - insert default rule_type.
> 
>    Please your opinion?

All these checks are enclosed with WARN_ON_ONCE(). I'm not sure it will help
to add kunit tests for them. It could be interesting to add kunit test to
check the behavior of standalone helpers though, e.g. managing rulesets or
trees.

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 00/17] Network support for Landlock
  2022-07-28 13:17     ` Mickaël Salaün
@ 2022-08-23  9:10       ` Konstantin Meskhidze (A)
  2022-08-27 13:30       ` Konstantin Meskhidze (A)
  1 sibling, 0 replies; 53+ messages in thread
From: Konstantin Meskhidze (A) @ 2022-08-23  9:10 UTC (permalink / raw)
  To: Mickaël Salaün
  Cc: willemdebruijn.kernel, linux-security-module, netdev,
	netfilter-devel, anton.sirazetdinov



7/28/2022 4:17 PM, Mickaël Salaün пишет:
> 
> On 27/07/2022 21:54, Mickaël Salaün wrote:
>> 
>> 
>> On 26/07/2022 19:43, Mickaël Salaün wrote:
>>>
>>> On 21/06/2022 10:22, Konstantin Meskhidze wrote:
>>>> Hi,
>>>> This is a new V6 patch related to Landlock LSM network confinement.
>>>> It is based on the latest landlock-wip branch on top of v5.19-rc2:
>>>> https://git.kernel.org/pub/scm/linux/kernel/git/mic/linux.git/log/?h=landlock-wip
>>>>
>>>> It brings refactoring of previous patch version V5:
>>>>       - Fixes some logic errors and typos.
>>>>       - Adds additional FIXTURE_VARIANT and FIXTURE_VARIANT_ADD helpers
>>>>       to support both ip4 and ip6 families and shorten seltests' code.
>>>>       - Makes TCP sockets confinement support optional in sandboxer demo.
>>>>       - Formats the code with clang-format-14
>>>>
>>>> All test were run in QEMU evironment and compiled with
>>>>    -static flag.
>>>>    1. network_test: 18/18 tests passed.
>>>>    2. base_test: 7/7 tests passed.
>>>>    3. fs_test: 59/59 tests passed.
>>>>    4. ptrace_test: 8/8 tests passed.
>>>>
>>>> Still have issue with base_test were compiled without -static flag
>>>> (landlock-wip branch without network support)
>>>> 1. base_test: 6/7 tests passed.
>>>>    Error:
>>>>    #  RUN           global.inconsistent_attr ...
>>>>    # base_test.c:54:inconsistent_attr:Expected ENOMSG (42) == errno (22)
>>>>    # inconsistent_attr: Test terminated by assertion
>>>>    #          FAIL  global.inconsistent_attr
>>>> not ok 1 global.inconsistent_attr
>>>>
>>>> LCOV - code coverage report:
>>>>               Hit  Total  Coverage
>>>> Lines:      952  1010    94.3 %
>>>> Functions:  79   82      96.3 %
>>>>
>>>> Previous versions:
>>>> v5:
>>>> https://lore.kernel.org/linux-security-module/20220516152038.39594-1-konstantin.meskhidze@huawei.com
>>>> v4:
>>>> https://lore.kernel.org/linux-security-module/20220309134459.6448-1-konstantin.meskhidze@huawei.com/
>>>> v3:
>>>> https://lore.kernel.org/linux-security-module/20220124080215.265538-1-konstantin.meskhidze@huawei.com/
>>>> v2:
>>>> https://lore.kernel.org/linux-security-module/20211228115212.703084-1-konstantin.meskhidze@huawei.com/
>>>> v1:
>>>> https://lore.kernel.org/linux-security-module/20211210072123.386713-1-konstantin.meskhidze@huawei.com/
>>>>
>>>> Konstantin Meskhidze (17):
>>>>     landlock: renames access mask
>>>>     landlock: refactors landlock_find/insert_rule
>>>>     landlock: refactors merge and inherit functions
>>>>     landlock: moves helper functions
>>>>     landlock: refactors helper functions
>>>>     landlock: refactors landlock_add_rule syscall
>>>>     landlock: user space API network support
>>>>     landlock: adds support network rules
>>>>     landlock: implements TCP network hooks
>>>>     seltests/landlock: moves helper function
>>>>     seltests/landlock: adds tests for bind() hooks
>>>>     seltests/landlock: adds tests for connect() hooks
>>>>     seltests/landlock: adds AF_UNSPEC family test
>>>>     seltests/landlock: adds rules overlapping test
>>>>     seltests/landlock: adds ruleset expanding test
>>>>     seltests/landlock: adds invalid input data test
>>>>     samples/landlock: adds network demo
>>>>
>>>>    include/uapi/linux/landlock.h               |  49 ++
>>>>    samples/landlock/sandboxer.c                | 118 ++-
>>>>    security/landlock/Kconfig                   |   1 +
>>>>    security/landlock/Makefile                  |   2 +
>>>>    security/landlock/fs.c                      | 162 +---
>>>>    security/landlock/limits.h                  |   8 +-
>>>>    security/landlock/net.c                     | 155 ++++
>>>>    security/landlock/net.h                     |  26 +
>>>>    security/landlock/ruleset.c                 | 448 +++++++++--
>>>>    security/landlock/ruleset.h                 |  91 ++-
>>>>    security/landlock/setup.c                   |   2 +
>>>>    security/landlock/syscalls.c                | 168 +++--
>>>>    tools/testing/selftests/landlock/common.h   |  10 +
>>>>    tools/testing/selftests/landlock/config     |   4 +
>>>>    tools/testing/selftests/landlock/fs_test.c  |  10 -
>>>>    tools/testing/selftests/landlock/net_test.c | 774 ++++++++++++++++++++
>>>>    16 files changed, 1737 insertions(+), 291 deletions(-)
>>>>    create mode 100644 security/landlock/net.c
>>>>    create mode 100644 security/landlock/net.h
>>>>    create mode 100644 tools/testing/selftests/landlock/net_test.c
>>>>
>>>> -- 
>>>> 2.25.1
>>>>
>>>
>>> I did a thorough review of all the code. I found that the main issue
>>> with this version is that we stick to the layers limit whereas it is
>>> only relevant for filesystem hierarchies. You'll find in the following
>>> patch miscellaneous fixes and improvement, with some TODOs to get rid of
>>> this layer limit. We'll need a test to check that too. You'll need to
>>> integrate this diff into your patches though.
>> 
>> You can find the related patch here:
>> https://git.kernel.org/mic/c/8f4104b3dc59e7f110c9b83cdf034d010a2d006f
> 
> Thinking more about the layer limit, I think you should keep your
> changes and continue using ruleset.access_masks . Indeed, while it might
> be a good thing to not be limited by the 16 layers, it would be an issue
> with the upcoming audit feature, i.e. being able to point to the ruleset
> responsible for a denied access. Here is a new patch (on top of the
> other) to improve the current code:
> https://git.kernel.org/mic/c/7d6cf40a6f81adf607ad3cc17aaa11e256beeea4
> 
   Thank you for help here. I have been refactoring my commits with your 
updates. Sorry for delay, had to deal with another issues.
> 
> * Add a new access_masks_t for struct ruleset.  This is now u16 but
>     would soon need to change to u32 (because of the upcoming
>     LANDLOCK_ACCESS_FS_TRUNCATE).  Set back rules' access_masks_t to u16,
>     it should be enough for a while.
> * Rename LANDLOCK_MASK_SHIFT_NET to LANDLOCK_SHIFT_ACCESS_NET and use
>     LANDLOCK_NUM_ACCESS_FS as value.
> * Rename landlock_set_*_access_mask() to landlock_add_*_access_mask()
>     because it OR values.
> * Make landlock_add_*_access_mask() more resilient incorrect values.
> * Rename some variable to make them more consistent with the rest of the
>     code.
> * Add and update kernel documentation.
> * Remove unused code.
> ---
>    security/landlock/limits.h  |   8 +-
>    security/landlock/ruleset.c |  31 +++-----
>    security/landlock/ruleset.h | 150 +++++++++++++++++++++---------------
>    3 files changed, 105 insertions(+), 84 deletions(-)
> 
> diff --git a/security/landlock/limits.h b/security/landlock/limits.h
> index 660335258466..e50a12c1b797 100644
> --- a/security/landlock/limits.h
> +++ b/security/landlock/limits.h
> @@ -21,15 +21,13 @@
>    #define LANDLOCK_LAST_ACCESS_FS		LANDLOCK_ACCESS_FS_REFER
>    #define LANDLOCK_MASK_ACCESS_FS		((LANDLOCK_LAST_ACCESS_FS << 1) - 1)
>    #define LANDLOCK_NUM_ACCESS_FS		__const_hweight64(LANDLOCK_MASK_ACCESS_FS)
> +#define LANDLOCK_SHIFT_ACCESS_FS	0
>    
>    #define LANDLOCK_LAST_ACCESS_NET	LANDLOCK_ACCESS_NET_CONNECT_TCP
>    #define LANDLOCK_MASK_ACCESS_NET	((LANDLOCK_LAST_ACCESS_NET << 1) - 1)
>    #define LANDLOCK_NUM_ACCESS_NET		__const_hweight64(LANDLOCK_MASK_ACCESS_NET)
> -// TODO: LANDLOCK_MASK_SHIFT_NET will not be useful with the new
> -// ruleset->net_access_mask
> -#define LANDLOCK_MASK_SHIFT_NET		16
> -
> -#define LANDLOCK_RULE_TYPE_NUM		LANDLOCK_RULE_NET_SERVICE
> +#define LANDLOCK_SHIFT_ACCESS_NET	LANDLOCK_NUM_ACCESS_FS
>    
>    /* clang-format on */
> +
>    #endif /* _SECURITY_LANDLOCK_LIMITS_H */
> diff --git a/security/landlock/ruleset.c b/security/landlock/ruleset.c
> index e7555b16069a..1b3433ea4c61 100644
> --- a/security/landlock/ruleset.c
> +++ b/security/landlock/ruleset.c
> @@ -47,21 +47,21 @@ static struct landlock_ruleset *create_ruleset(const u32 num_layers)
>    }
>    
>    struct landlock_ruleset *
> -landlock_create_ruleset(const access_mask_t access_mask_fs,
> -			const access_mask_t access_mask_net)
> +landlock_create_ruleset(const access_mask_t fs_access_mask,
> +			const access_mask_t net_access_mask)
>    {
>    	struct landlock_ruleset *new_ruleset;
>    
>    	/* Informs about useless ruleset. */
> -	if (!access_mask_fs && !access_mask_net)
> +	if (!fs_access_mask && !net_access_mask)
>    		return ERR_PTR(-ENOMSG);
>    	new_ruleset = create_ruleset(1);
>    	if (IS_ERR(new_ruleset))
>    		return new_ruleset;
> -	if (access_mask_fs)
> -		landlock_set_fs_access_mask(new_ruleset, access_mask_fs, 0);
> -	if (access_mask_net)
> -		landlock_set_net_access_mask(new_ruleset, access_mask_net, 0);
> +	if (fs_access_mask)
> +		landlock_add_fs_access_mask(new_ruleset, fs_access_mask, 0);
> +	if (net_access_mask)
> +		landlock_add_net_access_mask(new_ruleset, net_access_mask, 0);
>    	return new_ruleset;
>    }
>    
> @@ -160,13 +160,14 @@ static void build_check_ruleset(void)
>    		.num_rules = ~0,
>    		.num_layers = ~0,
>    	};
> -	typeof(ruleset.access_masks[0]) fs_access_mask = ~0;
> -	typeof(ruleset.access_masks[0]) net_access_mask = ~0;
> +	typeof(ruleset.access_masks[0]) access_masks = ~0;
>    
>    	BUILD_BUG_ON(ruleset.num_rules < LANDLOCK_MAX_NUM_RULES);
>    	BUILD_BUG_ON(ruleset.num_layers < LANDLOCK_MAX_NUM_LAYERS);
> -	BUILD_BUG_ON(fs_access_mask < LANDLOCK_MASK_ACCESS_FS);
> -	BUILD_BUG_ON(net_access_mask < LANDLOCK_MASK_ACCESS_NET);
> +	BUILD_BUG_ON(access_masks <
> +		     (LANDLOCK_MASK_ACCESS_FS << LANDLOCK_SHIFT_ACCESS_FS) +
> +			     (LANDLOCK_MASK_ACCESS_NET
> +			      << LANDLOCK_SHIFT_ACCESS_NET));
>    }
>    
>    /**
> @@ -250,8 +251,6 @@ static int insert_rule(struct landlock_ruleset *const ruleset,
>    		 * Intersects access rights when it is a merge between a
>    		 * ruleset and a domain.
>    		 */
> -		// TODO: Don't create a new rule but AND accesses (of the first
> -		// and only layer) if !is_object_pointer(id.type)
>    		new_rule = create_rule(id, &this->layers, this->num_layers,
>    				       &(*layers)[0]);
>    		if (IS_ERR(new_rule))
> @@ -332,7 +331,6 @@ static int merge_tree(struct landlock_ruleset *const dst,
>    	rbtree_postorder_for_each_entry_safe(walker_rule, next_rule, src_root,
>    					     node) {
>    		struct landlock_layer layers[] = { {
> -			// TODO: Set level to 1 if !is_object_pointer(key_type).
>    			.level = dst->num_layers,
>    		} };
>    		const struct landlock_id id = {
> @@ -531,7 +529,6 @@ landlock_merge_ruleset(struct landlock_ruleset *const parent,
>    		if (parent->num_layers >= LANDLOCK_MAX_NUM_LAYERS)
>    			return ERR_PTR(-E2BIG);
>    		num_layers = parent->num_layers + 1;
> -		// TODO: Don't increment num_layers if RB_EMPTY_ROOT(&ruleset->root_inode).
>    	} else {
>    		num_layers = 1;
>    	}
> @@ -698,10 +695,6 @@ access_mask_t init_layer_masks(const struct landlock_ruleset *const domain,
>    
>    	switch (key_type) {
>    	case LANDLOCK_KEY_INODE:
> -		// XXX: landlock_get_fs_access_mask() should not be removed
> -		// once we use ruleset->net_access_mask, and we can then
> -		// replace the @key_type argument with num_access to make the
> -		// code simpler.
>    		get_access_mask = landlock_get_fs_access_mask;
>    		num_access = LANDLOCK_NUM_ACCESS_FS;
>    		break;
> diff --git a/security/landlock/ruleset.h b/security/landlock/ruleset.h
> index 59229be378d6..669de66094ed 100644
> --- a/security/landlock/ruleset.h
> +++ b/security/landlock/ruleset.h
> @@ -19,8 +19,8 @@
>    #include "limits.h"
>    #include "object.h"
>    
> -// TODO: get back to u16 thanks to ruleset->net_access_mask
> -typedef u32 access_mask_t;
> +/* Rule access mask. */
> +typedef u16 access_mask_t;
>    /* Makes sure all filesystem access rights can be stored. */
>    static_assert(BITS_PER_TYPE(access_mask_t) >= LANDLOCK_NUM_ACCESS_FS);
>    /* Makes sure all network access rights can be stored. */
> @@ -28,6 +28,12 @@ static_assert(BITS_PER_TYPE(access_mask_t) >= LANDLOCK_NUM_ACCESS_NET);
>    /* Makes sure for_each_set_bit() and for_each_clear_bit() calls are OK. */
>    static_assert(sizeof(unsigned long) >= sizeof(access_mask_t));
>    
> +/* Ruleset access masks. */
> +typedef u16 access_masks_t;
> +/* Makes sure all ruleset access rights can be stored. */
> +static_assert(BITS_PER_TYPE(access_masks_t) >=
> +	      LANDLOCK_NUM_ACCESS_FS + LANDLOCK_NUM_ACCESS_NET);
> +
>    typedef u16 layer_mask_t;
>    /* Makes sure all layers can be checked. */
>    static_assert(BITS_PER_TYPE(layer_mask_t) >= LANDLOCK_MAX_NUM_LAYERS);
> @@ -47,16 +53,33 @@ struct landlock_layer {
>    	access_mask_t access;
>    };
>    
> +/**
> + * union landlock_key - Key of a ruleset's red-black tree
> + */
>    union landlock_key {
>    	struct landlock_object *object;
>    	uintptr_t data;
>    };
>    
> +/**
> + * enum landlock_key_type - Type of &union landlock_key
> + */
>    enum landlock_key_type {
> +	/**
> +	 * @LANDLOCK_KEY_INODE: Type of &landlock_ruleset.root_inode's node
> +	 * keys.
> +	 */
>    	LANDLOCK_KEY_INODE = 1,
> +	/**
> +	 * @LANDLOCK_KEY_NET_PORT: Type of &landlock_ruleset.root_net_port's
> +	 * node keys.
> +	 */
>    	LANDLOCK_KEY_NET_PORT = 2,
>    };
>    
> +/**
> + * struct landlock_id - Unique rule identifier for a ruleset
> + */
>    struct landlock_id {
>    	union landlock_key key;
>    	const enum landlock_key_type type;
> @@ -113,15 +136,17 @@ struct landlock_hierarchy {
>     */
>    struct landlock_ruleset {
>    	/**
> -	 * @root: Root of a red-black tree containing &struct landlock_rule
> -	 * nodes.  Once a ruleset is tied to a process (i.e. as a domain), this
> -	 * tree is immutable until @usage reaches zero.
> +	 * @root_inode: Root of a red-black tree containing &struct
> +	 * landlock_rule nodes with inode object.  Once a ruleset is tied to a
> +	 * process (i.e. as a domain), this tree is immutable until @usage
> +	 * reaches zero.
>    	 */
>    	struct rb_root root_inode;
>    	/**
> -	 * @root_net_port: Root of a red-black tree containing object nodes
> -	 * for network port. Once a ruleset is tied to a process (i.e. as a domain),
> -	 * this tree is immutable until @usage reaches zero.
> +	 * @root_net_port: Root of a red-black tree containing &struct
> +	 * landlock_rule nodes with network port. Once a ruleset is tied to a
> +	 * process (i.e. as a domain), this tree is immutable until @usage
> +	 * reaches zero.
>    	 */
>    	struct rb_root root_net_port;
>    	/**
> @@ -162,32 +187,25 @@ struct landlock_ruleset {
>    			 */
>    			u32 num_layers;
>    			/**
> -			 * TODO: net_access_mask: Contains the subset of network
> -			 * actions that are restricted by a ruleset.
> -			 */
> -			access_mask_t net_access_mask;
> -			/**
> -			 * @access_masks: Contains the subset of filesystem
> -			 * actions that are restricted by a ruleset.  A domain
> -			 * saves all layers of merged rulesets in a stack
> -			 * (FAM), starting from the first layer to the last
> -			 * one.  These layers are used when merging rulesets,
> -			 * for user space backward compatibility (i.e.
> -			 * future-proof), and to properly handle merged
> +			 * @access_masks: Contains the subset of filesystem and
> +			 * network actions that are restricted by a ruleset.
> +			 * A domain saves all layers of merged rulesets in a
> +			 * stack (FAM), starting from the first layer to the
> +			 * last one.  These layers are used when merging
> +			 * rulesets, for user space backward compatibility
> +			 * (i.e. future-proof), and to properly handle merged
>    			 * rulesets without overlapping access rights.  These
>    			 * layers are set once and never changed for the
>    			 * lifetime of the ruleset.
>    			 */
> -			// TODO: rename (back) to fs_access_mask because layers
> -			// are only useful for file hierarchies.
> -			access_mask_t access_masks[];
> +			access_masks_t access_masks[];
>    		};
>    	};
>    };
>    
>    struct landlock_ruleset *
> -landlock_create_ruleset(const access_mask_t access_mask_fs,
> -			const access_mask_t access_mask_net);
> +landlock_create_ruleset(const access_mask_t fs_access_mask,
> +			const access_mask_t net_access_mask);
>    
>    void landlock_put_ruleset(struct landlock_ruleset *const ruleset);
>    void landlock_put_ruleset_deferred(struct landlock_ruleset *const ruleset);
> @@ -210,41 +228,7 @@ static inline void landlock_get_ruleset(struct landlock_ruleset *const ruleset)
>    		refcount_inc(&ruleset->usage);
>    }
>    
> -// TODO: These helpers should not be required thanks to the new ruleset->net_access_mask.
> -/* A helper function to set a filesystem mask. */
> -static inline void
> -landlock_set_fs_access_mask(struct landlock_ruleset *ruleset,
> -			    const access_mask_t access_mask_fs, u16 mask_level)
> -{
> -	ruleset->access_masks[mask_level] = access_mask_fs;
> -}
> -
> -/* A helper function to get a filesystem mask. */
> -static inline u32
> -landlock_get_fs_access_mask(const struct landlock_ruleset *ruleset,
> -			    u16 mask_level)
> -{
> -	return (ruleset->access_masks[mask_level] & LANDLOCK_MASK_ACCESS_FS);
> -}
> -
> -/* A helper function to set a network mask. */
> -static inline void
> -landlock_set_net_access_mask(struct landlock_ruleset *ruleset,
> -			     const access_mask_t access_mask_net,
> -			     u16 mask_level)
> -{
> -	ruleset->access_masks[mask_level] |=
> -		(access_mask_net << LANDLOCK_MASK_SHIFT_NET);
> -}
> -
> -/* A helper function to get a network mask. */
> -static inline u32
> -landlock_get_net_access_mask(const struct landlock_ruleset *ruleset,
> -			     u16 mask_level)
> -{
> -	return (ruleset->access_masks[mask_level] >> LANDLOCK_MASK_SHIFT_NET);
> -}
> -
> +// TODO: Remove if only relevant for fs.c
>    access_mask_t get_handled_accesses(const struct landlock_ruleset *const domain,
>    				   const u16 rule_type, const u16 num_access);
>    
> @@ -258,4 +242,50 @@ access_mask_t init_layer_masks(const struct landlock_ruleset *const domain,
>    			       layer_mask_t (*const layer_masks)[],
>    			       const enum landlock_key_type key_type);
>    
> +static inline void
> +landlock_add_fs_access_mask(struct landlock_ruleset *const ruleset,
> +			    const access_mask_t fs_access_mask,
> +			    const u16 layer_level)
> +{
> +	access_mask_t fs_mask = fs_access_mask & LANDLOCK_MASK_ACCESS_FS;
> +
> +	/* Should already be checked in sys_landlock_create_ruleset(). */
> +	WARN_ON_ONCE(fs_access_mask != fs_mask);
> +	// TODO: Add tests to check "|=" and not "="
> +	ruleset->access_masks[layer_level] |=
> +		(fs_mask << LANDLOCK_SHIFT_ACCESS_FS);
> +}
> +
> +static inline void
> +landlock_add_net_access_mask(struct landlock_ruleset *const ruleset,
> +			     const access_mask_t net_access_mask,
> +			     const u16 layer_level)
> +{
> +	access_mask_t net_mask = net_access_mask & LANDLOCK_MASK_ACCESS_NET;
> +
> +	/* Should already be checked in sys_landlock_create_ruleset(). */
> +	WARN_ON_ONCE(net_access_mask != net_mask);
> +	// TODO: Add tests to check "|=" and not "="
> +	ruleset->access_masks[layer_level] |=
> +		(net_mask << LANDLOCK_SHIFT_ACCESS_NET);
> +}
> +
> +static inline access_mask_t
> +landlock_get_fs_access_mask(const struct landlock_ruleset *const ruleset,
> +			    const u16 layer_level)
> +{
> +	return (ruleset->access_masks[layer_level] >>
> +		LANDLOCK_SHIFT_ACCESS_FS) &
> +	       LANDLOCK_MASK_ACCESS_FS;
> +}
> +
> +static inline access_mask_t
> +landlock_get_net_access_mask(const struct landlock_ruleset *const ruleset,
> +			     const u16 layer_level)
> +{
> +	return (ruleset->access_masks[layer_level] >>
> +		LANDLOCK_SHIFT_ACCESS_NET) &
> +	       LANDLOCK_MASK_ACCESS_NET;
> +}
> +
>    #endif /* _SECURITY_LANDLOCK_RULESET_H */
> .

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 00/17] Network support for Landlock
  2022-07-28 13:17     ` Mickaël Salaün
  2022-08-23  9:10       ` Konstantin Meskhidze (A)
@ 2022-08-27 13:30       ` Konstantin Meskhidze (A)
  2022-08-29 13:10         ` Mickaël Salaün
  1 sibling, 1 reply; 53+ messages in thread
From: Konstantin Meskhidze (A) @ 2022-08-27 13:30 UTC (permalink / raw)
  To: Mickaël Salaün
  Cc: willemdebruijn.kernel, linux-security-module, netdev,
	netfilter-devel, anton.sirazetdinov



7/28/2022 4:17 PM, Mickaël Salaün пишет:
> 
> On 27/07/2022 21:54, Mickaël Salaün wrote:
>> 
>> 
>> On 26/07/2022 19:43, Mickaël Salaün wrote:
>>>
>>> On 21/06/2022 10:22, Konstantin Meskhidze wrote:
>>>> Hi,
>>>> This is a new V6 patch related to Landlock LSM network confinement.
>>>> It is based on the latest landlock-wip branch on top of v5.19-rc2:
>>>> https://git.kernel.org/pub/scm/linux/kernel/git/mic/linux.git/log/?h=landlock-wip
>>>>
>>>> It brings refactoring of previous patch version V5:
>>>>       - Fixes some logic errors and typos.
>>>>       - Adds additional FIXTURE_VARIANT and FIXTURE_VARIANT_ADD helpers
>>>>       to support both ip4 and ip6 families and shorten seltests' code.
>>>>       - Makes TCP sockets confinement support optional in sandboxer demo.
>>>>       - Formats the code with clang-format-14
>>>>
>>>> All test were run in QEMU evironment and compiled with
>>>>    -static flag.
>>>>    1. network_test: 18/18 tests passed.
>>>>    2. base_test: 7/7 tests passed.
>>>>    3. fs_test: 59/59 tests passed.
>>>>    4. ptrace_test: 8/8 tests passed.
>>>>
>>>> Still have issue with base_test were compiled without -static flag
>>>> (landlock-wip branch without network support)
>>>> 1. base_test: 6/7 tests passed.
>>>>    Error:
>>>>    #  RUN           global.inconsistent_attr ...
>>>>    # base_test.c:54:inconsistent_attr:Expected ENOMSG (42) == errno (22)
>>>>    # inconsistent_attr: Test terminated by assertion
>>>>    #          FAIL  global.inconsistent_attr
>>>> not ok 1 global.inconsistent_attr
>>>>
>>>> LCOV - code coverage report:
>>>>               Hit  Total  Coverage
>>>> Lines:      952  1010    94.3 %
>>>> Functions:  79   82      96.3 %
>>>>
>>>> Previous versions:
>>>> v5:
>>>> https://lore.kernel.org/linux-security-module/20220516152038.39594-1-konstantin.meskhidze@huawei.com
>>>> v4:
>>>> https://lore.kernel.org/linux-security-module/20220309134459.6448-1-konstantin.meskhidze@huawei.com/
>>>> v3:
>>>> https://lore.kernel.org/linux-security-module/20220124080215.265538-1-konstantin.meskhidze@huawei.com/
>>>> v2:
>>>> https://lore.kernel.org/linux-security-module/20211228115212.703084-1-konstantin.meskhidze@huawei.com/
>>>> v1:
>>>> https://lore.kernel.org/linux-security-module/20211210072123.386713-1-konstantin.meskhidze@huawei.com/
>>>>
>>>> Konstantin Meskhidze (17):
>>>>     landlock: renames access mask
>>>>     landlock: refactors landlock_find/insert_rule
>>>>     landlock: refactors merge and inherit functions
>>>>     landlock: moves helper functions
>>>>     landlock: refactors helper functions
>>>>     landlock: refactors landlock_add_rule syscall
>>>>     landlock: user space API network support
>>>>     landlock: adds support network rules
>>>>     landlock: implements TCP network hooks
>>>>     seltests/landlock: moves helper function
>>>>     seltests/landlock: adds tests for bind() hooks
>>>>     seltests/landlock: adds tests for connect() hooks
>>>>     seltests/landlock: adds AF_UNSPEC family test
>>>>     seltests/landlock: adds rules overlapping test
>>>>     seltests/landlock: adds ruleset expanding test
>>>>     seltests/landlock: adds invalid input data test
>>>>     samples/landlock: adds network demo
>>>>
>>>>    include/uapi/linux/landlock.h               |  49 ++
>>>>    samples/landlock/sandboxer.c                | 118 ++-
>>>>    security/landlock/Kconfig                   |   1 +
>>>>    security/landlock/Makefile                  |   2 +
>>>>    security/landlock/fs.c                      | 162 +---
>>>>    security/landlock/limits.h                  |   8 +-
>>>>    security/landlock/net.c                     | 155 ++++
>>>>    security/landlock/net.h                     |  26 +
>>>>    security/landlock/ruleset.c                 | 448 +++++++++--
>>>>    security/landlock/ruleset.h                 |  91 ++-
>>>>    security/landlock/setup.c                   |   2 +
>>>>    security/landlock/syscalls.c                | 168 +++--
>>>>    tools/testing/selftests/landlock/common.h   |  10 +
>>>>    tools/testing/selftests/landlock/config     |   4 +
>>>>    tools/testing/selftests/landlock/fs_test.c  |  10 -
>>>>    tools/testing/selftests/landlock/net_test.c | 774 ++++++++++++++++++++
>>>>    16 files changed, 1737 insertions(+), 291 deletions(-)
>>>>    create mode 100644 security/landlock/net.c
>>>>    create mode 100644 security/landlock/net.h
>>>>    create mode 100644 tools/testing/selftests/landlock/net_test.c
>>>>
>>>> -- 
>>>> 2.25.1
>>>>
>>>
>>> I did a thorough review of all the code. I found that the main issue
>>> with this version is that we stick to the layers limit whereas it is
>>> only relevant for filesystem hierarchies. You'll find in the following
>>> patch miscellaneous fixes and improvement, with some TODOs to get rid of
>>> this layer limit. We'll need a test to check that too. You'll need to
>>> integrate this diff into your patches though.
>> 
>> You can find the related patch here:
>> https://git.kernel.org/mic/c/8f4104b3dc59e7f110c9b83cdf034d010a2d006f
> 
> Thinking more about the layer limit, I think you should keep your
> changes and continue using ruleset.access_masks . Indeed, while it might
> be a good thing to not be limited by the 16 layers, it would be an issue
> with the upcoming audit feature, i.e. being able to point to the ruleset
> responsible for a denied access. Here is a new patch (on top of the
> other) to improve the current code:
> https://git.kernel.org/mic/c/7d6cf40a6f81adf607ad3cc17aaa11e256beeea4
> 
> 
> * Add a new access_masks_t for struct ruleset.  This is now u16 but
>     would soon need to change to u32 (because of the upcoming
>     LANDLOCK_ACCESS_FS_TRUNCATE).  Set back rules' access_masks_t to u16,
>     it should be enough for a while.
> * Rename LANDLOCK_MASK_SHIFT_NET to LANDLOCK_SHIFT_ACCESS_NET and use
>     LANDLOCK_NUM_ACCESS_FS as value.
> * Rename landlock_set_*_access_mask() to landlock_add_*_access_mask()
>     because it OR values.
> * Make landlock_add_*_access_mask() more resilient incorrect values.
> * Rename some variable to make them more consistent with the rest of the
>     code.
> * Add and update kernel documentation.
> * Remove unused code.
> ---
>    security/landlock/limits.h  |   8 +-
>    security/landlock/ruleset.c |  31 +++-----
>    security/landlock/ruleset.h | 150 +++++++++++++++++++++---------------
>    3 files changed, 105 insertions(+), 84 deletions(-)
> 
> diff --git a/security/landlock/limits.h b/security/landlock/limits.h
> index 660335258466..e50a12c1b797 100644
> --- a/security/landlock/limits.h
> +++ b/security/landlock/limits.h
> @@ -21,15 +21,13 @@
>    #define LANDLOCK_LAST_ACCESS_FS		LANDLOCK_ACCESS_FS_REFER
>    #define LANDLOCK_MASK_ACCESS_FS		((LANDLOCK_LAST_ACCESS_FS << 1) - 1)
>    #define LANDLOCK_NUM_ACCESS_FS		__const_hweight64(LANDLOCK_MASK_ACCESS_FS)
> +#define LANDLOCK_SHIFT_ACCESS_FS	0
>    
>    #define LANDLOCK_LAST_ACCESS_NET	LANDLOCK_ACCESS_NET_CONNECT_TCP
>    #define LANDLOCK_MASK_ACCESS_NET	((LANDLOCK_LAST_ACCESS_NET << 1) - 1)
>    #define LANDLOCK_NUM_ACCESS_NET		__const_hweight64(LANDLOCK_MASK_ACCESS_NET)
> -// TODO: LANDLOCK_MASK_SHIFT_NET will not be useful with the new
> -// ruleset->net_access_mask
> -#define LANDLOCK_MASK_SHIFT_NET		16
> -
> -#define LANDLOCK_RULE_TYPE_NUM		LANDLOCK_RULE_NET_SERVICE
> +#define LANDLOCK_SHIFT_ACCESS_NET	LANDLOCK_NUM_ACCESS_FS
>    
>    /* clang-format on */
> +
>    #endif /* _SECURITY_LANDLOCK_LIMITS_H */
> diff --git a/security/landlock/ruleset.c b/security/landlock/ruleset.c
> index e7555b16069a..1b3433ea4c61 100644
> --- a/security/landlock/ruleset.c
> +++ b/security/landlock/ruleset.c
> @@ -47,21 +47,21 @@ static struct landlock_ruleset *create_ruleset(const u32 num_layers)
>    }
>    
>    struct landlock_ruleset *
> -landlock_create_ruleset(const access_mask_t access_mask_fs,
> -			const access_mask_t access_mask_net)
> +landlock_create_ruleset(const access_mask_t fs_access_mask,
> +			const access_mask_t net_access_mask)
>    {
>    	struct landlock_ruleset *new_ruleset;
>    
>    	/* Informs about useless ruleset. */
> -	if (!access_mask_fs && !access_mask_net)
> +	if (!fs_access_mask && !net_access_mask)
>    		return ERR_PTR(-ENOMSG);
>    	new_ruleset = create_ruleset(1);
>    	if (IS_ERR(new_ruleset))
>    		return new_ruleset;
> -	if (access_mask_fs)
> -		landlock_set_fs_access_mask(new_ruleset, access_mask_fs, 0);
> -	if (access_mask_net)
> -		landlock_set_net_access_mask(new_ruleset, access_mask_net, 0);
> +	if (fs_access_mask)
> +		landlock_add_fs_access_mask(new_ruleset, fs_access_mask, 0);
> +	if (net_access_mask)
> +		landlock_add_net_access_mask(new_ruleset, net_access_mask, 0);
>    	return new_ruleset;
>    }
>    
> @@ -160,13 +160,14 @@ static void build_check_ruleset(void)
>    		.num_rules = ~0,
>    		.num_layers = ~0,
>    	};
> -	typeof(ruleset.access_masks[0]) fs_access_mask = ~0;
> -	typeof(ruleset.access_masks[0]) net_access_mask = ~0;
> +	typeof(ruleset.access_masks[0]) access_masks = ~0;
>    
>    	BUILD_BUG_ON(ruleset.num_rules < LANDLOCK_MAX_NUM_RULES);
>    	BUILD_BUG_ON(ruleset.num_layers < LANDLOCK_MAX_NUM_LAYERS);
> -	BUILD_BUG_ON(fs_access_mask < LANDLOCK_MASK_ACCESS_FS);
> -	BUILD_BUG_ON(net_access_mask < LANDLOCK_MASK_ACCESS_NET);
> +	BUILD_BUG_ON(access_masks <
> +		     (LANDLOCK_MASK_ACCESS_FS << LANDLOCK_SHIFT_ACCESS_FS) +
> +			     (LANDLOCK_MASK_ACCESS_NET
> +			      << LANDLOCK_SHIFT_ACCESS_NET));
>    }
>    
>    /**
> @@ -250,8 +251,6 @@ static int insert_rule(struct landlock_ruleset *const ruleset,
>    		 * Intersects access rights when it is a merge between a
>    		 * ruleset and a domain.
>    		 */
> -		// TODO: Don't create a new rule but AND accesses (of the first
> -		// and only layer) if !is_object_pointer(id.type)
>    		new_rule = create_rule(id, &this->layers, this->num_layers,
>    				       &(*layers)[0]);
>    		if (IS_ERR(new_rule))
> @@ -332,7 +331,6 @@ static int merge_tree(struct landlock_ruleset *const dst,
>    	rbtree_postorder_for_each_entry_safe(walker_rule, next_rule, src_root,
>    					     node) {
>    		struct landlock_layer layers[] = { {
> -			// TODO: Set level to 1 if !is_object_pointer(key_type).
>    			.level = dst->num_layers,
>    		} };
>    		const struct landlock_id id = {
> @@ -531,7 +529,6 @@ landlock_merge_ruleset(struct landlock_ruleset *const parent,
>    		if (parent->num_layers >= LANDLOCK_MAX_NUM_LAYERS)
>    			return ERR_PTR(-E2BIG);
>    		num_layers = parent->num_layers + 1;
> -		// TODO: Don't increment num_layers if RB_EMPTY_ROOT(&ruleset->root_inode).
>    	} else {
>    		num_layers = 1;
>    	}
> @@ -698,10 +695,6 @@ access_mask_t init_layer_masks(const struct landlock_ruleset *const domain,
>    
>    	switch (key_type) {
>    	case LANDLOCK_KEY_INODE:
> -		// XXX: landlock_get_fs_access_mask() should not be removed
> -		// once we use ruleset->net_access_mask, and we can then
> -		// replace the @key_type argument with num_access to make the
> -		// code simpler.
>    		get_access_mask = landlock_get_fs_access_mask;
>    		num_access = LANDLOCK_NUM_ACCESS_FS;
>    		break;
> diff --git a/security/landlock/ruleset.h b/security/landlock/ruleset.h
> index 59229be378d6..669de66094ed 100644
> --- a/security/landlock/ruleset.h
> +++ b/security/landlock/ruleset.h
> @@ -19,8 +19,8 @@
>    #include "limits.h"
>    #include "object.h"
>    
> -// TODO: get back to u16 thanks to ruleset->net_access_mask
> -typedef u32 access_mask_t;
> +/* Rule access mask. */
> +typedef u16 access_mask_t;
>    /* Makes sure all filesystem access rights can be stored. */
>    static_assert(BITS_PER_TYPE(access_mask_t) >= LANDLOCK_NUM_ACCESS_FS);
>    /* Makes sure all network access rights can be stored. */
> @@ -28,6 +28,12 @@ static_assert(BITS_PER_TYPE(access_mask_t) >= LANDLOCK_NUM_ACCESS_NET);
>    /* Makes sure for_each_set_bit() and for_each_clear_bit() calls are OK. */
>    static_assert(sizeof(unsigned long) >= sizeof(access_mask_t));
>    
> +/* Ruleset access masks. */
> +typedef u16 access_masks_t;
> +/* Makes sure all ruleset access rights can be stored. */
> +static_assert(BITS_PER_TYPE(access_masks_t) >=
> +	      LANDLOCK_NUM_ACCESS_FS + LANDLOCK_NUM_ACCESS_NET);
> +
>    typedef u16 layer_mask_t;
>    /* Makes sure all layers can be checked. */
>    static_assert(BITS_PER_TYPE(layer_mask_t) >= LANDLOCK_MAX_NUM_LAYERS);
> @@ -47,16 +53,33 @@ struct landlock_layer {
>    	access_mask_t access;
>    };
>    
> +/**
> + * union landlock_key - Key of a ruleset's red-black tree
> + */
>    union landlock_key {
>    	struct landlock_object *object;
>    	uintptr_t data;
>    };
>    
> +/**
> + * enum landlock_key_type - Type of &union landlock_key
> + */
>    enum landlock_key_type {
> +	/**
> +	 * @LANDLOCK_KEY_INODE: Type of &landlock_ruleset.root_inode's node
> +	 * keys.
> +	 */
>    	LANDLOCK_KEY_INODE = 1,
> +	/**
> +	 * @LANDLOCK_KEY_NET_PORT: Type of &landlock_ruleset.root_net_port's
> +	 * node keys.
> +	 */
>    	LANDLOCK_KEY_NET_PORT = 2,
>    };
>    
> +/**
> + * struct landlock_id - Unique rule identifier for a ruleset
> + */
>    struct landlock_id {
>    	union landlock_key key;
>    	const enum landlock_key_type type;
> @@ -113,15 +136,17 @@ struct landlock_hierarchy {
>     */
>    struct landlock_ruleset {
>    	/**
> -	 * @root: Root of a red-black tree containing &struct landlock_rule
> -	 * nodes.  Once a ruleset is tied to a process (i.e. as a domain), this
> -	 * tree is immutable until @usage reaches zero.
> +	 * @root_inode: Root of a red-black tree containing &struct
> +	 * landlock_rule nodes with inode object.  Once a ruleset is tied to a
> +	 * process (i.e. as a domain), this tree is immutable until @usage
> +	 * reaches zero.
>    	 */
>    	struct rb_root root_inode;
>    	/**
> -	 * @root_net_port: Root of a red-black tree containing object nodes
> -	 * for network port. Once a ruleset is tied to a process (i.e. as a domain),
> -	 * this tree is immutable until @usage reaches zero.
> +	 * @root_net_port: Root of a red-black tree containing &struct
> +	 * landlock_rule nodes with network port. Once a ruleset is tied to a
> +	 * process (i.e. as a domain), this tree is immutable until @usage
> +	 * reaches zero.
>    	 */
>    	struct rb_root root_net_port;
>    	/**
> @@ -162,32 +187,25 @@ struct landlock_ruleset {
>    			 */
>    			u32 num_layers;
>    			/**
> -			 * TODO: net_access_mask: Contains the subset of network
> -			 * actions that are restricted by a ruleset.
> -			 */
> -			access_mask_t net_access_mask;
> -			/**
> -			 * @access_masks: Contains the subset of filesystem
> -			 * actions that are restricted by a ruleset.  A domain
> -			 * saves all layers of merged rulesets in a stack
> -			 * (FAM), starting from the first layer to the last
> -			 * one.  These layers are used when merging rulesets,
> -			 * for user space backward compatibility (i.e.
> -			 * future-proof), and to properly handle merged
> +			 * @access_masks: Contains the subset of filesystem and
> +			 * network actions that are restricted by a ruleset.
> +			 * A domain saves all layers of merged rulesets in a
> +			 * stack (FAM), starting from the first layer to the
> +			 * last one.  These layers are used when merging
> +			 * rulesets, for user space backward compatibility
> +			 * (i.e. future-proof), and to properly handle merged
>    			 * rulesets without overlapping access rights.  These
>    			 * layers are set once and never changed for the
>    			 * lifetime of the ruleset.
>    			 */
> -			// TODO: rename (back) to fs_access_mask because layers
> -			// are only useful for file hierarchies.
> -			access_mask_t access_masks[];
> +			access_masks_t access_masks[];
>    		};
>    	};
>    };
>    
>    struct landlock_ruleset *
> -landlock_create_ruleset(const access_mask_t access_mask_fs,
> -			const access_mask_t access_mask_net);
> +landlock_create_ruleset(const access_mask_t fs_access_mask,
> +			const access_mask_t net_access_mask);
>    
>    void landlock_put_ruleset(struct landlock_ruleset *const ruleset);
>    void landlock_put_ruleset_deferred(struct landlock_ruleset *const ruleset);
> @@ -210,41 +228,7 @@ static inline void landlock_get_ruleset(struct landlock_ruleset *const ruleset)
>    		refcount_inc(&ruleset->usage);
>    }
>    
> -// TODO: These helpers should not be required thanks to the new ruleset->net_access_mask.
> -/* A helper function to set a filesystem mask. */
> -static inline void
> -landlock_set_fs_access_mask(struct landlock_ruleset *ruleset,
> -			    const access_mask_t access_mask_fs, u16 mask_level)
> -{
> -	ruleset->access_masks[mask_level] = access_mask_fs;
> -}
> -
> -/* A helper function to get a filesystem mask. */
> -static inline u32
> -landlock_get_fs_access_mask(const struct landlock_ruleset *ruleset,
> -			    u16 mask_level)
> -{
> -	return (ruleset->access_masks[mask_level] & LANDLOCK_MASK_ACCESS_FS);
> -}
> -
> -/* A helper function to set a network mask. */
> -static inline void
> -landlock_set_net_access_mask(struct landlock_ruleset *ruleset,
> -			     const access_mask_t access_mask_net,
> -			     u16 mask_level)
> -{
> -	ruleset->access_masks[mask_level] |=
> -		(access_mask_net << LANDLOCK_MASK_SHIFT_NET);
> -}
> -
> -/* A helper function to get a network mask. */
> -static inline u32
> -landlock_get_net_access_mask(const struct landlock_ruleset *ruleset,
> -			     u16 mask_level)
> -{
> -	return (ruleset->access_masks[mask_level] >> LANDLOCK_MASK_SHIFT_NET);
> -}
> -
> +// TODO: Remove if only relevant for fs.c
>    access_mask_t get_handled_accesses(const struct landlock_ruleset *const domain,
>    				   const u16 rule_type, const u16 num_access);
>    
> @@ -258,4 +242,50 @@ access_mask_t init_layer_masks(const struct landlock_ruleset *const domain,
>    			       layer_mask_t (*const layer_masks)[],
>    			       const enum landlock_key_type key_type);
>    
> +static inline void
> +landlock_add_fs_access_mask(struct landlock_ruleset *const ruleset,
> +			    const access_mask_t fs_access_mask,
> +			    const u16 layer_level)
> +{
> +	access_mask_t fs_mask = fs_access_mask & LANDLOCK_MASK_ACCESS_FS;
> +
> +	/* Should already be checked in sys_landlock_create_ruleset(). */
> +	WARN_ON_ONCE(fs_access_mask != fs_mask);
> +	// TODO: Add tests to check "|=" and not "Is it kunit test? If so, do you want to add this kind of tests in future
landlock versions?
> +	ruleset->access_masks[layer_level] |=
> +		(fs_mask << LANDLOCK_SHIFT_ACCESS_FS);
> +}
> +
> +static inline void
> +landlock_add_net_access_mask(struct landlock_ruleset *const ruleset,
> +			     const access_mask_t net_access_mask,
> +			     const u16 layer_level)
> +{
> +	access_mask_t net_mask = net_access_mask & LANDLOCK_MASK_ACCESS_NET;
> +
> +	/* Should already be checked in sys_landlock_create_ruleset(). */
> +	WARN_ON_ONCE(net_access_mask != net_mask);
> +	// TODO: Add tests to check "|=" and not "="
The same above.
I'm going add invalid network attribute checking into TEST_F(socket, 
inval) test in coming patch.
> +	ruleset->access_masks[layer_level] |=
> +		(net_mask << LANDLOCK_SHIFT_ACCESS_NET);
> +}
> +
> +static inline access_mask_t
> +landlock_get_fs_access_mask(const struct landlock_ruleset *const ruleset,
> +			    const u16 layer_level)
> +{
> +	return (ruleset->access_masks[layer_level] >>
> +		LANDLOCK_SHIFT_ACCESS_FS) &
> +	       LANDLOCK_MASK_ACCESS_FS;
> +}
> +
> +static inline access_mask_t
> +landlock_get_net_access_mask(const struct landlock_ruleset *const ruleset,
> +			     const u16 layer_level)
> +{
> +	return (ruleset->access_masks[layer_level] >>
> +		LANDLOCK_SHIFT_ACCESS_NET) &
> +	       LANDLOCK_MASK_ACCESS_NET;
> +}
> +
>    #endif /* _SECURITY_LANDLOCK_RULESET_H */
> .

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 00/17] Network support for Landlock
  2022-08-27 13:30       ` Konstantin Meskhidze (A)
@ 2022-08-29 13:10         ` Mickaël Salaün
  0 siblings, 0 replies; 53+ messages in thread
From: Mickaël Salaün @ 2022-08-29 13:10 UTC (permalink / raw)
  To: Konstantin Meskhidze (A)
  Cc: willemdebruijn.kernel, linux-security-module, netdev,
	netfilter-devel, anton.sirazetdinov


On 27/08/2022 15:30, Konstantin Meskhidze (A) wrote:
> 
> 
> 7/28/2022 4:17 PM, Mickaël Salaün пишет:

[...]

>> diff --git a/security/landlock/ruleset.h b/security/landlock/ruleset.h
>> index 59229be378d6..669de66094ed 100644
>> --- a/security/landlock/ruleset.h
>> +++ b/security/landlock/ruleset.h
>> @@ -19,8 +19,8 @@
>>     #include "limits.h"
>>     #include "object.h"
>>     
>> -// TODO: get back to u16 thanks to ruleset->net_access_mask
>> -typedef u32 access_mask_t;
>> +/* Rule access mask. */
>> +typedef u16 access_mask_t;
>>     /* Makes sure all filesystem access rights can be stored. */
>>     static_assert(BITS_PER_TYPE(access_mask_t) >= LANDLOCK_NUM_ACCESS_FS);
>>     /* Makes sure all network access rights can be stored. */
>> @@ -28,6 +28,12 @@ static_assert(BITS_PER_TYPE(access_mask_t) >= LANDLOCK_NUM_ACCESS_NET);
>>     /* Makes sure for_each_set_bit() and for_each_clear_bit() calls are OK. */
>>     static_assert(sizeof(unsigned long) >= sizeof(access_mask_t));
>>     
>> +/* Ruleset access masks. */
>> +typedef u16 access_masks_t;
>> +/* Makes sure all ruleset access rights can be stored. */
>> +static_assert(BITS_PER_TYPE(access_masks_t) >=
>> +	      LANDLOCK_NUM_ACCESS_FS + LANDLOCK_NUM_ACCESS_NET);
>> +
>>     typedef u16 layer_mask_t;
>>     /* Makes sure all layers can be checked. */
>>     static_assert(BITS_PER_TYPE(layer_mask_t) >= LANDLOCK_MAX_NUM_LAYERS);
>> @@ -47,16 +53,33 @@ struct landlock_layer {
>>     	access_mask_t access;
>>     };
>>     
>> +/**
>> + * union landlock_key - Key of a ruleset's red-black tree
>> + */
>>     union landlock_key {
>>     	struct landlock_object *object;
>>     	uintptr_t data;
>>     };
>>     
>> +/**
>> + * enum landlock_key_type - Type of &union landlock_key
>> + */
>>     enum landlock_key_type {
>> +	/**
>> +	 * @LANDLOCK_KEY_INODE: Type of &landlock_ruleset.root_inode's node
>> +	 * keys.
>> +	 */
>>     	LANDLOCK_KEY_INODE = 1,
>> +	/**
>> +	 * @LANDLOCK_KEY_NET_PORT: Type of &landlock_ruleset.root_net_port's
>> +	 * node keys.
>> +	 */
>>     	LANDLOCK_KEY_NET_PORT = 2,
>>     };
>>     
>> +/**
>> + * struct landlock_id - Unique rule identifier for a ruleset
>> + */
>>     struct landlock_id {
>>     	union landlock_key key;
>>     	const enum landlock_key_type type;
>> @@ -113,15 +136,17 @@ struct landlock_hierarchy {
>>      */
>>     struct landlock_ruleset {
>>     	/**
>> -	 * @root: Root of a red-black tree containing &struct landlock_rule
>> -	 * nodes.  Once a ruleset is tied to a process (i.e. as a domain), this
>> -	 * tree is immutable until @usage reaches zero.
>> +	 * @root_inode: Root of a red-black tree containing &struct
>> +	 * landlock_rule nodes with inode object.  Once a ruleset is tied to a
>> +	 * process (i.e. as a domain), this tree is immutable until @usage
>> +	 * reaches zero.
>>     	 */
>>     	struct rb_root root_inode;
>>     	/**
>> -	 * @root_net_port: Root of a red-black tree containing object nodes
>> -	 * for network port. Once a ruleset is tied to a process (i.e. as a domain),
>> -	 * this tree is immutable until @usage reaches zero.
>> +	 * @root_net_port: Root of a red-black tree containing &struct
>> +	 * landlock_rule nodes with network port. Once a ruleset is tied to a
>> +	 * process (i.e. as a domain), this tree is immutable until @usage
>> +	 * reaches zero.
>>     	 */
>>     	struct rb_root root_net_port;
>>     	/**
>> @@ -162,32 +187,25 @@ struct landlock_ruleset {
>>     			 */
>>     			u32 num_layers;
>>     			/**
>> -			 * TODO: net_access_mask: Contains the subset of network
>> -			 * actions that are restricted by a ruleset.
>> -			 */
>> -			access_mask_t net_access_mask;
>> -			/**
>> -			 * @access_masks: Contains the subset of filesystem
>> -			 * actions that are restricted by a ruleset.  A domain
>> -			 * saves all layers of merged rulesets in a stack
>> -			 * (FAM), starting from the first layer to the last
>> -			 * one.  These layers are used when merging rulesets,
>> -			 * for user space backward compatibility (i.e.
>> -			 * future-proof), and to properly handle merged
>> +			 * @access_masks: Contains the subset of filesystem and
>> +			 * network actions that are restricted by a ruleset.
>> +			 * A domain saves all layers of merged rulesets in a
>> +			 * stack (FAM), starting from the first layer to the
>> +			 * last one.  These layers are used when merging
>> +			 * rulesets, for user space backward compatibility
>> +			 * (i.e. future-proof), and to properly handle merged
>>     			 * rulesets without overlapping access rights.  These
>>     			 * layers are set once and never changed for the
>>     			 * lifetime of the ruleset.
>>     			 */
>> -			// TODO: rename (back) to fs_access_mask because layers
>> -			// are only useful for file hierarchies.
>> -			access_mask_t access_masks[];
>> +			access_masks_t access_masks[];
>>     		};
>>     	};
>>     };
>>     
>>     struct landlock_ruleset *
>> -landlock_create_ruleset(const access_mask_t access_mask_fs,
>> -			const access_mask_t access_mask_net);
>> +landlock_create_ruleset(const access_mask_t fs_access_mask,
>> +			const access_mask_t net_access_mask);
>>     
>>     void landlock_put_ruleset(struct landlock_ruleset *const ruleset);
>>     void landlock_put_ruleset_deferred(struct landlock_ruleset *const ruleset);
>> @@ -210,41 +228,7 @@ static inline void landlock_get_ruleset(struct landlock_ruleset *const ruleset)
>>     		refcount_inc(&ruleset->usage);
>>     }
>>     
>> -// TODO: These helpers should not be required thanks to the new ruleset->net_access_mask.
>> -/* A helper function to set a filesystem mask. */
>> -static inline void
>> -landlock_set_fs_access_mask(struct landlock_ruleset *ruleset,
>> -			    const access_mask_t access_mask_fs, u16 mask_level)
>> -{
>> -	ruleset->access_masks[mask_level] = access_mask_fs;
>> -}
>> -
>> -/* A helper function to get a filesystem mask. */
>> -static inline u32
>> -landlock_get_fs_access_mask(const struct landlock_ruleset *ruleset,
>> -			    u16 mask_level)
>> -{
>> -	return (ruleset->access_masks[mask_level] & LANDLOCK_MASK_ACCESS_FS);
>> -}
>> -
>> -/* A helper function to set a network mask. */
>> -static inline void
>> -landlock_set_net_access_mask(struct landlock_ruleset *ruleset,
>> -			     const access_mask_t access_mask_net,
>> -			     u16 mask_level)
>> -{
>> -	ruleset->access_masks[mask_level] |=
>> -		(access_mask_net << LANDLOCK_MASK_SHIFT_NET);
>> -}
>> -
>> -/* A helper function to get a network mask. */
>> -static inline u32
>> -landlock_get_net_access_mask(const struct landlock_ruleset *ruleset,
>> -			     u16 mask_level)
>> -{
>> -	return (ruleset->access_masks[mask_level] >> LANDLOCK_MASK_SHIFT_NET);
>> -}
>> -
>> +// TODO: Remove if only relevant for fs.c
>>     access_mask_t get_handled_accesses(const struct landlock_ruleset *const domain,
>>     				   const u16 rule_type, const u16 num_access);
>>     
>> @@ -258,4 +242,50 @@ access_mask_t init_layer_masks(const struct landlock_ruleset *const domain,
>>     			       layer_mask_t (*const layer_masks)[],
>>     			       const enum landlock_key_type key_type);
>>     
>> +static inline void
>> +landlock_add_fs_access_mask(struct landlock_ruleset *const ruleset,
>> +			    const access_mask_t fs_access_mask,
>> +			    const u16 layer_level)
>> +{
>> +	access_mask_t fs_mask = fs_access_mask & LANDLOCK_MASK_ACCESS_FS;
>> +
>> +	/* Should already be checked in sys_landlock_create_ruleset(). */
>> +	WARN_ON_ONCE(fs_access_mask != fs_mask);
>> +	// TODO: Add tests to check "|=" and not "=" > Is it kunit test? If so, do you want to add this kind of tests in future
> landlock versions?

In this sixth patch series, landlock_set_fs_access_mask() was replacing 
the content of access_masks[] whereas landlock_set_net_access_mask() was 
ORing it. It didn't lead to a bug because landlock_set_fs_access_mask() 
was called before landlock_set_net_access_mask(), but it was brittle.

Anyway, it was a good reminder to add a test to check that filesystem 
and network restrictions work well together. This can be added as a 
basic filesystem test using a ruleset handling network restrictions but 
no network rule (in fs_test.c), and as a basic network test using a 
ruleset handling filesystem restrictions but no filestem rule (in 
net_test.c).

This could also be part of a kunit test in the future.


>> +	ruleset->access_masks[layer_level] |=
>> +		(fs_mask << LANDLOCK_SHIFT_ACCESS_FS);
>> +}
>> +
>> +static inline void
>> +landlock_add_net_access_mask(struct landlock_ruleset *const ruleset,
>> +			     const access_mask_t net_access_mask,
>> +			     const u16 layer_level)
>> +{
>> +	access_mask_t net_mask = net_access_mask & LANDLOCK_MASK_ACCESS_NET;
>> +
>> +	/* Should already be checked in sys_landlock_create_ruleset(). */
>> +	WARN_ON_ONCE(net_access_mask != net_mask);
>> +	// TODO: Add tests to check "|=" and not "="
> The same above.
> I'm going add invalid network attribute checking into TEST_F(socket,
> inval) test in coming patch.

Good

^ permalink raw reply	[flat|nested] 53+ messages in thread

end of thread, other threads:[~2022-08-29 13:11 UTC | newest]

Thread overview: 53+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-06-21  8:22 [PATCH v6 00/17] Network support for Landlock Konstantin Meskhidze
2022-06-21  8:22 ` [PATCH v6 01/17] landlock: renames access mask Konstantin Meskhidze
2022-07-01 17:08   ` Mickaël Salaün
2022-07-04  9:23     ` Konstantin Meskhidze (A)
2022-07-05 11:29     ` Konstantin Meskhidze (A)
2022-07-05 13:26       ` Mickaël Salaün
2022-07-08 12:56         ` Konstantin Meskhidze (A)
2022-06-21  8:22 ` [PATCH v6 02/17] landlock: refactors landlock_find/insert_rule Konstantin Meskhidze
2022-07-07 16:44   ` Mickaël Salaün
2022-07-08 12:53     ` Konstantin Meskhidze (A)
2022-07-08 13:56       ` Mickaël Salaün
2022-07-08 14:14         ` Konstantin Meskhidze (A)
2022-07-08 14:20         ` Konstantin Meskhidze (A)
2022-07-08 16:57           ` Mickaël Salaün
2022-07-11  8:16             ` Konstantin Meskhidze (A)
2022-07-08 13:10     ` Konstantin Meskhidze (A)
2022-07-08 13:59       ` Mickaël Salaün
2022-07-08 14:14         ` Konstantin Meskhidze (A)
2022-07-08 14:35           ` Mickaël Salaün
2022-07-11 14:05             ` Konstantin Meskhidze (A)
2022-07-28 14:48               ` Mickaël Salaün
2022-07-07 16:46   ` Mickaël Salaün
2022-07-08 12:54     ` Konstantin Meskhidze (A)
2022-06-21  8:22 ` [PATCH v6 03/17] landlock: refactors merge and inherit functions Konstantin Meskhidze
2022-06-21  8:23 ` [PATCH v6 04/17] landlock: moves helper functions Konstantin Meskhidze
2022-06-21  8:23 ` [PATCH v6 05/17] landlock: refactors " Konstantin Meskhidze
2022-06-21  8:23 ` [PATCH v6 06/17] landlock: refactors landlock_add_rule syscall Konstantin Meskhidze
2022-06-21  8:23 ` [PATCH v6 07/17] landlock: user space API network support Konstantin Meskhidze
2022-06-21  8:23 ` [PATCH v6 08/17] landlock: adds support network rules Konstantin Meskhidze
2022-06-21  8:23 ` [PATCH v6 09/17] landlock: implements TCP network hooks Konstantin Meskhidze
2022-06-21  8:23 ` [PATCH v6 10/17] seltests/landlock: moves helper function Konstantin Meskhidze
2022-06-21  8:23 ` [PATCH v6 11/17] seltests/landlock: adds tests for bind() hooks Konstantin Meskhidze
2022-07-28 13:24   ` Mickaël Salaün
2022-06-21  8:23 ` [PATCH v6 12/17] seltests/landlock: adds tests for connect() hooks Konstantin Meskhidze
2022-06-21  8:23 ` [PATCH v6 13/17] seltests/landlock: adds AF_UNSPEC family test Konstantin Meskhidze
2022-06-21  8:23 ` [PATCH v6 14/17] seltests/landlock: adds rules overlapping test Konstantin Meskhidze
2022-06-21  8:23 ` [PATCH v6 15/17] seltests/landlock: adds ruleset expanding test Konstantin Meskhidze
2022-06-21  8:23 ` [PATCH v6 16/17] seltests/landlock: adds invalid input data test Konstantin Meskhidze
2022-06-21  8:23 ` [PATCH v6 17/17] samples/landlock: adds network demo Konstantin Meskhidze
2022-07-27 20:26   ` Mickaël Salaün
2022-07-28  9:21     ` Konstantin Meskhidze (A)
2022-07-26 17:43 ` [PATCH v6 00/17] Network support for Landlock Mickaël Salaün
2022-07-27 19:54   ` Mickaël Salaün
2022-07-28  9:19     ` Konstantin Meskhidze (A)
2022-07-28  9:25     ` Konstantin Meskhidze (A)
2022-07-28 10:12       ` Mickaël Salaün
2022-07-28 11:27         ` Konstantin Meskhidze (A)
2022-07-28 13:17     ` Mickaël Salaün
2022-08-23  9:10       ` Konstantin Meskhidze (A)
2022-08-27 13:30       ` Konstantin Meskhidze (A)
2022-08-29 13:10         ` Mickaël Salaün
2022-07-27 20:21   ` Mickaël Salaün
2022-07-28  9:20     ` Konstantin Meskhidze (A)

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.