mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 22:21:40 +00:00
afs: Fix use-after-loss-of-ref
afs_lookup() has a tracepoint to indicate the outcome of
d_splice_alias(), passing it the inode to retrieve the fid from.
However, the function gave up its ref on that inode when it called
d_splice_alias(), which may have failed and dropped the inode.
Fix this by caching the fid.
Fixes: 80548b0399
("afs: Add more tracepoints")
Reported-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
8379bb84be
commit
40a708bd62
12
fs/afs/dir.c
12
fs/afs/dir.c
@ -908,6 +908,7 @@ static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
|
||||
unsigned int flags)
|
||||
{
|
||||
struct afs_vnode *dvnode = AFS_FS_I(dir);
|
||||
struct afs_fid fid = {};
|
||||
struct inode *inode;
|
||||
struct dentry *d;
|
||||
struct key *key;
|
||||
@ -957,15 +958,16 @@ static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
|
||||
dentry->d_fsdata =
|
||||
(void *)(unsigned long)dvnode->status.data_version;
|
||||
}
|
||||
|
||||
if (!IS_ERR_OR_NULL(inode))
|
||||
fid = AFS_FS_I(inode)->fid;
|
||||
|
||||
d = d_splice_alias(inode, dentry);
|
||||
if (!IS_ERR_OR_NULL(d)) {
|
||||
d->d_fsdata = dentry->d_fsdata;
|
||||
trace_afs_lookup(dvnode, &d->d_name,
|
||||
inode ? AFS_FS_I(inode) : NULL);
|
||||
trace_afs_lookup(dvnode, &d->d_name, &fid);
|
||||
} else {
|
||||
trace_afs_lookup(dvnode, &dentry->d_name,
|
||||
IS_ERR_OR_NULL(inode) ? NULL
|
||||
: AFS_FS_I(inode));
|
||||
trace_afs_lookup(dvnode, &dentry->d_name, &fid);
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
@ -915,9 +915,9 @@ TRACE_EVENT(afs_call_state,
|
||||
|
||||
TRACE_EVENT(afs_lookup,
|
||||
TP_PROTO(struct afs_vnode *dvnode, const struct qstr *name,
|
||||
struct afs_vnode *vnode),
|
||||
struct afs_fid *fid),
|
||||
|
||||
TP_ARGS(dvnode, name, vnode),
|
||||
TP_ARGS(dvnode, name, fid),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field_struct(struct afs_fid, dfid )
|
||||
@ -928,13 +928,7 @@ TRACE_EVENT(afs_lookup,
|
||||
TP_fast_assign(
|
||||
int __len = min_t(int, name->len, 23);
|
||||
__entry->dfid = dvnode->fid;
|
||||
if (vnode) {
|
||||
__entry->fid = vnode->fid;
|
||||
} else {
|
||||
__entry->fid.vid = 0;
|
||||
__entry->fid.vnode = 0;
|
||||
__entry->fid.unique = 0;
|
||||
}
|
||||
__entry->fid = *fid;
|
||||
memcpy(__entry->name, name->name, __len);
|
||||
__entry->name[__len] = 0;
|
||||
),
|
||||
|
Loading…
Reference in New Issue
Block a user