Skip to content

Commit 03ac485

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. Back-patch of commit 3e6e86a. That's been in v15/HEAD long enough to have some confidence about it, so now let's fix the problem in older branches. Discussion: https://postgr.es/m/2273648.1634764485@sss.pgh.pa.us Discussion: https://postgr.es/m/7d7eb6128f40401d81b3b7a898b6b4de@W2012-02.nidsa.loc Discussion: https://postgr.es/m/45c93d57-9973-248e-d2df-e02ca9af48d4@darold.net
1 parent 55f30e6 commit 03ac485

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
@@ -3761,6 +3761,7 @@ void
37613761
getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
37623762
{
37633763
PQExpBuffer query;
3764+
PQExpBuffer tbloids;
37643765
PGresult *res;
37653766
PolicyInfo *polinfo;
37663767
int i_oid;
@@ -3776,15 +3777,17 @@ getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
37763777
j,
37773778
ntups;
37783779

3780+
/* No policies before 9.5 */
37793781
if (fout->remoteVersion < 90500)
37803782
return;
37813783

37823784
query = createPQExpBuffer();
3785+
tbloids = createPQExpBuffer();
37833786

37843787
/*
3785-
* First, check which tables have RLS enabled. We represent RLS being
3786-
* enabled on a table by creating a PolicyInfo object with null polname.
3788+
* Identify tables of interest, and check which ones have RLS enabled.
37873789
*/
3790+
appendPQExpBufferChar(tbloids, '{');
37883791
for (i = 0; i < numTables; i++)
37893792
{
37903793
TableInfo *tbinfo = &tblinfo[i];
@@ -3793,9 +3796,23 @@ getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
37933796
if (!(tbinfo->dobj.dump & DUMP_COMPONENT_POLICY))
37943797
continue;
37953798

3799+
/* It can't have RLS or policies if it's not a table */
3800+
if (tbinfo->relkind != RELKIND_RELATION &&
3801+
tbinfo->relkind != RELKIND_PARTITIONED_TABLE)
3802+
continue;
3803+
3804+
/* Add it to the list of table OIDs to be probed below */
3805+
if (tbloids->len > 1) /* do we have more than the '{'? */
3806+
appendPQExpBufferChar(tbloids, ',');
3807+
appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
3808+
3809+
/* Is RLS enabled? (That's separate from whether it has policies) */
37963810
if (tbinfo->rowsec)
37973811
{
37983812
/*
3813+
* We represent RLS being enabled on a table by creating a
3814+
* PolicyInfo object with null polname.
3815+
*
37993816
* Note: use tableoid 0 so that this object won't be mistaken for
38003817
* something that pg_depend entries apply to.
38013818
*/
@@ -3815,15 +3832,18 @@ getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
38153832
polinfo->polwithcheck = NULL;
38163833
}
38173834
}
3835+
appendPQExpBufferChar(tbloids, '}');
38183836

38193837
/*
3820-
* Now, read all RLS policies, and create PolicyInfo objects for all those
3821-
* that are of interest.
3838+
* Now, read all RLS policies belonging to the tables of interest, and
3839+
* create PolicyInfo objects for them. (Note that we must filter the
3840+
* results server-side not locally, because we dare not apply pg_get_expr
3841+
* to tables we don't have lock on.)
38223842
*/
38233843
pg_log_info("reading row-level security policies");
38243844

38253845
printfPQExpBuffer(query,
3826-
"SELECT oid, tableoid, pol.polrelid, pol.polname, pol.polcmd, ");
3846+
"SELECT pol.oid, pol.tableoid, pol.polrelid, pol.polname, pol.polcmd, ");
38273847
if (fout->remoteVersion >= 100000)
38283848
appendPQExpBuffer(query, "pol.polpermissive, ");
38293849
else
@@ -3833,7 +3853,9 @@ getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
38333853
" 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, "
38343854
"pg_catalog.pg_get_expr(pol.polqual, pol.polrelid) AS polqual, "
38353855
"pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid) AS polwithcheck "
3836-
"FROM pg_catalog.pg_policy pol");
3856+
"FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
3857+
"JOIN pg_catalog.pg_policy pol ON (src.tbloid = pol.polrelid)",
3858+
tbloids->data);
38373859

38383860
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
38393861

@@ -3857,13 +3879,6 @@ getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
38573879
Oid polrelid = atooid(PQgetvalue(res, j, i_polrelid));
38583880
TableInfo *tbinfo = findTableByOid(polrelid);
38593881

3860-
/*
3861-
* Ignore row security on tables not to be dumped. (This will
3862-
* result in some harmless wasted slots in polinfo[].)
3863-
*/
3864-
if (!(tbinfo->dobj.dump & DUMP_COMPONENT_POLICY))
3865-
continue;
3866-
38673882
polinfo[j].dobj.objType = DO_POLICY;
38683883
polinfo[j].dobj.catId.tableoid =
38693884
atooid(PQgetvalue(res, j, i_tableoid));
@@ -3898,6 +3913,7 @@ getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
38983913
PQclear(res);
38993914

39003915
destroyPQExpBuffer(query);
3916+
destroyPQExpBuffer(tbloids);
39013917
}
39023918

39033919
/*

0 commit comments

Comments
 (0)