ovl_lookup_layers() passes ctx->upperdentry to ovl_get_inode(), which takes over the reference. If an overlay inode for the upper inode is already cached, as for a second hard link, ovl_get_inode() puts the dentry and returns the cached inode. ovl_lookup_layers() then passes the put dentry to ovl_dentry_init_reval(), which reads its d_flags. With a local upper fs the put dentry usually stays in the dcache, but with a FUSE upper whose entry has timed out, dput() kills it, so this is a use-after-free. Fix this by taking the revalidate flags from the upper dentry of the overlay inode, which is the one that ovl_dentry_revalidate_common() revalidates. Reported-by: Sashiko Closes: https://sashiko.dev/#/bug/linux-986db859-840c-479d-944c-b9c43b93377e Fixes: bccece1ead36 ("ovl: allow remote upper") Cc: stable@vger.kernel.org Signed-off-by: Amir Goldstein --- fs/overlayfs/namei.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/fs/overlayfs/namei.c b/fs/overlayfs/namei.c index 64d63b260709c..98e846b3846c4 100644 --- a/fs/overlayfs/namei.c +++ b/fs/overlayfs/namei.c @@ -1382,9 +1382,17 @@ static int ovl_lookup_layers(struct ovl_lookup_ctx *ctx, struct ovl_lookup_data if (metacopy_size > OVL_METACOPY_MIN_SIZE) ovl_set_flag(OVL_HAS_DIGEST, ctx->inode); - } - ovl_dentry_init_reval(dentry, ctx->upperdentry, OVL_I_E(ctx->inode)); + /* + * ovl_get_inode() puts ctx->upperdentry if it finds a cached + * inode, e.g. for another hard link, so use the upper dentry + * of the inode. + */ + ovl_dentry_init_reval(dentry, ovl_i_dentry_upper(inode), + OVL_I_E(inode)); + } else { + ovl_dentry_init_reval(dentry, NULL, NULL); + } return 0; } -- 2.55.0