Skip to content

Commit 811015f

Browse files
committed
Check return value of strdup() in libpq connection option parsing.
An out-of-memory in most of these would lead to strange behavior, like connecting to a different database than intended, but some would lead to an outright segfault. Alex Shulgin and me. Backpatch to all supported versions.
1 parent 3852eab commit 811015f

File tree

1 file changed

+113
-19
lines changed

1 file changed

+113
-19
lines changed

src/interfaces/libpq/fe-connect.c

Lines changed: 113 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,7 @@ static int connectDBStart(PGconn *conn);
333333
static int connectDBComplete(PGconn *conn);
334334
static PGPing internal_ping(PGconn *conn);
335335
static PGconn *makeEmptyPGconn(void);
336-
static void fillPGconn(PGconn *conn, PQconninfoOption *connOptions);
336+
static bool fillPGconn(PGconn *conn, PQconninfoOption *connOptions);
337337
static void freePGconn(PGconn *conn);
338338
static void closePGconn(PGconn *conn);
339339
static PQconninfoOption *conninfo_init(PQExpBuffer errorMessage);
@@ -585,7 +585,11 @@ PQconnectStartParams(const char *const * keywords,
585585
/*
586586
* Move option values into conn structure
587587
*/
588-
fillPGconn(conn, connOptions);
588+
if (!fillPGconn(conn, connOptions))
589+
{
590+
PQconninfoFree(connOptions);
591+
return conn;
592+
}
589593

590594
/*
591595
* Free the option info - all is in conn now
@@ -665,19 +669,19 @@ PQconnectStart(const char *conninfo)
665669
return conn;
666670
}
667671

668-
static void
672+
/*
673+
* Move option values into conn structure
674+
*
675+
* Don't put anything cute here --- intelligence should be in
676+
* connectOptions2 ...
677+
*
678+
* Returns true on success. On failure, returns false and sets error message.
679+
*/
680+
static bool
669681
fillPGconn(PGconn *conn, PQconninfoOption *connOptions)
670682
{
671683
const internalPQconninfoOption *option;
672684

673-
/*
674-
* Move option values into conn structure
675-
*
676-
* Don't put anything cute here --- intelligence should be in
677-
* connectOptions2 ...
678-
*
679-
* XXX: probably worth checking strdup() return value here...
680-
*/
681685
for (option = PQconninfoOptions; option->keyword; option++)
682686
{
683687
const char *tmp = conninfo_getval(connOptions, option->keyword);
@@ -688,9 +692,22 @@ fillPGconn(PGconn *conn, PQconninfoOption *connOptions)
688692

689693
if (*connmember)
690694
free(*connmember);
691-
*connmember = tmp ? strdup(tmp) : NULL;
695+
if (tmp)
696+
{
697+
*connmember = strdup(tmp);
698+
if (*connmember == NULL)
699+
{
700+
printfPQExpBuffer(&conn->errorMessage,
701+
libpq_gettext("out of memory\n"));
702+
return false;
703+
}
704+
}
705+
else
706+
*connmember = NULL;
692707
}
693708
}
709+
710+
return true;
694711
}
695712

696713
/*
@@ -723,7 +740,12 @@ connectOptions1(PGconn *conn, const char *conninfo)
723740
/*
724741
* Move option values into conn structure
725742
*/
726-
fillPGconn(conn, connOptions);
743+
if (!fillPGconn(conn, connOptions))
744+
{
745+
conn->status = CONNECTION_BAD;
746+
PQconninfoFree(connOptions);
747+
return false;
748+
}
727749

