mirror of
https://github.com/postgres/postgres.git
synced 2025-07-17 06:41:09 +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:
@ -280,7 +280,7 @@ static bool connectOptions2(PGconn *conn);
|
|||||||
static int connectDBStart(PGconn *conn);
|
static int connectDBStart(PGconn *conn);
|
||||||
static int connectDBComplete(PGconn *conn);
|
static int connectDBComplete(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_parse(const char *conninfo,
|
static PQconninfoOption *conninfo_parse(const char *conninfo,
|
||||||
@ -452,7 +452,11 @@ PQconnectStartParams(const char **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
|
||||||
@ -532,59 +536,53 @@ PQconnectStart(const char *conninfo)
|
|||||||
return conn;
|
return conn;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
/*
|
||||||
|
* Move option values into conn structure
|
||||||
|
*
|
||||||
|
* Don't put anything cute here --- intelligence should be in
|
||||||
|
* connectOptions2 ...
|
||||||
|
*
|
||||||
|
* Returns true on success. On failure, returns false and sets error message.
|
||||||
|
*/
|
||||||
|
#define FILL_CONN_OPTION(dst, name) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
tmp = conninfo_getval(connOptions, name); \
|
||||||
|
if (tmp) \
|
||||||
|
{ \
|
||||||
|
dst = strdup(tmp); \
|
||||||
|
if (dst == NULL) \
|
||||||
|
goto oom_error; \
|
||||||
|
} \
|
||||||
|
else \
|
||||||
|
dst = NULL; \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
static bool
|
||||||
fillPGconn(PGconn *conn, PQconninfoOption *connOptions)
|
fillPGconn(PGconn *conn, PQconninfoOption *connOptions)
|
||||||
{
|
{
|
||||||
char *tmp;
|
char *tmp;
|
||||||
|
|
||||||
/*
|
FILL_CONN_OPTION(conn->pghostaddr, "hostaddr");
|
||||||
* Move option values into conn structure
|
FILL_CONN_OPTION(conn->pghost, "host");
|
||||||
*
|
FILL_CONN_OPTION(conn->pgport, "port");
|
||||||
* Don't put anything cute here --- intelligence should be in
|
FILL_CONN_OPTION(conn->pgtty, "tty");
|
||||||
* connectOptions2 ...
|
FILL_CONN_OPTION(conn->pgoptions, "options");
|
||||||
*
|
FILL_CONN_OPTION(conn->appname, "application_name");
|
||||||
* XXX: probably worth checking strdup() return value here...
|
FILL_CONN_OPTION(conn->fbappname, "fallback_application_name");
|
||||||
*/
|
FILL_CONN_OPTION(conn->dbName, "dbname");
|
||||||
tmp = conninfo_getval(connOptions, "hostaddr");
|
FILL_CONN_OPTION(conn->pguser, "user");
|
||||||
conn->pghostaddr = tmp ? strdup(tmp) : NULL;
|
FILL_CONN_OPTION(conn->pgpass, "password");
|
||||||
tmp = conninfo_getval(connOptions, "host");
|
FILL_CONN_OPTION(conn->connect_timeout, "connect_timeout");
|
||||||
conn->pghost = tmp ? strdup(tmp) : NULL;
|
FILL_CONN_OPTION(conn->keepalives, "keepalives");
|
||||||
tmp = conninfo_getval(connOptions, "port");
|
FILL_CONN_OPTION(conn->keepalives_idle, "keepalives_idle");
|
||||||
conn->pgport = tmp ? strdup(tmp) : NULL;
|
FILL_CONN_OPTION(conn->keepalives_interval, "keepalives_interval");
|
||||||
tmp = conninfo_getval(connOptions, "tty");
|
FILL_CONN_OPTION(conn->keepalives_count, "keepalives_count");
|
||||||
conn->pgtty = tmp ? strdup(tmp) : NULL;
|
FILL_CONN_OPTION(conn->sslmode, "sslmode");
|
||||||
tmp = conninfo_getval(connOptions, "options");
|
FILL_CONN_OPTION(conn->sslkey, "sslkey");
|
||||||
conn->pgoptions = tmp ? strdup(tmp) : NULL;
|
FILL_CONN_OPTION(conn->sslcert, "sslcert");
|
||||||
tmp = conninfo_getval(connOptions, "application_name");
|
FILL_CONN_OPTION(conn->sslrootcert, "sslrootcert");
|
||||||
conn->appname = tmp ? strdup(tmp) : NULL;
|
FILL_CONN_OPTION(conn->sslcrl, "sslcrl");
|
||||||
tmp = conninfo_getval(connOptions, "fallback_application_name");
|
|
||||||
conn->fbappname = tmp ? strdup(tmp) : NULL;
|
|
||||||
tmp = conninfo_getval(connOptions, "dbname");
|
|
||||||
conn->dbName = tmp ? strdup(tmp) : NULL;
|
|
||||||
tmp = conninfo_getval(connOptions, "user");
|
|
||||||
conn->pguser = tmp ? strdup(tmp) : NULL;
|
|
||||||
tmp = conninfo_getval(connOptions, "password");
|
|
||||||
conn->pgpass = tmp ? strdup(tmp) : NULL;
|
|
||||||
tmp = conninfo_getval(connOptions, "connect_timeout");
|
|
||||||
conn->connect_timeout = tmp ? strdup(tmp) : NULL;
|
|
||||||
tmp = conninfo_getval(connOptions, "keepalives");
|
|
||||||
conn->keepalives = tmp ? strdup(tmp) : NULL;
|
|
||||||
tmp = conninfo_getval(connOptions, "keepalives_idle");
|
|
||||||
conn->keepalives_idle = tmp ? strdup(tmp) : NULL;
|
|
||||||
tmp = conninfo_getval(connOptions, "keepalives_interval");
|
|
||||||
conn->keepalives_interval = tmp ? strdup(tmp) : NULL;
|
|
||||||
tmp = conninfo_getval(connOptions, "keepalives_count");
|
|
||||||
conn->keepalives_count = tmp ? strdup(tmp) : NULL;
|
|
||||||
tmp = conninfo_getval(connOptions, "sslmode");
|
|
||||||
conn->sslmode = tmp ? strdup(tmp) : NULL;
|
|
||||||
tmp = conninfo_getval(connOptions, "sslkey");
|
|
||||||
conn->sslkey = tmp ? strdup(tmp) : NULL;
|
|
||||||
tmp = conninfo_getval(connOptions, "sslcert");
|
|
||||||
conn->sslcert = tmp ? strdup(tmp) : NULL;
|
|
||||||
tmp = conninfo_getval(connOptions, "sslrootcert");
|
|
||||||
conn->sslrootcert = tmp ? strdup(tmp) : NULL;
|
|
||||||
tmp = conninfo_getval(connOptions, "sslcrl");
|
|
||||||
conn->sslcrl = tmp ? strdup(tmp) : NULL;
|
|
||||||
#ifdef USE_SSL
|
#ifdef USE_SSL
|
||||||
tmp = conninfo_getval(connOptions, "requiressl");
|
tmp = conninfo_getval(connOptions, "requiressl");
|
||||||
if (tmp && tmp[0] == '1')
|
if (tmp && tmp[0] == '1')
|
||||||
@ -593,18 +591,24 @@ fillPGconn(PGconn *conn, PQconninfoOption *connOptions)
|
|||||||
if (conn->sslmode)
|
if (conn->sslmode)
|
||||||
free(conn->sslmode);
|
free(conn->sslmode);
|
||||||
conn->sslmode = strdup("require");
|
conn->sslmode = strdup("require");
|
||||||
|
if (!conn->sslmode)
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#if defined(KRB5) || defined(ENABLE_GSS) || defined(ENABLE_SSPI)
|
#if defined(KRB5) || defined(ENABLE_GSS) || defined(ENABLE_SSPI)
|
||||||
tmp = conninfo_getval(connOptions, "krbsrvname");
|
FILL_CONN_OPTION(conn->krbsrvname, "krbsrvname");
|
||||||
conn->krbsrvname = tmp ? strdup(tmp) : NULL;
|
|
||||||
#endif
|
#endif
|
||||||
#if defined(ENABLE_GSS) && defined(ENABLE_SSPI)
|
#if defined(ENABLE_GSS) && defined(ENABLE_SSPI)
|
||||||
tmp = conninfo_getval(connOptions, "gsslib");
|
FILL_CONN_OPTION(conn->gsslib, "gsslib");
|
||||||
conn->gsslib = tmp ? strdup(tmp) : NULL;
|
|
||||||
#endif
|
#endif
|
||||||
tmp = conninfo_getval(connOptions, "replication");
|
FILL_CONN_OPTION(conn->replication, "replication");
|
||||||
conn->replication = tmp ? strdup(tmp) : NULL;
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
oom_error:
|
||||||
|
printfPQExpBuffer(&conn->errorMessage,
|
||||||
|
libpq_gettext("out of memory\n"));
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -637,7 +641,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
|
||||||
@ -667,6 +676,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -679,7 +690,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;
|
||||||
}
|
}
|
||||||
@ -737,7 +753,11 @@ connectOptions2(PGconn *conn)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
conn->sslmode = strdup(DefaultSSLMode);
|
conn->sslmode = strdup(DefaultSSLMode);
|
||||||
|
if (!conn->sslmode)
|
||||||
|
goto oom_error;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Only if we get this far is it appropriate to try to connect. (We need a
|
* Only if we get this far is it appropriate to try to connect. (We need a
|
||||||
@ -747,6 +767,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -829,6 +855,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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -841,6 +869,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')
|
||||||
@ -848,6 +878,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')
|
||||||
@ -855,6 +887,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')
|
||||||
@ -862,6 +896,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')
|
||||||
@ -869,6 +905,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')
|
||||||
@ -876,6 +914,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -891,6 +931,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -3530,7 +3576,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;
|
||||||
}
|
}
|
||||||
@ -3753,6 +3808,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;
|
||||||
}
|
}
|
||||||
@ -4180,6 +4242,14 @@ conninfo_array_parse(const char **keywords, const char **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(str_options);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4199,6 +4269,7 @@ conninfo_array_parse(const char **keywords, const char **values,
|
|||||||
printfPQExpBuffer(errorMessage,
|
printfPQExpBuffer(errorMessage,
|
||||||
libpq_gettext("out of memory\n"));
|
libpq_gettext("out of memory\n"));
|
||||||
PQconninfoFree(options);
|
PQconninfoFree(options);
|
||||||
|
PQconninfoFree(str_options);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user