Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c08c464d authored by Al Viro's avatar Al Viro
Browse files

mISDN: fix the races with timers going off just as they are deleted



timer callback in timerdev.c both accesses struct mISDNtimer it's
called for *and* moves it to dev->expired.  We need del_timer_sync(),
or we risk kfree() freeing it right under dev_expire_timer() *and*
dev->expired getting corrupted.

Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 03feee37
Loading
Loading
Loading
Loading
+12 −2
Original line number Diff line number Diff line
@@ -72,14 +72,24 @@ static int
mISDN_close(struct inode *ino, struct file *filep)
{
	struct mISDNtimerdev	*dev = filep->private_data;
	struct list_head	*list = &dev->pending;
	struct mISDNtimer	*timer, *next;

	if (*debug & DEBUG_TIMER)
		printk(KERN_DEBUG "%s(%p,%p)\n", __func__, ino, filep);
	list_for_each_entry_safe(timer, next, &dev->pending, list) {
		del_timer(&timer->tl);

	spin_lock_irq(&dev->lock);
	while (!list_empty(list)) {
		timer = list_first_entry(list, struct mISDNtimer, list);
		spin_unlock_irq(&dev->lock);
		del_timer_sync(&timer->tl);
		spin_lock_irq(&dev->lock);
		/* it might have been moved to ->expired */
		list_del(&timer->list);
		kfree(timer);
	}
	spin_unlock_irq(&dev->lock);

	list_for_each_entry_safe(timer, next, &dev->expired, list) {
		kfree(timer);
	}