Skip to content

Commit abe4eaa

Browse files
jmberg-intelrichardweinberger
authored andcommitted
um: time-travel: fix time corruption
In 'basic' time-travel mode (without =inf-cpu or =ext), we still get timer interrupts. These can happen at arbitrary points in time, i.e. while in timer_read(), which pushes time forward just a little bit. Then, if we happen to get the interrupt after calculating the new time to push to, but before actually finishing that, the interrupt will set the time to a value that's incompatible with the forward, and we'll crash because time goes backwards when we do the forwarding. Fix this by reading the time_travel_time, calculating the adjustment, and doing the adjustment all with interrupts disabled. Reported-by: Vincent Whitchurch <Vincent.Whitchurch@axis.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Richard Weinberger <richard@nod.at>
1 parent 7d748f6 commit abe4eaa

1 file changed

Lines changed: 27 additions & 5 deletions

File tree

arch/um/kernel/time.c

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -432,9 +432,29 @@ static void time_travel_update_time(unsigned long long next, bool idle)
432432
time_travel_del_event(&ne);
433433
}
434434

435+
static void time_travel_update_time_rel(unsigned long long offs)
436+
{
437+
unsigned long flags;
438+
439+
/*
440+
* Disable interrupts before calculating the new time so
441+
* that a real timer interrupt (signal) can't happen at
442+
* a bad time e.g. after we read time_travel_time but
443+
* before we've completed updating the time.
444+
*/
445+
local_irq_save(flags);
446+
time_travel_update_time(time_travel_time + offs, false);
447+
local_irq_restore(flags);
448+
}
449+
435450
void time_travel_ndelay(unsigned long nsec)
436451
{
437-
time_travel_update_time(time_travel_time + nsec, false);
452+
/*
453+
* Not strictly needed to use _rel() version since this is
454+
* only used in INFCPU/EXT modes, but it doesn't hurt and
455+
* is more readable too.
456+
*/
457+
time_travel_update_time_rel(nsec);
438458
}
439459
EXPORT_SYMBOL(time_travel_ndelay);
440460

@@ -568,7 +588,11 @@ static void time_travel_set_start(void)
568588
#define time_travel_time 0
569589
#define time_travel_ext_waiting 0
570590

571-
static inline void time_travel_update_time(unsigned long long ns, bool retearly)
591+
static inline void time_travel_update_time(unsigned long long ns, bool idle)
592+
{
593+
}
594+
595+
static inline void time_travel_update_time_rel(unsigned long long offs)
572596
{
573597
}
574598

@@ -720,9 +744,7 @@ static u64 timer_read(struct clocksource *cs)
720744
*/
721745
if (!irqs_disabled() && !in_interrupt() && !in_softirq() &&
722746
!time_travel_ext_waiting)
723-
time_travel_update_time(time_travel_time +
724-
TIMER_MULTIPLIER,
725-
false);
747+
time_travel_update_time_rel(TIMER_MULTIPLIER);
726748
return time_travel_time / TIMER_MULTIPLIER;
727749
}
728750

0 commit comments

Comments
 (0)