aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWill Deacon2020-12-15 10:24:55 -0600
committerGiuliano Procida2020-12-30 04:20:47 -0600
commit24a78046c104ab573a32504635d55abc494c8d65 (patch)
tree371da4d91a1666104ed318b4c60193b0e3392e31
parent926e1040f4037b12ffabac4e9a895b0832d3ac42 (diff)
downloadkernel-24a78046c104ab573a32504635d55abc494c8d65.tar.gz
kernel-24a78046c104ab573a32504635d55abc494c8d65.tar.xz
kernel-24a78046c104ab573a32504635d55abc494c8d65.zip
ANDROID: usb: f_accessory: Don't corrupt global state on double registration
If acc_setup() is called when there is already an allocated instance, misc_register() will fail but the error path leaves a dangling pointer to freed memory in the global 'acc_dev' state. Fix this by ensuring that the refcount is zero before we start, and then using a cmpxchg() from NULL to serialise any concurrent initialisers. Bug: 173789633 Signed-off-by: Will Deacon <willdeacon@google.com> Change-Id: I2c26289dcce7dbc493964516c49b05d04aaa6839 Signed-off-by: Giuliano Procida <gprocida@google.com>
-rw-r--r--drivers/usb/gadget/function/f_accessory.c16
1 files changed, 12 insertions, 4 deletions
diff --git a/drivers/usb/gadget/function/f_accessory.c b/drivers/usb/gadget/function/f_accessory.c
index ab3e47c1083e..0cae99243080 100644
--- a/drivers/usb/gadget/function/f_accessory.c
+++ b/drivers/usb/gadget/function/f_accessory.c
@@ -1349,6 +1349,9 @@ static int acc_setup(void)
1349 struct acc_dev *dev; 1349 struct acc_dev *dev;
1350 int ret; 1350 int ret;
1351 1351
1352 if (kref_read(&ref->kref))
1353 return -EBUSY;
1354
1352 dev = kzalloc(sizeof(*dev), GFP_KERNEL); 1355 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
1353 if (!dev) 1356 if (!dev)
1354 return -ENOMEM; 1357 return -ENOMEM;
@@ -1367,16 +1370,21 @@ static int acc_setup(void)
1367 INIT_WORK(&dev->sendstring_work, acc_sendstring_work); 1370 INIT_WORK(&dev->sendstring_work, acc_sendstring_work);
1368 1371
1369 dev->ref = ref; 1372 dev->ref = ref;
1370 kref_init(&ref->kref); 1373 if (cmpxchg_relaxed(&ref->acc_dev, NULL, dev)) {
1371 ref->acc_dev = dev; 1374 ret = -EBUSY;
1375 goto err_free_dev;
1376 }
1372 1377
1373 ret = misc_register(&acc_device); 1378 ret = misc_register(&acc_device);
1374 if (ret) 1379 if (ret)
1375 goto err; 1380 goto err_zap_ptr;
1376 1381
1382 kref_init(&ref->kref);
1377 return 0; 1383 return 0;
1378 1384
1379err: 1385err_zap_ptr:
1386 ref->acc_dev = NULL;
1387err_free_dev:
1380 kfree(dev); 1388 kfree(dev);
1381 pr_err("USB accessory gadget driver failed to initialize\n"); 1389 pr_err("USB accessory gadget driver failed to initialize\n");
1382 return ret; 1390 return ret;