Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/lib/libutil PR lib/46542
details: https://anonhg.NetBSD.org/src/rev/4e7ca4a80cd5
branches: trunk
changeset: 956444:4e7ca4a80cd5
user: kre <kre%NetBSD.org@localhost>
date: Fri Oct 30 22:03:11 2020 +0000
description:
PR lib/46542
Add checks to detect overflow, and also detect other invalid
(out of range) inputs for parsedate().
There could be more, and some of what is being added is not
perfect, but many calculation overflows will be detected now
(and cause an error return) and some of the most bizarre
inputs that were previously accepted no longer will be.
diffstat:
lib/libutil/parsedate.y | 157 ++++++++++++++++++++++++++++++++++++++++++-----
1 files changed, 139 insertions(+), 18 deletions(-)
diffs (truncated from 344 to 300 lines):
diff -r 9bffab170911 -r 4e7ca4a80cd5 lib/libutil/parsedate.y
--- a/lib/libutil/parsedate.y Fri Oct 30 21:44:49 2020 +0000
+++ b/lib/libutil/parsedate.y Fri Oct 30 22:03:11 2020 +0000
@@ -14,12 +14,13 @@
#include <sys/cdefs.h>
#ifdef __RCSID
-__RCSID("$NetBSD: parsedate.y,v 1.35 2020/10/19 17:47:45 kre Exp $");
+__RCSID("$NetBSD: parsedate.y,v 1.36 2020/10/30 22:03:11 kre Exp $");
#endif
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
+#include <limits.h>
#include <string.h>
#include <time.h>
#include <util.h>
@@ -95,6 +96,15 @@
int yyRelMonth;
} yyRel[MAXREL];
};
+
+static int RelVal(struct dateinfo *, time_t, time_t, int, int);
+
+#define CheckRelVal(a, b, c, d, e) do { \
+ if (!RelVal((a), (b), (c), (d), (e))) { \
+ YYREJECT; \
+ } \
+ } while (0)
+
%}
%union {
@@ -191,6 +201,8 @@
time:
tUNUMBER tMERIDIAN {
+ if ($1 > 24)
+ YYREJECT;
param->yyMinutes = 0;
param->yySeconds = 0;
if ($2 == MER_NOON || $2 == MER_MN) {
@@ -209,6 +221,8 @@
}
}
| tUNUMBER ':' tUNUMBER o_merid {
+ if ($1 > 24 || $3 >= 60)
+ YYREJECT;
param->yyMinutes = $3;
param->yySeconds = 0;
if ($4 == MER_NOON || $4 == MER_MN) {
@@ -227,6 +241,8 @@
}
}
| tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid {
+ if ($1 > 24 || $3 >= 60 || $5 > 60)
+ YYREJECT;
param->yyMinutes = $3;
param->yySeconds = $5;
if ($6 == MER_NOON || $6 == MER_MN) {
@@ -245,6 +261,8 @@
}
}
| tUNUMBER ':' tUNUMBER ':' tUNUMBER '.' tUNUMBER {
+ if ($1 > 24 || $3 >= 60 || $5 > 60)
+ YYREJECT;
param->yyHour = $1;
param->yyMinutes = $3;
param->yySeconds = $5;
@@ -252,6 +270,8 @@
/* XXX: Do nothing with fractional secs ($7) */
}
| tUNUMBER ':' tUNUMBER ':' tUNUMBER ',' tUNUMBER {
+ if ($1 > 24 || $3 >= 60 || $5 > 60)
+ YYREJECT;
param->yyHour = $1;
param->yyMinutes = $3;
param->yySeconds = $5;
@@ -280,6 +300,10 @@
time_numericzone:
tUNUMBER ':' tUNUMBER tSNUMBER {
+ if ($4 < -(47 * 100 + 59) || $4 > (47 * 100 + 59))
+ YYREJECT;
+ if ($1 > 24 || $3 > 59)
+ YYREJECT;
param->yyHour = $1;
param->yyMinutes = $3;
param->yyMeridian = MER24;
@@ -287,6 +311,10 @@
param->yyTimezone = - ($4 % 100 + ($4 / 100) * 60);
}
| tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER {
+ if ($6 < -(47 * 100 + 59) || $6 > (47 * 100 + 59))
+ YYREJECT;
+ if ($1 > 24 || $3 > 59 || $5 > 60)
+ YYREJECT;
param->yyHour = $1;
param->yyMinutes = $3;
param->yySeconds = $5;
@@ -303,6 +331,8 @@
| tSNUMBER {
if (param->yyHaveDate == 0 && param->yyHaveTime == 0)
YYREJECT;
+ if ($1 < -(47 * 100 + 59) || $1 > (47 * 100 + 59))
+ YYREJECT;
param->yyTimezone = - ($1 % 100 + ($1 / 100) * 60);
param->yyDSTmode = DSTmaybe;
}
@@ -316,15 +346,21 @@
date:
tUNUMBER '/' tUNUMBER {
+ if ($1 > 12 || $3 > 31 || $1 == 0 || $3 == 0)
+ YYREJECT;
param->yyMonth = $1;
param->yyDay = $3;
}
| tUNUMBER '/' tUNUMBER '/' tUNUMBER {
if ($1 >= 100) {
+ if ($3 > 12 || $5 > 31 || $3 == 0 || $5 == 0)
+ YYREJECT;
param->yyYear = $1;
param->yyMonth = $3;
param->yyDay = $5;
} else {
+ if ($1 >= 12 || $3 > 31 || $1 == 0 || $3 == 0)
+ YYREJECT;
param->yyMonth = $1;
param->yyDay = $3;
param->yyYear = $5;
@@ -332,39 +368,55 @@
}
| tUNUMBER tSNUMBER tSNUMBER {
/* ISO 8601 format. yyyy-mm-dd. */
+ if ($2 >= 0 || $2 < -12 || $3 >= 0 || $3 < -31)
+ YYREJECT;
param->yyYear = $1;
param->yyHaveFullYear = 1;
param->yyMonth = -$2;
param->yyDay = -$3;
}
| tUNUMBER tMONTH tSNUMBER {
+ if ($3 > 0 || $1 == 0 || $1 > 31)
+ YYREJECT;
/* e.g. 17-JUN-1992. */
param->yyDay = $1;
param->yyMonth = $2;
param->yyYear = -$3;
}
| tMONTH tUNUMBER {
+ if ($2 == 0 || $2 > 31)
+ YYREJECT;
param->yyMonth = $1;
param->yyDay = $2;
}
| tMONTH tUNUMBER ',' tUNUMBER {
+ if ($2 == 0 || $2 > 31)
+ YYREJECT;
param->yyMonth = $1;
param->yyDay = $2;
param->yyYear = $4;
}
| tUNUMBER tMONTH {
+ if ($1 == 0 || $1 > 31)
+ YYREJECT;
param->yyMonth = $2;
param->yyDay = $1;
}
| tUNUMBER tMONTH tUNUMBER {
- param->yyMonth = $2;
+ if ($1 > 31 && $3 > 31)
+ YYREJECT;
if ($1 < 35) {
+ if ($1 == 0)
+ YYREJECT;
param->yyDay = $1;
param->yyYear = $3;
} else {
+ if ($3 == 0)
+ YYREJECT;
param->yyDay = $3;
param->yyYear = $1;
}
+ param->yyMonth = $2;
}
;
@@ -377,15 +429,15 @@
;
relunit:
- tUNUMBER tMINUTE_UNIT { RelVal(param, $1 * $2 * 60L, 0); }
- | tSNUMBER tMINUTE_UNIT { RelVal(param, $1 * $2 * 60L, 0); }
- | tMINUTE_UNIT { RelVal(param, $1 * 60L, 0); }
- | tSNUMBER tSEC_UNIT { RelVal(param, $1, 0); }
- | tUNUMBER tSEC_UNIT { RelVal(param, $1, 0); }
- | tSEC_UNIT { RelVal(param, 1L, 0); }
- | tSNUMBER tMONTH_UNIT { RelVal(param, $1 * $2, 1); }
- | tUNUMBER tMONTH_UNIT { RelVal(param, $1 * $2, 1); }
- | tMONTH_UNIT { RelVal(param, $1, 1); }
+ tUNUMBER tMINUTE_UNIT { CheckRelVal(param, $1, $2, 60, 0); }
+ | tSNUMBER tMINUTE_UNIT { CheckRelVal(param, $1, $2, 60, 0); }
+ | tMINUTE_UNIT { CheckRelVal(param, 1, $1, 60, 0); }
+ | tSNUMBER tSEC_UNIT { CheckRelVal(param, $1, 1, 1, 0); }
+ | tUNUMBER tSEC_UNIT { CheckRelVal(param, $1, 1, 1, 0); }
+ | tSEC_UNIT { CheckRelVal(param, 1, 1, 1, 0); }
+ | tSNUMBER tMONTH_UNIT { CheckRelVal(param, $1, $2, 1, 1); }
+ | tUNUMBER tMONTH_UNIT { CheckRelVal(param, $1, $2, 1, 1); }
+ | tMONTH_UNIT { CheckRelVal(param, 1, $1, 1, 1); }
;
number:
@@ -661,15 +713,46 @@
/*
* Save a relative value, if it fits
*/
-static void
-RelVal(struct dateinfo *param, time_t v, int type)
+static int
+RelVal(struct dateinfo *param, time_t num, time_t unit, int scale, int type)
{
int i;
+ time_t v;
+ uintmax_t m;
+ int sign = 1;
if ((i = param->yyHaveRel) >= MAXREL)
- return;
+ return 0;
+
+ if (num < 0) {
+ sign = -sign;
+ num = -num;
+ }
+ if (unit < 0) {
+ sign = -sign;
+ unit = -unit;
+ }
+ /* scale is always positive */
+
+ m = LLONG_MAX; /* TIME_T_MAX */
+ if (scale > 1)
+ m /= scale;
+ if (unit > 1)
+ m /= unit;
+ if ((uintmax_t)num > m)
+ return 0;
+
+ m = num * unit * scale;
+ v = (time_t) m;
+ if (v < 0 || (uintmax_t)v != m)
+ return 0;
+ if (sign < 0)
+ v = -v;
+
param->yyRel[i].yyRelMonth = type;
param->yyRel[i].yyRelVal = v;
+
+ return 1;
}
/*
@@ -721,6 +804,10 @@
tm.tm_mday = Day;
tm.tm_mon = Month - 1;
tm.tm_year = Year - 1900;
+ if ((time_t)tm.tm_year + 1900 != Year) {
+ errno = EOVERFLOW;
+ return -1;
+ }
if (Timezone == USE_LOCAL_TIME) {
switch (DSTmode) {
case DSTon: tm.tm_isdst = 1; break;
@@ -797,12 +884,29 @@
{
struct tm tm;
time_t now;
+ time_t change;
now = Start;
if (localtime_r(&now, &tm) == NULL)
return -1;
- now += SECSPERDAY * ((DayNumber - tm.tm_wday + 7) % 7);
- now += 7 * SECSPERDAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1);
+
+ /* should be using TIME_T_MAX but there is no such thing, so just "know" */
+ if (llabs(DayOrdinal) >= LLONG_MAX / (7 * SECSPERDAY)) {
+ errno = EOVERFLOW;
+ return -1;
+ }
+
+ change = SECSPERDAY * ((DayNumber - tm.tm_wday + 7) % 7);
+ change += 7 * SECSPERDAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1);
+
+ /* same here for _MAX and _MIN */
+ if ((change > 0 && LLONG_MAX - change < now) ||
+ (change < 0 && LLONG_MIN - change > now)) {
+ errno = EOVERFLOW;
Home |
Main Index |
Thread Index |
Old Index