ANDROID: usb: f_accessory: Wrap '_acc_dev' in get()/put() accessors
The '_acc_dev' global variable is a fancy use-after-free factory. Wrap it in some get()/put() functions in preparation for introducing some refcounting. Bug: 173789633 Signed-off-by: Will Deacon <willdeacon@google.com> Change-Id: I4c839627648c209341a81efa0c001c8d71b878d4 Signed-off-by: Giuliano Procida <gprocida@google.com>
This commit is contained in:
committed by
Giuliano Procida
parent
01eeae3561
commit
300d539b8e
@@ -206,6 +206,15 @@ struct acc_instance {
|
||||
const char *name;
|
||||
};
|
||||
|
||||
static struct acc_dev *get_acc_dev(void)
|
||||
{
|
||||
return _acc_dev;
|
||||
}
|
||||
|
||||
static void put_acc_dev(struct acc_dev *dev)
|
||||
{
|
||||
}
|
||||
|
||||
static inline struct acc_dev *func_to_dev(struct usb_function *f)
|
||||
{
|
||||
return container_of(f, struct acc_dev, function);
|
||||
@@ -271,7 +280,10 @@ static void acc_set_disconnected(struct acc_dev *dev)
|
||||
|
||||
static void acc_complete_in(struct usb_ep *ep, struct usb_request *req)
|
||||
{
|
||||
struct acc_dev *dev = _acc_dev;
|
||||
struct acc_dev *dev = get_acc_dev();
|
||||
|
||||
if (!dev)
|
||||
return;
|
||||
|
||||
if (req->status == -ESHUTDOWN) {
|
||||
pr_debug("acc_complete_in set disconnected");
|
||||
@@ -281,11 +293,15 @@ static void acc_complete_in(struct usb_ep *ep, struct usb_request *req)
|
||||
req_put(dev, &dev->tx_idle, req);
|
||||
|
||||
wake_up(&dev->write_wq);
|
||||
put_acc_dev(dev);
|
||||
}
|
||||
|
||||
static void acc_complete_out(struct usb_ep *ep, struct usb_request *req)
|
||||
{
|
||||
struct acc_dev *dev = _acc_dev;
|
||||
struct acc_dev *dev = get_acc_dev();
|
||||
|
||||
if (!dev)
|
||||
return;
|
||||
|
||||
dev->rx_done = 1;
|
||||
if (req->status == -ESHUTDOWN) {
|
||||
@@ -294,6 +310,7 @@ static void acc_complete_out(struct usb_ep *ep, struct usb_request *req)
|
||||
}
|
||||
|
||||
wake_up(&dev->read_wq);
|
||||
put_acc_dev(dev);
|
||||
}
|
||||
|
||||
static void acc_complete_set_string(struct usb_ep *ep, struct usb_request *req)
|
||||
@@ -762,21 +779,36 @@ static long acc_ioctl(struct file *fp, unsigned code, unsigned long value)
|
||||
|
||||
static int acc_open(struct inode *ip, struct file *fp)
|
||||
{
|
||||
if (atomic_xchg(&_acc_dev->open_excl, 1))
|
||||
return -EBUSY;
|
||||
struct acc_dev *dev = get_acc_dev();
|
||||
|
||||
_acc_dev->disconnected = 0;
|
||||
fp->private_data = _acc_dev;
|
||||
if (!dev)
|
||||
return -ENODEV;
|
||||
|
||||
if (atomic_xchg(&dev->open_excl, 1)) {
|
||||
put_acc_dev(dev);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
dev->disconnected = 0;
|
||||
fp->private_data = dev;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acc_release(struct inode *ip, struct file *fp)
|
||||
{
|
||||
WARN_ON(!atomic_xchg(&_acc_dev->open_excl, 0));
|
||||
struct acc_dev *dev = fp->private_data;
|
||||
|
||||
if (!dev)
|
||||
return -ENOENT;
|
||||
|
||||
WARN_ON(!atomic_xchg(&dev->open_excl, 0));
|
||||
/* indicate that we are disconnected
|
||||
* still could be online so don't touch online flag
|
||||
*/
|
||||
_acc_dev->disconnected = 1;
|
||||
dev->disconnected = 1;
|
||||
|
||||
fp->private_data = NULL;
|
||||
put_acc_dev(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -829,7 +861,7 @@ static void acc_complete_setup_noop(struct usb_ep *ep, struct usb_request *req)
|
||||
int acc_ctrlrequest(struct usb_composite_dev *cdev,
|
||||
const struct usb_ctrlrequest *ctrl)
|
||||
{
|
||||
struct acc_dev *dev = _acc_dev;
|
||||
struct acc_dev *dev = get_acc_dev();
|
||||
int value = -EOPNOTSUPP;
|
||||
struct acc_hid_dev *hid;
|
||||
int offset;
|
||||
@@ -932,6 +964,7 @@ err:
|
||||
"%02x.%02x v%04x i%04x l%u\n",
|
||||
ctrl->bRequestType, ctrl->bRequest,
|
||||
w_value, w_index, w_length);
|
||||
put_acc_dev(dev);
|
||||
return value;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(acc_ctrlrequest);
|
||||
@@ -1002,10 +1035,6 @@ kill_all_hid_devices(struct acc_dev *dev)
|
||||
struct list_head *entry, *temp;
|
||||
unsigned long flags;
|
||||
|
||||
/* do nothing if usb accessory device doesn't exist */
|
||||
if (!dev)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&dev->lock, flags);
|
||||
list_for_each_safe(entry, temp, &dev->hid_list) {
|
||||
hid = list_entry(entry, struct acc_hid_dev, list);
|
||||
@@ -1090,12 +1119,15 @@ static void acc_hid_delete(struct acc_hid_dev *hid)
|
||||
|
||||
static void acc_hid_work(struct work_struct *data)
|
||||
{
|
||||
struct acc_dev *dev = _acc_dev;
|
||||
struct acc_dev *dev = get_acc_dev();
|
||||
struct list_head *entry, *temp;
|
||||
struct acc_hid_dev *hid;
|
||||
struct list_head new_list, dead_list;
|
||||
unsigned long flags;
|
||||
|
||||
if (!dev)
|
||||
return;
|
||||
|
||||
INIT_LIST_HEAD(&new_list);
|
||||
|
||||
spin_lock_irqsave(&dev->lock, flags);
|
||||
@@ -1141,6 +1173,8 @@ static void acc_hid_work(struct work_struct *data)
|
||||
hid_destroy_device(hid->hid);
|
||||
acc_hid_delete(hid);
|
||||
}
|
||||
|
||||
put_acc_dev(dev);
|
||||
}
|
||||
|
||||
static int acc_function_set_alt(struct usb_function *f,
|
||||
@@ -1231,15 +1265,23 @@ err:
|
||||
|
||||
void acc_disconnect(void)
|
||||
{
|
||||
struct acc_dev *dev = get_acc_dev();
|
||||
|
||||
/* unregister all HID devices if USB is disconnected */
|
||||
kill_all_hid_devices(_acc_dev);
|
||||
if (dev)
|
||||
kill_all_hid_devices(dev);
|
||||
|
||||
put_acc_dev(dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(acc_disconnect);
|
||||
|
||||
static void acc_cleanup(void)
|
||||
{
|
||||
struct acc_dev *dev = _acc_dev;
|
||||
|
||||
misc_deregister(&acc_device);
|
||||
kfree(_acc_dev);
|
||||
put_acc_dev(dev);
|
||||
kfree(dev);
|
||||
_acc_dev = NULL;
|
||||
}
|
||||
static struct acc_instance *to_acc_instance(struct config_item *item)
|
||||
@@ -1321,7 +1363,9 @@ static struct usb_function_instance *acc_alloc_inst(void)
|
||||
|
||||
static void acc_free(struct usb_function *f)
|
||||
{
|
||||
/*NO-OP: no function specific resource allocation in mtp_alloc*/
|
||||
struct acc_dev *dev = func_to_dev(f);
|
||||
|
||||
put_acc_dev(dev);
|
||||
}
|
||||
|
||||
int acc_ctrlrequest_configfs(struct usb_function *f,
|
||||
@@ -1334,7 +1378,7 @@ int acc_ctrlrequest_configfs(struct usb_function *f,
|
||||
|
||||
static struct usb_function *acc_alloc(struct usb_function_instance *fi)
|
||||
{
|
||||
struct acc_dev *dev = _acc_dev;
|
||||
struct acc_dev *dev = get_acc_dev();
|
||||
|
||||
dev->function.name = "accessory";
|
||||
dev->function.strings = acc_strings,
|
||||
|
||||
Reference in New Issue
Block a user