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>
This commit is contained in:
Will Deacon
2020-12-15 16:24:55 +00:00
committed by Giuliano Procida
parent 4df1d2ffe1
commit cd4f430770

View File

@@ -1258,6 +1258,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;
@@ -1274,16 +1277,21 @@ static int acc_setup(void)
INIT_WORK(&dev->hid_work, acc_hid_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;