genisoimage: Bad time stamps for post-2027 files

Bug #1946663 reported by Brian Murray
6
This bug affects 1 person
Affects Status Importance Assigned to Milestone
cdrkit (Debian)
New
Unknown
cdrkit (Ubuntu)
New
Undecided
Unassigned

Bug Description

Imported from Debian bug http://bugs.debian.org/990468:

Package: genisoimage
Version: 9:1.1.11-3+b2

Description of bug: .iso files generated with genisoimage will have
incorrect timestamps for files created on or after January 1, 2028

Steps to reproduce:

tar xvJf geniso-Y2076-test.tar.xz
# Please ignore timestamp in future warnings
genisoimage -J -V "test" -o test.iso geniso-Y2076-test/

Expected results:

The timestamps in the file test.iso will be between 5:03 and 5:05 am
(local time) for years between 2021 and 2076.

Actual results:

Some timestamp will have a different time because the
time zone value is invalid.

How to fix:

Edit the file genisoimage.c so that the function iso9660_date() does
not generate bad timestamps starting on January 1, 2028.

Here is a fixed version of the file (also, I made sure to have
reasonable values for timestamps for files dated before January 1,
1900 or after December 31, 2155):

int
iso9660_date(char *result, time_t crtime)
{
        struct tm *local;
        struct tm *gmt;
        int year, yday, hour, minute, second, zone;

        local = localtime(&crtime);
        result[0] = year = local->tm_year;
        result[1] = local->tm_mon + 1;
        result[2] = local->tm_mday;
        yday = local->tm_yday;
        result[3] = hour = local->tm_hour;
        result[4] = minute = local->tm_min;
        result[5] = second = local->tm_sec;

        /* Sam Trenholme's notes: The following code has been updated to be
         * Y2028 compliant. That is *not* a typo: Year twenty-*twenty*eight
         * (**not 2038!**).
         * In other words, result[6] (the time zone) had invalid values for
         * files created on or after January 1, 2028.
         */

        /* First of all, the 9660 spec only allows timestamps between
         * January 1, 1900 and December 31, 2155. So, handle timestamps
         * outside that spec by giving out timestamps at the end of the
         * spec. It is unknown here in 2021 whether or not 2155 will
         * have a leap second; I will assume programmers are smart enough
         * to not have things crash if we have a leap second. */
        if(year < 0) {
                /* January 1, 1900 00:00:00 GMT */
                result[0] = 0;
                result[1] = 1;
                result[2] = 1;
                result[3] = 0;
                result[4] = 0;
                result[5] = 0;
                result[6] = 0; /* Time zone */
                return 0;
        } else if(year > 255) {
                /* December 31, 2155, 23:59:60 GMT */
                result[0] = 255;
                result[1] = 12;
                result[2] = 31;
                result[3] = 23;
                result[4] = 59;
                result[5] = 60;
                result[6] = 0; /* Time zone */
                return 0;
        }

        /* I have no idea why POSIX does not have tm_gmtoff. Since it
         * doesn't, we have to calculate it ourselves. */
        gmt = gmtime(&crtime); /* Zaps local, be careful */

        zone = 0;

        /* We will never be more than one day off between GMT and local
         * time. That in mind, if the year is different, we are one day
         * behind or ahead. Otherwise, if the day is different, it will
         * always be a one day difference. */
        if(gmt->tm_year < year) {
                zone = 86400; /* 24 hours in seconds */
        } else if(gmt->tm_year > year) {
                zone = -86400;
        } else if(gmt->tm_yday < yday) {
                zone = 86400;
        } else if(gmt->tm_yday > yday) {
                zone = -86400;
        }

        /* Now that we account for different days, account for different
         * hours, minutes, and seconds. */
        zone += (hour - gmt->tm_hour) * 3600;
        zone += (minute - gmt->tm_min) * 60;
        zone += second - gmt->tm_sec;
        result[6] = zone / 900; /* Every 15 minutes in 9660 spec */

        return (0);
}

Additional notes:

File source code which uses 100% GPLv2 code and compiles and works in
Ubuntu 20.04 (probably also Debian) is at
https://github.com/samboy/9660img

Another comment:

I know there have been issues with the original upstream version of
the code possibly being linked to CDDL licensed code. Has anyone
attempted to contact Eric Youngdale and see if he’s willing to
dual-license the original mkisofs / cdrkit package to also have a CDDL
license so we can resolve the licensing dispute and have a version
directly derived from the version still maintained by the primary
mkisofs maintainer?

description: updated
Changed in cdrkit (Debian):
importance: Undecided → Unknown
To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.