From: Yu Kuai yukuai3@huawei.com
hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I7EENU CVE: NA
----------------------------------------
nbd->config = config and refcount_set(&nbd->config_refs, 1) in nbd_genl_connect may be out of order, causing config_refs to be set to 1 first, and then nbd_open accessing nbd->config reports a null pointer reference. T1 T2 vfs_open do_dentry_open blkdev_open blkdev_get __blkdev_get nbd_open nbd_get_config_unlocked genl_rcv_msg genl_family_rcv_msg genl_family_rcv_msg_doit nbd_genl_connect nbd_alloc_and_init_config // out of order execution refcount_set(&nbd->config_refs, 1); // 2 nbd->config // null point nbd->config = config; // 1
Fix it by adding a cpu memory barrier to guarantee sequential execution.
Signed-off-by: Yu Kuai yukuai3@huawei.com Signed-off-by: Zhong Jinghua zhongjinghua@huawei.com Reviewed-by: Yu Kuai yukuai3@huawei.com Signed-off-by: Yongqiang Liu liuyongqiang13@huawei.com --- drivers/block/nbd.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-)
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 2d8f6a77b831..fb4e9cb3d5d6 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -372,8 +372,16 @@ static void sock_shutdown(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 NULL; } @@ -1498,7 +1506,15 @@ static int nbd_alloc_and_init_config(struct nbd_device *nbd) init_waitqueue_head(&config->conn_wait); config->blksize = NBD_DEF_BLKSIZE; atomic_set(&config->live_connections, 0); + 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);
return 0;