nbd: fix null-ptr-dereference while accessing 'nbd->config'
Memory reordering may occur in nbd_genl_connect(), causing config_refs to be set to 1 while nbd->config is still empty. Opening nbd at this time will cause null-ptr-dereference. T1 T2 nbd_open nbd_get_config_unlocked nbd_genl_connect nbd_alloc_and_init_config //memory reordered refcount_set(&nbd->config_refs, 1) // 2 nbd->config ->null point nbd->config = config // 1 Fix it by adding smp barrier to guarantee the execution sequence. Signed-off-by: Li Nan <linan122@huawei.com> Reviewed-by: Josef Bacik <josef@toxicpanda.com> Link: https://lore.kernel.org/r/20231116162316.1740402-4-linan666@huaweicloud.com Signed-off-by: Jens Axboe <axboe@kernel.dk>
This commit is contained in:
parent
3123ac7792
commit
c2da049f41
|
@ -397,8 +397,16 @@ static u32 req_to_nbd_cmd_type(struct request *req)
|
||||||
|
|
||||||
static struct nbd_config *nbd_get_config_unlocked(struct nbd_device *nbd)
|
static struct nbd_config *nbd_get_config_unlocked(struct nbd_device *nbd)
|
||||||
{
|
{
|
||||||
if (refcount_inc_not_zero(&nbd->config_refs))
|
if (refcount_inc_not_zero(&nbd->config_refs)) {
|
||||||
|
/*
|
||||||
|
* Add smp_mb__after_atomic to ensure that reading nbd->config_refs
|
||||||
|
* and reading nbd->config is ordered. The pair is the barrier in
|
||||||
|
* nbd_alloc_and_init_config(), avoid nbd->config_refs is set
|
||||||
|
* before nbd->config.
|
||||||
|
*/
|
||||||
|
smp_mb__after_atomic();
|
||||||
return nbd->config;
|
return nbd->config;
|
||||||
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -1559,7 +1567,15 @@ static int nbd_alloc_and_init_config(struct nbd_device *nbd)
|
||||||
init_waitqueue_head(&config->conn_wait);
|
init_waitqueue_head(&config->conn_wait);
|
||||||
config->blksize_bits = NBD_DEF_BLKSIZE_BITS;
|
config->blksize_bits = NBD_DEF_BLKSIZE_BITS;
|
||||||
atomic_set(&config->live_connections, 0);
|
atomic_set(&config->live_connections, 0);
|
||||||
|
|
||||||
nbd->config = config;
|
nbd->config = config;
|
||||||
|
/*
|
||||||
|
* Order refcount_set(&nbd->config_refs, 1) and nbd->config assignment,
|
||||||
|
* its pair is the barrier in nbd_get_config_unlocked().
|
||||||
|
* So nbd_get_config_unlocked() won't see nbd->config as null after
|
||||||
|
* refcount_inc_not_zero() succeed.
|
||||||
|
*/
|
||||||
|
smp_mb__before_atomic();
|
||||||
refcount_set(&nbd->config_refs, 1);
|
refcount_set(&nbd->config_refs, 1);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Loading…
Reference in New Issue