mirror of
https://github.com/postgres/postgres.git
synced 2025-05-17 06:41:24 +03:00
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.
This commit is contained in:
parent
c57cdc9c1a
commit
d3b162a3dd
@ -333,7 +333,7 @@ static int connectDBStart(PGconn *conn);
|
|||||||
static int connectDBComplete(PGconn *conn);
|
static int connectDBComplete(PGconn *conn);
|
||||||
static PGPing internal_ping(PGconn *conn);
|
static PGPing internal_ping(PGconn *conn);
|
||||||
static PGconn *makeEmptyPGconn(void);
|
static PGconn *makeEmptyPGconn(void);
|
||||||
static void fillPGconn(PGconn *conn, PQconninfoOption *connOptions);
|
static bool fillPGconn(PGconn *conn, PQconninfoOption *connOptions);
|
||||||
static void freePGconn(PGconn *conn);
|
static void freePGconn(PGconn *conn);
|
||||||
static void closePGconn(PGconn *conn);
|
static void closePGconn(PGconn *conn);
|
||||||
static PQconninfoOption *conninfo_init(PQExpBuffer errorMessage);
|
static PQconninfoOption *conninfo_init(PQExpBuffer errorMessage);
|
||||||
@ -585,7 +585,11 @@ PQconnectStartParams(const char *const * keywords,
|
|||||||
/*
|
/*
|
||||||
* Move option values into conn structure
|
* Move option values into conn structure
|
||||||
*/
|
*/
|
||||||
fillPGconn(conn, connOptions);
|
if (!fillPGconn(conn, connOptions))
|
||||||
|
{
|
||||||
|
PQconninfoFree(connOptions);
|
||||||
|
return conn;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Free the option info - all is in conn now
|
* Free the option info - all is in conn now
|
||||||
@ -665,19 +669,19 @@ PQconnectStart(const char *conninfo)
|
|||||||
return conn;
|
return conn;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
/*
|
||||||
fillPGconn(PGconn *conn, PQconninfoOption *connOptions)
|
|
||||||
{
|
|
||||||
const internalPQconninfoOption *option;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Move option values into conn structure
|
* Move option values into conn structure
|
||||||
*
|
*
|
||||||
* Don't put anything cute here --- intelligence should be in
|
* Don't put anything cute here --- intelligence should be in
|
||||||
* connectOptions2 ...
|
* connectOptions2 ...
|
||||||
*
|
*
|
||||||
* XXX: probably worth checking strdup() return value here...
|
* Returns true on success. On failure, returns false and sets error message.
|
||||||
*/
|
*/
|
||||||
|
static bool
|
||||||
|
fillPGconn(PGconn *conn, PQconninfoOption *connOptions)
|
||||||
|
{
|
||||||
|
const internalPQconninfoOption *option;
|
||||||
|
|
||||||
for (option = PQconninfoOptions; option->keyword; option++)
|
for (option = PQconninfoOptions; option->keyword; option++)
|
||||||
{
|
{
|
||||||
const char *tmp = conninfo_getval(connOptions, option->keyword);
|
const char *tmp = conninfo_getval(connOptions, option->keyword);
|
||||||
@ -688,9 +692,22 @@ fillPGconn(PGconn *conn, PQconninfoOption *connOptions)
|
|||||||
|
|
||||||
if (*connmember)
|
if (*connmember)
|
||||||
free(*connmember);
|
free(*connmember);
|
||||||
*connmember = tmp ? strdup(tmp) : NULL;
|
if (tmp)
|
||||||
|
{
|
||||||
|
*connmember = strdup(tmp);
|
||||||
|
if (*connmember == NULL)
|
||||||
|
{
|
||||||
|
printfPQExpBuffer(&conn->errorMessage,
|
||||||
|
libpq_gettext("out of memory\n"));
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
*connmember = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -723,7 +740,12 @@ connectOptions1(PGconn *conn, const char *conninfo)
|
|||||||
/*
|
/*
|
||||||
* Move option values into conn structure
|
* Move option values into conn structure
|
||||||
*/
|
*/
|
||||||
fillPGconn(conn, connOptions);
|
if (!fillPGconn(conn, connOptions))
|
||||||
|
{
|
||||||
|
conn->status = CONNECTION_BAD;
|
||||||
|
PQconninfoFree(connOptions);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Free the option info - all is in conn now
|
* Free the option info - all is in conn now
|
||||||
@ -753,6 +775,8 @@ connectOptions2(PGconn *conn)
|
|||||||
if (conn->dbName)
|
if (conn->dbName)
|
||||||
free(conn->dbName);
|
free(conn->dbName);
|
||||||
conn->dbName = strdup(conn->pguser);
|
conn->dbName = strdup(conn->pguser);
|
||||||
|
if (!conn->dbName)
|
||||||
|
goto oom_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -765,7 +789,12 @@ connectOptions2(PGconn *conn)
|
|||||||
conn->pgpass = PasswordFromFile(conn->pghost, conn->pgport,
|
conn->pgpass = PasswordFromFile(conn->pghost, conn->pgport,
|
||||||
conn->dbName, conn->pguser);
|
conn->dbName, conn->pguser);
|
||||||
if (conn->pgpass == NULL)
|
if (conn->pgpass == NULL)
|
||||||
|
{
|
||||||
conn->pgpass = strdup(DefaultPassword);
|
conn->pgpass = strdup(DefaultPassword);
|
||||||
|
if (!conn->pgpass)
|
||||||
|
goto oom_error;
|
||||||
|
|
||||||
|
}
|
||||||
else
|
else
|
||||||
conn->dot_pgpass_used = true;
|
conn->dot_pgpass_used = true;
|
||||||
}
|
}
|
||||||
@ -823,7 +852,11 @@ connectOptions2(PGconn *conn)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
conn->sslmode = strdup(DefaultSSLMode);
|
conn->sslmode = strdup(DefaultSSLMode);
|
||||||
|
if (!conn->sslmode)
|
||||||
|
goto oom_error;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Resolve special "auto" client_encoding from the locale
|
* Resolve special "auto" client_encoding from the locale
|
||||||
@ -833,6 +866,8 @@ connectOptions2(PGconn *conn)
|
|||||||
{
|
{
|
||||||
free(conn->client_encoding_initial);
|
free(conn->client_encoding_initial);
|
||||||
conn->client_encoding_initial = strdup(pg_encoding_to_char(pg_get_encoding_from_locale(NULL, true)));
|
conn->client_encoding_initial = strdup(pg_encoding_to_char(pg_get_encoding_from_locale(NULL, true)));
|
||||||
|
if (!conn->client_encoding_initial)
|
||||||
|
goto oom_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -843,6 +878,12 @@ connectOptions2(PGconn *conn)
|
|||||||
conn->options_valid = true;
|
conn->options_valid = true;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
oom_error:
|
||||||
|
conn->status = CONNECTION_BAD;
|
||||||
|
printfPQExpBuffer(&conn->errorMessage,
|
||||||
|
libpq_gettext("out of memory\n"));
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -936,6 +977,8 @@ PQsetdbLogin(const char *pghost, const char *pgport, const char *pgoptions,
|
|||||||
if (conn->dbName)
|
if (conn->dbName)
|
||||||
free(conn->dbName);
|
free(conn->dbName);
|
||||||
conn->dbName = strdup(dbName);
|
conn->dbName = strdup(dbName);
|
||||||
|
if (!conn->dbName)
|
||||||
|
goto oom_error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -948,6 +991,8 @@ PQsetdbLogin(const char *pghost, const char *pgport, const char *pgoptions,
|
|||||||
if (conn->pghost)
|
if (conn->pghost)
|
||||||
free(conn->pghost);
|
free(conn->pghost);
|
||||||
conn->pghost = strdup(pghost);
|
conn->pghost = strdup(pghost);
|
||||||
|
if (!conn->pghost)
|
||||||
|
goto oom_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pgport && pgport[0] != '\0')
|
if (pgport && pgport[0] != '\0')
|
||||||
@ -955,6 +1000,8 @@ PQsetdbLogin(const char *pghost, const char *pgport, const char *pgoptions,
|
|||||||
if (conn->pgport)
|
if (conn->pgport)
|
||||||
free(conn->pgport);
|
free(conn->pgport);
|
||||||
conn->pgport = strdup(pgport);
|
conn->pgport = strdup(pgport);
|
||||||
|
if (!conn->pgport)
|
||||||
|
goto oom_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pgoptions && pgoptions[0] != '\0')
|
if (pgoptions && pgoptions[0] != '\0')
|
||||||
@ -962,6 +1009,8 @@ PQsetdbLogin(const char *pghost, const char *pgport, const char *pgoptions,
|
|||||||
if (conn->pgoptions)
|
if (conn->pgoptions)
|
||||||
free(conn->pgoptions);
|
free(conn->pgoptions);
|
||||||
conn->pgoptions = strdup(pgoptions);
|
conn->pgoptions = strdup(pgoptions);
|
||||||
|
if (!conn->pgoptions)
|
||||||
|
goto oom_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pgtty && pgtty[0] != '\0')
|
if (pgtty && pgtty[0] != '\0')
|
||||||
@ -969,6 +1018,8 @@ PQsetdbLogin(const char *pghost, const char *pgport, const char *pgoptions,
|
|||||||
if (conn->pgtty)
|
if (conn->pgtty)
|
||||||
free(conn->pgtty);
|
free(conn->pgtty);
|
||||||
conn->pgtty = strdup(pgtty);
|
conn->pgtty = strdup(pgtty);
|
||||||
|
if (!conn->pgtty)
|
||||||
|
goto oom_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (login && login[0] != '\0')
|
if (login && login[0] != '\0')
|
||||||
@ -976,6 +1027,8 @@ PQsetdbLogin(const char *pghost, const char *pgport, const char *pgoptions,
|
|||||||
if (conn->pguser)
|
if (conn->pguser)
|
||||||
free(conn->pguser);
|
free(conn->pguser);
|
||||||
conn->pguser = strdup(login);
|
conn->pguser = strdup(login);
|
||||||
|
if (!conn->pguser)
|
||||||
|
goto oom_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pwd && pwd[0] != '\0')
|
if (pwd && pwd[0] != '\0')
|
||||||
@ -983,6 +1036,8 @@ PQsetdbLogin(const char *pghost, const char *pgport, const char *pgoptions,
|
|||||||
if (conn->pgpass)
|
if (conn->pgpass)
|
||||||
free(conn->pgpass);
|
free(conn->pgpass);
|
||||||
conn->pgpass = strdup(pwd);
|
conn->pgpass = strdup(pwd);
|
||||||
|
if (!conn->pgpass)
|
||||||
|
goto oom_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -998,6 +1053,12 @@ PQsetdbLogin(const char *pghost, const char *pgport, const char *pgoptions,
|
|||||||
(void) connectDBComplete(conn);
|
(void) connectDBComplete(conn);
|
||||||
|
|
||||||
return conn;
|
return conn;
|
||||||
|
|
||||||
|
oom_error:
|
||||||
|
conn->status = CONNECTION_BAD;
|
||||||
|
printfPQExpBuffer(&conn->errorMessage,
|
||||||
|
libpq_gettext("out of memory\n"));
|
||||||
|
return conn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -3774,7 +3835,16 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options,
|
|||||||
if (strcmp(options[i].keyword, optname) == 0)
|
if (strcmp(options[i].keyword, optname) == 0)
|
||||||
{
|
{
|
||||||
if (options[i].val == NULL)
|
if (options[i].val == NULL)
|
||||||
|
{
|
||||||
options[i].val = strdup(optval);
|
options[i].val = strdup(optval);
|
||||||
|
if (!options[i].val)
|
||||||
|
{
|
||||||
|
printfPQExpBuffer(errorMessage,
|
||||||
|
libpq_gettext("out of memory\n"));
|
||||||
|
free(result);
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
found_keyword = true;
|
found_keyword = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -3997,6 +4067,13 @@ parseServiceFile(const char *serviceFile,
|
|||||||
{
|
{
|
||||||
if (options[i].val == NULL)
|
if (options[i].val == NULL)
|
||||||
options[i].val = strdup(val);
|
options[i].val = strdup(val);
|
||||||
|
if (!options[i].val)
|
||||||
|
{
|
||||||
|
printfPQExpBuffer(errorMessage,
|
||||||
|
libpq_gettext("out of memory\n"));
|
||||||
|
fclose(f);
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
found_keyword = true;
|
found_keyword = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -4416,6 +4493,14 @@ conninfo_array_parse(const char *const * keywords, const char *const * values,
|
|||||||
if (options[k].val)
|
if (options[k].val)
|
||||||
free(options[k].val);
|
free(options[k].val);
|
||||||
options[k].val = strdup(str_option->val);
|
options[k].val = strdup(str_option->val);
|
||||||
|
if (!options[k].val)
|
||||||
|
{
|
||||||
|
printfPQExpBuffer(errorMessage,
|
||||||
|
libpq_gettext("out of memory\n"));
|
||||||
|
PQconninfoFree(options);
|
||||||
|
PQconninfoFree(dbname_options);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4599,20 +4684,22 @@ conninfo_uri_parse_options(PQconninfoOption *options, const char *uri,
|
|||||||
{
|
{
|
||||||
int prefix_len;
|
int prefix_len;
|
||||||
char *p;
|
char *p;
|
||||||
char *buf = strdup(uri); /* need a modifiable copy of the input
|
char *buf;
|
||||||
* URI */
|
char *start;
|
||||||
char *start = buf;
|
|
||||||
char prevchar = '\0';
|
char prevchar = '\0';
|
||||||
char *user = NULL;
|
char *user = NULL;
|
||||||
char *host = NULL;
|
char *host = NULL;
|
||||||
bool retval = false;
|
bool retval = false;
|
||||||
|
|
||||||
|
/* need a modifiable copy of the input URI */
|
||||||
|
buf = strdup(uri);
|
||||||
if (buf == NULL)
|
if (buf == NULL)
|
||||||
{
|
{
|
||||||
printfPQExpBuffer(errorMessage,
|
printfPQExpBuffer(errorMessage,
|
||||||
libpq_gettext("out of memory\n"));
|
libpq_gettext("out of memory\n"));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
start = buf;
|
||||||
|
|
||||||
/* Skip the URI prefix */
|
/* Skip the URI prefix */
|
||||||
prefix_len = uri_prefix_length(uri);
|
prefix_len = uri_prefix_length(uri);
|
||||||
@ -4954,15 +5041,17 @@ conninfo_uri_parse_params(char *params,
|
|||||||
static char *
|
static char *
|
||||||
conninfo_uri_decode(const char *str, PQExpBuffer errorMessage)
|
conninfo_uri_decode(const char *str, PQExpBuffer errorMessage)
|
||||||
{
|
{
|
||||||
char *buf = malloc(strlen(str) + 1);
|
char *buf;
|
||||||
char *p = buf;
|
char *p;
|
||||||
const char *q = str;
|
const char *q = str;
|
||||||
|
|
||||||
|
buf = malloc(strlen(str) + 1);
|
||||||
if (buf == NULL)
|
if (buf == NULL)
|
||||||
{
|
{
|
||||||
printfPQExpBuffer(errorMessage, libpq_gettext("out of memory\n"));
|
printfPQExpBuffer(errorMessage, libpq_gettext("out of memory\n"));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
p = buf;
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
@ -5107,7 +5196,6 @@ conninfo_storeval(PQconninfoOption *connOptions,
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
value_copy = strdup(value);
|
value_copy = strdup(value);
|
||||||
|
|
||||||
if (value_copy == NULL)
|
if (value_copy == NULL)
|
||||||
{
|
{
|
||||||
printfPQExpBuffer(errorMessage, libpq_gettext("out of memory\n"));
|
printfPQExpBuffer(errorMessage, libpq_gettext("out of memory\n"));
|
||||||
@ -5667,6 +5755,12 @@ PasswordFromFile(char *hostname, char *port, char *dbname, char *username)
|
|||||||
ret = strdup(t);
|
ret = strdup(t);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
|
||||||
|
if (!ret)
|
||||||
|
{
|
||||||
|
/* Out of memory. XXX: an error message would be nice. */
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* De-escape password. */
|
/* De-escape password. */
|
||||||
for (p1 = p2 = ret; *p1 != ':' && *p1 != '\0'; ++p1, ++p2)
|
for (p1 = p2 = ret; *p1 != ':' && *p1 != '\0'; ++p1, ++p2)
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user