Skip to content

Commit 8d01027

Browse files
MasahikoSawadareshke
authored andcommitted
Restrict accesses to non-system views and foreign tables during pg_dump.
When pg_dump retrieves the list of database objects and performs the data dump, there was possibility that objects are replaced with others of the same name, such as views, and access them. This vulnerability could result in code execution with superuser privileges during the pg_dump process. This issue can arise when dumping data of sequences, foreign tables (only 13 or later), or tables registered with a WHERE clause in the extension configuration table. To address this, pg_dump now utilizes the newly introduced restrict_nonsystem_relation_kind GUC parameter to restrict the accesses to non-system views and foreign tables during the dump process. This new GUC parameter is added to back branches too, but these changes do not require cluster recreation. Back-patch to all supported branches. Reviewed-by: Noah Misch Security: CVE-2024-7348 Backpatch-through: 12
1 parent da47112 commit 8d01027

File tree

16 files changed

+277
-3
lines changed

16 files changed

+277
-3
lines changed

contrib/postgres_fdw/expected/postgres_fdw.out

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -707,6 +707,17 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft_empty ORDER BY c1;
707707
Remote SQL: SELECT c1, c2 FROM public.loct_empty ORDER BY c1 ASC NULLS LAST
708708
(3 rows)
709709

710+
-- test restriction on non-system foreign tables.
711+
SET restrict_nonsystem_relation_kind TO 'foreign-table';
712+
SELECT * from ft1 where c1 < 1; -- ERROR
713+
ERROR: access to non-system foreign table is restricted
714+
INSERT INTO ft1 (c1) VALUES (1); -- ERROR
715+
ERROR: access to non-system foreign table is restricted
716+
DELETE FROM ft1 WHERE c1 = 1; -- ERROR
717+
ERROR: access to non-system foreign table is restricted
718+
TRUNCATE ft1; -- ERROR
719+
ERROR: access to non-system foreign table is restricted
720+
RESET restrict_nonsystem_relation_kind;
710721
-- ===================================================================
711722
-- WHERE with remotely-executable conditions
712723
-- ===================================================================

contrib/postgres_fdw/sql/postgres_fdw.sql

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,14 @@ DELETE FROM loct_empty;
321321
ANALYZE ft_empty;
322322
EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft_empty ORDER BY c1;
323323

324+
-- test restriction on non-system foreign tables.
325+
SET restrict_nonsystem_relation_kind TO 'foreign-table';
326+
SELECT * from ft1 where c1 < 1; -- ERROR
327+
INSERT INTO ft1 (c1) VALUES (1); -- ERROR
328+
DELETE FROM ft1 WHERE c1 = 1; -- ERROR
329+
TRUNCATE ft1; -- ERROR
330+
RESET restrict_nonsystem_relation_kind;
331+
324332
-- ===================================================================
325333
-- WHERE with remotely-executable conditions
326334
-- ===================================================================

doc/src/sgml/config.sgml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9012,6 +9012,23 @@ SET XML OPTION { DOCUMENT | CONTENT };
90129012
</listitem>
90139013
</varlistentry>
90149014

9015+
<varlistentry id="guc-restrict-nonsystem-relation-kind" xreflabel="restrict_nonsystem_relation_kind">
9016+
<term><varname>restrict_nonsystem_relation_kind</varname> (<type>string</type>)
9017+
<indexterm>
9018+
<primary><varname>restrict_nonsystem_relation_kind</varname></primary>
9019+
<secondary>configuration parameter</secondary>
9020+
</indexterm>
9021+
</term>
9022+
<listitem>
9023+
<para>
9024+
This variable specifies relation kind to which access is restricted.
9025+
It contains a comma-separated list of relation kind. Currently, the
9026+
supported relation kinds are <literal>view</literal> and
9027+
<literal>foreign-table</literal>.
9028+
</para>
9029+
</listitem>
9030+
</varlistentry>
9031+
90159032
</variablelist>
90169033
</sect2>
90179034
<sect2 id="runtime-config-client-format">

doc/src/sgml/ref/pg_dump.sgml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -819,6 +819,14 @@ PostgreSQL documentation
819819
The only exception is that an empty pattern is disallowed.
820820
</para>
821821

822+
<note>
823+
<para>
824+
Using wildcards in <option>--include-foreign-data</option> may result
825+
in access to unexpected foreign servers. Also, to use this option securely,
826+
make sure that the named server must have a trusted owner.
827+
</para>
828+
</note>
829+
822830
<note>
823831
<para>
824832
When <option>--include-foreign-data</option> is specified,

