From 995601c621b5f6d1e57bccf267308b37b0d7ad49 Mon Sep 17 00:00:00 2001
From: "Todd C. Miller" <Todd.Miller@sudo.ws>
Date: Sat, 30 Jan 2021 05:39:23 -0700
Subject: [PATCH] Stricter parsing of generalized time. Fixes potential out of
 bounds read found by libfuzzer/oss-fuzz.

---
 plugins/sudoers/gentime.c | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/plugins/sudoers/gentime.c b/plugins/sudoers/gentime.c
index 7f7cf7e..efee05e 100644
--- a/plugins/sudoers/gentime.c
+++ b/plugins/sudoers/gentime.c
@@ -1,7 +1,7 @@
 /*
  * SPDX-License-Identifier: ISC
  *
- * Copyright (c) 2017 Todd C. Miller <Todd.Miller@sudo.ws>
+ * Copyright (c) 2017, 2021 Todd C. Miller <Todd.Miller@sudo.ws>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -47,7 +47,7 @@
 time_t
 parse_gentime(const char *timestr)
 {
-    char tcopy[sizeof("yyyymmddHHMMSS.F")];
+    char tcopy[sizeof("yyyymmddHHMMSS")];
     const char *cp;
     time_t result;
     struct tm tm;
@@ -56,9 +56,9 @@ parse_gentime(const char *timestr)
     bool islocal = false;
     debug_decl(parse_gentime, SUDOERS_DEBUG_PARSER);
 
-    /* Make a copy of the time without time zone for easy parsing. */
-    len = strspn(timestr, "0123456789.,");
-    if (len >= sizeof(tcopy)) {
+    /* Make a copy of the non-fractional time without zone for easy parsing. */
+    len = strspn(timestr, "0123456789");
+    if (len >= sizeof(tcopy) || len < sizeof("yyyymmddHH") -1 || (len & 1)) {
 	sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
 	    "unable to parse general time string %s", timestr);
 	debug_return_time_t(-1);
@@ -75,9 +75,9 @@ parse_gentime(const char *timestr)
 	    "only parsed %d items in general time string %s", items, timestr); 
 	debug_return_time_t(-1);
     }
-    cp = timestr + ((items + 1) * 2);
 
     /* Parse optional fractional hours/minute/second if present. */
+    cp = timestr + len;
     if ((cp[0] == '.' || cp[0] == ',') && isdigit((unsigned char)cp[1])) {
 	int frac = cp[1] - '0';
 	switch (items) {
@@ -96,6 +96,7 @@ parse_gentime(const char *timestr)
 	cp += 2;	/* skip over radix and fraction */
     }
 
+    /* Parse optional time zone. */
     switch (*cp) {
     case '-':
     case '+': {
-- 
1.8.3.1

