media: coda: fix memory corruption in case more than 32 instances are opened
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: Philipp Zabel <p.zabel@pengutronix.de> Signed-off-by: Hans Verkuil <hansverk@cisco.com> Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
This commit is contained in:
Родитель
c45fbdf24c
Коммит
649cfc2bdf
|
@ -17,6 +17,7 @@
|
|||
#include <linux/firmware.h>
|
||||
#include <linux/gcd.h>
|
||||
#include <linux/genalloc.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/irq.h>
|
||||
|
@ -2099,17 +2100,6 @@ int coda_decoder_queue_init(void *priv, struct vb2_queue *src_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
|
||||
*/
|
||||
|
@ -2118,7 +2108,8 @@ static int coda_open(struct file *file)
|
|||
{
|
||||
struct video_device *vdev = video_devdata(file);
|
||||
struct coda_dev *dev = video_get_drvdata(vdev);
|
||||
struct coda_ctx *ctx = NULL;
|
||||
struct coda_ctx *ctx;
|
||||
unsigned int max = ~0;
|
||||
char *name;
|
||||
int ret;
|
||||
int idx;
|
||||
|
@ -2127,12 +2118,13 @@ static int coda_open(struct file *file)
|
|||
if (!ctx)
|
||||
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) {
|
||||
ret = idx;
|
||||
goto err_coda_max;
|
||||
}
|
||||
set_bit(idx, &dev->instance_mask);
|
||||
|
||||
name = kasprintf(GFP_KERNEL, "context%d", idx);
|
||||
if (!name) {
|
||||
|
@ -2241,8 +2233,8 @@ err_clk_per:
|
|||
err_pm_get:
|
||||
v4l2_fh_del(&ctx->fh);
|
||||
v4l2_fh_exit(&ctx->fh);
|
||||
clear_bit(ctx->idx, &dev->instance_mask);
|
||||
err_coda_name_init:
|
||||
ida_free(&dev->ida, ctx->idx);
|
||||
err_coda_max:
|
||||
kfree(ctx);
|
||||
return ret;
|
||||
|
@ -2284,7 +2276,7 @@ static int coda_release(struct file *file)
|
|||
pm_runtime_put_sync(&dev->plat_dev->dev);
|
||||
v4l2_fh_del(&ctx->fh);
|
||||
v4l2_fh_exit(&ctx->fh);
|
||||
clear_bit(ctx->idx, &dev->instance_mask);
|
||||
ida_free(&dev->ida, ctx->idx);
|
||||
if (ctx->ops->release)
|
||||
ctx->ops->release(ctx);
|
||||
debugfs_remove_recursive(ctx->debugfs_entry);
|
||||
|
@ -2745,6 +2737,7 @@ static int coda_probe(struct platform_device *pdev)
|
|||
|
||||
mutex_init(&dev->dev_mutex);
|
||||
mutex_init(&dev->coda_mutex);
|
||||
ida_init(&dev->ida);
|
||||
|
||||
dev->debugfs_root = debugfs_create_dir("coda", NULL);
|
||||
if (!dev->debugfs_root)
|
||||
|
@ -2832,6 +2825,7 @@ static int coda_remove(struct platform_device *pdev)
|
|||
coda_free_aux_buf(dev, &dev->tempbuf);
|
||||
coda_free_aux_buf(dev, &dev->workbuf);
|
||||
debugfs_remove_recursive(dev->debugfs_root);
|
||||
ida_destroy(&dev->ida);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#define __CODA_H__
|
||||
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/irqreturn.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/kfifo.h>
|
||||
|
@ -95,7 +96,7 @@ struct coda_dev {
|
|||
struct workqueue_struct *workqueue;
|
||||
struct v4l2_m2m_dev *m2m_dev;
|
||||
struct list_head instances;
|
||||
unsigned long instance_mask;
|
||||
struct ida ida;
|
||||
struct dentry *debugfs_root;
|
||||
};
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче