Thread: [PATCH] Fix segfault calling PQflush on invalid connection

[PATCH] Fix segfault calling PQflush on invalid connection

From
Daniele Varrazzo
Date:
PQflush calls pqFlush, which performs struct access to the connection
without checking if it's valid, resulting in a segfault if called with
a null pointer.

Please find attached a patch adding a guard to PQflush().

Cheers

-- Daniele

Attachment

Re: [PATCH] Fix segfault calling PQflush on invalid connection

From
Tom Lane
Date:
Daniele Varrazzo <daniele.varrazzo@gmail.com> writes:
> PQflush calls pqFlush, which performs struct access to the connection
> without checking if it's valid, resulting in a segfault if called with
> a null pointer.

> Please find attached a patch adding a guard to PQflush().

Seems reasonable, but this tickled a thought that's been in my
hindbrain for awhile: just checking for a null pointer is not
much of a check for being passed a valid PGconn pointer.  Should
we add a magic number to struct PGconn, and modify all libpq's
entry points along the lines of

    if (!conn || conn->magic != PGCONN_MAGIC)
        return failure;

I'm honestly not entirely sure if this is worth the trouble;
I've not heard of many application bugs that this would've caught.
But the lack of any such check does seem like it's not up to
modern standards.

            regards, tom lane



Re: [PATCH] Fix segfault calling PQflush on invalid connection

From
Francisco Olarte
Date:
Tom:

On Mon, 15 Aug 2022 at 03:44, Tom Lane <tgl@sss.pgh.pa.us> wrote:
> > Please find attached a patch adding a guard to PQflush().
> Seems reasonable, but this tickled a thought that's been in my
> hindbrain for awhile: just checking for a null pointer is not
> much of a check for being passed a valid PGconn pointer.

Is there any place in the docs which states libpq just errors out ( as
opposed to dump core ) on null PGconn? I could not find it easily, and
I have always assumed the worst ( normally I use it wrapped, use
nullptr as invalid marked in my data and check that (and either do
nothing or intentionally SEGV for easier debugging ).

Even in PQstatus, which is the first one I would expect to tolerate a
null ptr, I have not been able to see it in the docs.

>  Should
> we add a magic number to struct PGconn, and modify all libpq's
> entry points along the lines of
>         if (!conn || conn->magic != PGCONN_MAGIC)
>                 return failure;
> I'm honestly not entirely sure if this is worth the trouble;
> I've not heard of many application bugs that this would've caught.

IMO stray pointers will lead to SEGV a little further down so it would
not catch many not already caught.


> But the lack of any such check does seem like it's not up to
> modern standards.

If conn->magic is assumed to be readable using and unsigned conn->idx
and an auxiliary table in the library holding the pointers it could be
made totally safe, check (conn && conn->idx<table_size &&
conn_table[conn->idx}==conn), find a free slot on conn creation ( I
assume this would need a lock plus a scan of the connection table, but
it seems tolerable for a connection build ), null the slot on freeing
pgconns. I'm probably forgetting something, and it is slower and more
cache-thrashing than just a magic check, but it seems fast enough for
DB access package.

But anyway, for this to be useful libpq should document the behaviour
of passing bad ptrs. IMO even the null ptr check is too much ( and can
lead to delayed bugs making tracing them more difficult, the nice
thing of not checking is a null dereference is easy to catch and
backtrace in a debugger. ) for anything not like PQfinish ( which I do
not see documented as tolerating nulls, but probably doing nothing,
like free(3), is useful there ). BTW, I do not see any reference of
PQconnect* being able to return null, but I suppose it is a
possibility on OOM.


Francisco Olarte.



Re: [PATCH] Fix segfault calling PQflush on invalid connection

From
Daniele Varrazzo
Date:
On Mon, 15 Aug 2022 at 13:21, Francisco Olarte <folarte@peoplecall.com> wrote:

> Is there any place in the docs which states libpq just errors out ( as
> opposed to dump core ) on null PGconn? I could not find it easily, and
> I have always assumed the worst ( normally I use it wrapped, use
> nullptr as invalid marked in my data and check that (and either do
> nothing or intentionally SEGV for easier debugging ).

After exercising most of the libpq API in psycopg 3, PQflush() seems
the only one requiring a guard [1]. All the other functions seem to
behave well when passed an "invalid connection" - aka either a NULL
pointer or a connection in BAD status.

[1]
https://github.com/psycopg/psycopg/blob/923bb834ce7601f2743d10bff7e007698429933a/psycopg/psycopg/pq/pq_ctypes.py#L541-L548

-- Daniele


-- Daniele



Re: [PATCH] Fix segfault calling PQflush on invalid connection

From
Tom Lane
Date:
Daniele Varrazzo <daniele.varrazzo@gmail.com> writes:
> After exercising most of the libpq API in psycopg 3, PQflush() seems
> the only one requiring a guard [1]. All the other functions seem to
> behave well when passed an "invalid connection" - aka either a NULL
> pointer or a connection in BAD status.

I went so far as to inspect every function listed in libpq/exports.txt.
All the ones that take a PGconn or PGresult check it for NULL except

PQflush
PQisnonblocking
PQdefaultSSLKeyPassHook_OpenSSL

PQisnonblocking is clearly an oversight, same as PQflush.
Maybe there is a case for not bothering to check in
PQdefaultSSLKeyPassHook_OpenSSL, on the grounds that you'd
not get that far without a connection, but I think for
consistency it should do so too.

There is not a lot of consistency about whether we insist on
the connection being in any particular "good" state.  For
some of the functions I think it's intentional that they should
still work on a failed connection, but I wonder if any of those
are likewise oversights.

            regards, tom lane



Re: [PATCH] Fix segfault calling PQflush on invalid connection

From
Francisco Olarte
Date:
Daniele:

On Mon, 15 Aug 2022 at 16:58, Daniele Varrazzo
<daniele.varrazzo@gmail.com> wrote:
> On Mon, 15 Aug 2022 at 13:21, Francisco Olarte <folarte@peoplecall.com> wrote:
> > Is there any place in the docs which states libpq just errors out ( as
> > opposed to dump core ) on null PGconn? I could not find it easily, and
> > I have always assumed the worst ( normally I use it wrapped, use
> > nullptr as invalid marked in my data and check that (and either do
> > nothing or intentionally SEGV for easier debugging ).
> After exercising most of the libpq API in psycopg 3, PQflush() seems
> the only one requiring a guard [1]. All the other functions seem to
> behave well when passed an "invalid connection" - aka either a NULL
> pointer or a connection in BAD status.

If this is the case may be it could be documented, somewhere near the
top with something like "passing a null pgconn will be treated
similarly to passing a connection with BAD status". It can be a nice /
simple feature and greatly simplify some use cases. Having been bitten
before I normally assume only what is documented is guaranteed /
reportable as a bug, and sometimes not even all of it.

Francisco Olarte.