Skip to content

Commit 30bf468

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 e453cc2 commit 30bf468

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

@@ -3760,7 +3821,16 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options,
37603821
if (strcmp(options[i].keyword, optname) == 0)
37613822
{
37623823
if (options[i].val == NULL)
3824+
{
37633825
options[i].val = strdup(optval);
3826+
if (!options[i].val)
3827+
{
3828+
printfPQExpBuffer(errorMessage,
3829+
libpq_gettext("out of memory\n"));
3830+
free(result);
3831+
return 3;
3832+
}
3833+
}
37643834
found_keyword = true;
37653835
break;
37663836
}
@@ -3983,6 +4053,13 @@ parseServiceFile(const char *serviceFile,
39834053
{
39844054
if (options[i].val == NULL)
39854055
options[i].val = strdup(val);
4056+
if (!options[i].val)
4057+
{
4058+
printfPQExpBuffer(errorMessage,
4059+
libpq_gettext("out of memory\n"));
4060+
fclose(f);
4061+
return 3;
4062+
}
39864063
found_keyword = true;
39874064
break;
39884065
}
@@ -4402,6 +4479,14 @@ conninfo_array_parse(const char *const * keywords, const char *const * values,
44024479
if (options[k].val)
44034480
free(options[k].val);
44044481
options[k].val = strdup(str_option->val);
4482+
if (!options[k].val)
4483+
{
4484+
printfPQExpBuffer(errorMessage,
4485+
libpq_gettext("out of memory\n"));
4486+
PQconninfoFree(options);
4487+
PQconninfoFree(dbname_options);
4488+
return NULL;
4489+
}
44054490
break;
44064491
}
44074492
}
@@ -4596,20 +4681,22 @@ conninfo_uri_parse_options(PQconninfoOption *options, const char *uri,
45964681
{
45974682
int prefix_len;
45984683
char *p;
4599-
char *buf = strdup(uri); /* need a modifiable copy of the input
4600-
* URI */
4601-
char *start = buf;
4684+
char *buf;
4685+
char *start;
46024686
char prevchar = '\0';
46034687
char *user = NULL;
46044688
char *host = NULL;
46054689
bool retval = false;
46064690

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

46144701
/* Skip the URI prefix */
46154702
prefix_len = uri_prefix_length(uri);
@@ -4951,15 +5038,17 @@ conninfo_uri_parse_params(char *params,
49515038
static char *
49525039
conninfo_uri_decode(const char *str, PQExpBuffer errorMessage)
49535040
{
4954-
char *buf = malloc(strlen(str) + 1);
4955-
char *p = buf;
5041+
char *buf;
5042+
char *p;
49565043
const char *q = str;
49575044

5045+
buf = malloc(strlen(str) + 1);
49585046
if (buf == NULL)
49595047
{
49605048
printfPQExpBuffer(errorMessage, libpq_gettext("out of memory\n"));
49615049
return NULL;
49625050
}
5051+
p = buf;
49635052

49645053
for (;;)
49655054
{
@@ -5104,7 +5193,6 @@ conninfo_storeval(PQconninfoOption *connOptions,
51045193
else
51055194
{
51065195
value_copy = strdup(value);
5107-
51085196
if (value_copy == NULL)
51095197
{
51105198
printfPQExpBuffer(errorMessage, libpq_gettext("out of memory\n"));
@@ -5672,6 +5760,12 @@ PasswordFromFile(char *hostname, char *port, char *dbname, char *username)
56725760
ret = strdup(t);
56735761
fclose(fp);
56745762

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

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