new file mode 100644
@@ -0,0 +1,342 @@
+From 13336c4054015bef84d93bf51b50b15df6e265bf Mon Sep 17 00:00:00 2001
+From: Guy Harris <gharris@sonic.net>
+Date: Mon, 30 Jan 2023 23:03:16 -0800
+Subject: [PATCH] tcpdump: Have a common routine for converting dates and times
+ to strings.
+
+Have a routine that takes a buffer, a strftime format, and a struct tm *
+as arguments, and:
+
+* checks whether the struct tm * is null and, if so, returns a string
+indicating that the date and time couldn't be converted;
+
+* otherwise, passes it to strftime(), along with the buffer and the
+format argument and, if strftime() returns 0, meaning the string didn't
+fit into the buffer and thus that the buffer's contents are undefined,
+returns a string indicating that the date and time didn't fit into the
+buffer;
+
+* otherwise, returns a pointer to the buffer.
+
+Call that routine instead of directly calling strftime() in printers;
+that prevents printing a buffer with undefined data if the buffer isn't
+big enough for the string.
+
+Also, when generating file names using an strftime format, check the
+return value of strftime() to make sure the buffer didn't overflow.
+
+Upstream-Status: Backport[https://github.com/the-tcpdump-group/tcpdump/commit/03c037bbd75588beba3ee09f26d17783d21e30bc]
+CVE: CVE-2023-1801
+
+Signed-off-by: Meenali Gupta <mgupta1@blr-linux-engg1.wrs.com>
+---
+ netdissect.h | 3 +++
+ ntp.c | 21 ++++++---------------
+ print-ahcp.c | 12 ++++--------
+ print-arista.c | 13 ++++---------
+ print-rx.c | 8 ++++----
+ print-zep.c | 7 +++----
+ smbutil.c | 16 +++++-----------
+ tcpdump.c | 22 ++++++++++++++++++++--
+ util-print.c | 36 ++++++++++++++++++++++++++++--------
+ 9 files changed, 77 insertions(+), 61 deletions(-)
+
+diff --git a/netdissect.h b/netdissect.h
+index 5c16be6..b1074ef 100644
+--- a/netdissect.h
++++ b/netdissect.h
+@@ -423,6 +423,9 @@ extern void ts_print(netdissect_options *, const struct timeval *);
+ extern void signed_relts_print(netdissect_options *, int32_t);
+ extern void unsigned_relts_print(netdissect_options *, uint32_t);
+
++extern const char *nd_format_time(char *buf, size_t bufsize,
++ const char *format, const struct tm *timeptr);
++
+ extern void fn_print_char(netdissect_options *, u_char);
+ extern void fn_print_str(netdissect_options *, const u_char *);
+ extern u_int nd_printztn(netdissect_options *, const u_char *, u_int, const u_char *);
+diff --git a/ntp.c b/ntp.c
+index 4d17932..0a79f81 100644
+--- a/ntp.c
++++ b/ntp.c
+@@ -55,8 +55,8 @@ p_ntp_time(netdissect_options *ndo,
+ if (i) {
+ int64_t seconds_64bit = (int64_t)i - JAN_1970;
+ time_t seconds;
+- struct tm *tm;
+ char time_buf[128];
++ const char *time_string;
+
+ seconds = (time_t)seconds_64bit;
+ if (seconds != seconds_64bit) {
+@@ -64,22 +64,13 @@ p_ntp_time(netdissect_options *ndo,
+ * It doesn't fit into a time_t, so we can't hand it
+ * to gmtime.
+ */
+- ND_PRINT(" (unrepresentable)");
++ time_string = "[Time is too large to fit into a time_t]";
+ } else {
+- tm = gmtime(&seconds);
+- if (tm == NULL) {
+- /*
+- * gmtime() can't handle it.
+- * (Yes, that might happen with some version of
+- * Microsoft's C library.)
+- */
+- ND_PRINT(" (unrepresentable)");
+- } else {
+- /* use ISO 8601 (RFC3339) format */
+- strftime(time_buf, sizeof (time_buf), "%Y-%m-%dT%H:%M:%SZ", tm);
+- ND_PRINT(" (%s)", time_buf);
+- }
++ /* use ISO 8601 (RFC3339) format */
++ time_string = nd_format_time(time_buf, sizeof (time_buf),
++ "%Y-%m-%dT%H:%M:%SZ", gmtime(&seconds));
+ }
++ ND_PRINT(" (%s)", time_string);
+ }
+ #endif
+ }
+diff --git a/print-ahcp.c b/print-ahcp.c
+index 9859f76..d57edda 100644
+--- a/print-ahcp.c
++++ b/print-ahcp.c
+@@ -102,18 +102,14 @@ ahcp_time_print(netdissect_options *ndo,
+ const u_char *cp, uint8_t len)
+ {
+ time_t t;
+- struct tm *tm;
+- char buf[BUFSIZE];
++ char buf[sizeof("-yyyyyyyyyy-mm-dd hh:mm:ss UTC")];
+
+ if (len != 4)
+ goto invalid;
+ t = GET_BE_U_4(cp);
+- if (NULL == (tm = gmtime(&t)))
+- ND_PRINT(": gmtime() error");
+- else if (0 == strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", tm))
+- ND_PRINT(": strftime() error");
+- else
+- ND_PRINT(": %s UTC", buf);
++ ND_PRINT(": %s",
++ nd_format_time(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S UTC",
++ gmtime(&t)));
+ return;
+
+ invalid:
+diff --git a/print-arista.c b/print-arista.c
+index 039a1ff..079ad68 100644
+--- a/print-arista.c
++++ b/print-arista.c
+@@ -10,7 +10,6 @@
+
+ #include "netdissect.h"
+ #include "extract.h"
+-#include "addrtoname.h"
+
+ /*
+
+@@ -93,17 +92,13 @@ arista_print_date_hms_time(netdissect_options *ndo, uint32_t seconds,
+ uint32_t nanoseconds)
+ {
+ time_t ts;
+- struct tm *tm;
+- char buf[BUFSIZE];
++ char buf[sizeof("-yyyyyyyyyy-mm-dd hh:mm:ss")];
+
+ ts = seconds + (nanoseconds / 1000000000);
+ nanoseconds %= 1000000000;
+- if (NULL == (tm = gmtime(&ts)))
+- ND_PRINT("gmtime() error");
+- else if (0 == strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", tm))
+- ND_PRINT("strftime() error");
+- else
+- ND_PRINT("%s.%09u", buf, nanoseconds);
++ ND_PRINT("%s.%09u",
++ nd_format_time(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S",
++ gmtime(&ts)), nanoseconds);
+ }
+
+ int
+diff --git a/print-rx.c b/print-rx.c
+index 3f7589e..dbef71c 100644
+--- a/print-rx.c
++++ b/print-rx.c
+@@ -794,12 +794,12 @@ rx_cache_find(netdissect_options *ndo, const struct rx_header *rxh,
+ ND_PRINT(" %" PRIu64, _i); \
+ }
+
+-#define DATEOUT() { time_t _t; struct tm *tm; char str[256]; \
++#define DATEOUT() { time_t _t; char str[256]; \
+ _t = (time_t) GET_BE_S_4(bp); \
+ bp += sizeof(int32_t); \
+- tm = localtime(&_t); \
+- strftime(str, 256, "%Y/%m/%d %H:%M:%S", tm); \
+- ND_PRINT(" %s", str); \
++ ND_PRINT(" %s", \
++ nd_format_time(str, sizeof(str), \
++ "%Y/%m/%d %H:%M:%S", localtime(&_t))); \
+ }
+
+ #define STOREATTROUT() { uint32_t mask, _i; \
+diff --git a/print-zep.c b/print-zep.c
+index fd74368..642b240 100644
+--- a/print-zep.c
++++ b/print-zep.c
+@@ -83,12 +83,11 @@ static void zep_print_ts(netdissect_options *ndo, const u_char *p)
+ */
+ if (i) {
+ time_t seconds = i - JAN_1970;
+- struct tm *tm;
+ char time_buf[128];
+
+- tm = localtime(&seconds);
+- strftime(time_buf, sizeof (time_buf), "%Y/%m/%d %H:%M:%S", tm);
+- ND_PRINT(" (%s)", time_buf);
++ ND_PRINT(" (%s)",
++ nd_format_time(time_buf, sizeof (time_buf), "%Y/%m/%d %H:%M:%S",
++ localtime(&seconds)));
+ }
+ #endif
+ }
+diff --git a/smbutil.c b/smbutil.c
+index 7f609f7..f33a323 100644
+--- a/smbutil.c
++++ b/smbutil.c
+@@ -768,9 +768,8 @@ smb_fdata1(netdissect_options *ndo,
+ case 'T':
+ {
+ time_t t;
+- struct tm *lt;
+ const char *tstring;
+- char buffer[sizeof("Www Mmm dd hh:mm:ss yyyy\n")];
++ char buffer[sizeof("Www Mmm dd hh:mm:ss yyyyy")];
+ uint32_t x;
+
+ switch (atoi(fmt + 1)) {
+@@ -800,16 +799,11 @@ smb_fdata1(netdissect_options *ndo,
+ break;
+ }
+ if (t != 0) {
+- lt = localtime(&t);
+- if (lt != NULL) {
+- strftime(buffer, sizeof(buffer), "%a %b %e %T %Y%n", lt);
+- tstring = buffer;
+- }
+- else
+- tstring = "(Can't convert time)\n";
++ tstring = nd_format_time(buffer, sizeof(buffer), "%a %b %e %T %Y",
++ localtime(&t));
+ } else
+- tstring = "NULL\n";
+- ND_PRINT("%s", tstring);
++ tstring = "NULL";
++ ND_PRINT("%s\n", tstring);
+ fmt++;
+ while (ND_ASCII_ISDIGIT(*fmt))
+ fmt++;
+diff --git a/tcpdump.c b/tcpdump.c
+index 78d0871..b0f75b9 100644
+--- a/tcpdump.c
++++ b/tcpdump.c
+@@ -843,6 +843,8 @@ MakeFilename(char *buffer, char *orig_name, int cnt, int max_chars)
+ char *filename = malloc(PATH_MAX + 1);
+ if (filename == NULL)
+ error("%s: malloc", __func__);
++ if (strlen(orig_name) == 0)
++ error("an empty string is not a valid file name");
+
+ /* Process with strftime if Gflag is set. */
+ if (Gflag != 0) {
+@@ -854,9 +856,25 @@ MakeFilename(char *buffer, char *orig_name, int cnt, int max_chars)
+ }
+
+ /* There's no good way to detect an error in strftime since a return
+- * value of 0 isn't necessarily failure.
++ * * value of 0 isn't necessarily failure; if orig_name is an empty
++ * string, the formatted string will be empty.
++ *
++ * However, the C90 standard says that, if there *is* a
++ * buffer overflow, the content of the buffer is undefined,
++ * so we must check for a buffer overflow.
++ *
++ * So we check above for an empty orig_name, and only call
++ * strftime() if it's non-empty, in which case the return
++ * value will only be 0 if the formatted date doesn't fit
++ * in the buffer.
++ *
++ * (We check above because, even if we don't use -G, we
++ * want a better error message than "tcpdump: : No such
++ * file or directory" for this case.)
+ */
+- strftime(filename, PATH_MAX, orig_name, local_tm);
++ if (strftime(filename, PATH_MAX, orig_name, local_tm) == 0) {
++ error("%s: strftime", __func__);
++ }
+ } else {
+ strncpy(filename, orig_name, PATH_MAX);
+ }
+diff --git a/util-print.c b/util-print.c
+index 8b20649..fea6b19 100644
+--- a/util-print.c
++++ b/util-print.c
+@@ -230,7 +230,8 @@ ts_date_hmsfrac_print(netdissect_options *ndo, long sec, long usec,
+ {
+ time_t Time = sec;
+ struct tm *tm;
+- char timestr[32];
++ char timebuf[32];
++ const char *timestr;
+
+ if ((unsigned)sec & 0x80000000) {
+ ND_PRINT("[Error converting time]");
+@@ -242,14 +243,14 @@ ts_date_hmsfrac_print(netdissect_options *ndo, long sec, long usec,
+ else
+ tm = gmtime(&Time);
+
+- if (!tm) {
+- ND_PRINT("[Error converting time]");
+- return;
++
++ if (date_flag == WITH_DATE) {
++ timestr = nd_format_time(timebuf, sizeof(timebuf),
++ "%Y-%m-%d %H:%M:%S", tm);
++ } else {
++ timestr = nd_format_time(timebuf, sizeof(timebuf),
++ "%H:%M:%S", tm);
+ }
+- if (date_flag == WITH_DATE)
+- strftime(timestr, sizeof(timestr), "%Y-%m-%d %H:%M:%S", tm);
+- else
+- strftime(timestr, sizeof(timestr), "%H:%M:%S", tm);
+ ND_PRINT("%s", timestr);
+
+ ts_frac_print(ndo, usec);
+@@ -404,6 +405,25 @@ signed_relts_print(netdissect_options *ndo,
+ }
+ unsigned_relts_print(ndo, secs);
+ }
++/*
++ * Format a struct tm with strftime().
++ * If the pointer to the struct tm is null, that means that the
++ * routine to convert a time_t to a struct tm failed; the localtime()
++ * and gmtime() in the Microsoft Visual Studio C library will fail,
++ * returning null, if the value is before the UNIX Epoch.
++ */
++const char *
++nd_format_time(char *buf, size_t bufsize, const char *format,
++ const struct tm *timeptr)
++{
++ if (timeptr != NULL) {
++ if (strftime(buf, bufsize, format, timeptr) != 0)
++ return (buf);
++ else
++ return ("[nd_format_time() buffer is too small]");
++ } else
++ return ("[localtime() or gmtime() couldn't convert the date and time]");
++}
+
+ /* Print the truncated string */
+ void nd_print_trunc(netdissect_options *ndo)
+--
+2.40.0
@@ -24,6 +24,7 @@ SRC_URI = " \
http://www.tcpdump.org/release/${BP}.tar.gz \
file://add-ptest.patch \
file://run-ptest \
+ file://CVE-2023-1801.patch \
"
SRC_URI[sha256sum] = "ad75a6ed3dc0d9732945b2e5483cb41dc8b4b528a169315e499c6861952e73b3"