[lvc-project] [PATCH v3] Input: sur40: fix error recovery in sur40_probe()

Dmitry Antipov dmantipov at yandex.ru
Tue Aug 11 09:44:04 MSK 2026


Since an input device which has passed 'input_register_device()'
should be released with 'input_unregister_device()', adjust
'sur40_probe()' to do so and call 'input_free_device()' to handle
device register error only. To avoid V4L2 memory leak, ensure that
'v4l2_ctrl_handler_free()' is called on all error handling paths,
including the one after 'video_register_device()' failure. Finally,
since 'sur40_poll()' which reads 'bulk_in_buffer' may become active
immediately after 'input_register_device()' has succeeded, ensure
that this buffer is freed after 'input_unregister_device()', just
like it's done in 'sur40_disconnect()'.

Reported-by: syzbot+2a123f6269da57ffefaa at syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=2a123f6269da57ffefaa
Fixes: 08b936012964 ("Input: sur40 - switch to using polled mode of input devices")
Signed-off-by: Dmitry Antipov <dmantipov at yandex.ru>
---
v3: free 'bulk_in_buffer' after an input device has passed
    'input_unregister_device()' (Sashiko)
v2: setup sur40 input device pointer after 'input_register_device()' and
    adjust error handling path to ensure that 'input_unregister_device()'
    is always called for a registered device only (Vasileios)
---
 drivers/input/touchscreen/sur40.c | 22 +++++++++++++++-------
 1 file changed, 15 insertions(+), 7 deletions(-)

diff --git a/drivers/input/touchscreen/sur40.c b/drivers/input/touchscreen/sur40.c
index fe63d53d56db..f7d6d89a028b 100644
--- a/drivers/input/touchscreen/sur40.c
+++ b/drivers/input/touchscreen/sur40.c
@@ -713,7 +713,6 @@ static int sur40_probe(struct usb_interface *interface,
 
 	sur40->usbdev = usbdev;
 	sur40->dev = &interface->dev;
-	sur40->input = input;
 
 	/* use the bulk-in endpoint tested above */
 	sur40->bulk_in_size = usb_endpoint_maxp(endpoint);
@@ -730,9 +729,12 @@ static int sur40_probe(struct usb_interface *interface,
 	if (error) {
 		dev_err(&interface->dev,
 			"Unable to register polled input device.");
-		goto err_free_buffer;
+		goto err_free_input;
 	}
 
+	/* announce an input device as completely initialized */
+	sur40->input = input;
+
 	/* register the video master device */
 	snprintf(sur40->v4l2.name, sizeof(sur40->v4l2.name), "%s", DRIVER_LONG);
 	error = v4l2_device_register(sur40->dev, &sur40->v4l2);
@@ -786,9 +788,8 @@ static int sur40_probe(struct usb_interface *interface,
 	if (sur40->hdl.error) {
 		dev_err(&interface->dev,
 			"Unable to register video controls.");
-		v4l2_ctrl_handler_free(&sur40->hdl);
 		error = sur40->hdl.error;
-		goto err_unreg_v4l2;
+		goto err_unreg_ctrl;
 	}
 
 	error = video_register_device(&sur40->vdev, VFL_TYPE_TOUCH, -1);
@@ -806,12 +807,19 @@ static int sur40_probe(struct usb_interface *interface,
 
 err_unreg_video:
 	video_unregister_device(&sur40->vdev);
+err_unreg_ctrl:
+	v4l2_ctrl_handler_free(&sur40->hdl);
 err_unreg_v4l2:
 	v4l2_device_unregister(&sur40->v4l2);
-err_free_buffer:
-	kfree(sur40->bulk_in_buffer);
 err_free_input:
-	input_free_device(input);
+	if (sur40->input)
+		/* device was successfully registered */
+		input_unregister_device(input);
+	else
+		/* device just needs to be freed */
+		input_free_device(input);
+	/* this should be done after unregistering an input device */
+	kfree(sur40->bulk_in_buffer);
 err_free_dev:
 	kfree(sur40);
 
-- 
2.55.0




More information about the lvc-project mailing list