rtc_calc_weekday() indexes the 12-entry month_offset[] array with
tm->tm_mon - 1 but never checks that tm_mon is in 1..12. A caller that
derives the month from untrusted data can pass a larger value, causing an
out-of-bounds read of month_offset[].
fs/fat reaches this with on-disk data: fat_readdir() calls fat2rtc() on
each directory entry's cdate/date/adate fields, and fat2rtc() does
tm->tm_mon = (date & 0x1e0) >> 5;
The month is a 4-bit field, so it can be 0..15. A directory-entry date
word with a month of 13..15 (which a compliant filesystem never writes,
but a crafted or corrupted image can contain) makes rtc_calc_weekday()
read past month_offset[]. This happens while merely listing a FAT volume
(fatls / ls), i.e. on attacker-controlled media before it is validated.
The impact is limited to an out-of-bounds read (a wrong weekday, or on a
sanitizer build an abort); there is no write. Reject an out-of-range
month, as is already done for the year. This also hardens the other
callers (mc146818, efi_runtime, cmd/date).
Found with a libFuzzer harness over the FAT parser (test/fuzz/fat.c).
Signed-off-by: Oscar Deschamps <[email protected]>
---
lib/date.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/lib/date.c b/lib/date.c
index 0deac8a1bee..7ac257fcb21 100644
--- a/lib/date.c
+++ b/lib/date.c
@@ -32,6 +32,8 @@ int rtc_calc_weekday(struct rtc_time *tm)
if (tm->tm_year < 1753)
return -1;
+ if (tm->tm_mon < 1 || tm->tm_mon > 12)
+ return -1;
last_year = tm->tm_year - 1;
/* Number of leap corrections to apply up to end of last year */
--
2.43.0