mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
fuse: fix NULL pointer dereference in fuse_request_find
fuse_dev_install_with_pq() publishes fud->chan before it stores
fud->pq.processing. The write/splice_write and read paths treat a non-NULL
fud->chan as "installed" and then walk fpq->processing[] without taking
fch->lock, so they can see the new chan while processing is still NULL and
oops in fuse_request_find().
Fix by taking fpq->lock around the cmpxchg + fud->pq.processing assignment.
This protects all call sites that dereference fpq->processing, since these
have fpq->lock held.
Fixes: 48649c0603 ("fuse: alloc pqueue before installing fch in fuse_dev")
Reported-by: Cen Zhang <zzzccc427@gmail.com>
Closes: https://lore.kernel.org/fuse-devel/pm-fuse-full-objects-candidate-0002-v2-17d6013e5066de33396c@gmail.com/
Reported-by: 马云龙 <yunlong_ma@buaa.edu.cn>
Closes: https://lore.kernel.org/all/5ddc8efe.1e6d2.1a11fbec860.Coremail.yunlong_ma@buaa.edu.cn/
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
This commit is contained in:
parent
294de5bbbc
commit
f8cef5c74d
|
|
@ -466,24 +466,27 @@ static bool fuse_dev_install_with_pq(struct fuse_dev *fud, struct fuse_chan *fch
|
|||
struct fuse_chan *old_fch;
|
||||
|
||||
guard(spinlock)(&fch->lock);
|
||||
/*
|
||||
* Pairs with:
|
||||
* - xchg() in fuse_dev_release()
|
||||
* - smp_load_acquire() in fuse_dev_fc_get()
|
||||
*/
|
||||
old_fch = cmpxchg(&fud->chan, NULL, fch);
|
||||
if (old_fch) {
|
||||
/* protect fud->pq.processing assignment */
|
||||
scoped_guard(spinlock, &fud->pq.lock) {
|
||||
/*
|
||||
* failed to set fud->chan because
|
||||
* - it was already set to a different fc
|
||||
* - it was set to disconneted
|
||||
* Pairs with:
|
||||
* - xchg() in fuse_dev_release()
|
||||
* - smp_load_acquire() in fuse_dev_fc_get()
|
||||
*/
|
||||
kfree(pq);
|
||||
return false;
|
||||
}
|
||||
if (pq) {
|
||||
WARN_ON(fud->pq.processing);
|
||||
fud->pq.processing = pq;
|
||||
old_fch = cmpxchg(&fud->chan, NULL, fch);
|
||||
if (old_fch) {
|
||||
/*
|
||||
* failed to set fud->chan because
|
||||
* - it was already set to a different fc
|
||||
* - it was set to disconneted
|
||||
*/
|
||||
kfree(pq);
|
||||
return false;
|
||||
}
|
||||
if (pq) {
|
||||
WARN_ON(fud->pq.processing);
|
||||
fud->pq.processing = pq;
|
||||
}
|
||||
}
|
||||
list_add_tail(&fud->entry, &fch->devices);
|
||||
fuse_conn_get(fch->conn);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user