dahdi: Stop tones on channel when updating tone zone.

If a channel is currently playing a tone when the tone zone is updated, the
existing tone zone could be freed while the channel keeps a reference to the
current tone (curtone) that points into the freed zone.

If the newly freed tone is then modified, there was a window where it was
possible to  corrupt 'struct dahdi_chan' (by overrunning swritechunk[])
resulting in a "BUG: unable to handle kernel paging request at virtual address"
panic in the context of __dahdi_transmit_chunk().

Reported-and-Tested-by: Matt Behrens <matt@zigg.com>
Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
This commit is contained in:
Shaun Ruffell 2014-07-05 14:52:46 -05:00 committed by Russ Meyerriecks
parent 089b593b56
commit a1ff3cb0c0

View File

@ -1811,6 +1811,17 @@ static int start_tone(struct dahdi_chan *chan, int tone)
return res; return res;
} }
/**
* stop_tone - Stops any tones on a channel.
*
* Must be called with chan->lock held.
*
*/
static inline int stop_tone(struct dahdi_chan *chan)
{
return start_tone(chan, -1);
}
static int set_tone_zone(struct dahdi_chan *chan, int zone) static int set_tone_zone(struct dahdi_chan *chan, int zone)
{ {
int res = 0; int res = 0;
@ -1838,6 +1849,9 @@ static int set_tone_zone(struct dahdi_chan *chan, int zone)
return -ENODATA; return -ENODATA;
spin_lock_irqsave(&chan->lock, flags); spin_lock_irqsave(&chan->lock, flags);
stop_tone(chan);
if (chan->curzone) { if (chan->curzone) {
struct dahdi_zone *zone = chan->curzone; struct dahdi_zone *zone = chan->curzone;
chan->curzone = NULL; chan->curzone = NULL;