Skip to content

Commit 3cf3060

Browse files
johnkeepingTreehugger Robot
authored andcommitted
UPSTREAM: usb: gadget: f_hid: fix f_hidg lifetime vs cdev
[ Upstream commit 89ff3dfac604614287ad5aad9370c3f984ea3f4b ] The embedded struct cdev does not have its lifetime correctly tied to the enclosing struct f_hidg, so there is a use-after-free if /dev/hidgN is held open while the gadget is deleted. This can readily be replicated with libusbgx's example programs (for conciseness - operating directly via configfs is equivalent): gadget-hid exec 3<> /dev/hidg0 gadget-vid-pid-remove exec 3<&- Pull the existing device up in to struct f_hidg and make use of the cdev_device_{add,del}() helpers. This changes the lifetime of the device object to match struct f_hidg, but note that it is still added and deleted at the same time. Bug: 176850153 Fixes: 71adf11 ("USB: gadget: add HID gadget driver") Tested-by: Lee Jones <lee@kernel.org> Reviewed-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com> Reviewed-by: Lee Jones <lee@kernel.org> Signed-off-by: John Keeping <john@metanate.com> Link: https://lore.kernel.org/r/20221122123523.3068034-2-john@metanate.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Sasha Levin <sashal@kernel.org> Signed-off-by: Lee Jones <joneslee@google.com> Change-Id: I5d37ca47c5f087d5b1b303b4e8a1614ea3f50159
1 parent 8864b03 commit 3cf3060

File tree

1 file changed

+28
-24
lines changed

1 file changed

+28
-24
lines changed

drivers/usb/gadget/function/f_hid.c

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ struct f_hidg {
7171
wait_queue_head_t write_queue;
7272
struct usb_request *req;
7373

74-
int minor;
74+
struct device dev;
7575
struct cdev cdev;
7676
struct usb_function func;
7777

@@ -84,6 +84,14 @@ static inline struct f_hidg *func_to_hidg(struct usb_function *f)
8484
return container_of(f, struct f_hidg, func);
8585
}
8686

87+
static void hidg_release(struct device *dev)
88+
{
89+
struct f_hidg *hidg = container_of(dev, struct f_hidg, dev);
90+
91+
kfree(hidg->set_report_buf);
92+
kfree(hidg);
93+
}
94+
8795
/*-------------------------------------------------------------------------*/
8896
/* Static descriptors */
8997

@@ -904,9 +912,7 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f)
904912
struct usb_ep *ep;
905913
struct f_hidg *hidg = func_to_hidg(f);
906914
struct usb_string *us;
907-
struct device *device;
908915
int status;
909-
dev_t dev;
910916

911917
/* maybe allocate device-global string IDs, and patch descriptors */
912918
us = usb_gstrings_attach(c->cdev, ct_func_strings,
@@ -999,21 +1005,11 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f)
9991005

10001006
/* create char device */
10011007
cdev_init(&hidg->cdev, &f_hidg_fops);
1002-
dev = MKDEV(major, hidg->minor);
1003-
status = cdev_add(&hidg->cdev, dev, 1);
1008+
status = cdev_device_add(&hidg->cdev, &hidg->dev);
10041009
if (status)
10051010
goto fail_free_descs;
10061011

1007-
device = device_create(hidg_class, NULL, dev, NULL,
1008-
"%s%d", "hidg", hidg->minor);
1009-
if (IS_ERR(device)) {
1010-
status = PTR_ERR(device);
1011-
goto del;
1012-
}
1013-
10141012
return 0;
1015-
del:
1016-
cdev_del(&hidg->cdev);
10171013
fail_free_descs:
10181014
usb_free_all_descriptors(f);
10191015
fail:
@@ -1244,9 +1240,7 @@ static void hidg_free(struct usb_function *f)
12441240

12451241
hidg = func_to_hidg(f);
12461242
opts = container_of(f->fi, struct f_hid_opts, func_inst);
1247-
kfree(hidg->report_desc);
1248-
kfree(hidg->set_report_buf);
1249-
kfree(hidg);
1243+
put_device(&hidg->dev);
12501244
mutex_lock(&opts->lock);
12511245
--opts->refcnt;
12521246
mutex_unlock(&opts->lock);
@@ -1256,8 +1250,7 @@ static void hidg_unbind(struct usb_configuration *c, struct usb_function *f)
12561250
{
12571251
struct f_hidg *hidg = func_to_hidg(f);
12581252

1259-
device_destroy(hidg_class, MKDEV(major, hidg->minor));
1260-
cdev_del(&hidg->cdev);
1253+
cdev_device_del(&hidg->cdev, &hidg->dev);
12611254

12621255
usb_free_all_descriptors(f);
12631256
}
@@ -1266,6 +1259,7 @@ static struct usb_function *hidg_alloc(struct usb_function_instance *fi)
12661259
{
12671260
struct f_hidg *hidg;
12681261
struct f_hid_opts *opts;
1262+
int ret;
12691263

12701264
/* allocate and initialize one new instance */
12711265
hidg = kzalloc(sizeof(*hidg), GFP_KERNEL);
@@ -1277,17 +1271,27 @@ static struct usb_function *hidg_alloc(struct usb_function_instance *fi)
12771271
mutex_lock(&opts->lock);
12781272
++opts->refcnt;
12791273

1280-
hidg->minor = opts->minor;
1274+
device_initialize(&hidg->dev);
1275+
hidg->dev.release = hidg_release;
1276+
hidg->dev.class = hidg_class;
1277+
hidg->dev.devt = MKDEV(major, opts->minor);
1278+
ret = dev_set_name(&hidg->dev, "hidg%d", opts->minor);
1279+
if (ret) {
1280+
--opts->refcnt;
1281+
mutex_unlock(&opts->lock);
1282+
return ERR_PTR(ret);
1283+
}
1284+
12811285
hidg->bInterfaceSubClass = opts->subclass;
12821286
hidg->bInterfaceProtocol = opts->protocol;
12831287
hidg->report_length = opts->report_length;
12841288
hidg->report_desc_length = opts->report_desc_length;
12851289
if (opts->report_desc) {
1286-
hidg->report_desc = kmemdup(opts->report_desc,
1287-
opts->report_desc_length,
1288-
GFP_KERNEL);
1290+
hidg->report_desc = devm_kmemdup(&hidg->dev, opts->report_desc,
1291+
opts->report_desc_length,
1292+
GFP_KERNEL);
12891293
if (!hidg->report_desc) {
1290-
kfree(hidg);
1294+
put_device(&hidg->dev);
12911295
mutex_unlock(&opts->lock);
12921296
return ERR_PTR(-ENOMEM);
12931297
}

0 commit comments

Comments
 (0)