From 8a1fbbe96cbca2284ee7bf4d8e42c6dcca3012ec Mon Sep 17 00:00:00 2001 From: Jonas 'Sortie' Termansen Date: Fri, 11 Apr 2025 16:50:21 +0200 Subject: isofs: fix Y2038 and Y2156 issues in Rock Ridge TF entry [ Upstream commit 5ea45f54c8d6ca2a95b7bd450ee9eb253310bfd3 ] This change implements the Rock Ridge TF entry LONG_FORM bit, which uses the ISO 9660 17-byte date format (up to year 9999, with 10ms precision) instead of the 7-byte date format (up to year 2155, with 1s precision). Previously the LONG_FORM bit was ignored; and isofs would entirely misinterpret the date as the wrong format, resulting in garbage timestamps on the filesystem. The Y2038 issue in iso_date() is fixed by returning a struct timespec64 instead of an int. parse_rock_ridge_inode_internal() is fixed so it does proper bounds checks of the TF entry timestamps. Signed-off-by: Jonas 'Sortie' Termansen Signed-off-by: Jan Kara Link: https://patch.msgid.link/20250411145022.2292255-1-sortie@maxsi.org Signed-off-by: Sasha Levin --- fs/isofs/util.c | 49 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 32 insertions(+), 17 deletions(-) (limited to 'fs/isofs/util.c') diff --git a/fs/isofs/util.c b/fs/isofs/util.c index e88dba721661..42f479da0b28 100644 --- a/fs/isofs/util.c +++ b/fs/isofs/util.c @@ -16,29 +16,44 @@ * to GMT. Thus we should always be correct. */ -int iso_date(u8 *p, int flag) +struct timespec64 iso_date(u8 *p, int flags) { int year, month, day, hour, minute, second, tz; - int crtime; + struct timespec64 ts; + + if (flags & ISO_DATE_LONG_FORM) { + year = (p[0] - '0') * 1000 + + (p[1] - '0') * 100 + + (p[2] - '0') * 10 + + (p[3] - '0') - 1900; + month = ((p[4] - '0') * 10 + (p[5] - '0')); + day = ((p[6] - '0') * 10 + (p[7] - '0')); + hour = ((p[8] - '0') * 10 + (p[9] - '0')); + minute = ((p[10] - '0') * 10 + (p[11] - '0')); + second = ((p[12] - '0') * 10 + (p[13] - '0')); + ts.tv_nsec = ((p[14] - '0') * 10 + (p[15] - '0')) * 10000000; + tz = p[16]; + } else { + year = p[0]; + month = p[1]; + day = p[2]; + hour = p[3]; + minute = p[4]; + second = p[5]; + ts.tv_nsec = 0; + /* High sierra has no time zone */ + tz = flags & ISO_DATE_HIGH_SIERRA ? 0 : p[6]; + } - year = p[0]; - month = p[1]; - day = p[2]; - hour = p[3]; - minute = p[4]; - second = p[5]; - if (flag == 0) tz = p[6]; /* High sierra has no time zone */ - else tz = 0; - if (year < 0) { - crtime = 0; + ts.tv_sec = 0; } else { - crtime = mktime64(year+1900, month, day, hour, minute, second); + ts.tv_sec = mktime64(year+1900, month, day, hour, minute, second); /* sign extend */ if (tz & 0x80) tz |= (-1 << 8); - + /* * The timezone offset is unreliable on some disks, * so we make a sanity check. In no case is it ever @@ -65,7 +80,7 @@ int iso_date(u8 *p, int flag) * for pointing out the sign error. */ if (-52 <= tz && tz <= 52) - crtime -= tz * 15 * 60; + ts.tv_sec -= tz * 15 * 60; } - return crtime; -} + return ts; +} -- cgit v1.2.3