apparmor: Fix regression in mount mediation
authorJohn Johansen <john.johansen@canonical.com>
Sun, 10 Sep 2023 10:35:22 +0000 (03:35 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 28 Nov 2023 17:20:07 +0000 (17:20 +0000)
[ Upstream commit 157a3537d6bc28ceb9a11fc8cb67f2152d860146 ]

commit 2db154b3ea8e ("vfs: syscall: Add move_mount(2) to move mounts around")

introduced a new move_mount(2) system call and a corresponding new LSM
security_move_mount hook but did not implement this hook for any
existing LSM. This creates a regression for AppArmor mediation of
mount. This patch provides a base mapping of the move_mount syscall to
the existing mount mediation. In the future we may introduce
additional mediations around the new mount calls.

Fixes: 2db154b3ea8e ("vfs: syscall: Add move_mount(2) to move mounts around")
CC: stable@vger.kernel.org
Reported-by: Andreas Steinmetz <anstein99@googlemail.com>
Signed-off-by: John Johansen <john.johansen@canonical.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
security/apparmor/include/mount.h
security/apparmor/lsm.c
security/apparmor/mount.c

index 10c76f906a653778395173a37b0777e0b2f4376a..46834f8281794d9f672b58e446ea506265d94c85 100644 (file)
@@ -38,9 +38,12 @@ int aa_mount_change_type(const struct cred *subj_cred,
                         struct aa_label *label, const struct path *path,
                         unsigned long flags);
 
+int aa_move_mount_old(const struct cred *subj_cred,
+                     struct aa_label *label, const struct path *path,
+                     const char *old_name);
 int aa_move_mount(const struct cred *subj_cred,
-                 struct aa_label *label, const struct path *path,
-                 const char *old_name);
+                 struct aa_label *label, const struct path *from_path,
+                 const struct path *to_path);
 
 int aa_new_mount(const struct cred *subj_cred,
                 struct aa_label *label, const char *dev_name,
index 60f95cc4532a860717eacf7ae5fc7dbd80474957..6fdab1b5ede5c50f6603a538e07b44e87c844c97 100644 (file)
@@ -607,8 +607,8 @@ static int apparmor_sb_mount(const char *dev_name, const struct path *path,
                        error = aa_mount_change_type(current_cred(), label,
                                                     path, flags);
                else if (flags & MS_MOVE)
-                       error = aa_move_mount(current_cred(), label, path,
-                                             dev_name);
+                       error = aa_move_mount_old(current_cred(), label, path,
+                                                 dev_name);
                else
                        error = aa_new_mount(current_cred(), label, dev_name,
                                             path, type, flags, data);
@@ -618,6 +618,21 @@ static int apparmor_sb_mount(const char *dev_name, const struct path *path,
        return error;
 }
 
+static int apparmor_move_mount(const struct path *from_path,
+                              const struct path *to_path)
+{
+       struct aa_label *label;
+       int error = 0;
+
+       label = __begin_current_label_crit_section();
+       if (!unconfined(label))
+               error = aa_move_mount(current_cred(), label, from_path,
+                                     to_path);
+       __end_current_label_crit_section(label);
+
+       return error;
+}
+
 static int apparmor_sb_umount(struct vfsmount *mnt, int flags)
 {
        struct aa_label *label;
@@ -1240,6 +1255,7 @@ static struct security_hook_list apparmor_hooks[] __ro_after_init = {
        LSM_HOOK_INIT(capget, apparmor_capget),
        LSM_HOOK_INIT(capable, apparmor_capable),
 
+       LSM_HOOK_INIT(move_mount, apparmor_move_mount),
        LSM_HOOK_INIT(sb_mount, apparmor_sb_mount),
        LSM_HOOK_INIT(sb_umount, apparmor_sb_umount),
        LSM_HOOK_INIT(sb_pivotroot, apparmor_sb_pivotroot),
index 2bb77aacc49ae120b67bc418c532b590286a9f00..f2a114e5400792158b0b3cf35549cf50833381d6 100644 (file)
@@ -483,36 +483,46 @@ int aa_mount_change_type(const struct cred *subj_cred,
 }
 
 int aa_move_mount(const struct cred *subj_cred,
-                 struct aa_label *label, const struct path *path,
-                 const char *orig_name)
+                 struct aa_label *label, const struct path *from_path,
+                 const struct path *to_path)
 {
        struct aa_profile *profile;
-       char *buffer = NULL, *old_buffer = NULL;
-       struct path old_path;
+       char *to_buffer = NULL, *from_buffer = NULL;
        int error;
 
        AA_BUG(!label);
-       AA_BUG(!path);
+       AA_BUG(!from_path);
+       AA_BUG(!to_path);
+
+       to_buffer = aa_get_buffer(false);
+       from_buffer = aa_get_buffer(false);
+       error = -ENOMEM;
+       if (!to_buffer || !from_buffer)
+               goto out;
+       error = fn_for_each_confined(label, profile,
+                       match_mnt(subj_cred, profile, to_path, to_buffer,
+                                 from_path, from_buffer,
+                                 NULL, MS_MOVE, NULL, false));
+out:
+       aa_put_buffer(to_buffer);
+       aa_put_buffer(from_buffer);
+
+       return error;
+}
+
+int aa_move_mount_old(const struct cred *subj_cred, struct aa_label *label,
+                     const struct path *path, const char *orig_name)
+{
+       struct path old_path;
+       int error;
 
        if (!orig_name || !*orig_name)
                return -EINVAL;
-
        error = kern_path(orig_name, LOOKUP_FOLLOW, &old_path);
        if (error)
                return error;
 
-       buffer = aa_get_buffer(false);
-       old_buffer = aa_get_buffer(false);
-       error = -ENOMEM;
-       if (!buffer || !old_buffer)
-               goto out;
-       error = fn_for_each_confined(label, profile,
-                       match_mnt(subj_cred, profile, path, buffer, &old_path,
-                                 old_buffer,
-                                 NULL, MS_MOVE, NULL, false));
-out:
-       aa_put_buffer(buffer);
-       aa_put_buffer(old_buffer);
+       error = aa_move_mount(subj_cred, label, &old_path, path);
        path_put(&old_path);
 
        return error;