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>,
<artem.kuzin@huawei.com>, <anton.sirazetdinov@huawei.com>
Subject: [RFC PATCH v4 08/15] landlock: add support network rules
Date: Wed, 9 Mar 2022 21:44:52 +0800 [thread overview]
Message-ID: <20220309134459.6448-9-konstantin.meskhidze@huawei.com> (raw)
In-Reply-To: <20220309134459.6448-1-konstantin.meskhidze@huawei.com>
This modification 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 v3:
* Split commit.
* Add network rule support for internal landlock functions.
* Add set_masks and get_masks for network.
* Add rb_root root_net_port.
---
security/landlock/fs.c | 2 +-
security/landlock/limits.h | 6 +++
security/landlock/ruleset.c | 88 +++++++++++++++++++++++++++++++++---
security/landlock/ruleset.h | 14 +++++-
security/landlock/syscalls.c | 10 +++-
5 files changed, 109 insertions(+), 11 deletions(-)
diff --git a/security/landlock/fs.c b/security/landlock/fs.c
index 75ebdce5cd16..5cd339061cdb 100644
--- a/security/landlock/fs.c
+++ b/security/landlock/fs.c
@@ -231,7 +231,7 @@ static int check_access_path(const struct landlock_ruleset *const domain,
inode = d_backing_inode(walker_path.dentry);
object_ptr = landlock_inode(inode)->object;
- layer_mask = landlock_unmask_layers(domain, object_ptr,
+ layer_mask = landlock_unmask_layers(domain, object_ptr, 0,
access_request, layer_mask,
LANDLOCK_RULE_PATH_BENEATH);
if (layer_mask == 0) {
diff --git a/security/landlock/limits.h b/security/landlock/limits.h
index 2a0a1095ee27..fdbef85e4de0 100644
--- a/security/landlock/limits.h
+++ b/security/landlock/limits.h
@@ -18,4 +18,10 @@
#define LANDLOCK_LAST_ACCESS_FS LANDLOCK_ACCESS_FS_MAKE_SYM
#define LANDLOCK_MASK_ACCESS_FS ((LANDLOCK_LAST_ACCESS_FS << 1) - 1)
+#define LANDLOCK_LAST_ACCESS_NET LANDLOCK_ACCESS_NET_CONNECT_TCP
+#define LANDLOCK_MASK_ACCESS_NET ((LANDLOCK_LAST_ACCESS_NET << 1) - 1)
+#define LANDLOCK_MASK_SHIFT_NET 16
+
+#define LANDLOCK_RULE_TYPE_NUM LANDLOCK_RULE_NET_SERVICE
+
#endif /* _SECURITY_LANDLOCK_LIMITS_H */
diff --git a/security/landlock/ruleset.c b/security/landlock/ruleset.c
index 7179b10f3538..1cecca59a942 100644
--- a/security/landlock/ruleset.c
+++ b/security/landlock/ruleset.c
@@ -35,6 +35,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
@@ -58,16 +59,32 @@ u32 landlock_get_fs_access_mask(const struct landlock_ruleset *ruleset, u16 mask
return ruleset->access_masks[mask_level];
}
+/* A helper function to set a network mask */
+void landlock_set_net_access_mask(struct landlock_ruleset *ruleset,
+ const struct landlock_access_mask *access_mask_set,
+ u16 mask_level)
+{
+ ruleset->access_masks[mask_level] |= (access_mask_set->net << LANDLOCK_MASK_SHIFT_NET);
+}
+
+/* A helper function to get a network mask */
+u32 landlock_get_net_access_mask(const struct landlock_ruleset *ruleset, u16 mask_level)
+{
+ return (ruleset->access_masks[mask_level] >> LANDLOCK_MASK_SHIFT_NET);
+}
+
struct landlock_ruleset *landlock_create_ruleset(const struct landlock_access_mask *access_mask_set)
{
struct landlock_ruleset *new_ruleset;
/* Informs about useless ruleset. */
- if (!access_mask_set->fs)
+ if (!access_mask_set->fs && !access_mask_set->net)
return ERR_PTR(-ENOMSG);
new_ruleset = create_ruleset(1);
- if (!IS_ERR(new_ruleset))
+ if (!IS_ERR(new_ruleset) && access_mask_set->fs)
landlock_set_fs_access_mask(new_ruleset, access_mask_set, 0);
+ if (!IS_ERR(new_ruleset) && access_mask_set->net)
+ landlock_set_net_access_mask(new_ruleset, access_mask_set, 0);
return new_ruleset;
}
@@ -111,6 +128,9 @@ static struct landlock_rule *create_rule(
landlock_get_object(object_ptr);
new_rule->object.ptr = object_ptr;
break;
+ case LANDLOCK_RULE_NET_SERVICE:
+ new_rule->object.data = object_data;
+ break;
default:
return ERR_PTR(-EINVAL);
}
@@ -145,10 +165,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);
}
/**
@@ -191,6 +213,12 @@ static int insert_rule(struct landlock_ruleset *const ruleset,
object = (uintptr_t)object_ptr;
root = &ruleset->root_inode;
break;
+ case LANDLOCK_RULE_NET_SERVICE:
+ if (WARN_ON_ONCE(!object_data || !layers))
+ return -ENOENT;
+ object = object_data;
+ root = &ruleset->root_net_port;
+ break;
default:
return -EINVAL;
}
@@ -242,6 +270,14 @@ static int insert_rule(struct landlock_ruleset *const ruleset,
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], rule_type);
+ 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;
}
@@ -259,6 +295,14 @@ 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, rule_type);
+ 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;
}
@@ -319,6 +363,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;
}
@@ -338,11 +385,14 @@ static int tree_merge(struct landlock_ruleset *const src,
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, &layers,
- ARRAY_SIZE(layers), rule_type);
+ ARRAY_SIZE(layers), rule_type);
+ break;
+ case LANDLOCK_RULE_NET_SERVICE:
+ err = insert_rule(dst, NULL, walker_rule->object.data, &layers,
+ ARRAY_SIZE(layers), rule_type);
break;
}
if (err)
@@ -379,6 +429,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);
@@ -398,6 +452,9 @@ 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;
}
@@ -410,6 +467,11 @@ static int tree_copy(struct landlock_ruleset *const parent,
&walker_rule->layers, walker_rule->num_layers,
rule_type);
break;
+ case LANDLOCK_RULE_NET_SERVICE:
+ err = insert_rule(child, NULL, walker_rule->object.data,
+ &walker_rule->layers, walker_rule->num_layers,
+ rule_type);
+ break;
}
if (err)
return err;
@@ -432,6 +494,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 inode tree. */
+ err = tree_copy(parent, child, LANDLOCK_RULE_NET_SERVICE);
if (err)
goto out_unlock;
@@ -464,6 +530,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);
}
@@ -565,6 +634,9 @@ const struct landlock_rule *landlock_find_rule(
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:
return ERR_PTR(-EINVAL);
}
@@ -586,8 +658,8 @@ const struct landlock_rule *landlock_find_rule(
/* Access-control management */
u64 landlock_unmask_layers(const struct landlock_ruleset *const domain,
const struct landlock_object *object_ptr,
- const u32 access_request, u64 layer_mask,
- const u16 rule_type)
+ const u16 port, const u32 access_request,
+ u64 layer_mask, const u16 rule_type)
{
const struct landlock_rule *rule;
size_t i;
@@ -600,6 +672,10 @@ u64 landlock_unmask_layers(const struct landlock_ruleset *const domain,
LANDLOCK_RULE_PATH_BENEATH);
rcu_read_unlock();
break;
+ case LANDLOCK_RULE_NET_SERVICE:
+ rule = landlock_find_rule(domain, (uintptr_t)port,
+ LANDLOCK_RULE_NET_SERVICE);
+ break;
}
if (!rule)
diff --git a/security/landlock/ruleset.h b/security/landlock/ruleset.h
index 0a7d4b1f51fd..abf3e09a65cd 100644
--- a/security/landlock/ruleset.h
+++ b/security/landlock/ruleset.h
@@ -24,6 +24,10 @@ struct landlock_access_mask {
* @fs: Filesystem access mask.
*/
u16 fs;
+ /**
+ * @net: Network access mask.
+ */
+ u16 net;
};
/**
@@ -98,6 +102,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.
@@ -185,7 +195,7 @@ u32 landlock_get_fs_access_mask(const struct landlock_ruleset *ruleset, u16 mask
u64 landlock_unmask_layers(const struct landlock_ruleset *const domain,
const struct landlock_object *object_ptr,
- const u32 access_request, u64 layer_mask,
- const u16 rule_type);
+ const u16 port, const u32 access_request,
+ u64 layer_mask, const u16 rule_type);
#endif /* _SECURITY_LANDLOCK_RULESET_H */
diff --git a/security/landlock/syscalls.c b/security/landlock/syscalls.c
index fcbce83d64ef..b91455a19356 100644
--- a/security/landlock/syscalls.c
+++ b/security/landlock/syscalls.c
@@ -160,7 +160,7 @@ SYSCALL_DEFINE3(landlock_create_ruleset,
{
struct landlock_ruleset_attr ruleset_attr;
struct landlock_ruleset *ruleset;
- struct landlock_access_mask access_mask_set = {.fs = 0};
+ struct landlock_access_mask access_mask_set = {.fs = 0, .net = 0};
int err, ruleset_fd;
/* Build-time checks. */
@@ -187,8 +187,14 @@ SYSCALL_DEFINE3(landlock_create_ruleset,
if ((ruleset_attr.handled_access_fs | LANDLOCK_MASK_ACCESS_FS) !=
LANDLOCK_MASK_ACCESS_FS)
return -EINVAL;
- access_mask_set.fs = ruleset_attr.handled_access_fs;
+ /* Checks network content (and 32-bits cast). */
+ if ((ruleset_attr.handled_access_net | LANDLOCK_MASK_ACCESS_NET) !=
+ LANDLOCK_MASK_ACCESS_NET)
+ return -EINVAL;
+
+ access_mask_set.fs = ruleset_attr.handled_access_fs;
+ access_mask_set.net = ruleset_attr.handled_access_net;
/* Checks arguments and transforms to kernel struct. */
ruleset = landlock_create_ruleset(&access_mask_set);
if (IS_ERR(ruleset))
--
2.25.1
next prev parent reply other threads:[~2022-03-09 13:45 UTC|newest]
Thread overview: 63+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-03-09 13:44 [RFC PATCH v4 00/15] Landlock LSM Konstantin Meskhidze
2022-03-09 13:44 ` [RFC PATCH v4 01/15] landlock: access mask renaming Konstantin Meskhidze
2022-04-01 16:47 ` Mickaël Salaün
2022-04-04 8:17 ` Konstantin Meskhidze
2022-03-09 13:44 ` [RFC PATCH v4 02/15] landlock: filesystem access mask helpers Konstantin Meskhidze
2022-03-15 17:48 ` Mickaël Salaün
2022-03-17 13:25 ` Konstantin Meskhidze
2022-03-17 18:03 ` Mickaël Salaün
2022-03-18 11:36 ` Konstantin Meskhidze
2022-03-09 13:44 ` [RFC PATCH v4 03/15] landlock: landlock_find/insert_rule refactoring Konstantin Meskhidze
2022-03-16 8:27 ` Mickaël Salaün
2022-03-17 14:29 ` Konstantin Meskhidze
2022-03-18 18:33 ` Mickaël Salaün
2022-03-22 12:33 ` Konstantin Meskhidze
2022-03-22 13:24 ` Mickaël Salaün
2022-03-23 8:41 ` Konstantin Meskhidze
2022-04-12 11:07 ` [RFC PATCH v4 03/15] landlock: landlock_find/insert_rule refactoring (TCP port 0) Mickaël Salaün
2022-04-26 9:15 ` Konstantin Meskhidze
2022-03-09 13:44 ` [RFC PATCH v4 04/15] landlock: merge and inherit function refactoring Konstantin Meskhidze
2022-03-09 13:44 ` [RFC PATCH v4 05/15] landlock: unmask_layers() " Konstantin Meskhidze
2022-03-09 13:44 ` [RFC PATCH v4 06/15] landlock: landlock_add_rule syscall refactoring Konstantin Meskhidze
2022-04-12 11:12 ` Mickaël Salaün
2022-04-26 8:30 ` Konstantin Meskhidze
2022-03-09 13:44 ` [RFC PATCH v4 07/15] landlock: user space API network support Konstantin Meskhidze
2022-04-12 11:21 ` Mickaël Salaün
2022-04-12 13:48 ` Mickaël Salaün
2022-04-12 14:05 ` Konstantin Meskhidze
2022-04-12 16:10 ` Mickaël Salaün
2022-04-26 10:17 ` Konstantin Meskhidze
2022-04-25 14:29 ` Konstantin Meskhidze
2022-03-09 13:44 ` Konstantin Meskhidze [this message]
2022-04-08 16:30 ` [RFC PATCH v4 08/15] landlock: add support network rules Mickaël Salaün
2022-04-11 13:44 ` Konstantin Meskhidze
2022-04-11 16:20 ` Mickaël Salaün
2022-04-12 8:38 ` Konstantin Meskhidze
2022-03-09 13:44 ` [RFC PATCH v4 09/15] landlock: TCP network hooks implementation Konstantin Meskhidze
2022-04-11 16:24 ` Mickaël Salaün
2022-04-26 8:36 ` Konstantin Meskhidze
2022-03-09 13:44 ` [RFC PATCH v4 10/15] seltest/landlock: add tests for bind() hooks Konstantin Meskhidze
2022-04-01 16:52 ` Mickaël Salaün
2022-04-04 8:28 ` Konstantin Meskhidze
2022-04-04 9:44 ` Mickaël Salaün
2022-04-06 14:12 ` Konstantin Meskhidze
2022-04-08 16:41 ` Mickaël Salaün
2022-04-26 9:35 ` Konstantin Meskhidze
2022-05-16 10:10 ` Mickaël Salaün
2022-05-16 10:22 ` Konstantin Meskhidze
2022-04-04 18:32 ` Mickaël Salaün
2022-04-06 14:17 ` Konstantin Meskhidze
2022-03-09 13:44 ` [RFC PATCH v4 11/15] seltest/landlock: add tests for connect() hooks Konstantin Meskhidze
2022-03-09 13:44 ` [RFC PATCH v4 12/15] seltest/landlock: connect() with AF_UNSPEC tests Konstantin Meskhidze
2022-03-09 13:44 ` [RFC PATCH v4 13/15] seltest/landlock: rules overlapping test Konstantin Meskhidze
2022-03-09 13:44 ` [RFC PATCH v4 14/15] seltest/landlock: ruleset expanding test Konstantin Meskhidze
2022-03-09 13:44 ` [RFC PATCH v4 15/15] seltest/landlock: invalid user input data test Konstantin Meskhidze
2022-03-15 17:02 ` [RFC PATCH v4 00/15] Landlock LSM Mickaël Salaün
2022-03-17 13:01 ` Konstantin Meskhidze
2022-03-17 17:26 ` Mickaël Salaün
2022-03-18 15:55 ` Konstantin Meskhidze
2022-03-23 16:30 ` Konstantin Meskhidze
2022-03-24 12:27 ` Mickaël Salaün
2022-03-24 13:34 ` Konstantin Meskhidze
2022-03-24 15:30 ` Mickaël Salaün
2022-03-24 16:19 ` Konstantin Meskhidze
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=20220309134459.6448-9-konstantin.meskhidze@huawei.com \
--to=konstantin.meskhidze@huawei.com \
--cc=anton.sirazetdinov@huawei.com \
--cc=artem.kuzin@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;
as well as URLs for NNTP newsgroup(s).