From 1564e92cea27a22ace7da635fe73fc23f96f8d4e Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Fri, 13 Jan 2006 18:06:45 +0000
Subject: [PATCH] Require the issuer of CREATE TYPE to own the functions
 mentioned in the type definition.  Because use of a type's I/O conversion
 functions isn't access-checked, CREATE TYPE amounts to granting public
 execute permissions on the functions, and so allowing it to anybody means
 that someone could theoretically gain access to a function he's not supposed
 to be able to execute.  The parameter-type restrictions already enforced by
 CREATE TYPE make it fairly unlikely that this oversight is meaningful in
 practice, but still it seems like a good idea to plug the hole going forward.
 Also, document the implicit grant just in case anybody gets the idea of
 building I/O functions that might need security restrictions.

---
 doc/src/sgml/ref/create_type.sgml | 13 ++++++++++++-
 src/backend/commands/typecmds.c   | 26 +++++++++++++++++++++++++-
 2 files changed, 37 insertions(+), 2 deletions(-)

diff --git a/doc/src/sgml/ref/create_type.sgml b/doc/src/sgml/ref/create_type.sgml
index 1205605ca36..a39c244c6c7 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.59 2005/11/01 21:09:50 tgl Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/create_type.sgml,v 1.60 2006/01/13 18:06:45 tgl Exp $
 PostgreSQL documentation
 -->
 
@@ -446,6 +446,17 @@ CREATE TYPE <replaceable class="parameter">name</replaceable> (
    internally-created array type names.
   </para>
 
+  <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
+   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
+   while converting it to or from external form.
+  </para>
+
   <para>
    In <productname>PostgreSQL</productname> versions before 7.3, it
    was customary to avoid creating a shell type by replacing the
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index 389fe133a58..143695252f4 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.85 2005/11/22 18:17:09 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.86 2006/01/13 18:06:45 tgl Exp $
  *
  * DESCRIPTION
  *	  The "DefineFoo" routines take the parse tree and pick out the
@@ -330,6 +330,30 @@ DefineType(List *names, List *parameters)
 	if (analyzeName)
 		analyzeOid = findTypeAnalyzeFunction(analyzeName, typoid);
 
+	/*
+	 * Check permissions on functions.  We choose to require the creator/owner
+	 * of a type to also own the underlying functions.  Since creating a type
+	 * is tantamount to granting public execute access on the functions, the
+	 * minimum sane check would be for execute-with-grant-option.  But we don't
+	 * have a way to make the type go away if the grant option is revoked, so
+	 * ownership seems better.
+	 */
+	if (inputOid && !pg_proc_ownercheck(inputOid, GetUserId()))
+		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
+					   NameListToString(inputName));
+	if (outputOid && !pg_proc_ownercheck(outputOid, GetUserId()))
+		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
+					   NameListToString(outputName));
+	if (receiveOid && !pg_proc_ownercheck(receiveOid, GetUserId()))
+		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
+					   NameListToString(receiveName));
+	if (sendOid && !pg_proc_ownercheck(sendOid, GetUserId()))
+		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
+					   NameListToString(sendName));
+	if (analyzeOid && !pg_proc_ownercheck(analyzeOid, GetUserId()))
+		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
+					   NameListToString(analyzeName));
+
 	/*
 	 * now have TypeCreate do all the real work.
 	 */
-- 
GitLab