Merge branch 'timers-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull timer fixes from Thomas Gleixner:
 "Three fixlets for timers:

   - Two hot-fixes for the alarmtimer based posix timers, which prevent
     a nasty DOS by self rescheduling timers. The proper cleanup of that
     mess is queued for 4.13

   - Make a function static"

* 'timers-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  tick/broadcast: Make tick_broadcast_setup_oneshot() static
  alarmtimer: Rate limit periodic intervals
  alarmtimer: Prevent overflow of relative timers
This commit is contained in:
Linus Torvalds 2017-06-18 18:46:51 +09:00
commit 4f51d57f3f
3 changed files with 14 additions and 6 deletions

View File

@ -387,7 +387,7 @@ void alarm_start_relative(struct alarm *alarm, ktime_t start)
{ {
struct alarm_base *base = &alarm_bases[alarm->type]; struct alarm_base *base = &alarm_bases[alarm->type];
start = ktime_add(start, base->gettime()); start = ktime_add_safe(start, base->gettime());
alarm_start(alarm, start); alarm_start(alarm, start);
} }
EXPORT_SYMBOL_GPL(alarm_start_relative); EXPORT_SYMBOL_GPL(alarm_start_relative);
@ -475,7 +475,7 @@ u64 alarm_forward(struct alarm *alarm, ktime_t now, ktime_t interval)
overrun++; overrun++;
} }
alarm->node.expires = ktime_add(alarm->node.expires, interval); alarm->node.expires = ktime_add_safe(alarm->node.expires, interval);
return overrun; return overrun;
} }
EXPORT_SYMBOL_GPL(alarm_forward); EXPORT_SYMBOL_GPL(alarm_forward);
@ -660,13 +660,21 @@ static int alarm_timer_set(struct k_itimer *timr, int flags,
/* start the timer */ /* start the timer */
timr->it.alarm.interval = timespec64_to_ktime(new_setting->it_interval); timr->it.alarm.interval = timespec64_to_ktime(new_setting->it_interval);
/*
* Rate limit to the tick as a hot fix to prevent DOS. Will be
* mopped up later.
*/
if (timr->it.alarm.interval < TICK_NSEC)
timr->it.alarm.interval = TICK_NSEC;
exp = timespec64_to_ktime(new_setting->it_value); exp = timespec64_to_ktime(new_setting->it_value);
/* Convert (if necessary) to absolute time */ /* Convert (if necessary) to absolute time */
if (flags != TIMER_ABSTIME) { if (flags != TIMER_ABSTIME) {
ktime_t now; ktime_t now;
now = alarm_bases[timr->it.alarm.alarmtimer.type].gettime(); now = alarm_bases[timr->it.alarm.alarmtimer.type].gettime();
exp = ktime_add(now, exp); exp = ktime_add_safe(now, exp);
} }
alarm_start(&timr->it.alarm.alarmtimer, exp); alarm_start(&timr->it.alarm.alarmtimer, exp);

View File

@ -37,9 +37,11 @@ static int tick_broadcast_forced;
static __cacheline_aligned_in_smp DEFINE_RAW_SPINLOCK(tick_broadcast_lock); static __cacheline_aligned_in_smp DEFINE_RAW_SPINLOCK(tick_broadcast_lock);
#ifdef CONFIG_TICK_ONESHOT #ifdef CONFIG_TICK_ONESHOT
static void tick_broadcast_setup_oneshot(struct clock_event_device *bc);
static void tick_broadcast_clear_oneshot(int cpu); static void tick_broadcast_clear_oneshot(int cpu);
static void tick_resume_broadcast_oneshot(struct clock_event_device *bc); static void tick_resume_broadcast_oneshot(struct clock_event_device *bc);
#else #else
static inline void tick_broadcast_setup_oneshot(struct clock_event_device *bc) { BUG(); }
static inline void tick_broadcast_clear_oneshot(int cpu) { } static inline void tick_broadcast_clear_oneshot(int cpu) { }
static inline void tick_resume_broadcast_oneshot(struct clock_event_device *bc) { } static inline void tick_resume_broadcast_oneshot(struct clock_event_device *bc) { }
#endif #endif
@ -867,7 +869,7 @@ static void tick_broadcast_init_next_event(struct cpumask *mask,
/** /**
* tick_broadcast_setup_oneshot - setup the broadcast device * tick_broadcast_setup_oneshot - setup the broadcast device
*/ */
void tick_broadcast_setup_oneshot(struct clock_event_device *bc) static void tick_broadcast_setup_oneshot(struct clock_event_device *bc)
{ {
int cpu = smp_processor_id(); int cpu = smp_processor_id();

View File

@ -126,7 +126,6 @@ static inline int tick_check_oneshot_change(int allow_nohz) { return 0; }
/* Functions related to oneshot broadcasting */ /* Functions related to oneshot broadcasting */
#if defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) && defined(CONFIG_TICK_ONESHOT) #if defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) && defined(CONFIG_TICK_ONESHOT)
extern void tick_broadcast_setup_oneshot(struct clock_event_device *bc);
extern void tick_broadcast_switch_to_oneshot(void); extern void tick_broadcast_switch_to_oneshot(void);
extern void tick_shutdown_broadcast_oneshot(unsigned int cpu); extern void tick_shutdown_broadcast_oneshot(unsigned int cpu);
extern int tick_broadcast_oneshot_active(void); extern int tick_broadcast_oneshot_active(void);
@ -134,7 +133,6 @@ extern void tick_check_oneshot_broadcast_this_cpu(void);
bool tick_broadcast_oneshot_available(void); bool tick_broadcast_oneshot_available(void);
extern struct cpumask *tick_get_broadcast_oneshot_mask(void); extern struct cpumask *tick_get_broadcast_oneshot_mask(void);
#else /* !(BROADCAST && ONESHOT): */ #else /* !(BROADCAST && ONESHOT): */
static inline void tick_broadcast_setup_oneshot(struct clock_event_device *bc) { BUG(); }
static inline void tick_broadcast_switch_to_oneshot(void) { } static inline void tick_broadcast_switch_to_oneshot(void) { }
static inline void tick_shutdown_broadcast_oneshot(unsigned int cpu) { } static inline void tick_shutdown_broadcast_oneshot(unsigned int cpu) { }
static inline int tick_broadcast_oneshot_active(void) { return 0; } static inline int tick_broadcast_oneshot_active(void) { return 0; }