Protocol de-synchronisation bug, bogus query sent - Mailing list pgsql-odbc

From Craig Ringer
Subject Protocol de-synchronisation bug, bogus query sent
Date
Msg-id 53A25C95.707@2ndquadrant.com
Whole thread Raw
Responses Re: Protocol de-synchronisation bug, bogus query sent  ("Inoue, Hiroshi" <inoue@tpf.co.jp>)
Re: Protocol de-synchronisation bug, bogus query sent  (Heikki Linnakangas <hlinnakangas@vmware.com>)
List pgsql-odbc
Hi folks

I've found a bug in psqlODBC, in CC_send_query_append, where psqlODBC
gets out of sync with the server's idea of the connection state and both
wait for each other indefinitely.

So far I've only reproduced it as part of debugging a larger issue. I've
only actually seen it when psqlODBC establishes an "isolated" XA
connection after failing to acquire a lock on the DTC connection in
IAsyncPG::getLockedXAConn(). If the client has specified a connect-time
query string with a DSN like:

    DRIVER={PostgreSQL ANSI};SERVER=LOCALHOST;DATABASE=postgres;A6=set
search_path to someschema;UID=;PWD=;BI=-5;debug=1;commlog=1;

... but it's clearly a bug in its own right, so I'll write it up here
and propose a fix.


Patch attached, or you can pull the branch:

    fix-febe-protocol-desync-emptyquery

from https://github.com/ringerc/psqlODBC.git



The whole code block around connection.c:3082 appears to be attempting
to send an empty query in order to elicit an 'I' (EmptyQueryResponse)
message. It sends a malformed protocol message:

    SOCK_put_string(self->sock, "Q ");
    SOCK_flush_output(self->sock);

so the server just waits for the rest of the message, never responding.

When the connection is killed by program exit later, the server will log:

LOG:  unexpected EOF within message length word
LOG:  disconnection: session time: 0:00:08.910 user=Administrator
database=XXXX host=127.0.0.1 port=53705
LOG:  could not receive data from client: No connection could be made
because the target machine actively refused it.


That's because the V3 protocol specifies that the message format for
Query is:

'Q'
[32 bit integer]
[query string]

http://www.postgresql.org/docs/current/static/protocol-message-formats.html

... but psqlODBC just sends:

'Q'
'\x20'
'\x00'

If it is really necessary to go through this empty-query dance, then for
the V3 protocol the correct message would be:

/* Send an empty query to elicit an 'I' (EmptyQueryResponse)
 * from the server */
SOCK_put_char(self->sock, 'Q');
SOCK_put_int(self->sock, 5, 4);
SOCK_put_char(self->sock, '\0');



Since no 'I' message is ever received the next message is 'Z'
(ReadyForQuery). psqlODBC consumes this and carries on waiting for the
next message, as it has set emptyreqs=1 to expect 'I' messages. So it
waits forever, since the server thinks it's waiting for psqlODBC to
finish sending the prior protocol message.

It isn't clear to me why psqlODBC does this weird dance with empty
queries at all, but it's certainly doing it wrong.

The attached patch fixes the immediate problem, but I'd like to see if
this can be simplified out entirely in favour of, in ascending
size-of-work order, (a) using a protocol sync message, then (b) deleting
as much as possible of this custom protocol handling code entirely and
using libpq.


--
 Craig Ringer                   http://www.2ndQuadrant.com/
 PostgreSQL Development, 24x7 Support, Training & Services

Attachment

pgsql-odbc by date:

Previous
From: "Inoue, Hiroshi"
Date:
Subject: Re: Building psqlODBC installers
Next
From: Craig Ringer
Date:
Subject: Re: Removing support for v1 and v2 protocols?