DescriptionEugene Teo (Security Response)
2010-09-06 08:05:51 UTC
Description of problem:
There is a bug in snd_seq_oss_open from sound/core/seq/oss/seq_oss_init.c. So here's the error path for some setup failure:
_error:
snd_seq_oss_writeq_delete(dp->writeq);
snd_seq_oss_readq_delete(dp->readq);
snd_seq_oss_synth_cleanup(dp);
snd_seq_oss_midi_cleanup(dp);
delete_port(dp);
delete_seq_queue(dp->queue);
kfree(dp);
This looks okay, but actually, delete_port calls port_delete (eventually...
this code is tough to follow) which does a free_devinfo on the owner struct
seq_oss_devinfo, here (around ~269 in seq_ports.c):
if (port->private_free)
port->private_free(port->private_data);
because of this (around ~334 in seq_oss_init.c):
memset(&callback, 0, sizeof(callback));
callback.owner = THIS_MODULE;
callback.private_data = dp;
callback.event_input = snd_seq_oss_event_input;
callback.private_free = free_devinfo;
port.kernel = &callback;
Which does this:
static void
free_devinfo(void *private)
{
struct seq_oss_devinfo *dp = (struct seq_oss_devinfo *)private;
if (dp->timer)
snd_seq_oss_timer_delete(dp->timer);
if (dp->writeq)
snd_seq_oss_writeq_delete(dp->writeq);
if (dp->readq)
snd_seq_oss_readq_delete(dp->readq);
kfree(dp);
}
So.....
delete_port(dp);
delete_seq_queue(dp->queue); <= Oops, dereferencing released pointer.
kfree(dp); <= Oops, double free.
Acknowledgements:
Red Hat would like to thank Tavis Ormandy for reporting this issue.
Comment 2Eugene Teo (Security Response)
2010-09-06 08:11:51 UTC
Statement:
This issue did not affect the version of Linux kernel as shipped with Red Hat Enterprise Linux 3, 4, and 5 as it did not include upstream commit 7034632d that introduced the problem. It did not affect Red Hat Enterprise MRG as the /dev/sequencer device file is restricted to root access only.
Comment 3Eugene Teo (Security Response)
2010-09-08 08:37:04 UTC