Bug#800627: linux: fs/isofs/util.c iso_date() will map years >= 2028 to 1970
Package: linux
Version: 4.1.6
Severity: normal
Dear Maintainer,
as the title says, we have 12 years left until timestamps
of newly created ISOs will begin to collapse.
Glimpse of future (assuming you have a file "/bin/true"):
xorriso -outdev test.iso \
-blank as_needed \
-map /bin/true /victim \
-alter_date m 'Oct 01 22:06:12 2030' /victim --
mount -o loop test.iso /mnt/iso
ls -l /mnt/iso/victim
shows something like
-rwxr-xr-x 1 root root 27080 Jan 1 1970 /mnt/iso/victim
The cause is a signedness issue in fs/isofs/util.c, function iso_date()
int iso_date(char * p, int flag)
{
int year, ...;
...
year = p[0];
...
if (year < 0) {
crtime = 0;
} else {
...
}
return crtime;
}
ECMA-119 9.1.5 and 7.1.1 specify byte p[0] as unsigned 8 bit
value counting the years since 1900. Signed p[0] will be less
than zero with unsigned value 128 = 2028.
If there was not the problem in year 2028, the next one would
appear in 2038 when seconds since 1970 exceed 2 exp 31 - 1.
Then the signed 32 bit return value of iso_date() will roll over
and throw us back to year 1901.
A minimal remedy (up to 2038) would be:
- year = p[0];
+ year = isonum_711(p + 0);
I am now testing a candidate which is hopefully ready for up to
year 2156, when the 8 bit counter of ISO 9660 rolls over
(with changed return type declared in fs/isofs/isofs.h):
--------------------------------------------------------------------
time64_t iso_date(char * p, int flag)
{
unsigned int year, month, day, hour, minute, second;
int tz;
time64_t crtime;
year = isonum_711(p + 0);
month = isonum_711(p + 1);
if (month > 12) month = 12;
day = isonum_711(p + 2);
if (day > 31) day = 31;
hour = isonum_711(p + 3);
if (hour > 23) hour = 23;
minute = isonum_711(p + 4);
if (minute > 59) minute = 59;
second = isonum_711(p + 5);
if (second > 59) second = 59;
if (flag == 0)
tz = isonum_712(p + 6); /* High sierra has no time zone */
else
tz = 0;
crtime = mktime64(year+1900, month, day, hour, minute, second);
/* sign extend */
if (tz & 0x80)
tz |= (-1 << 8);
/*
* The timezone offset is unreliable on some disks,
...
* Thanks to kuhlmav@elec.canterbury.ac.nz (Volker Kuhlmann)
* for pointing out the sign error.
*/
if (-52 <= tz && tz <= 52)
crtime -= tz * 15 * 60;
return crtime;
}
--------------------------------------------------------------------
It can say dates like
-rwxr-xr-x 1 root root 27080 Oct 4 2144 victim
Have a nice day :)
Thomas
-- System Information:
Debian Release: stretch/sid
APT prefers unstable
APT policy: (500, 'unstable')
Architecture: amd64 (x86_64)
Kernel: Linux 4.1.6 (SMP w/1 CPU core)
Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash
Init: systemd (via /run/systemd/system)
Reply to: