Commit d9e046de authored by Philipp Zabel's avatar Philipp Zabel Committed by Greg Kroah-Hartman

media: coda: fix memory corruption in case more than 32 instances are opened

[ Upstream commit 649cfc2b ]

The ffz() return value is undefined if the instance mask does not
contain any zeros. If it returned 32, the following set_bit would
corrupt the debugfs_root pointer.
Switch to IDA for context index allocation. This also removes the
artificial 32 instance limit for all except CodaDx6.
Signed-off-by: default avatarPhilipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: default avatarHans Verkuil <hansverk@cisco.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab+samsung@kernel.org>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent fbb4503e
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/firmware.h> #include <linux/firmware.h>
#include <linux/gcd.h> #include <linux/gcd.h>
#include <linux/genalloc.h> #include <linux/genalloc.h>
#include <linux/idr.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/irq.h> #include <linux/irq.h>
...@@ -2101,17 +2102,6 @@ int coda_decoder_queue_init(void *priv, struct vb2_queue *src_vq, ...@@ -2101,17 +2102,6 @@ int coda_decoder_queue_init(void *priv, struct vb2_queue *src_vq,
return coda_queue_init(priv, dst_vq); return coda_queue_init(priv, dst_vq);
} }
static int coda_next_free_instance(struct coda_dev *dev)
{
int idx = ffz(dev->instance_mask);
if ((idx < 0) ||
(dev->devtype->product == CODA_DX6 && idx > CODADX6_MAX_INSTANCES))
return -EBUSY;
return idx;
}
/* /*
* File operations * File operations
*/ */
...@@ -2120,7 +2110,8 @@ static int coda_open(struct file *file) ...@@ -2120,7 +2110,8 @@ static int coda_open(struct file *file)
{ {
struct video_device *vdev = video_devdata(file); struct video_device *vdev = video_devdata(file);
struct coda_dev *dev = video_get_drvdata(vdev); struct coda_dev *dev = video_get_drvdata(vdev);
struct coda_ctx *ctx = NULL; struct coda_ctx *ctx;
unsigned int max = ~0;
char *name; char *name;
int ret; int ret;
int idx; int idx;
...@@ -2129,12 +2120,13 @@ static int coda_open(struct file *file) ...@@ -2129,12 +2120,13 @@ static int coda_open(struct file *file)
if (!ctx) if (!ctx)
return -ENOMEM; return -ENOMEM;
idx = coda_next_free_instance(dev); if (dev->devtype->product == CODA_DX6)
max = CODADX6_MAX_INSTANCES - 1;
idx = ida_alloc_max(&dev->ida, max, GFP_KERNEL);
if (idx < 0) { if (idx < 0) {
ret = idx; ret = idx;
goto err_coda_max; goto err_coda_max;
} }
set_bit(idx, &dev->instance_mask);
name = kasprintf(GFP_KERNEL, "context%d", idx); name = kasprintf(GFP_KERNEL, "context%d", idx);
if (!name) { if (!name) {
...@@ -2243,8 +2235,8 @@ static int coda_open(struct file *file) ...@@ -2243,8 +2235,8 @@ static int coda_open(struct file *file)
err_pm_get: err_pm_get:
v4l2_fh_del(&ctx->fh); v4l2_fh_del(&ctx->fh);
v4l2_fh_exit(&ctx->fh); v4l2_fh_exit(&ctx->fh);
clear_bit(ctx->idx, &dev->instance_mask);
err_coda_name_init: err_coda_name_init:
ida_free(&dev->ida, ctx->idx);
err_coda_max: err_coda_max:
kfree(ctx); kfree(ctx);
return ret; return ret;
...@@ -2286,7 +2278,7 @@ static int coda_release(struct file *file) ...@@ -2286,7 +2278,7 @@ static int coda_release(struct file *file)
pm_runtime_put_sync(&dev->plat_dev->dev); pm_runtime_put_sync(&dev->plat_dev->dev);
v4l2_fh_del(&ctx->fh); v4l2_fh_del(&ctx->fh);
v4l2_fh_exit(&ctx->fh); v4l2_fh_exit(&ctx->fh);
clear_bit(ctx->idx, &dev->instance_mask); ida_free(&dev->ida, ctx->idx);
if (ctx->ops->release) if (ctx->ops->release)
ctx->ops->release(ctx); ctx->ops->release(ctx);
debugfs_remove_recursive(ctx->debugfs_entry); debugfs_remove_recursive(ctx->debugfs_entry);
...@@ -2747,6 +2739,7 @@ static int coda_probe(struct platform_device *pdev) ...@@ -2747,6 +2739,7 @@ static int coda_probe(struct platform_device *pdev)
mutex_init(&dev->dev_mutex); mutex_init(&dev->dev_mutex);
mutex_init(&dev->coda_mutex); mutex_init(&dev->coda_mutex);
ida_init(&dev->ida);
dev->debugfs_root = debugfs_create_dir("coda", NULL); dev->debugfs_root = debugfs_create_dir("coda", NULL);
if (!dev->debugfs_root) if (!dev->debugfs_root)
...@@ -2834,6 +2827,7 @@ static int coda_remove(struct platform_device *pdev) ...@@ -2834,6 +2827,7 @@ static int coda_remove(struct platform_device *pdev)
coda_free_aux_buf(dev, &dev->tempbuf); coda_free_aux_buf(dev, &dev->tempbuf);
coda_free_aux_buf(dev, &dev->workbuf); coda_free_aux_buf(dev, &dev->workbuf);
debugfs_remove_recursive(dev->debugfs_root); debugfs_remove_recursive(dev->debugfs_root);
ida_destroy(&dev->ida);
return 0; return 0;
} }
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#define __CODA_H__ #define __CODA_H__
#include <linux/debugfs.h> #include <linux/debugfs.h>
#include <linux/idr.h>
#include <linux/irqreturn.h> #include <linux/irqreturn.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/kfifo.h> #include <linux/kfifo.h>
...@@ -95,7 +96,7 @@ struct coda_dev { ...@@ -95,7 +96,7 @@ struct coda_dev {
struct workqueue_struct *workqueue; struct workqueue_struct *workqueue;
struct v4l2_m2m_dev *m2m_dev; struct v4l2_m2m_dev *m2m_dev;
struct list_head instances; struct list_head instances;
unsigned long instance_mask; struct ida ida;
struct dentry *debugfs_root; struct dentry *debugfs_root;
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment