Subject: bug#75900: doprnt.c buffer overflow

From: Pip Cet <[email-masked]>
Date: Mon, 27 Jan 2025 19:13:09 +0000

doprnt sometimes overflows its buffer, causing stack smashing and (if
we're lucky) a glibc abort when make_formatted_string calls it:

(gdb) p make_formatted_string
("01234567890123456789012345678901234567890123456789012345678901234567890123456789)0123456789)01234567890123456789012345678901234567890123456789")
[Thread 0x7fffda9ff6c0 (LWP 20144) exited]
*** stack smashing detected ***: terminated

The reason is that in doprnt, the variable bufsize indicates the number
of remaining bytes in the buf, and bufptr points to the current byte in
the buf, but sometimes a byte is written and bufsize is not updated:

      else if (! LEADING_CODE_P (fmtchar))
	{
	  if (EQ (quoting_style, Qstraight) && fmtchar == '`')
	    fmtchar = '\'';

	  *bufptr++ = fmtchar;
	  continue;
	}

and

	{
	  do
	    *bufptr++ = *src++;
	  while (--srclen != 0);
	}

do this.  In the former case, we must update bufsize as it will be used
again.  In the latter case, it's sufficient to set it to 0 as this is
the last successful printing operation in this call.

A related issue is that if a multibyte character produced by a %s format
option would overflow the buffer, doprnt returns the buffer size minus
one, as expected, but hasn't actually modified all of the buffer data:
the final bytes will refer to uninitialized stack data.

For example, on my system, where FRAME_MESSAGE_BUF_SIZE (f) is 832, this
call:

(gdb) p message ("%s%s", "xxxx", SDATA(Fmake_string (0x8aa, 0x10002, Qt)))

will print the string

"xxxx䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀䀀^@Z"

where the last characters are an ASCII NUL followed by a 'Z' (which I
put in the buffer after it was SAFE_ALLOCA'd).  The 'Z' should have been
overwritten, in which case message would still have printed two
unintended NUL characters.

I intend to fix the first two bugs, and fix message in a somewhat ugly
way for the other two.

Patches to follow once there is a bug number.

Pip