Skip to content

Commit 3e6e86a

Browse files
committed
pg_dump: avoid unsafe function calls in getPolicies().
getPolicies() had the same disease I fixed in other places in commit e3fcbbd, i.e., it was calling pg_get_expr() for expressions on tables that we don't necessarily have lock on. To fix, restrict the query to only collect interesting rows, rather than doing the filtering on the client side. Like the previous patch, apply to HEAD only for now. Discussion: https://postgr.es/m/[email protected] Discussion: https://postgr.es/m/[email protected]
1 parent d5e8930 commit 3e6e86a

File tree

1 file changed

+29
-13
lines changed

1 file changed

+29
-13
lines changed

src/bin/pg_dump/pg_dump.c

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3473,6 +3473,7 @@ void
34733473
getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
34743474
{
34753475
PQExpBuffer query;
3476+
PQExpBuffer tbloids;
34763477
PGresult *res;
34773478
PolicyInfo *polinfo;
34783479
int i_oid;
@@ -3488,15 +3489,17 @@ getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
34883489
j,
34893490
ntups;
34903491

3492+
/* No policies before 9.5 */
34913493
if (fout->remoteVersion < 90500)
34923494
return;
34933495

34943496
query = createPQExpBuffer();
3497+
tbloids = createPQExpBuffer();
34953498

34963499
/*
3497-
* First, check which tables have RLS enabled. We represent RLS being
3498-
* enabled on a table by creating a PolicyInfo object with null polname.
3500+
* Identify tables of interest, and check which ones have RLS enabled.
34993501
*/
3502+
appendPQExpBufferChar(tbloids, '{');
35003503
for (i = 0; i < numTables; i++)
35013504
{
35023505
TableInfo *tbinfo = &tblinfo[i];
@@ -3505,11 +3508,25 @@ getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
35053508
if (!(tbinfo->dobj.dump & DUMP_COMPONENT_POLICY))
35063509
continue;
35073510

3511+
/* It can't have RLS or policies if it's not a table */
3512+
if (tbinfo->relkind != RELKIND_RELATION &&
3513+
tbinfo->relkind != RELKIND_PARTITIONED_TABLE)
3514+
continue;
3515+
3516+
/* Add it to the list of table OIDs to be probed below */
3517+
if (tbloids->len > 1) /* do we have more than the '{'? */
3518+
appendPQExpBufferChar(tbloids, ',');
3519+
appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
3520+
3521+
/* Is RLS enabled? (That's separate from whether it has policies) */
35083522
if (tbinfo->rowsec)
35093523
{
35103524
tbinfo->dobj.components |= DUMP_COMPONENT_POLICY;
35113525

35123526
/*
3527+
* We represent RLS being enabled on a table by creating a
3528+
* PolicyInfo object with null polname.
3529+
*
35133530
* Note: use tableoid 0 so that this object won't be mistaken for
35143531
* something that pg_depend entries apply to.
35153532
*/
@@ -3529,15 +3546,18 @@ getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
35293546
polinfo->polwithcheck = NULL;
35303547
}
35313548
}
3549+
appendPQExpBufferChar(tbloids, '}');
35323550

35333551
/*
3534-
* Now, read all RLS policies, and create PolicyInfo objects for all those
3535-
* that are of interest.
3552+
* Now, read all RLS policies belonging to the tables of interest, and
3553+
* create PolicyInfo objects for them. (Note that we must filter the
3554+
* results server-side not locally, because we dare not apply pg_get_expr
3555+
* to tables we don't have lock on.)
35363556
*/
35373557
pg_log_info("reading row-level security policies");
35383558

35393559
printfPQExpBuffer(query,
3540-
"SELECT oid, tableoid, pol.polrelid, pol.polname, pol.polcmd, ");
3560+
"SELECT pol.oid, pol.tableoid, pol.polrelid, pol.polname, pol.polcmd, ");
35413561
if (fout->remoteVersion >= 100000)
35423562
appendPQExpBuffer(query, "pol.polpermissive, ");
35433563
else
@@ -3547,7 +3567,9 @@ getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
35473567
" pg_catalog.array_to_string(ARRAY(SELECT pg_catalog.quote_ident(rolname) from pg_catalog.pg_roles WHERE oid = ANY(pol.polroles)), ', ') END AS polroles, "
35483568
"pg_catalog.pg_get_expr(pol.polqual, pol.polrelid) AS polqual, "
35493569
"pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid) AS polwithcheck "
3550-
"FROM pg_catalog.pg_policy pol");
3570+
"FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
3571+
"JOIN pg_catalog.pg_policy pol ON (src.tbloid = pol.polrelid)",
3572+
tbloids->data);
35513573

35523574
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
35533575

@@ -3571,13 +3593,6 @@ getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
35713593
Oid polrelid = atooid(PQgetvalue(res, j, i_polrelid));
35723594
TableInfo *tbinfo = findTableByOid(polrelid);
35733595

3574-
/*
3575-
* Ignore row security on tables not to be dumped. (This will
3576-
* result in some harmless wasted slots in polinfo[].)
3577-
*/
3578-
if (!(tbinfo->dobj.dump & DUMP_COMPONENT_POLICY))
3579-
continue;
3580-
35813596
tbinfo->dobj.components |= DUMP_COMPONENT_POLICY;
35823597

35833598
polinfo[j].dobj.objType = DO_POLICY;
@@ -3614,6 +3629,7 @@ getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
36143629
PQclear(res);
36153630

36163631
destroyPQExpBuffer(query);
3632+
destroyPQExpBuffer(tbloids);
36173633
}
36183634

36193635
/*

0 commit comments

Comments
 (0)