Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'timers-urgent-2023-02-19' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull timer fix from Thomas Gleixner:
"A fix for a long standing issue in the alarmtimer code.

Posix-timers armed with a short interval with an ignored signal result
in an unpriviledged DoS. Due to the ignored signal the timer switches
into self rearm mode. This issue had been "fixed" before but a rework
of the alarmtimer code 5 years ago lost that workaround.

There is no real good solution for this issue, which is also worked
around in the core posix-timer code in the same way, but it certainly
moved way up on the ever growing todo list"

* tag 'timers-urgent-2023-02-19' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
alarmtimer: Prevent starvation by small intervals and SIG_IGN

+29 -4
+29 -4
kernel/time/alarmtimer.c
··· 470 470 } 471 471 EXPORT_SYMBOL_GPL(alarm_forward); 472 472 473 - u64 alarm_forward_now(struct alarm *alarm, ktime_t interval) 473 + static u64 __alarm_forward_now(struct alarm *alarm, ktime_t interval, bool throttle) 474 474 { 475 475 struct alarm_base *base = &alarm_bases[alarm->type]; 476 + ktime_t now = base->get_ktime(); 476 477 477 - return alarm_forward(alarm, base->get_ktime(), interval); 478 + if (IS_ENABLED(CONFIG_HIGH_RES_TIMERS) && throttle) { 479 + /* 480 + * Same issue as with posix_timer_fn(). Timers which are 481 + * periodic but the signal is ignored can starve the system 482 + * with a very small interval. The real fix which was 483 + * promised in the context of posix_timer_fn() never 484 + * materialized, but someone should really work on it. 485 + * 486 + * To prevent DOS fake @now to be 1 jiffie out which keeps 487 + * the overrun accounting correct but creates an 488 + * inconsistency vs. timer_gettime(2). 489 + */ 490 + ktime_t kj = NSEC_PER_SEC / HZ; 491 + 492 + if (interval < kj) 493 + now = ktime_add(now, kj); 494 + } 495 + 496 + return alarm_forward(alarm, now, interval); 497 + } 498 + 499 + u64 alarm_forward_now(struct alarm *alarm, ktime_t interval) 500 + { 501 + return __alarm_forward_now(alarm, interval, false); 478 502 } 479 503 EXPORT_SYMBOL_GPL(alarm_forward_now); 480 504 ··· 575 551 if (posix_timer_event(ptr, si_private) && ptr->it_interval) { 576 552 /* 577 553 * Handle ignored signals and rearm the timer. This will go 578 - * away once we handle ignored signals proper. 554 + * away once we handle ignored signals proper. Ensure that 555 + * small intervals cannot starve the system. 579 556 */ 580 - ptr->it_overrun += alarm_forward_now(alarm, ptr->it_interval); 557 + ptr->it_overrun += __alarm_forward_now(alarm, ptr->it_interval, true); 581 558 ++ptr->it_requeue_pending; 582 559 ptr->it_active = 1; 583 560 result = ALARMTIMER_RESTART;