CVE-2023-1801 (C, published 2023-04-07T21:15Z)
Description: value: The SMB protocol decoder in tcpdump version 4.99.3 can perform an out-of-bounds write when decoding a crafted network packet.
Severity: nan (CVSS v3 base score: 6.5)
Weakness: CWE-787 \u2014 Out-of-bounds Write
The product writes data past the end, or before the beginning, of the intended buffer.
Repository: https://github.com/the-tcpdump-group/tcpdump
Files changed:
netdissect.h
ntp.c
print-ahcp.c
print-arista.c
print-rx.c
print-zep.c
smbutil.c
tcpdump.c
util-print.c
Commit message: 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.


Vulnerable code:
	    struct tm *tm;
		ND_PRINT(" (unrepresentable)");
		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);
		}
	struct tm *tm;
	char buf[BUFSIZE];
	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);
#include "addrtoname.h"
	struct tm *tm;
	char buf[BUFSIZE];
	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);
#define DATEOUT() { time_t _t; struct tm *tm; char str[256]; \
			tm = localtime(&_t); \
			strftime(str, 256, "%Y/%m/%d %H:%M:%S", tm); \
			ND_PRINT(" %s", str); \
		struct tm *tm;
		tm = localtime(&seconds);
		strftime(time_buf, sizeof (time_buf), "%Y/%m/%d %H:%M:%S", tm);
		ND_PRINT(" (%s)", time_buf);
	    struct tm *lt;
	    char buffer[sizeof("Www Mmm dd hh:mm:ss yyyyy\n")];
		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 = "NULL\n";
	    ND_PRINT("%s", tstring);
           * value of 0 isn't necessarily failure.
          strftime(filename, PATH_MAX, orig_name, local_tm);
	char timestr[32];
	if (!tm) {
		ND_PRINT("[Error converting time]");
		return;
	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);

Fixed code:
extern const char *nd_format_time(char *buf, size_t bufsize,
    const char *format, const struct tm *timeptr);

	    const char *time_string;
		time_string = "[Time is too large to fit into a time_t]";
		/* 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);
	char buf[sizeof("-yyyyyyyyyy-mm-dd hh:mm:ss UTC")];
	ND_PRINT(": %s",
	    nd_format_time(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S UTC",
	      gmtime(&t)));
	char buf[sizeof("-yyyyyyyyyy-mm-dd hh:mm:ss")];
	ND_PRINT("%s.%09u",
	    nd_format_time(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S",
	       gmtime(&ts)), nanoseconds);
#define DATEOUT() { time_t _t; char str[256]; \
			ND_PRINT(" %s", \
			    nd_format_time(str, sizeof(str), \
			      "%Y/%m/%d %H:%M:%S", localtime(&_t))); \
		ND_PRINT(" (%s)",
		    nd_format_time(time_buf, sizeof (time_buf), "%Y/%m/%d %H:%M:%S",
		      localtime(&seconds)));
	    char buffer[sizeof("Www Mmm dd hh:mm:ss yyyyy")];
		    tstring = nd_format_time(buffer, sizeof(buffer), "%a %b %e %T %Y",
		    localtime(&t));
		tstring = "NULL";
	    ND_PRINT("%s\n", tstring);
        if (strlen(orig_name) == 0)
            error("an empty string is not a valid file name");
           * 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.)
          if (strftime(filename, PATH_MAX, orig_name, local_tm) == 0) {
            error("%s: strftime", __func__);
          }
	char timebuf[32];
	const char *timestr;
	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);
/*
 * 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]");
}