Thread: Continue: Bug #924: Segmentation fault in libpq/PQconsumeInput on SSL connection
Continue: Bug #924: Segmentation fault in libpq/PQconsumeInput on SSL connection
From
"Sergey N. Yatskevich"
Date:
I try to explain this bug. Attached files contains example and patch for libpq. I hope, that you look at it and replay me what you think. --- Segey N. Yatskevich <syatskevich@n21lab.gosniias.msk.ru> # # $Id$ # ssl-async-query: ssl-async-query.cc c++ -g -I`pg_config --includedir` /usr/lib/libpq.so.3 -o ssl-async-query ssl-async-query.cc clean: rm -f ssl-async-query --- fe-secure.c.orig 2003-01-09 02:18:35 +0300 +++ fe-secure.c 2003-04-02 02:06:27 +0400 @@ -268,7 +268,10 @@ case SSL_ERROR_NONE: break; case SSL_ERROR_WANT_READ: - n = pqsecure_read(conn, ptr, len); + // I think this mean, that SSL layer have + // no any data for us and we must try + // to read it later. + n = 0; break; case SSL_ERROR_SYSCALL: printfPQExpBuffer(&conn->errorMessage, @@ -314,7 +317,10 @@ case SSL_ERROR_NONE: break; case SSL_ERROR_WANT_WRITE: - n = pqsecure_write(conn, ptr, len); + // I think this mean, that SSL layer have + // no free space for buffering our data and + // we must try to write it later. + n = 0; break; case SSL_ERROR_SYSCALL: printfPQExpBuffer(&conn->errorMessage, /* * SSL-test */ #include <iostream> #include <libpq-fe.h> static void exit_nicely (PGconn *conn) { std::cerr << "ERROR: " << PQerrorMessage (conn) << '\n'; PQfinish (conn); exit (1); } int main (int _argc, char *_argv[]) { PGconn *conn = PQconnectdb ("user=postgres dbname=template1 host=127.0.0.1 requiressl=1"); if (PQstatus (conn) == CONNECTION_BAD) exit_nicely (conn); PQsendQuery (conn, "select * from pg_class; select * from pg_type; select * from pg_proc"); for (;;) { std::cout << "before DANGEROUS section of code\n"; #ifndef NO_STACK_OVERFLOW_DEMO // This is a DANGEROUS code. If we call PQconsumeInput here, // after getting last PGresult, we will go into infinite // recursive call of pqsecure_read on SSL_ERROR_WANT_READ. PQconsumeInput (conn); if (PQisBusy (conn)) continue; // Call PQcounsumeInput on SSL connection when server // don't send any data to us is DANGEROUS. #else // This code is safe, becouse end of data determine before // call of PQconsumeInput and we don't go into pqsecure_read // when server have no data. if (PQisBusy (conn)) { PQconsumeInput (conn); continue; } #endif // But I think PQconsumeInput must be safe to be called in // any time, becouse, for example, we can use it not only // for async query processing, but for getting asynhronous // notification from server in case when we don't send any // query to it and can't be sure, that server have data for // us. std::cout << "after DANGEROUS section of code\n"; // When we don't use SSL this code in both case is completly // safe, becouse recv simple return 0 if no data avaliable. // I think this is good for SSL connection too. PGresult *res = PQgetResult (conn); if (res) { if (PQresultStatus (res) == PGRES_TUPLES_OK) std::cout << "SELECT\n"; else std::cerr << "UNKNOWN\n"; PQclear (res); continue; } break; } PQfinish(conn); return 0; }
This is fixed in the upcoming 7.3.3 release. --------------------------------------------------------------------------- Sergey N. Yatskevich wrote: > I try to explain this bug. Attached files contains example and patch > for libpq. > > I hope, that you look at it and replay me what you think. > > --- > Segey N. Yatskevich <syatskevich@n21lab.gosniias.msk.ru> > # > # $Id$ > # > > ssl-async-query: ssl-async-query.cc > c++ -g -I`pg_config --includedir` /usr/lib/libpq.so.3 -o ssl-async-query ssl-async-query.cc > > clean: > rm -f ssl-async-query > --- fe-secure.c.orig 2003-01-09 02:18:35 +0300 > +++ fe-secure.c 2003-04-02 02:06:27 +0400 > @@ -268,7 +268,10 @@ > case SSL_ERROR_NONE: > break; > case SSL_ERROR_WANT_READ: > - n = pqsecure_read(conn, ptr, len); > + // I think this mean, that SSL layer have > + // no any data for us and we must try > + // to read it later. > + n = 0; > break; > case SSL_ERROR_SYSCALL: > printfPQExpBuffer(&conn->errorMessage, > @@ -314,7 +317,10 @@ > case SSL_ERROR_NONE: > break; > case SSL_ERROR_WANT_WRITE: > - n = pqsecure_write(conn, ptr, len); > + // I think this mean, that SSL layer have > + // no free space for buffering our data and > + // we must try to write it later. > + n = 0; > break; > case SSL_ERROR_SYSCALL: > printfPQExpBuffer(&conn->errorMessage, > /* > * SSL-test > */ > #include <iostream> > #include <libpq-fe.h> > > static void > exit_nicely (PGconn *conn) { > std::cerr << "ERROR: " << PQerrorMessage (conn) << '\n'; > > PQfinish (conn); > exit (1); > } > > int > main (int _argc, char *_argv[]) { > PGconn *conn = PQconnectdb ("user=postgres dbname=template1 host=127.0.0.1 requiressl=1"); > if (PQstatus (conn) == CONNECTION_BAD) > exit_nicely (conn); > > PQsendQuery (conn, "select * from pg_class; select * from pg_type; select * from pg_proc"); > > for (;;) { > std::cout << "before DANGEROUS section of code\n"; > > #ifndef NO_STACK_OVERFLOW_DEMO > // This is a DANGEROUS code. If we call PQconsumeInput here, > // after getting last PGresult, we will go into infinite > // recursive call of pqsecure_read on SSL_ERROR_WANT_READ. > PQconsumeInput (conn); > if (PQisBusy (conn)) > continue; > // Call PQcounsumeInput on SSL connection when server > // don't send any data to us is DANGEROUS. > #else > // This code is safe, becouse end of data determine before > // call of PQconsumeInput and we don't go into pqsecure_read > // when server have no data. > if (PQisBusy (conn)) { > PQconsumeInput (conn); > continue; > } > #endif > // But I think PQconsumeInput must be safe to be called in > // any time, becouse, for example, we can use it not only > // for async query processing, but for getting asynhronous > // notification from server in case when we don't send any > // query to it and can't be sure, that server have data for > // us. > std::cout << "after DANGEROUS section of code\n"; > > // When we don't use SSL this code in both case is completly > // safe, becouse recv simple return 0 if no data avaliable. > // I think this is good for SSL connection too. > > PGresult *res = PQgetResult (conn); > if (res) { > if (PQresultStatus (res) == PGRES_TUPLES_OK) > std::cout << "SELECT\n"; > else > std::cerr << "UNKNOWN\n"; > > PQclear (res); > continue; > } > > break; > } > > PQfinish(conn); > return 0; > } > > ---------------------------(end of broadcast)--------------------------- > TIP 6: Have you searched our list archives? > > http://archives.postgresql.org -- Bruce Momjian | http://candle.pha.pa.us pgman@candle.pha.pa.us | (610) 359-1001 + If your life is a hard drive, | 13 Roberts Road + Christ can be your backup. | Newtown Square, Pennsylvania 19073