1
0
mirror of https://github.com/postgres/postgres.git synced 2025-05-31 03:21:24 +03:00

Ignore attempts to \gset into specially treated variables.

If an interactive psql session used \gset when querying a compromised
server, the attacker could execute arbitrary code as the operating
system account running psql.  Using a prefix not found among specially
treated variables, e.g. every lowercase string, precluded the attack.
Fix by issuing a warning and setting no variable for the column in
question.  Users wanting the old behavior can use a prefix and then a
meta-command like "\set HISTSIZE :prefix_HISTSIZE".  Back-patch to 9.5
(all supported versions).

Reviewed by Robert Haas.  Reported by Nick Cleaton.

Security: CVE-2020-25696
This commit is contained in:
Noah Misch 2020-11-09 07:32:09 -08:00
parent ff3de4c21a
commit 12fd81cb7f
5 changed files with 33 additions and 0 deletions

View File

@ -795,6 +795,13 @@ StoreQueryTuple(const PGresult *result)
/* concatenate prefix and column name */ /* concatenate prefix and column name */
varname = psprintf("%s%s", pset.gset_prefix, colname); varname = psprintf("%s%s", pset.gset_prefix, colname);
if (VariableHasHook(pset.vars, varname))
{
psql_error("attempt to \\gset into specially treated variable \"%s\" ignored\n",
varname);
continue;
}
if (!PQgetisnull(result, 0, i)) if (!PQgetisnull(result, 0, i))
value = PQgetvalue(result, 0, i); value = PQgetvalue(result, 0, i);
else else

View File

@ -264,6 +264,24 @@ SetVariableAssignHook(VariableSpace space, const char *name, VariableAssignHook
return true; return true;
} }
/*
* Return true iff the named variable has an assign hook function.
*/
bool
VariableHasHook(VariableSpace space, const char *name)
{
struct _variable *current;
Assert(space);
Assert(name);
for (current = space->next; current; current = current->next)
if (strcmp(current->name, name) == 0)
return current->assign_hook != NULL;
return false;
}
bool bool
SetVariableBool(VariableSpace space, const char *name) SetVariableBool(VariableSpace space, const char *name)
{ {

View File

@ -50,6 +50,7 @@ void PrintVariables(VariableSpace space);
bool SetVariable(VariableSpace space, const char *name, const char *value); bool SetVariable(VariableSpace space, const char *name, const char *value);
bool SetVariableAssignHook(VariableSpace space, const char *name, VariableAssignHook hook); bool SetVariableAssignHook(VariableSpace space, const char *name, VariableAssignHook hook);
bool VariableHasHook(VariableSpace space, const char *name);
bool SetVariableBool(VariableSpace space, const char *name); bool SetVariableBool(VariableSpace space, const char *name);
bool DeleteVariable(VariableSpace space, const char *name); bool DeleteVariable(VariableSpace space, const char *name);

View File

@ -10,6 +10,10 @@ select 10 as test01, 20 as test02, 'Hello' as test03 \gset pref01_
select 10 as "bad name" select 10 as "bad name"
\gset \gset
could not set variable "bad name" could not set variable "bad name"
select 'terse' as "OSITY", 'ok' as _foo \gset VERB
attempt to \gset into specially treated variable "VERBOSITY" ignored
\echo :VERB_foo :VERBOSITY
ok default
-- multiple backslash commands in one line -- multiple backslash commands in one line
select 1 as x, 2 as y \gset pref01_ \\ \echo :pref01_x select 1 as x, 2 as y \gset pref01_ \\ \echo :pref01_x
1 1

View File

@ -13,6 +13,9 @@ select 10 as test01, 20 as test02, 'Hello' as test03 \gset pref01_
select 10 as "bad name" select 10 as "bad name"
\gset \gset
select 'terse' as "OSITY", 'ok' as _foo \gset VERB
\echo :VERB_foo :VERBOSITY
-- multiple backslash commands in one line -- multiple backslash commands in one line
select 1 as x, 2 as y \gset pref01_ \\ \echo :pref01_x select 1 as x, 2 as y \gset pref01_ \\ \echo :pref01_x
select 3 as x, 4 as y \gset pref01_ \echo :pref01_x \echo :pref01_y select 3 as x, 4 as y \gset pref01_ \echo :pref01_x \echo :pref01_y