src/backend/foreign/foreign.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include "optimizer/planmain.h"
3434
#include "optimizer/restrictinfo.h"
3535
#include "optimizer/tlist.h"
36+
#include "tcop/tcopprot.h"
3637
#include "utils/builtins.h"
3738
#include "utils/memutils.h"
3839
#include "utils/rel.h"
@@ -590,6 +591,15 @@ GetFdwRoutine(Oid fdwhandler)
590591
Datum datum;
591592
FdwRoutine *routine;
592593

594+
/* Check if the access to foreign tables is restricted */
595+
if (unlikely((restrict_nonsystem_relation_kind & RESTRICT_RELKIND_FOREIGN_TABLE) != 0))
596+
{
597+
/* there must not be built-in FDW handler */
598+
ereport(ERROR,
599+
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
600+
errmsg("access to non-system foreign table is restricted")));
601+
}
602+
593603
datum = OidFunctionCall0(fdwhandler);
594604
routine = (FdwRoutine *) DatumGetPointer(datum);
595605

src/backend/optimizer/plan/createplan.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
#include "parser/parsetree.h"
4848
#include "partitioning/partdesc.h"
4949
#include "partitioning/partprune.h"
50+
#include "tcop/tcopprot.h"
5051
#include "utils/lsyscache.h"
5152
#include "utils/uri.h"
5253

@@ -8482,7 +8483,19 @@ make_modifytable(PlannerInfo *root, Plan *subplan,
84828483

84838484
Assert(rte->rtekind == RTE_RELATION);
84848485
if (rte->relkind == RELKIND_FOREIGN_TABLE)
8486+
{
8487+
/* Check if the access to foreign tables is restricted */
8488+
if (unlikely((restrict_nonsystem_relation_kind & RESTRICT_RELKIND_FOREIGN_TABLE) != 0))
8489+
{
8490+
/* there must not be built-in foreign tables */
8491+
Assert(rte->relid >= FirstNormalObjectId);
8492+
ereport(ERROR,
8493+
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
8494+
errmsg("access to non-system foreign table is restricted")));
8495+
}
8496+
84858497
fdwroutine = GetFdwRoutineByRelId(rte->relid);
8498+
}
84868499
else
84878500
fdwroutine = NULL;
84888501
}

