History

landlock: Fix d_parent walk

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.

Mickaël Salaün committed 2 years ago

Commit 88da52c1 parent 1613e601 file · +11 −2Browse files

Unified · Split

security/landlock/fs.c+11−2
@@ -1110,6 +1110,7 @@ static int current_check_refer_path(struct dentry *const old_dentry, · 1109 unmodified lines
1110 bool allow_parent1, allow_parent2;1110 bool allow_parent1, allow_parent2;
1111 access_mask_t access_request_parent1, access_request_parent2;1111 access_mask_t access_request_parent1, access_request_parent2;
1112 struct path mnt_dir;1112 struct path mnt_dir;
1113 struct dentry *old_parent;
1113 layer_mask_t layer_masks_parent1[LANDLOCK_NUM_ACCESS_FS] = {},1114 layer_mask_t layer_masks_parent1[LANDLOCK_NUM_ACCESS_FS] = {},
1114 layer_masks_parent2[LANDLOCK_NUM_ACCESS_FS] = {};1115 layer_masks_parent2[LANDLOCK_NUM_ACCESS_FS] = {};
1115 1116
@@ -1157,9 +1158,17 @@ static int current_check_refer_path(struct dentry *const old_dentry, · 41 unmodified lines
1157 mnt_dir.mnt = new_dir->mnt;1158 mnt_dir.mnt = new_dir->mnt;
1158 mnt_dir.dentry = new_dir->mnt->mnt_root;1159 mnt_dir.dentry = new_dir->mnt->mnt_root;
1159 1160
1161 /*
1162 * old_dentry may be the root of the common mount point and
1163 * !IS_ROOT(old_dentry) at the same time (e.g. with open_tree() and
1164 * OPEN_TREE_CLONE). We do not need to call dget(old_parent) because
1165 * we keep a reference to old_dentry.
1166 */
1167 old_parent = (old_dentry == mnt_dir.dentry) ? old_dentry :
1168 old_dentry->d_parent;
1169
1160 /* new_dir->dentry is equal to new_dentry->d_parent */1170 /* new_dir->dentry is equal to new_dentry->d_parent */
1161 allow_parent1 = collect_domain_accesses(dom, mnt_dir.dentry,1171 allow_parent1 = collect_domain_accesses(dom, mnt_dir.dentry, old_parent,
1162 old_dentry->d_parent,
1163 &layer_masks_parent1);1172 &layer_masks_parent1);
1164 allow_parent2 = collect_domain_accesses(1173 allow_parent2 = collect_domain_accesses(
1165 dom, mnt_dir.dentry, new_dir->dentry, &layer_masks_parent2);1174 dom, mnt_dir.dentry, new_dir->dentry, &layer_masks_parent2);