728750
/*
729751
* Free the option info - all is in conn now
@@ -753,6 +775,8 @@ connectOptions2(PGconn *conn)
753775
if (conn->dbName)
754776
free(conn->dbName);
755777
conn->dbName = strdup(conn->pguser);
778+
if (!conn->dbName)
779+
goto oom_error;
756780
}
757781

758782
/*
@@ -765,7 +789,12 @@ connectOptions2(PGconn *conn)
765789
conn->pgpass = PasswordFromFile(conn->pghost, conn->pgport,
766790
conn->dbName, conn->pguser);
767791
if (conn->pgpass == NULL)
792+
{
768793
conn->pgpass = strdup(DefaultPassword);
794+
if (!conn->pgpass)
795+
goto oom_error;
796+
797+
}
769798
else
770799
conn->dot_pgpass_used = true;
771800
}
@@ -823,7 +852,11 @@ connectOptions2(PGconn *conn)
823852
#endif
824853
}
825854
else
855+
{
826856
conn->sslmode = strdup(DefaultSSLMode);
857+
if (!conn->sslmode)
858+
goto oom_error;
859+
}
827860

828861
/*
829862
* Resolve special "auto" client_encoding from the locale
@@ -833,6 +866,8 @@ connectOptions2(PGconn *conn)
833866
{
834867
free(conn->client_encoding_initial);
835868
conn->client_encoding_initial = strdup(pg_encoding_to_char(pg_get_encoding_from_locale(NULL, true)));
869+
if (!conn->client_encoding_initial)
870+
goto oom_error;
836871
}
837872

838873
/*
@@ -843,6 +878,12 @@ connectOptions2(PGconn *conn)
843878
conn->options_valid = true;
844879

845880
return true;
881+
882+
oom_error:
883+
conn->status = CONNECTION_BAD;
884+
printfPQExpBuffer(&conn->errorMessage,
885+
libpq_gettext("out of memory\n"));
886+
return false;
846887
}
847888

848889
/*
@@ -937,6 +978,8 @@ PQsetdbLogin(const char *pghost, const char *pgport, const char *pgoptions,
937978
if (conn->dbName)
938979
free(conn->dbName);
939980
conn->dbName = strdup(dbName);
981+
if (!conn->dbName)
982+
goto oom_error;
940983
}
941984
}
942985

@@ -949,41 +992,53 @@ PQsetdbLogin(const char *pghost, const char *pgport, const char *pgoptions,
949992
if (conn->pghost)
950993
free(conn->pghost);
951994
conn->pghost = strdup(pghost);
995+
if (!conn->pghost)
996+
goto oom_error;
952997
}
953998

954999
if (pgport && pgport[0] != '\0')
9551000
{
9561001
if (conn->pgport)
9571002
free(conn->pgport);
9581003
conn->pgport = strdup(pgport);
1004+
if (!conn->pgport)
1005+
goto oom_error;
9591006
}
9601007

9611008
if (pgoptions && pgoptions[0] != '\0')
9621009
{
9631010
if (conn->pgoptions)
9641011
free(conn->pgoptions);
9651012
conn->pgoptions = strdup(pgoptions);
1013+
if (!conn->pgoptions)
1014+
goto oom_error;
9661015
}
9671016

9681017
if (pgtty && pgtty[0] != '\0')
9691018
{
9701019
if (conn->pgtty)
9711020
free(conn->pgtty);
9721021
conn->pgtty = strdup(pgtty);
1022+
if (!conn->pgtty)
1023+
goto oom_error;
9731024
}
9741025

9751026
if (login && login[0] != '\0')
9761027
{
9771028
if (conn->pguser)
9781029
free(conn->pguser);
9791030
conn->pguser = strdup(login);
1031+
if (!conn->pguser)
1032+
goto oom_error;
9801033
}
9811034

9821035
if (pwd && pwd[0] != '\0')
9831036
{
9841037
if (conn->pgpass)
9851038
free(conn->pgpass);
9861039
conn->pgpass = strdup(pwd);
1040+
if (!conn->pgpass)
1041+
goto oom_error;
9871042
}
9881043

9891044
/*
@@ -999,6 +1054,12 @@ PQsetdbLogin(const char *pghost, const char *pgport, const char *pgoptions,
9991054
(void) connectDBComplete(conn);
10001055

10011056
return conn;
1057+
1058+
oom_error:
1059+
conn->status = CONNECTION_BAD;
1060+
printfPQExpBuffer(&conn->errorMessage,
1061+
libpq_gettext("out of memory\n"));
1062+
return conn;
10021063
}
10031064

10041065

@@ -3759,7 +3820,16 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options,
37593820
if (strcmp(options[i].keyword, optname) == 0)
37603821
{
37613822
if (options[i].val == NULL)
3823+
{
37623824
options[i].val = strdup(optval);
3825+
if (!options[i].val)
3826+
{
3827+
printfPQExpBuffer(errorMessage,
3828+
libpq_gettext("out of memory\n"));
3829+
free(result);
3830+
return 3;
3831+
}
3832+
}
37633833
found_keyword = true;
37643834
break;
37653835
}
@@ -3982,6 +4052,13 @@ parseServiceFile(const char *serviceFile,
39824052
{
39834053
if (options[i].val == NULL)
39844054
options[i].val = strdup(val);
4055+
if (!options[i].val)
4056+
{
4057+
printfPQExpBuffer(errorMessage,
4058+
libpq_gettext("out of memory\n"));
4059+
fclose(f);
4060+
return 3;
4061+
}
39854062
found_keyword = true;
39864063
break;
39874064
}
@@ -4401,6 +4478,14 @@ conninfo_array_parse(const char *const * keywords, const char *const * values,
44014478
if (options[k].val)
44024479
free(options[k].val);
44034480
options[k].val = strdup(str_option->val);
4481+
if (!options[k].val)
4482+
{
4483+
printfPQExpBuffer(errorMessage,
4484+
libpq_gettext("out of memory\n"));
4485+
PQconninfoFree(options);
4486+
PQconninfoFree(dbname_options);
4487+
return NULL;
4488+
}
44044489
break;
44054490
}
44064491
}
@@ -4595,20 +4680,22 @@ conninfo_uri_parse_options(PQconninfoOption *options, const char *uri,
45954680
{
45964681
int prefix_len;
45974682
char *p;
4598-
char *buf = strdup(uri); /* need a modifiable copy of the input
4599-
* URI */
4600-
char *start = buf;
4683+
char *buf;
4684+
char *start;
46014685
char prevchar = '\0';
46024686
char *user = NULL;
46034687
char *host = NULL;
46044688
bool retval = false;
46054689

