| From 477c22d349ef57f88ee44d9bedb1dc1cec489ac4 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Wed, 21 Apr 2021 21:43:45 +0200 |
| Subject: media: cpia2: fix memory leak in cpia2_usb_probe |
| |
| From: Pavel Skripkin <paskripkin@gmail.com> |
| |
| [ Upstream commit be8656e62e9e791837b606a027802b504a945c97 ] |
| |
| syzbot reported leak in cpia2 usb driver. The problem was |
| in invalid error handling. |
| |
| v4l2_device_register() is called in cpia2_init_camera_struct(), but |
| all error cases after cpia2_init_camera_struct() did not call the |
| v4l2_device_unregister() |
| |
| Reported-by: syzbot+d1e69c888f0d3866ead4@syzkaller.appspotmail.com |
| Signed-off-by: Pavel Skripkin <paskripkin@gmail.com> |
| Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl> |
| Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/media/usb/cpia2/cpia2.h | 1 + |
| drivers/media/usb/cpia2/cpia2_core.c | 12 ++++++++++++ |
| drivers/media/usb/cpia2/cpia2_usb.c | 13 +++++++------ |
| 3 files changed, 20 insertions(+), 6 deletions(-) |
| |
| diff --git a/drivers/media/usb/cpia2/cpia2.h b/drivers/media/usb/cpia2/cpia2.h |
| index 50835f5f7512..57b7f1ea68da 100644 |
| --- a/drivers/media/usb/cpia2/cpia2.h |
| +++ b/drivers/media/usb/cpia2/cpia2.h |
| @@ -429,6 +429,7 @@ int cpia2_send_command(struct camera_data *cam, struct cpia2_command *cmd); |
| int cpia2_do_command(struct camera_data *cam, |
| unsigned int command, |
| unsigned char direction, unsigned char param); |
| +void cpia2_deinit_camera_struct(struct camera_data *cam, struct usb_interface *intf); |
| struct camera_data *cpia2_init_camera_struct(struct usb_interface *intf); |
| int cpia2_init_camera(struct camera_data *cam); |
| int cpia2_allocate_buffers(struct camera_data *cam); |
| diff --git a/drivers/media/usb/cpia2/cpia2_core.c b/drivers/media/usb/cpia2/cpia2_core.c |
| index e747548ab286..b5a2d06fb356 100644 |
| --- a/drivers/media/usb/cpia2/cpia2_core.c |
| +++ b/drivers/media/usb/cpia2/cpia2_core.c |
| @@ -2163,6 +2163,18 @@ static void reset_camera_struct(struct camera_data *cam) |
| cam->height = cam->params.roi.height; |
| } |
| |
| +/****************************************************************************** |
| + * |
| + * cpia2_init_camera_struct |
| + * |
| + * Deinitialize camera struct |
| + *****************************************************************************/ |
| +void cpia2_deinit_camera_struct(struct camera_data *cam, struct usb_interface *intf) |
| +{ |
| + v4l2_device_unregister(&cam->v4l2_dev); |
| + kfree(cam); |
| +} |
| + |
| /****************************************************************************** |
| * |
| * cpia2_init_camera_struct |
| diff --git a/drivers/media/usb/cpia2/cpia2_usb.c b/drivers/media/usb/cpia2/cpia2_usb.c |
| index 3ab80a7b4498..76aac06f9fb8 100644 |
| --- a/drivers/media/usb/cpia2/cpia2_usb.c |
| +++ b/drivers/media/usb/cpia2/cpia2_usb.c |
| @@ -844,15 +844,13 @@ static int cpia2_usb_probe(struct usb_interface *intf, |
| ret = set_alternate(cam, USBIF_CMDONLY); |
| if (ret < 0) { |
| ERR("%s: usb_set_interface error (ret = %d)\n", __func__, ret); |
| - kfree(cam); |
| - return ret; |
| + goto alt_err; |
| } |
| |
| |
| if((ret = cpia2_init_camera(cam)) < 0) { |
| ERR("%s: failed to initialize cpia2 camera (ret = %d)\n", __func__, ret); |
| - kfree(cam); |
| - return ret; |
| + goto alt_err; |
| } |
| LOG(" CPiA Version: %d.%02d (%d.%d)\n", |
| cam->params.version.firmware_revision_hi, |
| @@ -872,11 +870,14 @@ static int cpia2_usb_probe(struct usb_interface *intf, |
| ret = cpia2_register_camera(cam); |
| if (ret < 0) { |
| ERR("%s: Failed to register cpia2 camera (ret = %d)\n", __func__, ret); |
| - kfree(cam); |
| - return ret; |
| + goto alt_err; |
| } |
| |
| return 0; |
| + |
| +alt_err: |
| + cpia2_deinit_camera_struct(cam, intf); |
| + return ret; |
| } |
| |
| /****************************************************************************** |
| -- |
| 2.30.2 |
| |