Module Name: src Committed By: kre Date: Thu Feb 8 02:54:07 UTC 2024
Modified Files: src/usr.bin/touch: touch.c Log Message: Check that mktime() (or timegm() the one time it is used) do not alter any of the material fields of the struct tm that was handed to it. If any were altered, then the time string passed in was not a valid time representation, and so should be rejected. This one is not an invisible change, it prevents use of things like "-t 202402300000" (which previously would have been interpreted as "-t 202403010000" - the day after the 29th of Feb in 2024). I believe this is an improvement however, and in line with the general intent that if you specify a date and time, that exact date and time is what touch should be using. It does mean that specifying "60" for the seconds field is almost guaranteed to fail on any POSIX system, as leap seconds simply don't exist there (on a non-POSIX-conforming system that uses leap seconds, the :60 should work, if specified with the correct date and time at which the leap second actually occurs). The one exception is when parsedate(3) is used, as that does not do this check (which allows things like "-1 day" on the 1st of a month to work). (This is the last of this sequence of updates to touch.c, an update to touch.1 follows). To generate a diff of this commit: cvs rdiff -u -r1.37 -r1.38 src/usr.bin/touch/touch.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/usr.bin/touch/touch.c diff -u src/usr.bin/touch/touch.c:1.37 src/usr.bin/touch/touch.c:1.38 --- src/usr.bin/touch/touch.c:1.37 Thu Feb 8 02:53:53 2024 +++ src/usr.bin/touch/touch.c Thu Feb 8 02:54:07 2024 @@ -1,4 +1,4 @@ -/* $NetBSD: touch.c,v 1.37 2024/02/08 02:53:53 kre Exp $ */ +/* $NetBSD: touch.c,v 1.38 2024/02/08 02:54:07 kre Exp $ */ /* * Copyright (c) 1993 @@ -39,7 +39,7 @@ __COPYRIGHT("@(#) Copyright (c) 1993\ #if 0 static char sccsid[] = "@(#)touch.c 8.2 (Berkeley) 4/28/95"; #endif -__RCSID("$NetBSD: touch.c,v 1.37 2024/02/08 02:53:53 kre Exp $"); +__RCSID("$NetBSD: touch.c,v 1.38 2024/02/08 02:54:07 kre Exp $"); #endif /* not lint */ #include <sys/types.h> @@ -67,6 +67,7 @@ static void stime_arg1(char *, struct ti static void stime_arg2(const char *, int, struct timespec *); static void stime_file(const char *, struct timespec *); static int stime_posix(const char *, struct timespec *); +static int difftm(const struct tm *, const struct tm *); __dead static void usage(void); struct option touch_longopts[] = { @@ -233,7 +234,7 @@ stime_arg0(const char *arg, struct times static void stime_arg1(char *arg, struct timespec *tsp) { - struct tm *t; + struct tm *t, tm; time_t tmptime; int yearset; char *p; @@ -290,8 +291,9 @@ stime_arg1(char *arg, struct timespec *t } t->tm_isdst = -1; /* Figure out DST. */ + tm = *t; tsp[0].tv_sec = tsp[1].tv_sec = mktime(t); - if (tsp[0].tv_sec == NO_TIME) + if (tsp[0].tv_sec == NO_TIME || difftm(t, &tm)) terr: errx(EXIT_FAILURE, "out of range or bad time specification:\n" "\t'%s' should be [[CC]YY]MMDDhhmm[.ss]", initarg); @@ -301,7 +303,7 @@ stime_arg1(char *arg, struct timespec *t static void stime_arg2(const char *arg, int year, struct timespec *tsp) { - struct tm *t; + struct tm *t, tm; time_t tmptime; /* Start with the current time. */ tmptime = tsp[0].tv_sec; @@ -323,8 +325,9 @@ stime_arg2(const char *arg, int year, st t->tm_sec = 0; t->tm_isdst = -1; /* Figure out DST. */ + tm = *t; tsp[0].tv_sec = tsp[1].tv_sec = mktime(t); - if (tsp[0].tv_sec == NO_TIME) + if (tsp[0].tv_sec == NO_TIME || difftm(t, &tm)) errx(EXIT_FAILURE, "out of range or bad time specification: MMDDhhmm[YY]"); @@ -345,7 +348,7 @@ stime_file(const char *fname, struct tim static int stime_posix(const char *arg, struct timespec *tsp) { - struct tm tm; + struct tm tm, tms; const char *p; char *ep; int utc = 0; @@ -361,6 +364,8 @@ stime_posix(const char *arg, struct time if (!isdigch(arg[0])) /* and the first must be a digit! */ return 0; + (void)memset(&tm, 0, sizeof tm); + errno = 0; val = strtol(arg, &ep, 10); /* YYYY */ if (val < 0 || val > INT_MAX) @@ -472,17 +477,46 @@ stime_posix(const char *arg, struct time return 0; tm.tm_isdst = -1; + tms = tm; if (utc) tsp[0].tv_sec = tsp[1].tv_sec = timegm(&tm); else tsp[0].tv_sec = tsp[1].tv_sec = mktime(&tm); - if (errno != 0 && tsp[1].tv_sec == NO_TIME) + if ((errno != 0 && tsp[1].tv_sec == NO_TIME) || difftm(&tm, &tms)) return 0; return 1; } +/* + * Determine whether 2 struct tn's are different + * return true (1) if theu are, false (0) otherwise. + * + * Note that we only consider the fields that are set + * for mktime() to use - if mktime() returns them + * differently than was set, then there was a problem + * with the setting. + */ +static int +difftm(const struct tm *t1, const struct tm *t2) +{ +#define CHK(fld) do { \ + if (t1->tm_##fld != t2->tm_##fld) { \ + return 1; \ + } \ + } while(/*CONSTCOND*/0) + + CHK(year); + CHK(mon); + CHK(mday); + CHK(hour); + CHK(min); + CHK(sec); + + return 0; +} + static void usage(void) {