[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

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: