rtc: mc146818: Prevent reading garbage
authorThomas Gleixner <tglx@linutronix.de>
Sun, 6 Dec 2020 21:46:14 +0000 (22:46 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 14 Dec 2022 10:31:55 +0000 (11:31 +0100)
commit7c7075c88da4e108deb80257a3a5352ddf22ba4c
tree86bd4f1d6162309cbf72c4bcd0ba5f1cf7c1ad6a
parent7f445ca2e0e59c7971d0b7b853465e50844ab596
rtc: mc146818: Prevent reading garbage

[ Upstream commit 05a0302c35481e9b47fb90ba40922b0a4cae40d8 ]

The MC146818 driver is prone to read garbage from the RTC. There are
several issues all related to the update cycle of the MC146818. The chip
increments seconds obviously once per second and indicates that by a bit in
a register. The bit goes high 244us before the actual update starts. During
the update the readout of the time values is undefined.

The code just checks whether the update in progress bit (UIP) is set before
reading the clock. If it's set it waits arbitrary 20ms before retrying,
which is ample because the maximum update time is ~2ms.

But this check does not guarantee that the UIP bit goes high and the actual
update happens during the readout. So the following can happen

 0.997         UIP = False
   -> Interrupt/NMI/preemption
 0.998        UIP -> True
 0.999        Readout <- Undefined

To prevent this rework the code so it checks UIP before and after the
readout and if set after the readout try again.

But that's not enough to cover the following:

 0.997         UIP = False
         Readout seconds
   -> NMI (or vCPU scheduled out)
 0.998        UIP -> True
         update completes
       UIP -> False
 1.000        Readout minutes,....
         UIP check succeeds

That can make the readout wrong up to 59 seconds.

To prevent this, read the seconds value before the first UIP check,
validate it after checking UIP and after reading out the rest.

It's amazing that the original i386 code had this actually correct and
the generic implementation of the MC146818 driver got it wrong in 2002 and
it stayed that way until today.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Acked-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
Link: https://lore.kernel.org/r/20201206220541.594826678@linutronix.de
Stable-dep-of: cd17420ebea5 ("rtc: cmos: avoid UIP when writing alarm time")
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/rtc/rtc-mc146818-lib.c