From 24a78046c104ab573a32504635d55abc494c8d65 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Tue, 15 Dec 2020 16:24:55 +0000 Subject: [PATCH] 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 Change-Id: I2c26289dcce7dbc493964516c49b05d04aaa6839 Signed-off-by: Giuliano Procida --- drivers/usb/gadget/function/f_accessory.c | 16 ++++++++++++---- 1 file 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) struct acc_dev *dev; int ret; + if (kref_read(&ref->kref)) + return -EBUSY; + dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM; @@ -1367,16 +1370,21 @@ static int acc_setup(void) INIT_WORK(&dev->sendstring_work, acc_sendstring_work); dev->ref = ref; - kref_init(&ref->kref); - ref->acc_dev = dev; + if (cmpxchg_relaxed(&ref->acc_dev, NULL, dev)) { + ret = -EBUSY; + goto err_free_dev; + } ret = misc_register(&acc_device); if (ret) - goto err; + goto err_zap_ptr; + kref_init(&ref->kref); return 0; -err: +err_zap_ptr: + ref->acc_dev = NULL; +err_free_dev: kfree(dev); pr_err("USB accessory gadget driver failed to initialize\n"); return ret;