Buffer overrun in handle_notice_message()

Buffer overrun in handle_notice_message()

am 18.08.2006 16:13:29 von Bart Samwel

Hi all,

I'd like to report a buffer overrun in handle_notice_message().
Analysis: when I run a query >4096 characters that has a 'C' at a
specific location (at a specific, small offset before a multiple of
4096), then the stack is trashed and the driver crashes. The code fragment:

for (;;)
{
truncated = SOCK_get_string(sock, msgbuffer, sizeof(msgbuffer));
if (!msgbuffer[0])
break;

mylog("%s: 'N' - %s\n", comment, msgbuffer);
qlog("NOTICE from backend during %s: '%s'\n", comment, msgbuffer);
switch (msgbuffer[0])
{
case 'S':
strncat(msgbuf, msgbuffer + 1, buflen);
strncat(msgbuf, ": ", buflen);
buflen -= (strlen(msgbuffer) + 1);
break;
case 'M':
strncat(msgbuf, msgbuffer + 1, buflen);
msg_truncated = truncated;
break;
case 'C':
if (sqlstate && !sqlstate[0] && strcmp(msgbuffer + 1, "00000"))
strcpy(sqlstate, msgbuffer + 1);
break;
}
}



The problem is that PostgreSQL replies to the query with a "LOG"-type
message, quoting the _complete_ query. This loop retrieves the message
in chunks of 4096 bytes (i.e., sizeof(msgbuffer)) and normally just
outputs things to mylog and qlog, _except_ if the first character of a
chunk just happens to be 'S', 'M' or 'C'. In the 'S' or 'M' cases,
nothing bad happens, but in the 'C' case, the
strcpy(sqlstate,msgbuffer+1) copies 4 kbytes of data into the 8-byte
sqlstate buffer.

The way I understand it, the switch on msgbuffer[0] should only happen
on the first iteration, not on subsequent iterations. After I changed
the loop like that, my application ran without any problems.

Oh, in case you're wondering: protocol is 7.4+, PostgreSQL server
version is 8.1.4.

Cheers,
Bart

---------------------------(end of broadcast)---------------------------
TIP 9: In versions below 8.0, the planner will ignore your desire to
choose an index scan if your joining column's datatypes do not
match

Re: Buffer overrun in handle_notice_message()

am 18.08.2006 23:30:18 von Hiroshi Inoue

Bart Samwel wrote:
> Hi all,
>
> I'd like to report a buffer overrun in handle_notice_message().
> Analysis: when I run a query >4096 characters that has a 'C' at a
> specific location (at a specific, small offset before a multiple of
> 4096), then the stack is trashed and the driver crashes. The code
> fragment:
>
> for (;;)
> {
> truncated = SOCK_get_string(sock, msgbuffer, sizeof(msgbuffer));
> if (!msgbuffer[0])
> break;
>
> mylog("%s: 'N' - %s\n", comment, msgbuffer);
> qlog("NOTICE from backend during %s: '%s'\n", comment, msgbuffer);
> switch (msgbuffer[0])
> {
> case 'S':
> strncat(msgbuf, msgbuffer + 1, buflen);
> strncat(msgbuf, ": ", buflen);
> buflen -= (strlen(msgbuffer) + 1);
> break;
> case 'M':
> strncat(msgbuf, msgbuffer + 1, buflen);
> msg_truncated = truncated;
> break;
> case 'C':
> if (sqlstate && !sqlstate[0] && strcmp(msgbuffer + 1,
> "00000"))
> strcpy(sqlstate, msgbuffer + 1);
> break;
> }
> }

Hi Bart,
Hmm, ISTM I should place the following code at the end of the above loop
not after the above code..

while (truncated)
truncated = SOCK_get_string(sock, msgbuffer,
sizeof(msgbuffer));

Actually I do so In handle_error_message().
I would fix it ASAP.
Thanks.

regards,
Hiroshi Inoue



---------------------------(end of broadcast)---------------------------
TIP 3: Have you checked our extensive FAQ?

http://www.postgresql.org/docs/faq