CVE-2024-24479 (C, published 2024-02-21T19:15Z)
Description: value: A Buffer Overflow in Wireshark before 4.2.0 allows a remote attacker to cause a denial of service via the wsutil/to_str.c, and format_fractional_part_nsecs components. NOTE: this is disputed by the vendor because neither release 4.2.0 nor any other release was affected.
Severity: nan (CVSS v3 base score: )
Weakness: NVD-CWE-noinfo \u2014 Insufficient Information
There is insufficient information about the issue to classify it; details are unkown or unspecified.
Repository: https://github.com/wireshark/wireshark
Files changed:
wsutil/to_str.c
wsutil/to_str.h
Commit message: Various enhancements and fixes to format_fractional_part_nsecs().

Have format_fractional_part_nsecs() return the number of bytes
formatted.  This matches what snprintf() and strlcpy() do, for the
benefit of routines constructing a string in a fixed-length buffer with
multiple calls, one of which is format_fractional_part_nsecs().

Have format_fractional_part_nsecs() check for a count of nanoseconds
greatre than or equal to 1 billion, and report that specially.

Fix places wher it used the bufer pointer and size of the buffer, rather
than the current position in the buffer and the remaining space in the
buffer, to append to the buffer and make sure doing so doesn't overrun
the buffer.

Rename some variable names (rename buf_remaining to just remaining,
rename num_chars to num_bytes as it counts bytes).

Fix some comments.


Vulnerable code:
 * Format the fractonal part of a time, with the specified precision)
void
		return;
		 * and was truncated.  Nothing more to do.
		return;
	buf += decimal_point_len;
	buflen -= decimal_point_len;
		num_ptr = uint_to_str_back_len(num_end,
		    nsecs / 100000000, precision);
		num_ptr = uint_to_str_back_len(num_end,
		    nsecs / 10000000, precision);
		num_ptr = uint_to_str_back_len(num_end,
		    nsecs / 1000000, precision);
		num_ptr = uint_to_str_back_len(num_end,
		    nsecs / 100000, precision);
		num_ptr = uint_to_str_back_len(num_end,
		    nsecs / 10000, precision);
		num_ptr = uint_to_str_back_len(num_end,
		    nsecs / 1000, precision);
		num_ptr = uint_to_str_back_len(num_end,
		    nsecs / 100, precision);
		num_ptr = uint_to_str_back_len(num_end,
		    nsecs / 10, precision);
		num_ptr = uint_to_str_back_len(num_end, nsecs,
		    precision);
	 *    the size of the buffer, minus 1 for the terminating
	 *      '\0'.
	num_len = MIN((size_t)(num_end - num_ptr), buflen - 1);
		return;
	memcpy(buf, num_ptr, num_len);
	*(buf + num_len) = '\0';
	size_t buf_remaining;
	int num_chars;
	buf_remaining = buflen;
	num_chars = snprintf(ptr, buf_remaining,
	if (num_chars < 0) {
	if ((unsigned int)num_chars >= buf_remaining) {
		 * Either that got an error (num_chars < 0) or it
		 * filled up or would have overflowed the buffer
		 * (num_chars >= buf_remaining).
	ptr += num_chars;
	buf_remaining -= num_chars;
	if (precision == 0) {
		 * Seconds precision, so no nanosecond.
		return;

	/*
	 * Append the fractional part.
	 */
	format_fractional_part_nsecs(ptr, buf_remaining, (guint32)ns->nsecs, decimal_point, precision);
WS_DLL_PUBLIC void format_fractional_part_nsecs(gchar *, size_t, guint32, const char *, int);

Fixed code:
 * Format the fractional part of a time, with the specified precision.
 * Returns the number of bytes formatted.
int
	gchar *ptr;
	size_t remaining;
	int num_bytes;
	guint32 frac_part;
		return 0;
	}

	/*
	 * If the fractional part is >= 1, don't show it as a
	 * fractional part.
	 */
	if (nsecs >= 1000000000U) {
		num_bytes = snprintf(buf, buflen, "%s(%u nanoseconds)",
		    decimal_point, nsecs);
		if ((unsigned int)num_bytes >= buflen) {
			/*
			 * That filled up or would have overflowed
			 * the buffer.  Nothing more to do; return
			 * the remaining space in the buffer, minus
			 * one byte for the terminating '\0',* as
			 * that's the number of bytes we copied.
			 */
			return (int)(buflen - 1);
		}
		return num_bytes;
	ptr = buf;
	remaining = buflen;
	num_bytes = 0;

		 * and was truncated.  Nothing more to do;
		 * return the remaining space in the buffer,
		 * minus one byte for the terminating '\0',
		 * as that's the number of bytes we copied.
		return (int)(buflen - 1);
	ptr += decimal_point_len;
	remaining -= decimal_point_len;
	num_bytes += decimal_point_len;
		frac_part = nsecs / 100000000U;
		frac_part = nsecs / 10000000U;
		frac_part = nsecs / 1000000U;
		frac_part = nsecs / 100000U;
		frac_part = nsecs / 10000U;
		frac_part = nsecs / 1000U;
		frac_part = nsecs / 100U;
		frac_part = nsecs / 10U;
		frac_part = nsecs;
	num_ptr = uint_to_str_back_len(num_end, frac_part, precision);

	 *    the remaining space in the buffer, minus 1 for the
	 *      terminating '\0'.
	num_len = MIN((size_t)(num_end - num_ptr), remaining - 1);
		 * Return the number of bytes we've generated.
		return num_bytes;
	memcpy(ptr, num_ptr, num_len);
	ptr += num_len;
	num_bytes += num_len;
	*ptr = '\0';
	return num_bytes;
	size_t remaining;
	int num_bytes;
	remaining = buflen;
	num_bytes = snprintf(ptr, remaining,
	if (num_bytes < 0) {
		 * That got an error.
	if ((unsigned int)num_bytes >= remaining) {
		 * That filled up or would have overflowed the buffer.
	ptr += num_bytes;
	remaining -= num_bytes;
	if (precision != 0) {
		 * Append the fractional part.
		 * Get the nsecs as a 32-bit unsigned value, as it should
		 * never be negative, so we treat it as unsigned.
		format_fractional_part_nsecs(ptr, remaining, (guint32)ns->nsecs, decimal_point, precision);
WS_DLL_PUBLIC int format_fractional_part_nsecs(gchar *, size_t, guint32, const char *, int);