From: Takashi Iwai <tiwai@suse.de>
Subject: kABI workaround for posix-timers it_overrun 64bit changes
Patch-mainline: Never, kABI fix
References: CVE-2018-12896,bsc#1099922
This is a very messy workaround for kABI breakage due to the change to
64bit values of it_overrun and it_overrun_last in struct k_itimer.
We just keep the shadow copy of 32bit values in the original place,
updating them along with 64bit values.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
include/linux/posix-timers.h | 16 ++++++++++++++--
kernel/time/alarmtimer.c | 1 +
kernel/time/posix-cpu-timers.c | 6 ++++++
kernel/time/posix-timers.c | 9 ++++++++-
4 files changed, 29 insertions(+), 3 deletions(-)
--- a/include/linux/posix-timers.h
+++ b/include/linux/posix-timers.h
@@ -55,8 +55,13 @@ struct k_itimer {
spinlock_t it_lock;
clockid_t it_clock; /* which timer type */
timer_t it_id; /* timer id */
- s64 it_overrun; /* overrun on pending signal */
- s64 it_overrun_last; /* overrun on last delivered signal */
+#ifdef __GENKSYMS__
+ int it_overrun; /* overrun on pending signal */
+ int it_overrun_last; /* overrun on last delivered signal */
+#else
+ int __it_overrun; /* shadow copy of 32bit it_overrun */
+ int __it_overrun_last; /* shadow copy of 32bit it_overrun_last */
+#endif
int it_requeue_pending; /* waiting to requeue this timer */
#define REQUEUE_PENDING 1
int it_sigev_notify; /* notify word of sigevent struct */
@@ -84,6 +89,13 @@ struct k_itimer {
} alarm;
struct rcu_head rcu;
} it;
+#ifndef __GENKSYMS__
+ /* real values of it_overrun and it_overrun_last are kept here for
+ * kABI compatibility
+ */
+ s64 it_overrun; /* overrun on pending signal */
+ s64 it_overrun_last; /* overrun on last delivered signal */
+#endif
};
struct k_clock {
--- a/kernel/time/posix-timers.c
+++ b/kernel/time/posix-timers.c
@@ -380,6 +380,8 @@ static void schedule_next_timer(struct k
timr->it_overrun_last = timr->it_overrun;
timr->it_overrun = -1LL;
+ timr->__it_overrun_last = (unsigned int)timr->it_overrun_last;
+ timr->__it_overrun = -1;
++timr->it_requeue_pending;
hrtimer_restart(timer);
}
@@ -505,6 +507,7 @@ static enum hrtimer_restart posix_timer_
#endif
timr->it_overrun += hrtimer_forward(timer, now,
timr->it.real.interval);
+ timr->__it_overrun = (unsigned int)timr->it_overrun;
ret = HRTIMER_RESTART;
++timr->it_requeue_pending;
}
@@ -654,6 +657,7 @@ SYSCALL_DEFINE3(timer_create, const cloc
new_timer->it_id = (timer_t) new_timer_id;
new_timer->it_clock = which_clock;
new_timer->it_overrun = -1LL;
+ new_timer->__it_overrun = -1;
if (timer_event_spec) {
if (copy_from_user(&event, timer_event_spec, sizeof (event))) {
@@ -781,8 +785,10 @@ common_timer_get(struct k_itimer *timr,
* expiry is > now.
*/
if (iv && (timr->it_requeue_pending & REQUEUE_PENDING ||
- timr->it_sigev_notify == SIGEV_NONE))
+ timr->it_sigev_notify == SIGEV_NONE)) {
timr->it_overrun += hrtimer_forward(timer, now, iv);
+ timr->__it_overrun = (unsigned int)timr->it_overrun;
+ }
remaining = __hrtimer_expires_remaining_adjusted(timer, now);
/* Return 0 only, when the timer is expired and not pending */
@@ -876,6 +882,7 @@ common_timer_set(struct k_itimer *timr,
timr->it_requeue_pending = (timr->it_requeue_pending + 2) &
~REQUEUE_PENDING;
timr->it_overrun_last = 0;
+ timr->__it_overrun_last = 0;
/* switch off the timer when it_value is zero */
if (!new_setting->it_value.tv_sec && !new_setting->it_value.tv_nsec)
--- a/kernel/time/alarmtimer.c
+++ b/kernel/time/alarmtimer.c
@@ -529,6 +529,7 @@ static enum alarmtimer_restart alarm_han
ptr->it.alarm.interval);
result = ALARMTIMER_RESTART;
}
+ ptr->__it_overrun = (unsigned int)ptr->it_overrun;
spin_unlock_irqrestore(&ptr->it_lock, flags);
return result;
--- a/kernel/time/posix-cpu-timers.c
+++ b/kernel/time/posix-cpu-timers.c
@@ -79,6 +79,7 @@ static void bump_cpu_timer(struct k_itim
timer->it.cpu.expires += incr;
timer->it_overrun += 1LL << i;
+ timer->__it_overrun = (unsigned int)timer->it_overrun;
delta -= incr;
}
}
@@ -682,6 +683,8 @@ static int posix_cpu_timer_set(struct k_
~REQUEUE_PENDING;
timer->it_overrun_last = 0;
timer->it_overrun = -1LL;
+ timer->__it_overrun_last = 0;
+ timer->__it_overrun = -1;
if (new_expires != 0 && !(val < new_expires)) {
/*
@@ -1034,6 +1037,8 @@ void posix_cpu_timer_schedule(struct k_i
out:
timer->it_overrun_last = timer->it_overrun;
timer->it_overrun = -1LL;
+ timer->__it_overrun_last = (unsigned int)timer->it_overrun_last;
+ timer->__it_overrun = -1;
++timer->it_requeue_pending;
}
@@ -1239,6 +1244,7 @@ static int do_cpu_nanosleep(const clocki
spin_lock_init(&timer.it_lock);
timer.it_clock = which_clock;
timer.it_overrun = -1LL;
+ timer.__it_overrun = -1;
error = posix_cpu_timer_create(&timer);
timer.it_process = current;
if (!error) {