Commit c2da049f authored by Li Nan's avatar Li Nan Committed by Jens Axboe

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: default avatarLi Nan <linan122@huawei.com>
Reviewed-by: default avatarJosef Bacik <josef@toxicpanda.com>
Link: https://lore.kernel.org/r/20231116162316.1740402-4-linan666@huaweicloud.comSigned-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent 3123ac77
...@@ -397,8 +397,16 @@ static u32 req_to_nbd_cmd_type(struct request *req) ...@@ -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) ...@@ -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;
......
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