aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoe Conway <mail@joeconway.com>2015-07-28 16:24:09 -0700
committerJoe Conway <mail@joeconway.com>2015-07-28 16:24:09 -0700
commit344703bcc453ac3ce0060785d4958ddec7d2dbe9 (patch)
treec5b4b2cec7d60f0d402e11eff472c22b70c2e286
parent992c9d345f6607c5b2cab2787f7cf72fba96673d (diff)
downloadpostgresql-344703bcc453ac3ce0060785d4958ddec7d2dbe9.tar.gz
postgresql-344703bcc453ac3ce0060785d4958ddec7d2dbe9.zip
Disallow converting a table to a view if row security is present.
When DefineQueryRewrite() is about to convert a table to a view, it checks the table for features unavailable to views. For example, it rejects tables having triggers. It omits to reject tables having relrowsecurity or a pg_policy record. Fix that. To faciliate the repair, invent relation_has_policies() which indicates the presence of policies on a relation even when row security is disabled for that relation. Reported by Noah Misch. Patch by me, review by Stephen Frost. Back-patch to 9.5 where RLS was introduced.
-rw-r--r--src/backend/commands/policy.c29
-rw-r--r--src/backend/rewrite/rewriteDefine.c24
-rw-r--r--src/include/commands/policy.h1
-rw-r--r--src/test/regress/expected/rowsecurity.out23
-rw-r--r--src/test/regress/sql/rowsecurity.sql25
5 files changed, 97 insertions, 5 deletions
diff --git a/src/backend/commands/policy.c b/src/backend/commands/policy.c
index 9544f75032b..0d4e557d5ab 100644
--- a/src/backend/commands/policy.c
+++ b/src/backend/commands/policy.c
@@ -1037,3 +1037,32 @@ get_relation_policy_oid(Oid relid, const char *policy_name, bool missing_ok)
return policy_oid;
}
+
+/*
+ * relation_has_policies - Determine if relation has any policies
+ */
+bool
+relation_has_policies(Relation rel)
+{
+ Relation catalog;
+ ScanKeyData skey;
+ SysScanDesc sscan;
+ HeapTuple policy_tuple;
+ bool ret = false;
+
+ catalog = heap_open(PolicyRelationId, AccessShareLock);
+ ScanKeyInit(&skey,
+ Anum_pg_policy_polrelid,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(RelationGetRelid(rel)));
+ sscan = systable_beginscan(catalog, PolicyPolrelidPolnameIndexId, true,
+ NULL, 1, &skey);
+ policy_tuple = systable_getnext(sscan);
+ if (HeapTupleIsValid(policy_tuple))
+ ret = true;
+
+ systable_endscan(sscan);
+ heap_close(catalog, AccessShareLock);
+
+ return ret;
+}
diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c
index a88d73e15f2..39c83a605ca 100644
--- a/src/backend/rewrite/rewriteDefine.c
+++ b/src/backend/rewrite/rewriteDefine.c
@@ -27,6 +27,7 @@
#include "catalog/objectaccess.h"
#include "catalog/pg_rewrite.h"
#include "catalog/storage.h"
+#include "commands/policy.h"
#include "miscadmin.h"
#include "nodes/nodeFuncs.h"
#include "parser/parse_utilcmd.h"
@@ -410,11 +411,12 @@ DefineQueryRewrite(char *rulename,
*
* If so, check that the relation is empty because the storage for the
* relation is going to be deleted. Also insist that the rel not have
- * any triggers, indexes, or child tables. (Note: these tests are too
- * strict, because they will reject relations that once had such but
- * don't anymore. But we don't really care, because this whole
- * business of converting relations to views is just a kluge to allow
- * dump/reload of views that participate in circular dependencies.)
+ * any triggers, indexes, child tables, policies, or RLS enabled.
+ * (Note: these tests are too strict, because they will reject
+ * relations that once had such but don't anymore. But we don't
+ * really care, because this whole business of converting relations
+ * to views is just a kluge to allow dump/reload of views that
+ * participate in circular dependencies.)
*/
if (event_relation->rd_rel->relkind != RELKIND_VIEW &&
event_relation->rd_rel->relkind != RELKIND_MATVIEW)
@@ -451,6 +453,18 @@ DefineQueryRewrite(char *rulename,
errmsg("could not convert table \"%s\" to a view because it has child tables",
RelationGetRelationName(event_relation))));
+ if (event_relation->rd_rel->relrowsecurity)
+ ereport(ERROR,
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("could not convert table \"%s\" to a view because it has row security enabled",
+ RelationGetRelationName(event_relation))));
+
+ if (relation_has_policies(event_relation))
+ ereport(ERROR,
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("could not convert table \"%s\" to a view because it has row security policies",
+ RelationGetRelationName(event_relation))));
+
RelisBecomingView = true;
}
}
diff --git a/src/include/commands/policy.h b/src/include/commands/policy.h
index ac322e0db92..be000432312 100644
--- a/src/include/commands/policy.h
+++ b/src/include/commands/policy.h
@@ -31,5 +31,6 @@ extern Oid get_relation_policy_oid(Oid relid, const char *policy_name,
extern ObjectAddress rename_policy(RenameStmt *stmt);
+extern bool relation_has_policies(Relation rel);
#endif /* POLICY_H */
diff --git a/src/test/regress/expected/rowsecurity.out b/src/test/regress/expected/rowsecurity.out
index 4749efc5679..b0f2565b60a 100644
--- a/src/test/regress/expected/rowsecurity.out
+++ b/src/test/regress/expected/rowsecurity.out
@@ -2997,6 +2997,29 @@ DROP ROLE bob; -- succeeds
ROLLBACK TO q;
ROLLBACK; -- cleanup
--
+-- Converting table to view
+--
+BEGIN;
+SET ROW_SECURITY = FORCE;
+CREATE TABLE t (c int);
+CREATE POLICY p ON t USING (c % 2 = 1);
+ALTER TABLE t ENABLE ROW LEVEL SECURITY;
+SAVEPOINT q;
+CREATE RULE "_RETURN" AS ON SELECT TO t DO INSTEAD
+ SELECT * FROM generate_series(1,5) t0(c); -- fails due to row level security enabled
+ERROR: could not convert table "t" to a view because it has row security enabled
+ROLLBACK TO q;
+ALTER TABLE t DISABLE ROW LEVEL SECURITY;
+SAVEPOINT q;
+CREATE RULE "_RETURN" AS ON SELECT TO t DO INSTEAD
+ SELECT * FROM generate_series(1,5) t0(c); -- fails due to policy p on t
+ERROR: could not convert table "t" to a view because it has row security policies
+ROLLBACK TO q;
+DROP POLICY p ON t;
+CREATE RULE "_RETURN" AS ON SELECT TO t DO INSTEAD
+ SELECT * FROM generate_series(1,5) t0(c); -- succeeds
+ROLLBACK;
+--
-- Clean up objects
--
RESET SESSION AUTHORIZATION;
diff --git a/src/test/regress/sql/rowsecurity.sql b/src/test/regress/sql/rowsecurity.sql
index 529edd01c7f..03f82987c47 100644
--- a/src/test/regress/sql/rowsecurity.sql
+++ b/src/test/regress/sql/rowsecurity.sql
@@ -1261,6 +1261,31 @@ ROLLBACK TO q;
ROLLBACK; -- cleanup
--
+-- Converting table to view
+--
+BEGIN;
+SET ROW_SECURITY = FORCE;
+CREATE TABLE t (c int);
+CREATE POLICY p ON t USING (c % 2 = 1);
+ALTER TABLE t ENABLE ROW LEVEL SECURITY;
+
+SAVEPOINT q;
+CREATE RULE "_RETURN" AS ON SELECT TO t DO INSTEAD
+ SELECT * FROM generate_series(1,5) t0(c); -- fails due to row level security enabled
+ROLLBACK TO q;
+
+ALTER TABLE t DISABLE ROW LEVEL SECURITY;
+SAVEPOINT q;
+CREATE RULE "_RETURN" AS ON SELECT TO t DO INSTEAD
+ SELECT * FROM generate_series(1,5) t0(c); -- fails due to policy p on t
+ROLLBACK TO q;
+
+DROP POLICY p ON t;
+CREATE RULE "_RETURN" AS ON SELECT TO t DO INSTEAD
+ SELECT * FROM generate_series(1,5) t0(c); -- succeeds
+ROLLBACK;
+
+--
-- Clean up objects
--
RESET SESSION AUTHORIZATION;