gfs2_drevalidate(): use stable parent inode and name passed by caller
No need to mess with dget_parent() for the former; for the latter we really should not rely upon ->d_name.name remaining stable. Theoretically a UAF, but it's hard to exfiltrate the information... Reviewed-by: Andreas Gruenbacher <agruenba@redhat.com> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>pull/1136/head
parent
19e1dbdc6b
commit
eab2a11e5b
|
|
@ -35,48 +35,40 @@
|
||||||
static int gfs2_drevalidate(struct inode *dir, const struct qstr *name,
|
static int gfs2_drevalidate(struct inode *dir, const struct qstr *name,
|
||||||
struct dentry *dentry, unsigned int flags)
|
struct dentry *dentry, unsigned int flags)
|
||||||
{
|
{
|
||||||
struct dentry *parent;
|
struct gfs2_sbd *sdp = GFS2_SB(dir);
|
||||||
struct gfs2_sbd *sdp;
|
struct gfs2_inode *dip = GFS2_I(dir);
|
||||||
struct gfs2_inode *dip;
|
|
||||||
struct inode *inode;
|
struct inode *inode;
|
||||||
struct gfs2_holder d_gh;
|
struct gfs2_holder d_gh;
|
||||||
struct gfs2_inode *ip = NULL;
|
struct gfs2_inode *ip = NULL;
|
||||||
int error, valid = 0;
|
int error, valid;
|
||||||
int had_lock = 0;
|
int had_lock = 0;
|
||||||
|
|
||||||
if (flags & LOOKUP_RCU)
|
if (flags & LOOKUP_RCU)
|
||||||
return -ECHILD;
|
return -ECHILD;
|
||||||
|
|
||||||
parent = dget_parent(dentry);
|
|
||||||
sdp = GFS2_SB(d_inode(parent));
|
|
||||||
dip = GFS2_I(d_inode(parent));
|
|
||||||
inode = d_inode(dentry);
|
inode = d_inode(dentry);
|
||||||
|
|
||||||
if (inode) {
|
if (inode) {
|
||||||
if (is_bad_inode(inode))
|
if (is_bad_inode(inode))
|
||||||
goto out;
|
return 0;
|
||||||
ip = GFS2_I(inode);
|
ip = GFS2_I(inode);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sdp->sd_lockstruct.ls_ops->lm_mount == NULL) {
|
if (sdp->sd_lockstruct.ls_ops->lm_mount == NULL)
|
||||||
valid = 1;
|
return 1;
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
had_lock = (gfs2_glock_is_locked_by_me(dip->i_gl) != NULL);
|
had_lock = (gfs2_glock_is_locked_by_me(dip->i_gl) != NULL);
|
||||||
if (!had_lock) {
|
if (!had_lock) {
|
||||||
error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &d_gh);
|
error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &d_gh);
|
||||||
if (error)
|
if (error)
|
||||||
goto out;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
error = gfs2_dir_check(d_inode(parent), &dentry->d_name, ip);
|
error = gfs2_dir_check(dir, name, ip);
|
||||||
valid = inode ? !error : (error == -ENOENT);
|
valid = inode ? !error : (error == -ENOENT);
|
||||||
|
|
||||||
if (!had_lock)
|
if (!had_lock)
|
||||||
gfs2_glock_dq_uninit(&d_gh);
|
gfs2_glock_dq_uninit(&d_gh);
|
||||||
out:
|
|
||||||
dput(parent);
|
|
||||||
return valid;
|
return valid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue