ecryptfs_lookup_interpose(): lower_dentry->d_inode is not stable
lower_dentry can't go from positive to negative (we have it pinned), but it *can* go from negative to positive. So fetching ->d_inode into a local variable, doing a blocking allocation, checking that now ->d_inode is non-NULL and feeding the value we'd fetched earlier to a function that won't accept NULL is not a good idea. Cc: stable@vger.kernel.org Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
parent
bcf0d9d4b7
commit
e72b9dd6a5
@ -319,7 +319,7 @@ static int ecryptfs_i_size_read(struct dentry *dentry, struct inode *inode)
|
|||||||
static struct dentry *ecryptfs_lookup_interpose(struct dentry *dentry,
|
static struct dentry *ecryptfs_lookup_interpose(struct dentry *dentry,
|
||||||
struct dentry *lower_dentry)
|
struct dentry *lower_dentry)
|
||||||
{
|
{
|
||||||
struct inode *inode, *lower_inode = d_inode(lower_dentry);
|
struct inode *inode, *lower_inode;
|
||||||
struct ecryptfs_dentry_info *dentry_info;
|
struct ecryptfs_dentry_info *dentry_info;
|
||||||
struct vfsmount *lower_mnt;
|
struct vfsmount *lower_mnt;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
@ -339,7 +339,15 @@ static struct dentry *ecryptfs_lookup_interpose(struct dentry *dentry,
|
|||||||
dentry_info->lower_path.mnt = lower_mnt;
|
dentry_info->lower_path.mnt = lower_mnt;
|
||||||
dentry_info->lower_path.dentry = lower_dentry;
|
dentry_info->lower_path.dentry = lower_dentry;
|
||||||
|
|
||||||
if (d_really_is_negative(lower_dentry)) {
|
/*
|
||||||
|
* negative dentry can go positive under us here - its parent is not
|
||||||
|
* locked. That's OK and that could happen just as we return from
|
||||||
|
* ecryptfs_lookup() anyway. Just need to be careful and fetch
|
||||||
|
* ->d_inode only once - it's not stable here.
|
||||||
|
*/
|
||||||
|
lower_inode = READ_ONCE(lower_dentry->d_inode);
|
||||||
|
|
||||||
|
if (!lower_inode) {
|
||||||
/* We want to add because we couldn't find in lower */
|
/* We want to add because we couldn't find in lower */
|
||||||
d_add(dentry, NULL);
|
d_add(dentry, NULL);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
Loading…
Reference in New Issue
Block a user