Received: by 2002:a05:6a10:1d13:0:0:0:0 with SMTP id pp19csp2904895pxb; Tue, 24 Aug 2021 10:16:36 -0700 (PDT) X-Google-Smtp-Source: ABdhPJzSAZ69mGNRkKR+y20HmQFLe36SfISKTG5mDx9GBP9Y2a0jZXl4L8ZqYubRzW8LNb5oOSAA X-Received: by 2002:a05:600c:4eca:: with SMTP id g10mr4838054wmq.89.1629825395699; Tue, 24 Aug 2021 10:16:35 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1629825395; cv=none; d=google.com; s=arc-20160816; b=QclbAyAxwVLWcxX++aeIjYdmUmEA31WBwppep1t6dq8avKMw350OkTnDOsBlL/u9L2 3V6d1QLHCzPkk3y+WufOguTj0Hi2tHr3I9ZBtFnJ72INiROD4kCVA+DANJJoGRPfar7b LZRB4oeSF1EriG3bSddBshav3bui5vm6Dus9IXTbYwPpP6+a8PM8qSKTupR8bgyTDQSY Nf/xKhqvpu0q2F+D7LVqJ0Qs6NqyFqOV+/V4FIDakat241eRPqP5WN1X6Cu/IqdBSQwd GnvLMpv8faMDJSYfY5KqsogUW6lplYTudZtokim3wmOQ+iYCPwrk6r7ygkmMUqItSXv5 B1YA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=ZTt9jWZAQ9zzw56y1qb7uNhO1hJ7f/rR7pv/v8gkFM0=; b=JbZUzKCX2SK0HSJDQtPh4TTBY2fg8fE3ldgn/rgnWZR8M+cN7ZeD4eyUamFe8olF73 YSAo7cngJTtKbaOZlrFHt9yDZLwcsWkRYiMpzQJc4pa5HLmANt1ro7Smnl7/fhIIxSry Ad0SS/kf/vmngCsPAuX11rp+kIp31y7aap/v82Au3+txQ2fxePeL9hy5UIovt5YOtS58 p3lhNsa9Wzb48NralLBlTo4l68q9Yo1yFlwY6cD1OYqcTcwEjlYl+owuyey67L0rVOMc W/Kq8gpepEgStpYn2EDBF1bCIJkyM/BcxgrONtXZzmdJkeri7yLLh+BzICcpmHwPiZF9 iXjA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=k20201202 header.b=qqo5bHZT; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id p19si1102521edr.100.2021.08.24.10.16.11; Tue, 24 Aug 2021 10:16:35 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@kernel.org header.s=k20201202 header.b=qqo5bHZT; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S239536AbhHXRPh (ORCPT + 99 others); Tue, 24 Aug 2021 13:15:37 -0400 Received: from mail.kernel.org ([198.145.29.99]:52014 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S239594AbhHXRMD (ORCPT ); Tue, 24 Aug 2021 13:12:03 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id C22A661A3A; Tue, 24 Aug 2021 17:01:17 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1629824478; bh=CLWYhLurGZMJ/Qztq7lT3hpxNuw6bQlgUBpaMpwARis=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=qqo5bHZTM7YHN/R8K0ogt5rMYlQNAsBizdoHm6grC5r9dy4npsVkTJ0cQpNiRvJEs bbuZqHIK4o8xCIOwoSJvERvFbsSma8JcNEH9qe1mkf9Ga69xLdmsKuVp3XWOyypci0 QDTXLtNUUcEwL5iKgU0yPk22Pcvf69+7W5Bjapr5CH+tmXg/RZPjE/jvcVUc1ql7l7 RaG9NveLhnw2wOINss8CVuDaR4XyT4blMrV3RI12+2DZvShC6+3TSaUk9wqmg3p3Ax ZDCvs+dVS3PvMaGsARXKFkH+NlITb3zZAnzKd5BxcdkUycCvZNV87LMq0PGc9oySLF KnJL8ZPXHSLmg== From: Sasha Levin To: linux-kernel@vger.kernel.org, stable@vger.kernel.org Cc: Dan Carpenter , syzbot+b4d54814b339b5c6bbd4@syzkaller.appspotmail.com, Hans Verkuil , Mauro Carvalho Chehab , Sasha Levin Subject: [PATCH 5.4 10/61] media: zr364xx: fix memory leaks in probe() Date: Tue, 24 Aug 2021 13:00:15 -0400 Message-Id: <20210824170106.710221-11-sashal@kernel.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210824170106.710221-1-sashal@kernel.org> References: <20210824170106.710221-1-sashal@kernel.org> MIME-Version: 1.0 X-KernelTest-Patch: http://kernel.org/pub/linux/kernel/v5.x/stable-review/patch-5.4.143-rc1.gz X-KernelTest-Tree: git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.git X-KernelTest-Branch: linux-5.4.y X-KernelTest-Patches: git://git.kernel.org/pub/scm/linux/kernel/git/stable/stable-queue.git X-KernelTest-Version: 5.4.143-rc1 X-KernelTest-Deadline: 2021-08-26T17:01+00:00 X-stable: review X-Patchwork-Hint: Ignore Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Dan Carpenter [ Upstream commit ea354b6ddd6f09be29424f41fa75a3e637fea234 ] Syzbot discovered that the probe error handling doesn't clean up the resources allocated in zr364xx_board_init(). There are several related bugs in this code so I have re-written the error handling. 1) Introduce a new function zr364xx_board_uninit() which cleans up the resources in zr364xx_board_init(). 2) In zr364xx_board_init() if the call to zr364xx_start_readpipe() fails then release the "cam->buffer.frame[i].lpvbits" memory before returning. This way every function either allocates everything successfully or it cleans up after itself. 3) Re-write the probe function so that each failure path goto frees the most recent allocation. That way we don't free anything before it has been allocated and we can also verify that everything is freed. 4) Originally, in the probe function the "cam->v4l2_dev.release" pointer was set to "zr364xx_release" near the start but I moved that assignment to the end, after everything had succeeded. The release function was never actually called during the probe cleanup process, but with this change I wanted to make it clear that we don't want to call zr364xx_release() until everything is allocated successfully. Next I re-wrote the zr364xx_release() function. Ideally this would have been a simple matter of copy and pasting the cleanup code from probe and adding an additional call to video_unregister_device(). But there are a couple quirks to note. 1) The probe function does not call videobuf_mmap_free() and I don't know where the videobuf_mmap is allocated. I left the code as-is to avoid introducing a bug in code I don't understand. 2) The zr364xx_board_uninit() has a call to zr364xx_stop_readpipe() which is a change from the original behavior with regards to unloading the driver. Calling zr364xx_stop_readpipe() on a stopped pipe is not a problem so this is safe and is potentially a bugfix. Reported-by: syzbot+b4d54814b339b5c6bbd4@syzkaller.appspotmail.com Signed-off-by: Dan Carpenter Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sasha Levin --- drivers/media/usb/zr364xx/zr364xx.c | 49 ++++++++++++++++++----------- 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/drivers/media/usb/zr364xx/zr364xx.c b/drivers/media/usb/zr364xx/zr364xx.c index 22b34690a016..b3f01de9cf37 100644 --- a/drivers/media/usb/zr364xx/zr364xx.c +++ b/drivers/media/usb/zr364xx/zr364xx.c @@ -1187,15 +1187,11 @@ out: return err; } -static void zr364xx_release(struct v4l2_device *v4l2_dev) +static void zr364xx_board_uninit(struct zr364xx_camera *cam) { - struct zr364xx_camera *cam = - container_of(v4l2_dev, struct zr364xx_camera, v4l2_dev); unsigned long i; - v4l2_device_unregister(&cam->v4l2_dev); - - videobuf_mmap_free(&cam->vb_vidq); + zr364xx_stop_readpipe(cam); /* release sys buffers */ for (i = 0; i < FRAMES; i++) { @@ -1206,9 +1202,19 @@ static void zr364xx_release(struct v4l2_device *v4l2_dev) cam->buffer.frame[i].lpvbits = NULL; } - v4l2_ctrl_handler_free(&cam->ctrl_handler); /* release transfer buffer */ kfree(cam->pipe->transfer_buffer); +} + +static void zr364xx_release(struct v4l2_device *v4l2_dev) +{ + struct zr364xx_camera *cam = + container_of(v4l2_dev, struct zr364xx_camera, v4l2_dev); + + videobuf_mmap_free(&cam->vb_vidq); + v4l2_ctrl_handler_free(&cam->ctrl_handler); + zr364xx_board_uninit(cam); + v4l2_device_unregister(&cam->v4l2_dev); kfree(cam); } @@ -1382,11 +1388,14 @@ static int zr364xx_board_init(struct zr364xx_camera *cam) /* start read pipe */ err = zr364xx_start_readpipe(cam); if (err) - goto err_free; + goto err_free_frames; DBG(": board initialized\n"); return 0; +err_free_frames: + for (i = 0; i < FRAMES; i++) + vfree(cam->buffer.frame[i].lpvbits); err_free: kfree(cam->pipe->transfer_buffer); cam->pipe->transfer_buffer = NULL; @@ -1415,12 +1424,10 @@ static int zr364xx_probe(struct usb_interface *intf, if (!cam) return -ENOMEM; - cam->v4l2_dev.release = zr364xx_release; err = v4l2_device_register(&intf->dev, &cam->v4l2_dev); if (err < 0) { dev_err(&udev->dev, "couldn't register v4l2_device\n"); - kfree(cam); - return err; + goto free_cam; } hdl = &cam->ctrl_handler; v4l2_ctrl_handler_init(hdl, 1); @@ -1429,7 +1436,7 @@ static int zr364xx_probe(struct usb_interface *intf, if (hdl->error) { err = hdl->error; dev_err(&udev->dev, "couldn't register control\n"); - goto fail; + goto unregister; } /* save the init method used by this camera */ cam->method = id->driver_info; @@ -1502,7 +1509,7 @@ static int zr364xx_probe(struct usb_interface *intf, if (!cam->read_endpoint) { err = -ENOMEM; dev_err(&intf->dev, "Could not find bulk-in endpoint\n"); - goto fail; + goto unregister; } /* v4l */ @@ -1513,10 +1520,11 @@ static int zr364xx_probe(struct usb_interface *intf, /* load zr364xx board specific */ err = zr364xx_board_init(cam); - if (!err) - err = v4l2_ctrl_handler_setup(hdl); if (err) - goto fail; + goto unregister; + err = v4l2_ctrl_handler_setup(hdl); + if (err) + goto board_uninit; spin_lock_init(&cam->slock); @@ -1531,16 +1539,21 @@ static int zr364xx_probe(struct usb_interface *intf, err = video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1); if (err) { dev_err(&udev->dev, "video_register_device failed\n"); - goto fail; + goto free_handler; } + cam->v4l2_dev.release = zr364xx_release; dev_info(&udev->dev, DRIVER_DESC " controlling device %s\n", video_device_node_name(&cam->vdev)); return 0; -fail: +free_handler: v4l2_ctrl_handler_free(hdl); +board_uninit: + zr364xx_board_uninit(cam); +unregister: v4l2_device_unregister(&cam->v4l2_dev); +free_cam: kfree(cam); return err; } -- 2.30.2