Re: dvb shared datastructure bug?

From: Marcel Siegert
Date: Tue Feb 13 2007 - 06:30:57 EST


On Tuesday 13 February 2007, Arjan van de Ven wrote:
> Hi,
>
> while working on the last pieces of the file_ops constantification, DVB
> is the small village in France that is holding the Romans at bay... but
> I think I found the final flaw in it now:
>
> *pdvbdev = dvbdev = kmalloc(sizeof(struct dvb_device), GFP_KERNEL);
>
> if (!dvbdev) {
> mutex_unlock(&dvbdev_register_lock);
> return -ENOMEM;
> }
>
> memcpy(dvbdev, template, sizeof(struct dvb_device));
> dvbdev->type = type;
> dvbdev->id = id;
> dvbdev->adapter = adap;
> dvbdev->priv = priv;
>
> dvbdev->fops->owner = adap->module;
>
>
> this is the place in DVB that is writing to a struct file_operations.
> But as with almost all such cases in the kernel, this one is buggy:
> While the code nicely copies a template dvbdev, that template only has a
> pointer to a *shared* fops struct, the copy doesn't help that. So this
> code is overwriting the fops owner field for ALL active devices, not
> just the ones the copy of the template is for....
>
> I'm lost in the maze of this part of DVB (it seems to have some magic
> potion to resist me) but I was hoping some of the local citizens could
> take a look at this buglet...
>
> Greetings,
> Arjan van de Ven

hi arjan,
thanks for pointing out this issue.

attached find a patch that fixes the problem.

@mauro - please pull changeset a7ac92d208fe
dvbdev: fix illegal re-usage of fileoperations struct

from http://www.linuxtv.org/hg/~mws/v4l-dvb-fixtree

for upstream to kernel. thanks.

best regards
marcel
diff -r 667e84e2e762 linux/drivers/media/dvb/dvb-core/dvbdev.c
--- a/linux/drivers/media/dvb/dvb-core/dvbdev.c Tue Feb 13 07:00:55 2007 -0200
+++ b/linux/drivers/media/dvb/dvb-core/dvbdev.c Tue Feb 13 12:00:13 2007 +0100
@@ -211,12 +211,14 @@ int dvb_register_device(struct dvb_adapt
const struct dvb_device *template, void *priv, int type)
{
struct dvb_device *dvbdev;
+ struct file_operations *dvbdevfops;
+
int id;

if (mutex_lock_interruptible(&dvbdev_register_lock))
return -ERESTARTSYS;

- if ((id = dvbdev_get_free_id (adap, type)) < 0) {
+ if ((id = dvbdev_get_free_id (adap, type)) < 0){
mutex_unlock(&dvbdev_register_lock);
*pdvbdev = NULL;
printk ("%s: could get find free device id...\n", __FUNCTION__);
@@ -225,7 +227,15 @@ int dvb_register_device(struct dvb_adapt

*pdvbdev = dvbdev = kmalloc(sizeof(struct dvb_device), GFP_KERNEL);

- if (!dvbdev) {
+ if (!dvbdev){
+ mutex_unlock(&dvbdev_register_lock);
+ return -ENOMEM;
+ }
+
+ dvbdevfops = kzalloc(sizeof(struct file_operations), GFP_KERNEL);
+
+ if (!dvbdevfops){
+ kfree (dvbdev);
mutex_unlock(&dvbdev_register_lock);
return -ENOMEM;
}
@@ -235,7 +245,7 @@ int dvb_register_device(struct dvb_adapt
dvbdev->id = id;
dvbdev->adapter = adap;
dvbdev->priv = priv;
-
+ dvbdev->fops = dvbdevfops;
dvbdev->fops->owner = adap->module;

list_add_tail (&dvbdev->list_head, &adap->device_list);
@@ -263,6 +273,7 @@ void dvb_unregister_device(struct dvb_de
dvbdev->type, dvbdev->id)));

list_del (&dvbdev->list_head);
+ kfree (dvbdev->fops);
kfree (dvbdev);
}
EXPORT_SYMBOL(dvb_unregister_device);

Attachment: pgp00000.pgp
Description: PGP signature