Mailing List archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[linux-dvb] DVB driver bug, fixed it (quick hack)



I found a problem with the DVB driber (any one from
2000 up).
The problem showed itself when tuning a signal, and
then 
doing
cat /dev/dvb/adapter0/dvr0 > filename.ts

After a while, especially with high system load on a
slow machine,
the 'cat' aborts with 'Value to large for defined data
type'
Looking it up in errno.h shows this to be a buffer
overflow.
Looking in the driver source I found the problem came
from 'dmxdev.c'.

I put some printk statements in it, and ran some
tests.

The cause is in the typing., it is wrong all over
the place in that driver ....

In the original (uncorrected) driver only HALF the 32
bit
buffer is used, and if more data enters, the number
flips
to negative with as a result the 'Value to large for
defined data type error'
error abort (and a possible crash of the application
that uses the driver).
Even cat /dev/dvb/adapter0/dvr0 > file.ts crashed!

Here are the 2 routines I changed so it works.
 
convergence.de uses 32 bit buffer......
this returned int, changed to long!   
static inline long
dvb_dmxdev_buffer_write(dmxdev_buffer_t *buf, uint8_t
*src, size_t len)
{
unsigned int split; // changed was int
unsigned int free; // changed, was int
unsigned int todo; // changed, was int

if(! len)  return 0;
 
if(! buf->data) return 0;

free = buf->pread - buf->pwrite;
 
split = 0;
if(free == 0)
{
free += buf->size;
split = buf->size - buf->pwrite;
}
 
if(len >= free)
{
// added kernel reporting
printk("dmxdev: buffer overflow len=%lu free=%ld\n",
len, free);

return -1;
}
 
if (split >= len) split = 0;
todo = len;
if(split)  
{
memcpy(buf->data + buf->pwrite, src, split);
todo -= split;
buf->pwrite = 0;
}
 
memcpy(buf -> data + buf -> pwrite, src + split,
todo);

buf -> pwrite = (buf -> pwrite + todo) % buf->size;


return len; // at least now if it returns it can
return the full length of
            // a 32 bit buffer as a POSTIVE
number!!!!.
}
 
 
static int dvb_dmxdev_ts_callback(\
u8 *buffer1, size_t buffer1_len, u8 *buffer2, size_t
buffer2_len, dmx_ts_feed_t *feed,\
dmx_success_t success)
{
dmxdev_filter_t *dmxdevfilter = (dmxdev_filter_t *)
feed->priv;

dmxdev_buffer_t *buffer;
long int ret; // changed was int

spin_lock(&dmxdevfilter -> dev -> lock);

if(dmxdevfilter->params.pes.output == DMX_OUT_DECODER)
{
spin_unlock(&dmxdevfilter -> dev -> lock);
return 0;
}
 
if(dmxdevfilter -> params.pes.output == DMX_OUT_TAP)
buffer =& dmxdevfilter -> buffer;
else buffer =& dmxdevfilter -> dev -> dvr_buffer;

if(buffer -> error)
{
spin_unlock(&dmxdevfilter -> dev -> lock);
wake_up(&buffer -> queue);
return 0;
}
 
ret = dvb_dmxdev_buffer_write(buffer, buffer1,
buffer1_len);

if(ret == buffer1_len)  ret =
dvb_dmxdev_buffer_write(buffer, buffer2, buffer2_len);

if(ret < 0)
{
buffer->pwrite = buffer -> pread;
buffer->error =- EOVERFLOW;

// added kernel reporting
printk("WAS dvb_dmxdev_ts_callback(): EOVERFLOW
ret=%d\n", ret);
}
 
spin_unlock(&dmxdevfilter -> dev->lock);
wake_up(&buffer -> queue);
return 0;
}
 
 
So, the gist is guys, IF you use the DVB driver (any
one since 2000),
and you get strange errors / segfaults, aborts, when
reading from the
dvr device, then make this fix perhaps.
But all the rest is crummy too, I will subcribe to
their mailinglist
and post this and then run ;-)
I will also post to the VDR mailing list, as it
explains many problems
there ....




__________________________________________________
Do You Yahoo!?
Tired of spam?  Yahoo! Mail has the best spam protection around 
http://mail.yahoo.com 




Home | Main Index | Thread Index