From: Vitaly Mayatskikh <vmayatsk@redhat.com> Date: Thu, 23 Oct 2008 14:52:10 +0200 Subject: [misc] rtc: disable SIGIO notification on close Message-id: m3fxmnzd6t.wl%vmayatsk@redhat.com O-Subject: [RHEL-5.3 PATCH] bz465747 rtc: fix kernel panic on second use of SIGIO notification Bugzilla: 465747 RH-Acked-by: Chuck Ebbert <cebbert@redhat.com> RH-Acked-by: Jerome Marchand <jmarchan@redhat.com> RH-Acked-by: Prarit Bhargava <prarit@redhat.com> RH-Acked-by: Oleg Nesterov <oleg@redhat.com> Bugzilla: 465747 https://bugzilla.redhat.com/show_bug.cgi?id=465747 Description: ============ Marcin Slusarz reported: When userspace uses SIGIO notification and forgets to disable it before closing file descriptor, rtc->async_queue contains stale pointer to struct file. When user space enables again SIGIO notification in different process, kernel dereferences this (poisoned) pointer and crashes. So disable SIGIO notification on close. Upstream status: ================ commit 2e4a75cdcb89ff53bb182dda3a6dcdc14befe007 Test status: ============ I wasn't able to panic kernel with qemu or reproducer (qemu-like work with rtc), but looking at the fasync code there truly may occur bad pointer dereference. So it's better to prevent possible crashes in future. diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c index 61a5825..9a78ed7 100644 --- a/drivers/rtc/rtc-dev.c +++ b/drivers/rtc/rtc-dev.c @@ -350,6 +350,12 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file, return err; } +static int rtc_dev_fasync(int fd, struct file *file, int on) +{ + struct rtc_device *rtc = to_rtc_device(file->private_data); + return fasync_helper(fd, file, on, &rtc->async_queue); +} + static int rtc_dev_release(struct inode *inode, struct file *file) { struct rtc_device *rtc = to_rtc_device(file->private_data); @@ -360,16 +366,13 @@ static int rtc_dev_release(struct inode *inode, struct file *file) if (rtc->ops->release) rtc->ops->release(rtc->class_dev.dev); + if (file->f_flags & FASYNC) + rtc_dev_fasync(-1, file, 0); + mutex_unlock(&rtc->char_lock); return 0; } -static int rtc_dev_fasync(int fd, struct file *file, int on) -{ - struct rtc_device *rtc = to_rtc_device(file->private_data); - return fasync_helper(fd, file, on, &rtc->async_queue); -} - static struct file_operations rtc_dev_fops = { .owner = THIS_MODULE, .llseek = no_llseek,