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 kuhl...@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 via email to