Commit 40a708bd authored by David Howells's avatar David Howells Committed by Linus Torvalds

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: 80548b03 ("afs: Add more tracepoints")
Reported-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 8379bb84
...@@ -908,6 +908,7 @@ static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry, ...@@ -908,6 +908,7 @@ static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
unsigned int flags) unsigned int flags)
{ {
struct afs_vnode *dvnode = AFS_FS_I(dir); struct afs_vnode *dvnode = AFS_FS_I(dir);
struct afs_fid fid = {};
struct inode *inode; struct inode *inode;
struct dentry *d; struct dentry *d;
struct key *key; struct key *key;
...@@ -957,15 +958,16 @@ static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry, ...@@ -957,15 +958,16 @@ static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
dentry->d_fsdata = dentry->d_fsdata =
(void *)(unsigned long)dvnode->status.data_version; (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); d = d_splice_alias(inode, dentry);
if (!IS_ERR_OR_NULL(d)) { if (!IS_ERR_OR_NULL(d)) {
d->d_fsdata = dentry->d_fsdata; d->d_fsdata = dentry->d_fsdata;
trace_afs_lookup(dvnode, &d->d_name, trace_afs_lookup(dvnode, &d->d_name, &fid);
inode ? AFS_FS_I(inode) : NULL);
} else { } else {
trace_afs_lookup(dvnode, &dentry->d_name, trace_afs_lookup(dvnode, &dentry->d_name, &fid);
IS_ERR_OR_NULL(inode) ? NULL
: AFS_FS_I(inode));
} }
return d; return d;
} }
......
...@@ -915,9 +915,9 @@ TRACE_EVENT(afs_call_state, ...@@ -915,9 +915,9 @@ TRACE_EVENT(afs_call_state,
TRACE_EVENT(afs_lookup, TRACE_EVENT(afs_lookup,
TP_PROTO(struct afs_vnode *dvnode, const struct qstr *name, 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( TP_STRUCT__entry(
__field_struct(struct afs_fid, dfid ) __field_struct(struct afs_fid, dfid )
...@@ -928,13 +928,7 @@ TRACE_EVENT(afs_lookup, ...@@ -928,13 +928,7 @@ TRACE_EVENT(afs_lookup,
TP_fast_assign( TP_fast_assign(
int __len = min_t(int, name->len, 23); int __len = min_t(int, name->len, 23);
__entry->dfid = dvnode->fid; __entry->dfid = dvnode->fid;
if (vnode) { __entry->fid = *fid;
__entry->fid = vnode->fid;
} else {
__entry->fid.vid = 0;
__entry->fid.vnode = 0;
__entry->fid.unique = 0;
}
memcpy(__entry->name, name->name, __len); memcpy(__entry->name, name->name, __len);
__entry->name[__len] = 0; __entry->name[__len] = 0;
), ),
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment