summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorStephen Frost2015-09-15 19:49:31 +0000
committerPavan Deolasee2016-10-26 07:45:49 +0000
commit9a2e56b3f9cccffe71cd1691c658bc053200b618 (patch)
tree0fb198415c74f263a631a34bfcbc0e5accd0d0de /src
parent612b9cfc3178966962ff85cd7c571583bbdf2da2 (diff)
Enforce ALL/SELECT policies in RETURNING for RLS
For the UPDATE/DELETE RETURNING case, filter the records which are not visible to the user through ALL or SELECT policies from those considered for the UPDATE or DELETE. This is similar to how the GRANT system works, which prevents RETURNING unless the caller has SELECT rights on the relation. Per discussion with Robert, Dean, Tom, and Kevin. Back-patch to 9.5 where RLS was introduced.
Diffstat (limited to 'src')
-rw-r--r--src/backend/rewrite/rowsecurity.c47
-rw-r--r--src/test/regress/expected/rowsecurity.out3
2 files changed, 47 insertions, 3 deletions
diff --git a/src/backend/rewrite/rowsecurity.c b/src/backend/rewrite/rowsecurity.c
index 69eb9bdb2a..c3d4b7ec14 100644
--- a/src/backend/rewrite/rowsecurity.c
+++ b/src/backend/rewrite/rowsecurity.c
@@ -189,6 +189,33 @@ get_row_security_policies(Query *root, RangeTblEntry *rte, int rt_index,
hasSubLinks);
/*
+ * For the target relation, when there is a returning list, we need to
+ * collect up CMD_SELECT policies and add them via add_security_quals.
+ * This is because, for the RETURNING case, we have to filter any records
+ * which are not visible through an ALL or SELECT USING policy.
+ *
+ * We don't need to worry about the non-target relation case because we are
+ * checking the ALL and SELECT policies for those relations anyway (see
+ * above).
+ */
+ if (root->returningList != NIL &&
+ (commandType == CMD_UPDATE || commandType == CMD_DELETE))
+ {
+ List *returning_permissive_policies;
+ List *returning_restrictive_policies;
+
+ get_policies_for_relation(rel, CMD_SELECT, user_id,
+ &returning_permissive_policies,
+ &returning_restrictive_policies);
+
+ add_security_quals(rt_index,
+ returning_permissive_policies,
+ returning_restrictive_policies,
+ securityQuals,
+ hasSubLinks);
+ }
+
+ /*
* For INSERT and UPDATE, add withCheckOptions to verify that any new
* records added are consistent with the security policies. This will use
* each policy's WITH CHECK clause, or its USING clause if no explicit
@@ -235,6 +262,26 @@ get_row_security_policies(Query *root, RangeTblEntry *rte, int rt_index,
withCheckOptions,
hasSubLinks);
+ /*
+ * Get and add ALL/SELECT policies, if there is a RETURNING clause,
+ * also as WCO policies, again, to avoid silently dropping data.
+ */
+ if (root->returningList != NIL)
+ {
+ List *conflict_returning_permissive_policies = NIL;
+ List *conflict_returning_restrictive_policies = NIL;
+
+ get_policies_for_relation(rel, CMD_SELECT, user_id,
+ &conflict_returning_permissive_policies,
+ &conflict_returning_restrictive_policies);
+ add_with_check_options(rel, rt_index,
+ WCO_RLS_CONFLICT_CHECK,
+ conflict_returning_permissive_policies,
+ conflict_returning_restrictive_policies,
+ withCheckOptions,
+ hasSubLinks);
+ }
+
/* Enforce the WITH CHECK clauses of the UPDATE policies */
add_with_check_options(rel, rt_index,
WCO_RLS_UPDATE_CHECK,
diff --git a/src/test/regress/expected/rowsecurity.out b/src/test/regress/expected/rowsecurity.out
index 576bcafa49..de6b618789 100644
--- a/src/test/regress/expected/rowsecurity.out
+++ b/src/test/regress/expected/rowsecurity.out
@@ -1954,9 +1954,6 @@ DELETE FROM x1 WHERE f_leak(b) RETURNING *;
2 | bcd_updt_updt | rls_regress_user1
6 | fgh_updt_updt | rls_regress_user1
8 | fgh_updt_updt | rls_regress_user2
- 3 | cde_updt | rls_regress_user2
- 7 | fgh_updt | rls_regress_user2
- 4 | def_updt_updt | rls_regress_user2
(6 rows)
--