src/backend/optimizer/util/plancat.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
#include "rewrite/rewriteManip.h"
5050
#include "statistics/statistics.h"
5151
#include "storage/bufmgr.h"
52+
#include "tcop/tcopprot.h"
5253
#include "utils/builtins.h"
5354
#include "utils/lsyscache.h"
5455
#include "utils/partcache.h"
@@ -468,6 +469,17 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
468469
/* Grab foreign-table info using the relcache, while we have it */
469470
if (relation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
470471
{
472+
/* Check if the access to foreign tables is restricted */
473+
if (unlikely((restrict_nonsystem_relation_kind & RESTRICT_RELKIND_FOREIGN_TABLE) != 0))
474+
{
475+
/* there must not be built-in foreign tables */
476+
Assert(RelationGetRelid(relation) >= FirstNormalObjectId);
477+
478+
ereport(ERROR,
479+
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
480+
errmsg("access to non-system foreign table is restricted")));
481+
}
482+
471483
rel->serverid = GetForeignServerIdByRelId(RelationGetRelid(relation));
472484
rel->segSeverids = GetForeignServerSegsByRelId(RelationGetRelid(relation));
473485
rel->fdwroutine = GetFdwRoutineForRelation(relation, true);

src/backend/rewrite/rewriteHandler.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
#include "rewrite/rewriteManip.h"
4343
#include "rewrite/rewriteSearchCycle.h"
4444
#include "rewrite/rowsecurity.h"
45+
#include "tcop/tcopprot.h"
4546
#include "utils/builtins.h"
4647
#include "utils/lsyscache.h"
4748
#include "utils/rel.h"
@@ -1789,6 +1790,14 @@ ApplyRetrieveRule(Query *parsetree,
17891790
if (rule->qual != NULL)
17901791
elog(ERROR, "cannot handle qualified ON SELECT rule");
17911792

1793+
/* Check if the expansion of non-system views are restricted */
1794+
if (unlikely((restrict_nonsystem_relation_kind & RESTRICT_RELKIND_VIEW) != 0 &&
1795+
RelationGetRelid(relation) >= FirstNormalObjectId))
1796+
ereport(ERROR,
1797+
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1798+
errmsg("access to non-system view \"%s\" is restricted",
1799+
RelationGetRelationName(relation))));
1800+
17921801
if (rt_index == parsetree->resultRelation)
17931802
{
17941803
/*
@@ -3172,6 +3181,14 @@ rewriteTargetView(Query *parsetree, Relation view)
31723181
}
31733182
}
31743183

3184+
/* Check if the expansion of non-system views are restricted */
3185+
if (unlikely((restrict_nonsystem_relation_kind & RESTRICT_RELKIND_VIEW) != 0 &&
3186+
RelationGetRelid(view) >= FirstNormalObjectId))
3187+
ereport(ERROR,
3188+
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3189+
errmsg("access to non-system view \"%s\" is restricted",
3190+
RelationGetRelationName(view))));
3191+
31753192
/*
31763193
* For INSERT/UPDATE the modified columns must all be updatable. Note that
31773194
* we get the modified columns from the query's targetlist, not from the

src/backend/tcop/postgres.c

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@
8989
#include "utils/snapmgr.h"
9090
#include "utils/timeout.h"
9191
#include "utils/timestamp.h"
92+
#include "utils/varlena.h"
9293

9394
#include "cdb/cdbutil.h"
9495
#include "cdb/cdbvars.h"
@@ -151,6 +152,8 @@ cancel_pending_hook_type cancel_pending_hook = NULL;
151152
* Hook for query execution.
152153
*/
153154
exec_simple_query_hook_type exec_simple_query_hook = NULL;
155+
/* flags for non-system relation kinds to restrict use */
156+
int restrict_nonsystem_relation_kind;
154157

155158
/* ----------------
156159
* private typedefs etc
@@ -4546,6 +4549,66 @@ assign_max_stack_depth(int newval, void *extra)
45464549
max_stack_depth_bytes = newval_bytes;
45474550
}
45484551

4552+
/*
4553+
* GUC check_hook for restrict_nonsystem_relation_kind
4554+
*/
4555+
bool
4556+
check_restrict_nonsystem_relation_kind(char **newval, void **extra, GucSource source)
4557+
{
4558+
char *rawstring;
4559+
List *elemlist;
4560+
ListCell *l;
4561+
int flags = 0;
4562+
4563+
/* Need a modifiable copy of string */
4564+
rawstring = pstrdup(*newval);
4565+
4566+
if (!SplitIdentifierString(rawstring, ',', &elemlist))
4567+
{
4568+
/* syntax error in list */
4569+
GUC_check_errdetail("List syntax is invalid.");
4570+
pfree(rawstring);
4571+
list_free(elemlist);
4572+
return false;
4573+
}
4574+
4575+
foreach(l, elemlist)
4576+
{
4577+
char *tok = (char *) lfirst(l);
4578+
4579+
if (pg_strcasecmp(tok, "view") == 0)
4580+
flags |= RESTRICT_RELKIND_VIEW;
4581+
else if (pg_strcasecmp(tok, "foreign-table") == 0)
4582+
flags |= RESTRICT_RELKIND_FOREIGN_TABLE;
4583+
else
4584+
{
4585+
GUC_check_errdetail("Unrecognized key word: \"%s\".", tok);
4586+
pfree(rawstring);
4587+
list_free(elemlist);
4588+
return false;
4589+
}
4590+
}
4591+
4592+
pfree(rawstring);
4593+
list_free(elemlist);
4594+
4595+
/* Save the flags in *extra, for use by the assign function */
4596+
*extra = malloc(sizeof(int));
4597+
*((int *) *extra) = flags;
4598+
4599+
return true;
4600+
}
4601+
4602+
/*
4603+
* GUC assign_hook for restrict_nonsystem_relation_kind
4604+
*/
4605+
void
4606+
assign_restrict_nonsystem_relation_kind(const char *newval, void *extra)
4607+
{
4608+
int *flags = (int *) extra;
4609+
4610+
restrict_nonsystem_relation_kind = *flags;
4611+
}
45494612

45504613
/*
45514614
* set_debug_options --- apply "-d N" command line option

src/backend/utils/misc/guc.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -686,6 +686,8 @@ static char *recovery_target_xid_string;
686686
static char *recovery_target_name_string;
687687
static char *recovery_target_lsn_string;
688688
static char *file_encryption_method_str;
689+
static char *restrict_nonsystem_relation_kind_string;
690+
689691

690692
/* should be static, but commands/variable.c needs to get at this */
691693
char *role_string;
@@ -4761,7 +4763,18 @@ static struct config_string ConfigureNamesString[] =
47614763
"",
47624764
NULL, NULL, NULL
47634765
},
4764-
4766+
4767+
{
4768+
{"restrict_nonsystem_relation_kind", PGC_USERSET, CLIENT_CONN_STATEMENT,
4769+
gettext_noop("Sets relation kinds of non-system relation to restrict use"),
4770+
NULL,
4771+
GUC_LIST_INPUT | GUC_NOT_IN_SAMPLE
4772+
},
4773+
&restrict_nonsystem_relation_kind_string,
4774+
"",
4775+
check_restrict_nonsystem_relation_kind, assign_restrict_nonsystem_relation_kind, NULL
4776+
},
4777+
47654778
/* End-of-list marker */
47664779
{
47674780
{NULL, 0, 0, NULL, NULL}, NULL, NULL, NULL, NULL, NULL

0 commit comments

Comments
 (0)