Skip to content

Commit 89be8aa

Browse files
author
Benjamin Tissoires
committed
HID: bpf: actually free hdev memory after attaching a HID-BPF program
Turns out that I got my reference counts wrong and each successful bus_find_device() actually calls get_device(), and we need to manually call put_device(). Ensure each bus_find_device() gets a matching put_device() when releasing the bpf programs and fix all the error paths. Cc: <[email protected]> Fixes: f5c27da ("HID: initial BPF implementation") Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Benjamin Tissoires <[email protected]>
1 parent 7cdd210 commit 89be8aa

File tree

2 files changed

+40
-9
lines changed

2 files changed

+40
-9
lines changed

drivers/hid/bpf/hid_bpf_dispatch.c

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ hid_bpf_attach_prog(unsigned int hid_id, int prog_fd, __u32 flags)
292292
struct hid_device *hdev;
293293
struct bpf_prog *prog;
294294
struct device *dev;
295-
int fd;
295+
int err, fd;
296296

297297
if (!hid_bpf_ops)
298298
return -EINVAL;
@@ -311,14 +311,24 @@ hid_bpf_attach_prog(unsigned int hid_id, int prog_fd, __u32 flags)
311311
* on errors or when it'll be detached
312312
*/
313313
prog = bpf_prog_get(prog_fd);
314-
if (IS_ERR(prog))
315-
return PTR_ERR(prog);
314+
if (IS_ERR(prog)) {
315+
err = PTR_ERR(prog);
316+
goto out_dev_put;
317+
}
316318

317319
fd = do_hid_bpf_attach_prog(hdev, prog_fd, prog, flags);
318-
if (fd < 0)
319-
bpf_prog_put(prog);
320+
if (fd < 0) {
321+
err = fd;
322+
goto out_prog_put;
323+
}
320324

321325
return fd;
326+
327+
out_prog_put:
328+
bpf_prog_put(prog);
329+
out_dev_put:
330+
put_device(dev);
331+
return err;
322332
}
323333

324334
/**
@@ -345,8 +355,10 @@ hid_bpf_allocate_context(unsigned int hid_id)
345355
hdev = to_hid_device(dev);
346356

347357
ctx_kern = kzalloc(sizeof(*ctx_kern), GFP_KERNEL);
348-
if (!ctx_kern)
358+
if (!ctx_kern) {
359+
put_device(dev);
349360
return NULL;
361+
}
350362

351363
ctx_kern->ctx.hid = hdev;
352364

@@ -363,10 +375,15 @@ noinline void
363375
hid_bpf_release_context(struct hid_bpf_ctx *ctx)
364376
{
365377
struct hid_bpf_ctx_kern *ctx_kern;
378+
struct hid_device *hid;
366379

367380
ctx_kern = container_of(ctx, struct hid_bpf_ctx_kern, ctx);
381+
hid = (struct hid_device *)ctx_kern->ctx.hid; /* ignore const */
368382

369383
kfree(ctx_kern);
384+
385+
/* get_device() is called by bus_find_device() */
386+
put_device(&hid->dev);
370387
}
371388

372389
/**

drivers/hid/bpf/hid_bpf_jmp_table.c

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ static void __hid_bpf_do_release_prog(int map_fd, unsigned int idx)
196196
static void hid_bpf_release_progs(struct work_struct *work)
197197
{
198198
int i, j, n, map_fd = -1;
199+
bool hdev_destroyed;
199200

200201
if (!jmp_table.map)
201202
return;
@@ -220,6 +221,12 @@ static void hid_bpf_release_progs(struct work_struct *work)
220221
if (entry->hdev) {
221222
hdev = entry->hdev;
222223
type = entry->type;
224+
/*
225+
* hdev is still valid, even if we are called after hid_destroy_device():
226+
* when hid_bpf_attach() gets called, it takes a ref on the dev through
227+
* bus_find_device()
228+
*/
229+
hdev_destroyed = hdev->bpf.destroyed;
223230

224231
hid_bpf_populate_hdev(hdev, type);
225232

@@ -232,12 +239,19 @@ static void hid_bpf_release_progs(struct work_struct *work)
232239
if (test_bit(next->idx, jmp_table.enabled))
233240
continue;
234241

235-
if (next->hdev == hdev && next->type == type)
242+
if (next->hdev == hdev && next->type == type) {
243+
/*
244+
* clear the hdev reference and decrement the device ref
245+
* that was taken during bus_find_device() while calling
246+
* hid_bpf_attach()
247+
*/
236248
next->hdev = NULL;
249+
put_device(&hdev->dev);
250+
}
237251
}
238252

239-
/* if type was rdesc fixup, reconnect device */
240-
if (type == HID_BPF_PROG_TYPE_RDESC_FIXUP)
253+
/* if type was rdesc fixup and the device is not gone, reconnect device */
254+
if (type == HID_BPF_PROG_TYPE_RDESC_FIXUP && !hdev_destroyed)
241255
hid_bpf_reconnect(hdev);
242256
}
243257
}

0 commit comments

Comments
 (0)