Netdev List
 help / color / mirror / Atom feed
From: Konstantin Meskhidze <konstantin.meskhidze@huawei.com>
To: <mic@digikod.net>
Cc: <willemdebruijn.kernel@gmail.com>,
	<linux-security-module@vger.kernel.org>, <netdev@vger.kernel.org>,
	<netfilter-devel@vger.kernel.org>, <yusongping@huawei.com>,
	<anton.sirazetdinov@huawei.com>
Subject: [PATCH v6 08/17] landlock: adds support network rules
Date: Tue, 21 Jun 2022 16:23:04 +0800	[thread overview]
Message-ID: <20220621082313.3330667-9-konstantin.meskhidze@huawei.com> (raw)
In-Reply-To: <20220621082313.3330667-1-konstantin.meskhidze@huawei.com>

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


  parent reply	other threads:[~2022-06-21  8:24 UTC|newest]

Thread overview: 53+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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 ` Konstantin Meskhidze [this message]
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)

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220621082313.3330667-9-konstantin.meskhidze@huawei.com \
    --to=konstantin.meskhidze@huawei.com \
    --cc=anton.sirazetdinov@huawei.com \
    --cc=linux-security-module@vger.kernel.org \
    --cc=mic@digikod.net \
    --cc=netdev@vger.kernel.org \
    --cc=netfilter-devel@vger.kernel.org \
    --cc=willemdebruijn.kernel@gmail.com \
    --cc=yusongping@huawei.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox