From 7bd7b2002bd018e25d024322c983e856237a50d9 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Thu, 31 Jul 2008 16:27:16 +0000
Subject: [PATCH] Require superuser privilege to create base types (but not
 composites, enums, or domains).  This was already effectively required
 because you had to own the I/O functions, and the I/O functions pretty much
 have to be written in C since we don't let PL functions take or return
 cstring.  But given the possible security consequences of a malicious type
 definition, it seems prudent to enforce superuser requirement directly.  Per
 recent discussion.

---
 doc/src/sgml/ref/create_type.sgml | 14 ++++++++++----
 src/backend/commands/typecmds.c   | 27 ++++++++++++++++++++++++---
 2 files changed, 34 insertions(+), 7 deletions(-)

diff --git a/doc/src/sgml/ref/create_type.sgml b/doc/src/sgml/ref/create_type.sgml
index 665bc805af8..a5d07a21206 100644
--- a/doc/src/sgml/ref/create_type.sgml
+++ b/doc/src/sgml/ref/create_type.sgml
@@ -1,5 +1,5 @@
 <!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/create_type.sgml,v 1.76 2008/07/30 19:35:12 tgl Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/create_type.sgml,v 1.77 2008/07/31 16:27:16 tgl Exp $
 PostgreSQL documentation
 -->
 
@@ -99,7 +99,13 @@ CREATE TYPE <replaceable class="parameter">name</replaceable>
 
   <para>
    The third form of <command>CREATE TYPE</command> creates a new base type
-   (scalar type).  The parameters can appear in any order, not only that
+   (scalar type).  To create a new base type, you must be a superuser.
+   (This restriction is made because an erroneous type definition could
+   confuse or even crash the server.)
+  </para>
+
+  <para>
+   The parameters can appear in any order, not only that
    illustrated above, and most are optional.  You must register
    two or more functions (using <command>CREATE FUNCTION</command>) before
    defining the type.  The support functions
@@ -580,8 +586,8 @@ CREATE TYPE <replaceable class="parameter">name</replaceable>
   <para>
    Because there are no restrictions on use of a data type once it's been
    created, creating a base type is tantamount to granting public execute
-   permission on the functions mentioned in the type definition.  (The creator
-   of the type is therefore required to own these functions.)  This is usually
+   permission on the functions mentioned in the type definition.
+   This is usually
    not an issue for the sorts of functions that are useful in a type
    definition.  But you might want to think twice before designing a type
    in a way that would require <quote>secret</> information to be used
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index 1b3caab2e1b..ee30d32704a 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.121 2008/07/30 19:35:13 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.122 2008/07/31 16:27:16 tgl Exp $
  *
  * DESCRIPTION
  *	  The "DefineFoo" routines take the parse tree and pick out the
@@ -92,14 +92,13 @@ static char *domainAddConstraint(Oid domainOid, Oid domainNamespace,
 
 /*
  * DefineType
- *		Registers a new type.
+ *		Registers a new base type.
  */
 void
 DefineType(List *names, List *parameters)
 {
 	char	   *typeName;
 	Oid			typeNamespace;
-	AclResult	aclresult;
 	int16		internalLength = -1;	/* default: variable-length */
 	Oid			elemType = InvalidOid;
 	List	   *inputName = NIL;
@@ -130,14 +129,33 @@ DefineType(List *names, List *parameters)
 	Oid			resulttype;
 	Relation	pg_type;
 
+	/*
+	 * As of Postgres 8.4, we require superuser privilege to create a base
+	 * type.  This is simple paranoia: there are too many ways to mess up the
+	 * system with an incorrect type definition (for instance, representation
+	 * parameters that don't match what the C code expects).  In practice
+	 * it takes superuser privilege to create the I/O functions, and so the
+	 * former requirement that you own the I/O functions pretty much forced
+	 * superuserness anyway.  We're just making doubly sure here.
+	 *
+	 * XXX re-enable NOT_USED code sections below if you remove this test.
+	 */
+	if (!superuser())
+		ereport(ERROR,
+				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+				 errmsg("must be superuser to create a base type")));
+
 	/* Convert list of names to a name and namespace */
 	typeNamespace = QualifiedNameGetCreationNamespace(names, &typeName);
 
+#ifdef NOT_USED
+	/* XXX this is unnecessary given the superuser check above */
 	/* Check we have creation rights in target namespace */
 	aclresult = pg_namespace_aclcheck(typeNamespace, GetUserId(), ACL_CREATE);
 	if (aclresult != ACLCHECK_OK)
 		aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
 					   get_namespace_name(typeNamespace));
+#endif
 
 	/*
 	 * Look to see if type already exists (presumably as a shell; if not,
@@ -398,6 +416,8 @@ DefineType(List *names, List *parameters)
 	 * don't have a way to make the type go away if the grant option is
 	 * revoked, so ownership seems better.
 	 */
+#ifdef NOT_USED
+	/* XXX this is unnecessary given the superuser check above */
 	if (inputOid && !pg_proc_ownercheck(inputOid, GetUserId()))
 		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
 					   NameListToString(inputName));
@@ -419,6 +439,7 @@ DefineType(List *names, List *parameters)
 	if (analyzeOid && !pg_proc_ownercheck(analyzeOid, GetUserId()))
 		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
 					   NameListToString(analyzeName));
+#endif
 
 	/* Preassign array type OID so we can insert it in pg_type.typarray */
 	pg_type = heap_open(TypeRelationId, AccessShareLock);
-- 
GitLab