From: "Mickaël Salaün" <mic@digikod.net>
To: Konstantin Meskhidze <konstantin.meskhidze@huawei.com>
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: Re: [RFC PATCH v4 03/15] landlock: landlock_find/insert_rule refactoring
Date: Wed, 16 Mar 2022 09:27:15 +0100 [thread overview]
Message-ID: <bc44f11f-0eaa-a5f6-c5dc-1d36570f1be1@digikod.net> (raw)
In-Reply-To: <20220309134459.6448-4-konstantin.meskhidze@huawei.com>
On 09/03/2022 14:44, Konstantin Meskhidze wrote:
> A new object union added to support a socket port
> rule type. To support it landlock_insert_rule() and
> landlock_find_rule() were refactored. 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 v3:
> * Split commit.
> * Refactoring landlock_insert_rule and landlock_find_rule functions.
> * Rename new_ruleset->root_inode.
>
> ---
> security/landlock/fs.c | 5 +-
> security/landlock/ruleset.c | 108 +++++++++++++++++++++++++-----------
> security/landlock/ruleset.h | 26 +++++----
> 3 files changed, 94 insertions(+), 45 deletions(-)
>
> diff --git a/security/landlock/fs.c b/security/landlock/fs.c
> index 97f5c455f5a7..1497948d754f 100644
> --- a/security/landlock/fs.c
> +++ b/security/landlock/fs.c
> @@ -168,7 +168,7 @@ 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);
For consistency, please use 80 columns everywhere.
> mutex_unlock(&ruleset->lock);
> /*
> * No need to check for an error because landlock_insert_rule()
> @@ -195,7 +195,8 @@ static inline u64 unmask_layers(
> inode = d_backing_inode(path->dentry);
> rcu_read_lock();
> rule = landlock_find_rule(domain,
> - rcu_dereference(landlock_inode(inode)->object));
> + (uintptr_t)rcu_dereference(landlock_inode(inode)->object),
> + LANDLOCK_RULE_PATH_BENEATH);
> rcu_read_unlock();
> if (!rule)
> return layer_mask;
> diff --git a/security/landlock/ruleset.c b/security/landlock/ruleset.c
> index a6212b752549..971685c48641 100644
> --- a/security/landlock/ruleset.c
> +++ b/security/landlock/ruleset.c
> @@ -34,7 +34,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
> @@ -81,10 +81,12 @@ static void build_check_rule(void)
> }
>
> static struct landlock_rule *create_rule(
> - struct landlock_object *const object,
> + 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)
> + const struct landlock_layer *const new_layer,
> + const u16 rule_type)
> {
> struct landlock_rule *new_rule;
> u32 new_num_layers;
> @@ -103,8 +105,16 @@ static struct landlock_rule *create_rule(
> if (!new_rule)
> return ERR_PTR(-ENOMEM);
> RB_CLEAR_NODE(&new_rule->node);
> - landlock_get_object(object);
> - new_rule->object = object;
> +
> + switch (rule_type) {
> + case LANDLOCK_RULE_PATH_BENEATH:
> + landlock_get_object(object_ptr);
> + new_rule->object.ptr = object_ptr;
> + break;
> + default:
> + return ERR_PTR(-EINVAL);
This would lead to memory leak. You should at least add a
WARN_ON_ONCE(1) here, but a proper solution would be to remove the use
of rule_type and only rely on object_ptr and object_data values. You can
also add a WARN_ON_ONCE(object_ptr && object_data).
> + }
> +
> new_rule->num_layers = new_num_layers;
> /* Copies the original layer stack. */
> memcpy(new_rule->layers, layers,
> @@ -120,7 +130,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);
> }
>
> @@ -156,26 +166,38 @@ 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,
> + const uintptr_t object_data,
> const struct landlock_layer (*const layers)[],
> - size_t num_layers)
> + size_t num_layers, u16 rule_type)
> {
> struct rb_node **walker_node;
> struct rb_node *parent_node = NULL;
> struct landlock_rule *new_rule;
> + uintptr_t object;
> + struct rb_root *root;
>
> might_sleep();
> lockdep_assert_held(&ruleset->lock);
> - if (WARN_ON_ONCE(!object || !layers))
> - return -ENOENT;
You can leave this code here.
> - walker_node = &(ruleset->root.rb_node);
> + /* Choose rb_tree structure depending on a rule type */
> + switch (rule_type) {
> + case LANDLOCK_RULE_PATH_BENEATH:
> + if (WARN_ON_ONCE(!object_ptr || !layers))
> + return -ENOENT;
> + object = (uintptr_t)object_ptr;
> + root = &ruleset->root_inode;
> + break;
> + default:
> + 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) {
> parent_node = *walker_node;
> - if (this->object < object)
> + if (this->object.data < object)
> walker_node = &((*walker_node)->rb_right);
> else
> walker_node = &((*walker_node)->rb_left);
> @@ -207,11 +229,15 @@ 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:
Same here and for the following code, you should replace such
switch/case with an if (object_ptr).
> + new_rule = create_rule(object_ptr, 0, &this->layers, this->num_layers,
> + &(*layers)[0], rule_type);
> + 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);
Use the root variable here. Same for the following code and patches.
> free_rule(this);
> return 0;
> }
> @@ -220,11 +246,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, rule_type);
> + 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;
> }
> @@ -242,7 +272,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 u32 access)
> + struct landlock_object *const object_ptr,
> + const uintptr_t object_data,
> + const u32 access, const u16 rule_type)
> {
> struct landlock_layer layers[] = {{
> .access = access,
> @@ -251,7 +283,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, &layers,
> + ARRAY_SIZE(layers), rule_type);
> }
>
> static inline void get_hierarchy(struct landlock_hierarchy *const hierarchy)
> @@ -297,7 +330,7 @@ static int merge_ruleset(struct landlock_ruleset *const dst,
>
> /* Merges the @src tree. */
> rbtree_postorder_for_each_entry_safe(walker_rule, next_rule,
> - &src->root, node) {
> + &src->root_inode, node) {
> struct landlock_layer layers[] = {{
> .level = dst->num_layers,
> }};
> @@ -311,8 +344,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,
> - ARRAY_SIZE(layers));
> + err = insert_rule(dst, walker_rule->object.ptr, 0, &layers,
> + ARRAY_SIZE(layers), LANDLOCK_RULE_PATH_BENEATH);
> if (err)
> goto out_unlock;
> }
> @@ -323,6 +356,8 @@ static int merge_ruleset(struct landlock_ruleset *const dst,
> return err;
> }
>
> +
> +
Useless lines.
> static int inherit_ruleset(struct landlock_ruleset *const parent,
> struct landlock_ruleset *const child)
> {
> @@ -339,9 +374,10 @@ 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,
> - &walker_rule->layers, walker_rule->num_layers);
> + &parent->root_inode, node) {
> + err = insert_rule(child, walker_rule->object.ptr, 0,
> + &walker_rule->layers, walker_rule->num_layers,
> + LANDLOCK_RULE_PATH_BENEATH);
> if (err)
> goto out_unlock;
> }
> @@ -372,7 +408,7 @@ 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,
> + rbtree_postorder_for_each_entry_safe(freeme, next, &ruleset->root_inode,
> node)
> free_rule(freeme);
> put_hierarchy(ruleset->hierarchy);
> @@ -465,20 +501,28 @@ struct landlock_ruleset *landlock_merge_ruleset(
> */
> 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)
object_data can be 0. You need to add a test with such value.
We need to be sure that this change cannot affect the current FS code.
> return NULL;
> - node = ruleset->root.rb_node;
> +
> + switch (rule_type) {
> + case LANDLOCK_RULE_PATH_BENEATH:
> + node = ruleset->root_inode.rb_node;
> + break;
> + default:
> + return ERR_PTR(-EINVAL);
This is a bug. There is no check for such value. You need to check and
update all call sites to catch such errors. Same for all new use of
ERR_PTR().
> + }
> +
> 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 bc87e5f787f7..088b8d95f653 100644
> --- a/security/landlock/ruleset.h
> +++ b/security/landlock/ruleset.h
> @@ -50,15 +50,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 socket port object.
…or a raw data value (e.g. a network socket port).
> This is used as a key for this ruleset element.
> + * This pointer is set once and never modified. It always points to an
s/This pointer/@object.ptr/
> + * 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
> @@ -95,7 +97,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.
> @@ -157,7 +159,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 u32 access);
> + struct landlock_object *const object_ptr,
> + const uintptr_t object_data,
> + const u32 access, const u16 rule_type);
>
> struct landlock_ruleset *landlock_merge_ruleset(
> struct landlock_ruleset *const parent,
> @@ -165,7 +169,7 @@ struct landlock_ruleset *landlock_merge_ruleset(
>
> 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
>
next prev parent reply other threads:[~2022-03-16 8:26 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 [this message]
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 ` [RFC PATCH v4 08/15] landlock: add support network rules Konstantin Meskhidze
2022-04-08 16:30 ` 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=bc44f11f-0eaa-a5f6-c5dc-1d36570f1be1@digikod.net \
--to=mic@digikod.net \
--cc=anton.sirazetdinov@huawei.com \
--cc=artem.kuzin@huawei.com \
--cc=konstantin.meskhidze@huawei.com \
--cc=linux-security-module@vger.kernel.org \
--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).