Skip to content

Commit ad14239

Browse files
committed
ovl: make sure that ovl_create_real() returns a hashed dentry
e8bd877 ("ovl: fix possible double unlink") added a sanity check of !d_unhashed(child) to try to verify that child dentry was not unlinked while parent dir was unlocked. This "was not unlink" check has a false positive result in the case of casefolded parent dir, because in that case, ovl_create_temp() returns an unhashed dentry after ovl_create_real() gets an unhashed dentry from ovl_lookup_upper() and makes it positive. To avoid returning unhashed dentry from ovl_create_temp(), let ovl_create_real() lookup again after making the newdentry positive, so it always returns a hashed positive dentry (or an error). This fixes the error in ovl_parent_lock() in ovl_check_rename_whiteout() after ovl_create_temp() and allows mount of overlayfs with casefolding enabled layers. Reported-by: André Almeida <andrealmeid@igalia.com> Closes: https://lore.kernel.org/r/18704e8c-c734-43f3-bc7c-b8be345e1bf5@igalia.com/ Suggested-by: Neil Brown <neil@brown.name> Reviewed-by: Neil Brown <neil@brown.name> Signed-off-by: Amir Goldstein <amir73il@gmail.com>
1 parent 16754d6 commit ad14239

1 file changed

Lines changed: 21 additions & 1 deletion

File tree

fs/overlayfs/dir.c

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,12 +212,32 @@ struct dentry *ovl_create_real(struct ovl_fs *ofs, struct dentry *parent,
212212
err = -EPERM;
213213
}
214214
}
215-
if (!err && WARN_ON(!newdentry->d_inode)) {
215+
if (err)
216+
goto out;
217+
218+
if (WARN_ON(!newdentry->d_inode)) {
216219
/*
217220
* Not quite sure if non-instantiated dentry is legal or not.
218221
* VFS doesn't seem to care so check and warn here.
219222
*/
220223
err = -EIO;
224+
} else if (d_unhashed(newdentry)) {
225+
struct dentry *d;
226+
/*
227+
* Some filesystems (i.e. casefolded) may return an unhashed
228+
* negative dentry from the ovl_lookup_upper() call before
229+
* ovl_create_real().
230+
* In that case, lookup again after making the newdentry
231+
* positive, so ovl_create_upper() always returns a hashed
232+
* positive dentry.
233+
*/
234+
d = ovl_lookup_upper(ofs, newdentry->d_name.name, parent,
235+
newdentry->d_name.len);
236+
dput(newdentry);
237+
if (IS_ERR_OR_NULL(d))
238+
err = d ? PTR_ERR(d) : -ENOENT;
239+
else
240+
return d;
221241
}
222242
out:
223243
if (err) {

0 commit comments

Comments
 (0)