]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
landlock: Refactor merge/inherit_ruleset helpers
authorKonstantin Meskhidze <konstantin.meskhidze@huawei.com>
Thu, 26 Oct 2023 01:47:43 +0000 (09:47 +0800)
committerMickaël Salaün <mic@digikod.net>
Thu, 26 Oct 2023 19:07:12 +0000 (21:07 +0200)
Refactor merge_ruleset() and inherit_ruleset() functions to support new
rule types. Add merge_tree() and inherit_tree() helpers.  They use a
specific ruleset's red-black tree according to a key type argument.

Signed-off-by: Konstantin Meskhidze <konstantin.meskhidze@huawei.com>
Link: https://lore.kernel.org/r/20231026014751.414649-5-konstantin.meskhidze@huawei.com
Signed-off-by: Mickaël Salaün <mic@digikod.net>
security/landlock/ruleset.c

index 3553632e76d9344bb24a05510132555cad7f3b52..cf88754a3f308c262e12b8663507ccb590518fb7 100644 (file)
@@ -300,36 +300,22 @@ static void put_hierarchy(struct landlock_hierarchy *hierarchy)
        }
 }
 
-static int merge_ruleset(struct landlock_ruleset *const dst,
-                        struct landlock_ruleset *const src)
+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;
 
        might_sleep();
-       /* Should already be checked by landlock_merge_ruleset() */
-       if (WARN_ON_ONCE(!src))
-               return 0;
-       /* Only merge into a domain. */
-       if (WARN_ON_ONCE(!dst || !dst->hierarchy))
-               return -EINVAL;
+       lockdep_assert_held(&dst->lock);
+       lockdep_assert_held(&src->lock);
 
-       src_root = get_root(src, LANDLOCK_KEY_INODE);
+       src_root = get_root(src, key_type);
        if (IS_ERR(src_root))
                return PTR_ERR(src_root);
 
-       /* Locks @dst first because we are its only owner. */
-       mutex_lock(&dst->lock);
-       mutex_lock_nested(&src->lock, SINGLE_DEPTH_NESTING);
-
-       /* Stacks the new layer. */
-       if (WARN_ON_ONCE(src->num_layers != 1 || dst->num_layers < 1)) {
-               err = -EINVAL;
-               goto out_unlock;
-       }
-       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) {
@@ -338,23 +324,52 @@ static int merge_ruleset(struct landlock_ruleset *const dst,
                } };
                const struct landlock_id id = {
                        .key = walker_rule->key,
-                       .type = LANDLOCK_KEY_INODE,
+                       .type = key_type,
                };
 
-               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;
-               }
+               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;
 
                err = insert_rule(dst, id, &layers, ARRAY_SIZE(layers));
                if (err)
-                       goto out_unlock;
+                       return err;
        }
+       return err;
+}
+
+static int merge_ruleset(struct landlock_ruleset *const dst,
+                        struct landlock_ruleset *const src)
+{
+       int err = 0;
+
+       might_sleep();
+       /* Should already be checked by landlock_merge_ruleset() */
+       if (WARN_ON_ONCE(!src))
+               return 0;
+       /* Only merge into a domain. */
+       if (WARN_ON_ONCE(!dst || !dst->hierarchy))
+               return -EINVAL;
+
+       /* Locks @dst first because we are its only owner. */
+       mutex_lock(&dst->lock);
+       mutex_lock_nested(&src->lock, SINGLE_DEPTH_NESTING);
+
+       /* Stacks the new layer. */
+       if (WARN_ON_ONCE(src->num_layers != 1 || dst->num_layers < 1)) {
+               err = -EINVAL;
+               goto out_unlock;
+       }
+       dst->access_masks[dst->num_layers - 1] = src->access_masks[0];
+
+       /* Merges the @src inode tree. */
+       err = merge_tree(dst, src, LANDLOCK_KEY_INODE);
+       if (err)
+               goto out_unlock;
 
 out_unlock:
        mutex_unlock(&src->lock);
@@ -362,38 +377,55 @@ out_unlock:
        return err;
 }
 
-static int inherit_ruleset(struct landlock_ruleset *const parent,
-                          struct landlock_ruleset *const child)
+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;
 
        might_sleep();
-       if (!parent)
-               return 0;
+       lockdep_assert_held(&parent->lock);
+       lockdep_assert_held(&child->lock);
 
-       parent_root = get_root(parent, LANDLOCK_KEY_INODE);
+       parent_root = get_root(parent, key_type);
        if (IS_ERR(parent_root))
                return PTR_ERR(parent_root);
 
-       /* Locks @child first because we are its only owner. */
-       mutex_lock(&child->lock);
-       mutex_lock_nested(&parent->lock, SINGLE_DEPTH_NESTING);
-
-       /* Copies the @parent tree. */
+       /* Copies the @parent inode or network tree. */
        rbtree_postorder_for_each_entry_safe(walker_rule, next_rule,
                                             parent_root, node) {
                const struct landlock_id id = {
                        .key = walker_rule->key,
-                       .type = LANDLOCK_KEY_INODE,
+                       .type = key_type,
                };
 
                err = insert_rule(child, id, &walker_rule->layers,
                                  walker_rule->num_layers);
                if (err)
-                       goto out_unlock;
+                       return err;
        }
+       return err;
+}
+
+static int inherit_ruleset(struct landlock_ruleset *const parent,
+                          struct landlock_ruleset *const child)
+{
+       int err = 0;
+
+       might_sleep();
+       if (!parent)
+               return 0;
+
+       /* Locks @child first because we are its only owner. */
+       mutex_lock(&child->lock);
+       mutex_lock_nested(&parent->lock, SINGLE_DEPTH_NESTING);
+
+       /* Copies the @parent inode tree. */
+       err = inherit_tree(parent, child, LANDLOCK_KEY_INODE);
+       if (err)
+               goto out_unlock;
 
        if (WARN_ON_ONCE(child->num_layers <= parent->num_layers)) {
                err = -EINVAL;