summaryrefslogtreecommitdiff
path: root/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
diff options
context:
space:
mode:
authorMike Isely <isely@pobox.com>2006-12-27 20:19:42 -0600
committerMike Isely <isely@pobox.com>2006-12-27 20:19:42 -0600
commit9b5392b7df5610270f040c693a77a2ddb6c8f061 (patch)
tree28a024116a42e7e9b245edbefe77f70c4f793583 /linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
parent83ae242c47af9df6d3ea6c1ec17f95c302960dd1 (diff)
downloadmediapointer-dvb-s2-9b5392b7df5610270f040c693a77a2ddb6c8f061.tar.gz
mediapointer-dvb-s2-9b5392b7df5610270f040c693a77a2ddb6c8f061.tar.bz2
pvrusb2: Fix heap corruption introduced by radio mods
From: Mike Isely <isely@pobox.com> We can't allocate v4l device structures in a block, since the v4l core governs when each device actually gets freed. This bug was introduced as part of the core radio implementation. Fix it. Signed-off-by: Mike Isely <isely@pobox.com>
Diffstat (limited to 'linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c')
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c103
1 files changed, 74 insertions, 29 deletions
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
index 2536c6d08..2ab2a0143 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
@@ -33,8 +33,6 @@
#include <media/v4l2-dev.h>
#include <media/v4l2-common.h>
-#define PVR2_NR_STREAMS 3
-
struct pvr2_v4l2_dev;
struct pvr2_v4l2_fh;
struct pvr2_v4l2;
@@ -66,8 +64,11 @@ struct pvr2_v4l2 {
struct v4l2_prio_state prio;
- /* streams */
- struct pvr2_v4l2_dev *vdev;
+ /* streams - Note that these must be separately, individually,
+ * allocated pointers. This is because the v4l core is going to
+ * manage their deletion - separately, individually... */
+ struct pvr2_v4l2_dev *dev_video;
+ struct pvr2_v4l2_dev *dev_radio;
};
static int video_nr[PVR_NUM] = {[0 ... PVR_NUM-1] = -1};
@@ -731,8 +732,26 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
static void pvr2_v4l2_dev_destroy(struct pvr2_v4l2_dev *dip)
{
- printk(KERN_INFO "pvrusb2: unregistering device video%d [%s]\n",
- dip->devbase.minor,pvr2_config_get_name(dip->config));
+ enum pvr2_config cfg = dip->config;
+ int minor_id = dip->devbase.minor;
+ enum pvr2_v4l_type pvt;
+ struct pvr2_hdw *hdw = dip->v4lp->channel.mc_head->hdw;
+
+ switch (cfg) {
+ case pvr2_config_mpeg:
+ pvt = pvr2_v4l_type_video;
+ break;
+ case pvr2_config_vbi:
+ pvt = pvr2_v4l_type_vbi;
+ break;
+ case pvr2_config_radio:
+ pvt = pvr2_v4l_type_radio;
+ break;
+ default: /* paranoia */
+ pvt = pvr2_v4l_type_video;
+ break;
+ }
+ pvr2_hdw_v4l_store_minor_number(hdw,pvt,-1);
/* Paranoia */
dip->v4lp = NULL;
@@ -741,18 +760,40 @@ static void pvr2_v4l2_dev_destroy(struct pvr2_v4l2_dev *dip)
/* Actual deallocation happens later when all internal references
are gone. */
video_unregister_device(&dip->devbase);
+
+ switch (cfg) {
+ case pvr2_config_mpeg:
+ printk(KERN_INFO "pvrusb2: unregistered device video%d [%s]\n",
+ minor_id & 0x1f,
+ pvr2_config_get_name(cfg));
+ break;
+ case pvr2_config_radio:
+ printk(KERN_INFO "pvrusb2: unregistered device radio%d [%s]\n",
+ minor_id & 0x1f,
+ pvr2_config_get_name(cfg));
+ break;
+ case pvr2_config_vbi:
+ printk(KERN_INFO "pvrusb2: unregistered device vbi%d [%s]\n",
+ minor_id & 0x1f,
+ pvr2_config_get_name(cfg));
+ break;
+ default:
+ break;
+ }
+
}
static void pvr2_v4l2_destroy_no_lock(struct pvr2_v4l2 *vp)
{
- pvr2_hdw_v4l_store_minor_number(vp->channel.mc_head->hdw,
- pvr2_v4l_type_video,-1);
- pvr2_hdw_v4l_store_minor_number(vp->channel.mc_head->hdw,
- pvr2_v4l_type_vbi,-1);
- pvr2_hdw_v4l_store_minor_number(vp->channel.mc_head->hdw,
- pvr2_v4l_type_radio,-1);
- pvr2_v4l2_dev_destroy(vp->vdev);
+ if (vp->dev_video) {
+ pvr2_v4l2_dev_destroy(vp->dev_video);
+ vp->dev_video = 0;
+ }
+ if (vp->dev_radio) {
+ pvr2_v4l2_dev_destroy(vp->dev_radio);
+ vp->dev_radio = 0;
+ }
pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr2_v4l2 id=%p",vp);
pvr2_channel_done(&vp->channel);
@@ -1107,7 +1148,7 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip,
usbdev = pvr2_hdw_get_dev(vp->channel.mc_head->hdw);
#endif
- switch (cfg) {
+ switch (dip->config) {
case pvr2_config_mpeg:
v4l_type = VFL_TYPE_GRABBER;
pvt = pvr2_v4l_type_video;
@@ -1129,7 +1170,7 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip,
}
/* radio device doesn 't need its own stream */
- if (!dip->stream && cfg != pvr2_config_radio) {
+ if (!dip->stream && dip->config != pvr2_config_radio) {
err("Failed to set up pvrusb2 v4l dev"
" due to missing stream instance");
return;
@@ -1165,24 +1206,24 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip,
(video_register_device(&dip->devbase, v4l_type, -1) < 0)) {
err("Failed to register pvrusb2 v4l device");
}
- switch (cfg) {
+ switch (dip->config) {
case pvr2_config_mpeg:
printk(KERN_INFO "pvrusb2: registered device video%d [%s]\n",
dip->devbase.minor & 0x1f,
pvr2_config_get_name(dip->config));
- break;
- case pvr2_config_vbi:
- printk(KERN_INFO "pvrusb2: registered device vbi%d [%s]\n",
- dip->devbase.minor & 0x1f,
- pvr2_config_get_name(dip->config));
- break;
+ break;
case pvr2_config_radio:
printk(KERN_INFO "pvrusb2: registered device radio%d [%s]\n",
dip->devbase.minor & 0x1f,
pvr2_config_get_name(dip->config));
- break;
+ break;
+ case pvr2_config_vbi:
+ printk(KERN_INFO "pvrusb2: registered device vbi%d [%s]\n",
+ dip->devbase.minor & 0x1f,
+ pvr2_config_get_name(dip->config));
+ break;
default:
- break;
+ break;
}
pvr2_hdw_v4l_store_minor_number(vp->channel.mc_head->hdw,
@@ -1197,20 +1238,24 @@ struct pvr2_v4l2 *pvr2_v4l2_create(struct pvr2_context *mnp)
vp = kmalloc(sizeof(*vp),GFP_KERNEL);
if (!vp) return vp;
memset(vp,0,sizeof(*vp));
- vp->vdev = kmalloc(sizeof(*vp->vdev)*PVR2_NR_STREAMS,GFP_KERNEL);
- if (!vp->vdev) {
+ vp->dev_video = kmalloc(sizeof(*vp->dev_video),GFP_KERNEL);
+ vp->dev_radio = kmalloc(sizeof(*vp->dev_radio),GFP_KERNEL);
+ if (!(vp->dev_video && vp->dev_radio)) {
+ if (vp->dev_video) kfree(vp->dev_video);
+ if (vp->dev_radio) kfree(vp->dev_radio);
kfree(vp);
return NULL;
}
- memset(vp->vdev,0,sizeof(*vp->vdev)*PVR2_NR_STREAMS);
+ memset(vp->dev_video,0,sizeof(*vp->dev_video));
+ memset(vp->dev_radio,0,sizeof(*vp->dev_radio));
pvr2_channel_init(&vp->channel,mnp);
pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr2_v4l2 id=%p",vp);
vp->channel.check_func = pvr2_v4l2_internal_check;
/* register streams */
- pvr2_v4l2_dev_init(&vp->vdev[0],vp,pvr2_config_mpeg);
- pvr2_v4l2_dev_init(&vp->vdev[2],vp,pvr2_config_radio);
+ pvr2_v4l2_dev_init(vp->dev_video,vp,pvr2_config_mpeg);
+ pvr2_v4l2_dev_init(vp->dev_radio,vp,pvr2_config_radio);
return vp;
}