aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWill Deacon2020-12-15 08:24:17 -0600
committerGiuliano Procida2020-12-30 04:20:47 -0600
commit3a01ad8acc2461dc42a88cd80434c8d0ba8099a5 (patch)
treec9259f243675a54b307b71e4033cb3ce431435fa
parent351bb866d4417f605ee9e5fdc7afe50a5f483deb (diff)
downloadkernel-3a01ad8acc2461dc42a88cd80434c8d0ba8099a5.tar.gz
kernel-3a01ad8acc2461dc42a88cd80434c8d0ba8099a5.tar.xz
kernel-3a01ad8acc2461dc42a88cd80434c8d0ba8099a5.zip
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>
-rw-r--r--drivers/usb/gadget/function/f_accessory.c78
1 files changed, 61 insertions, 17 deletions
diff --git a/drivers/usb/gadget/function/f_accessory.c b/drivers/usb/gadget/function/f_accessory.c
index fdf55ca81467..5bc32de494c8 100644
--- a/drivers/usb/gadget/function/f_accessory.c
+++ b/drivers/usb/gadget/function/f_accessory.c
@@ -281,6 +281,15 @@ struct acc_instance {
281 const char *name; 281 const char *name;
282}; 282};
283 283
284static struct acc_dev *get_acc_dev(void)
285{
286 return _acc_dev;
287}
288
289static void put_acc_dev(struct acc_dev *dev)
290{
291}
292
284static inline struct acc_dev *func_to_dev(struct usb_function *f) 293static inline struct acc_dev *func_to_dev(struct usb_function *f)
285{ 294{
286 return container_of(f, struct acc_dev, function); 295 return container_of(f, struct acc_dev, function);
@@ -346,7 +355,10 @@ static void acc_set_disconnected(struct acc_dev *dev)
346 355
347static void acc_complete_in(struct usb_ep *ep, struct usb_request *req) 356static void acc_complete_in(struct usb_ep *ep, struct usb_request *req)
348{ 357{
349 struct acc_dev *dev = _acc_dev; 358 struct acc_dev *dev = get_acc_dev();
359
360 if (!dev)
361 return;
350 362
351 if (req->status == -ESHUTDOWN) { 363 if (req->status == -ESHUTDOWN) {
352 pr_debug("acc_complete_in set disconnected"); 364 pr_debug("acc_complete_in set disconnected");
@@ -356,11 +368,15 @@ static void acc_complete_in(struct usb_ep *ep, struct usb_request *req)
356 req_put(dev, &dev->tx_idle, req); 368 req_put(dev, &dev->tx_idle, req);
357 369
358 wake_up(&dev->write_wq); 370 wake_up(&dev->write_wq);
371 put_acc_dev(dev);
359} 372}
360 373
361static void acc_complete_out(struct usb_ep *ep, struct usb_request *req) 374static void acc_complete_out(struct usb_ep *ep, struct usb_request *req)
362{ 375{
363 struct acc_dev *dev = _acc_dev; 376 struct acc_dev *dev = get_acc_dev();
377
378 if (!dev)
379 return;
364 380
365 dev->rx_done = 1; 381 dev->rx_done = 1;
366 if (req->status == -ESHUTDOWN) { 382 if (req->status == -ESHUTDOWN) {
@@ -369,6 +385,7 @@ static void acc_complete_out(struct usb_ep *ep, struct usb_request *req)
369 } 385 }
370 386
371 wake_up(&dev->read_wq); 387 wake_up(&dev->read_wq);
388 put_acc_dev(dev);
372} 389}
373 390
374static void acc_complete_set_string(struct usb_ep *ep, struct usb_request *req) 391static void acc_complete_set_string(struct usb_ep *ep, struct usb_request *req)
@@ -836,21 +853,36 @@ static long acc_ioctl(struct file *fp, unsigned code, unsigned long value)
836 853
837static int acc_open(struct inode *ip, struct file *fp) 854static int acc_open(struct inode *ip, struct file *fp)
838{ 855{
839 if (atomic_xchg(&_acc_dev->open_excl, 1)) 856 struct acc_dev *dev = get_acc_dev();
857
858 if (!dev)
859 return -ENODEV;
860
861 if (atomic_xchg(&dev->open_excl, 1)) {
862 put_acc_dev(dev);
840 return -EBUSY; 863 return -EBUSY;
864 }
841 865
842 _acc_dev->disconnected = 0; 866 dev->disconnected = 0;
843 fp->private_data = _acc_dev; 867 fp->private_data = dev;
844 return 0; 868 return 0;
845} 869}
846 870
847static int acc_release(struct inode *ip, struct file *fp) 871static int acc_release(struct inode *ip, struct file *fp)
848{ 872{
849 WARN_ON(!atomic_xchg(&_acc_dev->open_excl, 0)); 873 struct acc_dev *dev = fp->private_data;
874
875 if (!dev)
876 return -ENOENT;
877
878 WARN_ON(!atomic_xchg(&dev->open_excl, 0));
850 /* indicate that we are disconnected 879 /* indicate that we are disconnected
851 * still could be online so don't touch online flag 880 * still could be online so don't touch online flag
852 */ 881 */
853 _acc_dev->disconnected = 1; 882 dev->disconnected = 1;
883
884 fp->private_data = NULL;
885 put_acc_dev(dev);
854 return 0; 886 return 0;
855} 887}
856 888
@@ -903,7 +935,7 @@ static void acc_complete_setup_noop(struct usb_ep *ep, struct usb_request *req)
903int acc_ctrlrequest(struct usb_composite_dev *cdev, 935int acc_ctrlrequest(struct usb_composite_dev *cdev,
904 const struct usb_ctrlrequest *ctrl) 936 const struct usb_ctrlrequest *ctrl)
905{ 937{
906 struct acc_dev *dev = _acc_dev; 938 struct acc_dev *dev = get_acc_dev();
907 int value = -EOPNOTSUPP; 939 int value = -EOPNOTSUPP;
908 struct acc_hid_dev *hid; 940 struct acc_hid_dev *hid;
909 int offset; 941 int offset;
@@ -1008,6 +1040,7 @@ err:
1008 "%02x.%02x v%04x i%04x l%u\n", 1040 "%02x.%02x v%04x i%04x l%u\n",
1009 ctrl->bRequestType, ctrl->bRequest, 1041 ctrl->bRequestType, ctrl->bRequest,
1010 w_value, w_index, w_length); 1042 w_value, w_index, w_length);
1043 put_acc_dev(dev);
1011 return value; 1044 return value;
1012} 1045}
1013EXPORT_SYMBOL_GPL(acc_ctrlrequest); 1046EXPORT_SYMBOL_GPL(acc_ctrlrequest);
@@ -1078,10 +1111,6 @@ kill_all_hid_devices(struct acc_dev *dev)
1078 struct list_head *entry, *temp; 1111 struct list_head *entry, *temp;
1079 unsigned long flags; 1112 unsigned long flags;
1080 1113
1081 /* do nothing if usb accessory device doesn't exist */
1082 if (!dev)
1083 return;
1084
1085 spin_lock_irqsave(&dev->lock, flags); 1114 spin_lock_irqsave(&dev->lock, flags);
1086 list_for_each_safe(entry, temp, &dev->hid_list) { 1115 list_for_each_safe(entry, temp, &dev->hid_list) {
1087 hid = list_entry(entry, struct acc_hid_dev, list); 1116 hid = list_entry(entry, struct acc_hid_dev, list);
@@ -1180,12 +1209,15 @@ static void acc_hid_delete(struct acc_hid_dev *hid)
1180 1209
1181static void acc_hid_work(struct work_struct *data) 1210static void acc_hid_work(struct work_struct *data)
1182{ 1211{
1183 struct acc_dev *dev = _acc_dev; 1212 struct acc_dev *dev = get_acc_dev();
1184 struct list_head *entry, *temp; 1213 struct list_head *entry, *temp;
1185 struct acc_hid_dev *hid; 1214 struct acc_hid_dev *hid;
1186 struct list_head new_list, dead_list; 1215 struct list_head new_list, dead_list;
1187 unsigned long flags; 1216 unsigned long flags;
1188 1217
1218 if (!dev)
1219 return;
1220
1189 INIT_LIST_HEAD(&new_list); 1221 INIT_LIST_HEAD(&new_list);
1190 1222
1191 spin_lock_irqsave(&dev->lock, flags); 1223 spin_lock_irqsave(&dev->lock, flags);
@@ -1231,6 +1263,8 @@ static void acc_hid_work(struct work_struct *data)
1231 hid_destroy_device(hid->hid); 1263 hid_destroy_device(hid->hid);
1232 acc_hid_delete(hid); 1264 acc_hid_delete(hid);
1233 } 1265 }
1266
1267 put_acc_dev(dev);
1234} 1268}
1235 1269
1236static int acc_function_set_alt(struct usb_function *f, 1270static int acc_function_set_alt(struct usb_function *f,
@@ -1323,15 +1357,23 @@ err:
1323 1357
1324void acc_disconnect(void) 1358void acc_disconnect(void)
1325{ 1359{
1360 struct acc_dev *dev = get_acc_dev();
1361
1326 /* unregister all HID devices if USB is disconnected */ 1362 /* unregister all HID devices if USB is disconnected */
1327 kill_all_hid_devices(_acc_dev); 1363 if (dev)
1364 kill_all_hid_devices(dev);
1365
1366 put_acc_dev(dev);
1328} 1367}
1329EXPORT_SYMBOL_GPL(acc_disconnect); 1368EXPORT_SYMBOL_GPL(acc_disconnect);
1330 1369
1331static void acc_cleanup(void) 1370static void acc_cleanup(void)
1332{ 1371{
1372 struct acc_dev *dev = _acc_dev;
1373
1333 misc_deregister(&acc_device); 1374 misc_deregister(&acc_device);
1334 kfree(_acc_dev); 1375 put_acc_dev(dev);
1376 kfree(dev);
1335 _acc_dev = NULL; 1377 _acc_dev = NULL;
1336} 1378}
1337static struct acc_instance *to_acc_instance(struct config_item *item) 1379static struct acc_instance *to_acc_instance(struct config_item *item)
@@ -1413,7 +1455,9 @@ static struct usb_function_instance *acc_alloc_inst(void)
1413 1455
1414static void acc_free(struct usb_function *f) 1456static void acc_free(struct usb_function *f)
1415{ 1457{
1416/*NO-OP: no function specific resource allocation in mtp_alloc*/ 1458 struct acc_dev *dev = func_to_dev(f);
1459
1460 put_acc_dev(dev);
1417} 1461}
1418 1462
1419int acc_ctrlrequest_configfs(struct usb_function *f, 1463int acc_ctrlrequest_configfs(struct usb_function *f,
@@ -1426,7 +1470,7 @@ int acc_ctrlrequest_configfs(struct usb_function *f,
1426 1470
1427static struct usb_function *acc_alloc(struct usb_function_instance *fi) 1471static struct usb_function *acc_alloc(struct usb_function_instance *fi)
1428{ 1472{
1429 struct acc_dev *dev = _acc_dev; 1473 struct acc_dev *dev = get_acc_dev();
1430 1474
1431 dev->function.name = "accessory"; 1475 dev->function.name = "accessory";
1432 dev->function.strings = acc_strings, 1476 dev->function.strings = acc_strings,