Require superuser privilege to create base types (but not composites, enums,
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 31 Jul 2008 16:27:16 +0000 (16:27 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 31 Jul 2008 16:27:16 +0000 (16:27 +0000)
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
src/backend/commands/typecmds.c

index 665bc805af8d45369e58f7187452b12efa44c19c..a5d07a2120631a1053dffa0d29e856379d4dead0 100644 (file)
@@ -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
index 1b3caab2e1b39b5552cf53d5a1d855f9627b0b44..ee30d32704ab7b393b459fedbac1fbd13f65d5b7 100644 (file)
@@ -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);