4690+
/* need a modifiable copy of the input URI */
4691+
buf = strdup(uri);
46064692
if (buf == NULL)
46074693
{
46084694
printfPQExpBuffer(errorMessage,
46094695
libpq_gettext("out of memory\n"));
46104696
return false;
46114697
}
4698+
start = buf;
46124699

46134700
/* Skip the URI prefix */
46144701
prefix_len = uri_prefix_length(uri);
@@ -4950,15 +5037,17 @@ conninfo_uri_parse_params(char *params,
49505037
static char *
49515038
conninfo_uri_decode(const char *str, PQExpBuffer errorMessage)
49525039
{
4953-
char *buf = malloc(strlen(str) + 1);
4954-
char *p = buf;
5040+
char *buf;
5041+
char *p;
49555042
const char *q = str;
49565043

5044+
buf = malloc(strlen(str) + 1);
49575045
if (buf == NULL)
49585046
{
49595047
printfPQExpBuffer(errorMessage, libpq_gettext("out of memory\n"));
49605048
return NULL;
49615049
}
5050+
p = buf;
49625051

49635052
for (;;)
49645053
{
@@ -5103,7 +5192,6 @@ conninfo_storeval(PQconninfoOption *connOptions,
51035192
else
51045193
{
51055194
value_copy = strdup(value);
5106-
51075195
if (value_copy == NULL)
51085196
{
51095197
printfPQExpBuffer(errorMessage, libpq_gettext("out of memory\n"));
@@ -5671,6 +5759,12 @@ PasswordFromFile(char *hostname, char *port, char *dbname, char *username)
56715759
ret = strdup(t);
56725760
fclose(fp);
56735761

5762+
if (!ret)
5763+
{
5764+
/* Out of memory. XXX: an error message would be nice. */
5765+
return NULL;
5766+
}
5767+
56745768
/* De-escape password. */
56755769
for (p1 = p2 = ret; *p1 != ':' && *p1 != '\0'; ++p1, ++p2)
56765770
{

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy