diff options
author | Greg Hackmann <ghackmann@google.com> | 2016-02-19 13:33:31 -0800 |
---|---|---|
committer | Winnie Hsu <whsu@nvidia.com> | 2017-05-16 12:38:01 -0700 |
commit | 651cce8f33cff889007ca563cdcff98abe3a5e90 (patch) | |
tree | 0916235878259b82b86f0abab31481ebecfe77b4 /drivers | |
parent | c15231b2c2b5799645d599310421d1d6c46b395b (diff) |
media: tegra: camera: sanity-check ioctl parameter
Several places in the camera stack can hit integer overflows or cause
bad allocations if userspace passes in a bogus sizeofvalue parameter.
Protect against this by using appropriately-sized integer types, adding
range checks, replacing array-allocation calls with kcalloc(), and
checking for allocations returning ZERO_SIZE_PTR.
For one specific ioctl (PCLLK_IOCTL_UPDATE) sizeofvalue = 0 is fine,
since when that happens the subdrivers won't actually touch the returned
allocation. In fact the existing userspace camera driver makes calls
like these and expects them to succeed! Handle this special case by
adding a __camera_get_params variant that optionally treats zero-sized
inputs as valid.
(back ported from Nexus N9 project)
Bug 1832830
Change-Id: Ie3250d8a4b814de5820fa0190b4cbd1af3ca4b3f
Reported-by: Jianqiang Zhao <zhaojianqiang1@gmail.com>
Signed-off-by: Greg Hackmann <ghackmann@google.com>
Reviewed-on: http://git-master/r/1271367
Reviewed-by: Automatic_Commit_Validation_User
GVS: Gerrit_Virtual_Submit
Reviewed-by: Frank Chen <frankc@nvidia.com>
Tested-by: Frank Chen <frankc@nvidia.com>
Reviewed-by: Jihoon Bang <jbang@nvidia.com>
Reviewed-by: Winnie Hsu <whsu@nvidia.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/media/platform/tegra/cam_dev/imx135.c | 6 | ||||
-rw-r--r-- | drivers/media/platform/tegra/cam_dev/of_camera.c | 4 | ||||
-rw-r--r-- | drivers/media/platform/tegra/cam_dev/virtual.c | 4 | ||||
-rw-r--r-- | drivers/media/platform/tegra/camera.c | 22 |
4 files changed, 21 insertions, 15 deletions
diff --git a/drivers/media/platform/tegra/cam_dev/imx135.c b/drivers/media/platform/tegra/cam_dev/imx135.c index eaa085637aa4..7dd3e9bd61be 100644 --- a/drivers/media/platform/tegra/cam_dev/imx135.c +++ b/drivers/media/platform/tegra/cam_dev/imx135.c @@ -4,7 +4,7 @@ * the virtual PCL driver to handle some special features (hardware resources, * sequences, etc.). * - * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2013-2016, NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -42,11 +42,11 @@ struct imx135_info { }; static int imx135_update( - struct camera_device *cdev, struct cam_update *upd, int num) + struct camera_device *cdev, struct cam_update *upd, u32 num) { /* struct imx135_info *info = dev_get_drvdata(cdev->dev); */ int err = 0; - int idx; + u32 idx; dev_dbg(cdev->dev, "%s %d\n", __func__, num); mutex_lock(&cdev->mutex); diff --git a/drivers/media/platform/tegra/cam_dev/of_camera.c b/drivers/media/platform/tegra/cam_dev/of_camera.c index 460ca1a844e8..f293b9a27cd0 100644 --- a/drivers/media/platform/tegra/cam_dev/of_camera.c +++ b/drivers/media/platform/tegra/cam_dev/of_camera.c @@ -1,7 +1,7 @@ /* * debugfs.c * - * Copyright (c) 2013-2014, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2013-2016, NVIDIA CORPORATION. All rights reserved. * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -222,7 +222,7 @@ int of_camera_get_property(struct camera_info *cam, unsigned long arg) } /* sanity check */ - if (!param.sizeofvalue) { + if (!param.sizeofvalue || param.sizeofvalue > INT_MAX) { dev_err(cam->dev, "%s invalid property name length %d\n", __func__, param.sizeofvalue); return -EBADF; diff --git a/drivers/media/platform/tegra/cam_dev/virtual.c b/drivers/media/platform/tegra/cam_dev/virtual.c index f08ad1563a73..d25becc1ec24 100644 --- a/drivers/media/platform/tegra/cam_dev/virtual.c +++ b/drivers/media/platform/tegra/cam_dev/virtual.c @@ -41,10 +41,10 @@ struct chip_config { }; static int virtual_update( - struct camera_device *cdev, struct cam_update *upd, int num) + struct camera_device *cdev, struct cam_update *upd, u32 num) { int err = 0; - int idx; + u32 idx; dev_dbg(cdev->dev, "%s %d\n", __func__, num); mutex_lock(&cdev->mutex); diff --git a/drivers/media/platform/tegra/camera.c b/drivers/media/platform/tegra/camera.c index 2542f4210de6..f54a3c01d38d 100644 --- a/drivers/media/platform/tegra/camera.c +++ b/drivers/media/platform/tegra/camera.c @@ -1,7 +1,7 @@ /* * camera.c - generic camera device driver * - * Copyright (c) 2013-2014, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2013-2016, NVIDIA CORPORATION. All rights reserved. * * Contributors: * Charlie Huang <chahuang@nvidia.com> @@ -131,12 +131,12 @@ int camera_copy_user_params(unsigned long arg, struct nvc_param *prm) } #endif -int camera_get_params( +int __camera_get_params( struct camera_info *cam, unsigned long arg, int u_size, - struct nvc_param *prm, void **data) + struct nvc_param *prm, void **data, bool zero_size_ok) { void *buf; - unsigned size; + size_t size; #ifdef CONFIG_COMPAT memset(prm, 0, sizeof(*prm)); @@ -156,9 +156,14 @@ int camera_get_params( if (!data) return 0; + if (zero_size_ok && prm->sizeofvalue == 0) { + *data = ZERO_SIZE_PTR; + return 0; + } + size = prm->sizeofvalue * u_size; - buf = kzalloc(size, GFP_KERNEL); - if (!buf) { + buf = kcalloc(prm->sizeofvalue, u_size, GFP_KERNEL); + if (ZERO_OR_NULL_PTR(buf)) { dev_err(cam->dev, "%s allocate memory failed!\n", __func__); return -ENOMEM; } @@ -231,7 +236,7 @@ static int camera_seq_wr(struct camera_info *cam, unsigned long arg) } p_i2c_table = devm_kzalloc(cdev->dev, params.sizeofvalue, GFP_KERNEL); - if (p_i2c_table == NULL) { + if (ZERO_OR_NULL_PTR(p_i2c_table)) { dev_err(cam->dev, "%s devm_kzalloc err line %d\n", __func__, __LINE__); return -ENOMEM; @@ -586,7 +591,8 @@ static int camera_update(struct camera_info *cam, unsigned long arg) return err; } - err = camera_get_params(cam, arg, sizeof(*upd), ¶m, (void **)&upd); + err = __camera_get_params(cam, arg, sizeof(*upd), ¶m, (void **)&upd, + true); if (err) return err; |