summaryrefslogtreecommitdiff
path: root/security
diff options
context:
space:
mode:
authorMickaël Salaün <mic@digikod.net>2024-05-16 21:19:34 +0300
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2024-06-21 15:40:12 +0300
commitc7618c7b0b8c45bcef34410cc1d1e953eb17f8f6 (patch)
treed549d94727096cccad4a4bf4ecee82ffd37b8257 /security
parent9437abaf293fe34e5823e1b7f5408ab58940f490 (diff)
downloadlinux-c7618c7b0b8c45bcef34410cc1d1e953eb17f8f6.tar.xz
landlock: Fix d_parent walk
commit 88da52ccd66e65f2e63a6c35c9dff55d448ef4dc upstream. The WARN_ON_ONCE() in collect_domain_accesses() can be triggered when trying to link a root mount point. This cannot work in practice because this directory is mounted, but the VFS check is done after the call to security_path_link(). Do not use source directory's d_parent when the source directory is the mount point. Cc: Günther Noack <gnoack@google.com> Cc: Paul Moore <paul@paul-moore.com> Cc: stable@vger.kernel.org Reported-by: syzbot+bf4903dc7e12b18ebc87@syzkaller.appspotmail.com Fixes: b91c3e4ea756 ("landlock: Add support for file reparenting with LANDLOCK_ACCESS_FS_REFER") Closes: https://lore.kernel.org/r/000000000000553d3f0618198200@google.com Link: https://lore.kernel.org/r/20240516181935.1645983-2-mic@digikod.net [mic: Fix commit message] Signed-off-by: Mickaël Salaün <mic@digikod.net> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'security')
-rw-r--r--security/landlock/fs.c13
1 files changed, 11 insertions, 2 deletions
diff --git a/security/landlock/fs.c b/security/landlock/fs.c
index c15559432d3d..3e43e68a6339 100644
--- a/security/landlock/fs.c
+++ b/security/landlock/fs.c
@@ -950,6 +950,7 @@ static int current_check_refer_path(struct dentry *const old_dentry,
bool allow_parent1, allow_parent2;
access_mask_t access_request_parent1, access_request_parent2;
struct path mnt_dir;
+ struct dentry *old_parent;
layer_mask_t layer_masks_parent1[LANDLOCK_NUM_ACCESS_FS] = {},
layer_masks_parent2[LANDLOCK_NUM_ACCESS_FS] = {};
@@ -997,9 +998,17 @@ static int current_check_refer_path(struct dentry *const old_dentry,
mnt_dir.mnt = new_dir->mnt;
mnt_dir.dentry = new_dir->mnt->mnt_root;
+ /*
+ * old_dentry may be the root of the common mount point and
+ * !IS_ROOT(old_dentry) at the same time (e.g. with open_tree() and
+ * OPEN_TREE_CLONE). We do not need to call dget(old_parent) because
+ * we keep a reference to old_dentry.
+ */
+ old_parent = (old_dentry == mnt_dir.dentry) ? old_dentry :
+ old_dentry->d_parent;
+
/* new_dir->dentry is equal to new_dentry->d_parent */
- allow_parent1 = collect_domain_accesses(dom, mnt_dir.dentry,
- old_dentry->d_parent,
+ allow_parent1 = collect_domain_accesses(dom, mnt_dir.dentry, old_parent,
&layer_masks_parent1);
allow_parent2 = collect_domain_accesses(
dom, mnt_dir.dentry, new_dir->dentry, &layer_masks_parent2);