From: glider@google.com If uvcg_config_create_children() fails in uvcg_attach_configfs(), the error path calls config_group_put(&opts->func_inst.group). This drops the reference count of the group to 0, triggering its release function, uvc_func_item_release(). uvc_func_item_release() then calls usb_put_function_instance(&opts->func_inst). However, at this point, the usb_function_instance is not fully initialized. Specifically, fi->fd is NULL because it is only assigned in try_get_usb_function_instance() after alloc_inst() (which is uvc_alloc_inst()) returns successfully. usb_put_function_instance() immediately dereferences fi->fd, resulting in a null-pointer dereference. Furthermore, if the null-pointer dereference didn't occur, usb_put_function_instance() would proceed to call fi->free_func_inst(fi), which maps to uvc_free_inst(). This function calls kfree(opts). After config_group_put() returns, uvcg_attach_configfs() returns the error code back to uvc_alloc_inst(), which then also calls kfree(opts), leading to a double free. Fix this by replacing config_group_put() with uvcg_config_remove_children() in the error path of uvcg_attach_configfs(). This safely removes any partially allocated configfs groups from the default_groups list and frees them, without triggering the parent's release function. The parent opts structure will then be safely and correctly freed by the existing kfree(opts) in uvc_alloc_inst(). Oops: general protection fault, probably for non-canonical address 0xdffffc0000000001: 0000 [#1] SMP KASAN NOPTI KASAN: null-ptr-deref in range [0x0000000000000008-0x000000000000000f] CPU: 0 UID: 0 PID: 5875 Comm: syz-executor234 Not tainted RIP: 0010:usb_put_function_instance+0x54/0xb0 drivers/usb/gadget/functions.c:76 Call Trace: config_item_cleanup fs/configfs/item.c:128 [inline] config_item_release+0x13a/0x2d0 fs/configfs/item.c:137 config_group_put include/linux/configfs.h:102 [inline] uvcg_attach_configfs+0x56/0x60 drivers/usb/gadget/function/uvc_configfs.c:3832 uvc_alloc_inst+0x6f9/0xa90 drivers/usb/gadget/function/f_uvc.c:999 try_get_usb_function_instance drivers/usb/gadget/functions.c:28 [inline] usb_get_function_instance+0xe3/0x2f0 drivers/usb/gadget/functions.c:44 function_make+0x127/0x360 drivers/usb/gadget/configfs.c:626 configfs_mkdir+0x4f6/0x9e0 fs/configfs/dir.c:1360 Fixes: efbf0af70b4f ("usb: gadget: uvc: configfs: Allocate groups dynamically") Assisted-by: Gemini:gemini-3.1-pro-preview syzbot Link: https://syzkaller.appspot.com/ai_job?id=48ba7a22-ac64-47f1-9ab8-a7f7b0f6e195 Signed-off-by: glider@google.com To: To: "Greg Kroah-Hartman" To: To: "Laurent Pinchart" Cc: "Andrew Morton" Cc: "Andy Shevchenko" Cc: "Christophe JAILLET" Cc: "Kees Cook" Cc: Cc: "Akash Kumar" Cc: "Randy Dunlap" --- diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c index 70a1415ea..da0fc8084 100644 --- a/drivers/usb/gadget/function/uvc_configfs.c +++ b/drivers/usb/gadget/function/uvc_configfs.c @@ -3829,7 +3829,7 @@ int uvcg_attach_configfs(struct f_uvc_opts *opts) ret = uvcg_config_create_children(&opts->func_inst.group, &uvc_func_type); if (ret < 0) - config_group_put(&opts->func_inst.group); + uvcg_config_remove_children(&opts->func_inst.group); return ret; } base-commit: a13c140cc289c0b7b3770bce5b3ad42ab35074aa -- This is an AI-generated patch subject to moderation. Reply with '#syz upstream' to Sign-off the patch as a human author and send it to the upstream kernel mailing lists. Reply with '#syz reject' to reject it ('#syz unreject' to undo). See https://goo.gle/syzbot-ai-patches for information about AI-generated patches. You can comment on the patch as usual, syzbot will try to address the comments and send a new version of the patch if necessary. syzbot engineers can be reached at syzkaller@googlegroups.com.