mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-31 09:20:13 -04:00
fuse: use release/acquire for fch->initialized
fuse_chan_set_initialized() sets values for the connection state and then sets fch->initialized to true, but lockless readers read fch->initialized and if true, go to read the connection state values, without using any barriers. There are a few instances where this happens (fuse_uring_cmd() before dispatching register / commit-and-fetch cmds, fuse_dev_do_wriite() for handling notify retrieves, etc). To make this as simple as possible, use release/acquire semantics for writing/reading fch->initialized. Add the missing read barriers. This is not marked for stable as these are not realistically reachable on a well-behaved server, and buggy/malicious servers who trigger this path fail benignly rather than crash or deadlock the kernel. Signed-off-by: Joanne Koong <joannelkoong@gmail.com> Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
This commit is contained in:
committed by
Miklos Szeredi
parent
edb310bc27
commit
4ef7c8cc98
@@ -530,7 +530,8 @@ static int cuse_channel_open(struct inode *inode, struct file *file)
|
||||
|
||||
INIT_LIST_HEAD(&cc->list);
|
||||
|
||||
cc->fc.chan->initialized = 1;
|
||||
/* Pairs with smp_load_acquire() readers of fch->initialized */
|
||||
smp_store_release(&cc->fc.chan->initialized, 1);
|
||||
rc = cuse_send_init(cc);
|
||||
if (rc) {
|
||||
fuse_dev_put(fud);
|
||||
|
||||
@@ -77,20 +77,17 @@ void fuse_chan_set_initialized(struct fuse_chan *fch, struct fuse_chan_param *pa
|
||||
fch->max_pages = param->max_pages;
|
||||
}
|
||||
|
||||
/* Make sure stores before this are seen on another CPU */
|
||||
smp_wmb();
|
||||
fch->initialized = 1;
|
||||
/* Pairs with smp_load_acquire() readers of fch->initialized */
|
||||
smp_store_release(&fch->initialized, 1);
|
||||
wake_up_all(&fch->blocked_waitq);
|
||||
}
|
||||
|
||||
static bool fuse_block_alloc(struct fuse_chan *fch, bool for_background)
|
||||
{
|
||||
if (!fch->initialized)
|
||||
/* Pairs with smp_store_release() in fuse_chan_set_initialized() */
|
||||
if (!smp_load_acquire(&fch->initialized))
|
||||
return true;
|
||||
|
||||
/* Pairs with smp_wmb() in fuse_chan_set_initialized() */
|
||||
smp_rmb();
|
||||
|
||||
return (for_background && fch->blocked) ||
|
||||
(fch->io_uring && fch->connected && !fuse_uring_ready(fch));
|
||||
}
|
||||
@@ -1892,7 +1889,8 @@ static ssize_t fuse_dev_do_write(struct fuse_dev *fud,
|
||||
* initialized and connected state
|
||||
*/
|
||||
err = -EINVAL;
|
||||
if (!fch->initialized || !fch->connected)
|
||||
/* Pairs with smp_store_release() in fuse_chan_set_initialized() */
|
||||
if (!smp_load_acquire(&fch->initialized) || !fch->connected)
|
||||
goto copy_finish;
|
||||
|
||||
/* Don't try to move folios (yet) */
|
||||
|
||||
@@ -1251,8 +1251,10 @@ int fuse_uring_cmd(struct io_uring_cmd *cmd, unsigned int issue_flags)
|
||||
/*
|
||||
* fuse_uring_register() needs the ring to be initialized,
|
||||
* we need to know the max payload size
|
||||
*
|
||||
* Pairs with smp_store_release() in fuse_chan_set_initialized()
|
||||
*/
|
||||
if (!fch->initialized)
|
||||
if (!smp_load_acquire(&fch->initialized))
|
||||
return -EAGAIN;
|
||||
|
||||
switch (cmd_op) {
|
||||
|
||||
Reference in New Issue
Block a user