Add permission checks on SELECT INTO

Started by Kohei KaiGaiabout 14 years ago1 messages
#1Kohei KaiGai
kaigai@kaigai.gr.jp
1 attachment(s)

This patch adds checks of INSERT permission on new tables constructed
by SELECT INTO or CREATE TABLE AS.

It does not change existing behavior except for tiny bit of cases when
a default privilege setting does not allow owner to insert tuples,
because table's default acl allows everything to its owner.
However, this check has significant meaning from the perspective of
mac; to prevent a user who can reference credential information to
write-out tables with public label; this characteristic is called as
data-flow-control.

Please also see the previous discussion as: http://bit.ly/uxeOhO

Thanks,
--
KaiGai Kohei <kaigai@kaigai.gr.jp>

Attachments:

pgsql-v9.2-add-select-into-checks.v1.patchapplication/octet-stream; name=pgsql-v9.2-add-select-into-checks.v1.patchDownload
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index fd7a9ed..4b28bfd 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -2395,6 +2395,8 @@ OpenIntoRel(QueryDesc *queryDesc)
 	Datum		reloptions;
 	Oid			intoRelationId;
 	DR_intorel *myState;
+	RangeTblEntry  *rte;
+	AttrNumber		attnum;
 	static char *validnsps[] = HEAP_RELOPT_NAMESPACES;
 
 	Assert(into);
@@ -2517,6 +2519,21 @@ OpenIntoRel(QueryDesc *queryDesc)
 	intoRelationDesc = heap_open(intoRelationId, AccessExclusiveLock);
 
 	/*
+	 * check INSERT permission on the constructed table.
+	 */
+	rte = makeNode(RangeTblEntry);
+	rte->rtekind = RTE_RELATION;
+	rte->relid = intoRelationId;
+	rte->relkind = RELKIND_RELATION;
+	rte->requiredPerms = ACL_INSERT;
+
+	for (attnum = 0; attnum < queryDesc->tupDesc->natts; attnum++)
+		rte->modifiedCols = bms_add_member(rte->modifiedCols,
+				attnum - FirstLowInvalidHeapAttributeNumber);
+
+	ExecCheckRTPerms(list_make1(rte), true);
+
+	/*
 	 * Now replace the query's DestReceiver with one for SELECT INTO
 	 */
 	queryDesc->dest = CreateDestReceiver(DestIntoRel);
diff --git a/src/test/regress/expected/select_into.out b/src/test/regress/expected/select_into.out
index 503efe0..777268e 100644
--- a/src/test/regress/expected/select_into.out
+++ b/src/test/regress/expected/select_into.out
@@ -11,3 +11,17 @@ SELECT *
    FROM onek2
    WHERE onek2.unique1 < 2;
 DROP TABLE tmp1;
+--
+-- SELECT INTO and INSERT permission, if owner is not allowed to insert.
+--
+CREATE SCHEMA selinto_schema;
+CREATE USER selinto_user;
+ALTER DEFAULT PRIVILEGES IN SCHEMA selinto_schema
+	  REVOKE INSERT ON TABLES FROM selinto_user;
+SET SESSION AUTHORIZATION selinto_user;
+SELECT * INTO TABLE selinto_schema.tmp1
+	  FROM onek WHERE onek.unique1 < 2;	-- Error
+ERROR:  permission denied for relation onek
+RESET SESSION AUTHORIZATION;
+DROP SCHEMA selinto_schema CASCADE;
+DROP USER selinto_user;
diff --git a/src/test/regress/sql/select_into.sql b/src/test/regress/sql/select_into.sql
index 2fa3d1e..4b4ff1c 100644
--- a/src/test/regress/sql/select_into.sql
+++ b/src/test/regress/sql/select_into.sql
@@ -15,3 +15,19 @@ SELECT *
    WHERE onek2.unique1 < 2;
 
 DROP TABLE tmp1;
+
+--
+-- SELECT INTO and INSERT permission, if owner is not allowed to insert.
+--
+CREATE SCHEMA selinto_schema;
+CREATE USER selinto_user;
+ALTER DEFAULT PRIVILEGES IN SCHEMA selinto_schema
+	  REVOKE INSERT ON TABLES FROM selinto_user;
+
+SET SESSION AUTHORIZATION selinto_user;
+SELECT * INTO TABLE selinto_schema.tmp1
+	  FROM onek WHERE onek.unique1 < 2;	-- Error
+RESET SESSION AUTHORIZATION;
+
+DROP SCHEMA selinto_schema CASCADE;
+DROP USER selinto_user;