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 2077fa89d988e38bccc31d49580197c4b8d42036..70ddae648879660171e826c2b0e333255b010672 100644 (file)
@@ -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 f95f41dfbc353ee2869fddc3b6aa6134255b646b..903aeb56b286ff4b9de73fb4cb6145d342591a18 100644 (file)
@@ -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);