From 83a06bf50bdf2074b9404951ff60e142d159d93b Mon Sep 17 00:00:00 2001 From: Marcelo Roberto Jimenez Date: Wed, 2 Feb 2011 16:04:02 -0200 Subject: RTC: Prevents a division by zero in kernel code. This patch prevents a user space program from calling the RTC_IRQP_SET ioctl with a negative value of frequency. Also, if this call is make with a zero value of frequency, there would be a division by zero in the kernel code. [jstultz: Also initialize irq_freq to 1 to catch other divbyzero issues] CC: Alessandro Zummo CC: Thomas Gleixner Signed-off-by: Marcelo Roberto Jimenez Signed-off-by: John Stultz --- drivers/rtc/interface.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/rtc/interface.c') diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index 925006d33109..a0c01967244d 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -464,6 +464,9 @@ int rtc_irq_set_freq(struct rtc_device *rtc, struct rtc_task *task, int freq) int err = 0; unsigned long flags; + if (freq <= 0) + return -EINVAL; + spin_lock_irqsave(&rtc->irq_task_lock, flags); if (rtc->irq_task != NULL && task == NULL) err = -EBUSY; -- cgit v1.2.3 From 516373b8b60fa4152334b6b6f2ece0f178c540ce Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Mon, 14 Feb 2011 11:33:17 +0100 Subject: RTC: Release mutex in error path of rtc_alarm_irq_enable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On hardware that doesn't support alarm interrupts, rtc_alarm_irq_enable could return without releasing the ops_lock mutex. This was introduced in aa0be0f (RTC: Propagate error handling via rtc_timer_enqueue properly) This patch corrects the issue by only returning once the mutex is released. [john.stultz: Reworded the commit log] Signed-off-by: Uwe Kleine-König Signed-off-by: John Stultz --- drivers/rtc/interface.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/rtc/interface.c') diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index a0c01967244d..413ae0537915 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -209,9 +209,8 @@ int rtc_alarm_irq_enable(struct rtc_device *rtc, unsigned int enabled) } if (err) - return err; - - if (!rtc->ops) + /* nothing */; + else if (!rtc->ops) err = -ENODEV; else if (!rtc->ops->alarm_irq_enable) err = -EINVAL; -- cgit v1.2.3 From 456d66ecd09e3bc326b93174745faafb6ac378d6 Mon Sep 17 00:00:00 2001 From: John Stultz Date: Fri, 11 Feb 2011 18:15:23 -0800 Subject: RTC: Re-enable UIE timer/polling emulation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch re-enables UIE timer/polling emulation for rtc devices that do not support alarm irqs. CC: Uwe Kleine-König CC: Thomas Gleixner Reported-by: Uwe Kleine-König Tested-by: Uwe Kleine-König Signed-off-by: John Stultz --- drivers/rtc/interface.c | 18 +++++++++++++++++- drivers/rtc/rtc-dev.c | 2 +- include/linux/rtc.h | 1 + 3 files changed, 19 insertions(+), 2 deletions(-) (limited to 'drivers/rtc/interface.c') diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index 413ae0537915..cb2f0728fd70 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -228,6 +228,12 @@ int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled) if (err) return err; +#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL + if (enabled == 0 && rtc->uie_irq_active) { + mutex_unlock(&rtc->ops_lock); + return rtc_dev_update_irq_enable_emul(rtc, 0); + } +#endif /* make sure we're changing state */ if (rtc->uie_rtctimer.enabled == enabled) goto out; @@ -247,6 +253,16 @@ int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled) out: mutex_unlock(&rtc->ops_lock); +#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL + /* + * Enable emulation if the driver did not provide + * the update_irq_enable function pointer or if returned + * -EINVAL to signal that it has been configured without + * interrupts or that are not available at the moment. + */ + if (err == -EINVAL) + err = rtc_dev_update_irq_enable_emul(rtc, enabled); +#endif return err; } @@ -262,7 +278,7 @@ EXPORT_SYMBOL_GPL(rtc_update_irq_enable); * * Triggers the registered irq_task function callback. */ -static void rtc_handle_legacy_irq(struct rtc_device *rtc, int num, int mode) +void rtc_handle_legacy_irq(struct rtc_device *rtc, int num, int mode) { unsigned long flags; diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c index dfa72c9c2687..d0e06edb14c5 100644 --- a/drivers/rtc/rtc-dev.c +++ b/drivers/rtc/rtc-dev.c @@ -76,7 +76,7 @@ static void rtc_uie_task(struct work_struct *work) } spin_unlock_irq(&rtc->irq_lock); if (num) - rtc_update_irq(rtc, num, RTC_UF | RTC_IRQF); + rtc_handle_legacy_irq(rtc, num, RTC_UF); } static void rtc_uie_timer(unsigned long data) { diff --git a/include/linux/rtc.h b/include/linux/rtc.h index 80408e711bed..89c3e5182991 100644 --- a/include/linux/rtc.h +++ b/include/linux/rtc.h @@ -250,6 +250,7 @@ extern int rtc_alarm_irq_enable(struct rtc_device *rtc, unsigned int enabled); extern int rtc_dev_update_irq_enable_emul(struct rtc_device *rtc, unsigned int enabled); +void rtc_handle_legacy_irq(struct rtc_device *rtc, int num, int mode); void rtc_aie_update_irq(void *private); void rtc_uie_update_irq(void *private); enum hrtimer_restart rtc_pie_update_irq(struct hrtimer *timer); -- cgit v1.2.3