]> granicus.if.org Git - postgresql/commitdiff
Disallow RESET ROLE and RESET SESSION AUTHORIZATION inside security-definer
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 3 Sep 2009 22:08:23 +0000 (22:08 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 3 Sep 2009 22:08:23 +0000 (22:08 +0000)
functions.

This extends the previous patch that forbade SETting these variables inside
security-definer functions.  RESET is equally a security hole, since it
would allow regaining privileges of the caller; furthermore it can trigger
Assert failures and perhaps other internal errors, since the code is not
expecting these variables to change in such contexts.  The previous patch
did not cover this case because assign hooks don't really have enough
information, so move the responsibility for preventing this into guc.c.

Problem discovered by Heikki Linnakangas.

Security: no CVE assigned yet, extends CVE-2007-6600

src/backend/commands/variable.c
src/backend/utils/misc/guc.c
src/include/utils/guc_tables.h

index 2c234071d2119e679e51e1606fc54d93b996bb3b..b16c1d38f60b34786f81cec6b76be6b65f8c5fb0 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/commands/variable.c,v 1.125 2008/01/03 21:23:15 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/commands/variable.c,v 1.125.2.1 2009/09/03 22:08:22 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -717,21 +717,6 @@ assign_session_authorization(const char *value, bool doit, GucSource source)
                /* not a saved ID, so look it up */
                HeapTuple       roleTup;
 
-               if (InSecurityDefinerContext())
-               {
-                       /*
-                        * Disallow SET SESSION AUTHORIZATION inside a security definer
-                        * context.  We need to do this because when we exit the context,
-                        * GUC won't be notified, leaving things out of sync.  Note that
-                        * this test is positioned so that restoring a previously saved
-                        * setting isn't prevented.
-                        */
-                       ereport(GUC_complaint_elevel(source),
-                                       (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-                                        errmsg("cannot set session authorization within security-definer function")));
-                       return NULL;
-               }
-
                if (!IsTransactionState())
                {
                        /*
@@ -838,24 +823,6 @@ assign_role(const char *value, bool doit, GucSource source)
                }
        }
 
-       if (roleid == InvalidOid && InSecurityDefinerContext())
-       {
-               /*
-                * Disallow SET ROLE inside a security definer context.  We need to do
-                * this because when we exit the context, GUC won't be notified,
-                * leaving things out of sync.  Note that this test is arranged so
-                * that restoring a previously saved setting isn't prevented.
-                *
-                * XXX it would be nice to allow this case in future, with the
-                * behavior being that the SET ROLE's effects end when the security
-                * definer context is exited.
-                */
-               ereport(GUC_complaint_elevel(source),
-                               (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-                                errmsg("cannot set role within security-definer function")));
-               return NULL;
-       }
-
        if (roleid == InvalidOid &&
                strcmp(actual_rolename, "none") != 0)
        {
index 19d71151e632438258b9af7d60d9d3e6a1f80bef..c65e5af55b150cdc6bafc13f328a6133fc58c2b8 100644 (file)
@@ -10,7 +10,7 @@
  * Written by Peter Eisentraut <peter_e@gmx.net>.
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.432.2.3 2009/04/02 03:51:50 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.432.2.4 2009/09/03 22:08:22 tgl Exp $
  *
  *--------------------------------------------------------------------
  */
@@ -2224,7 +2224,7 @@ static struct config_string ConfigureNamesString[] =
                {"role", PGC_USERSET, UNGROUPED,
                        gettext_noop("Sets the current role."),
                        NULL,
-                       GUC_IS_NAME | GUC_NO_SHOW_ALL | GUC_NO_RESET_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
+                       GUC_IS_NAME | GUC_NO_SHOW_ALL | GUC_NO_RESET_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_NOT_WHILE_SEC_DEF
                },
                &role_string,
                "none", assign_role, show_role
@@ -2235,7 +2235,7 @@ static struct config_string ConfigureNamesString[] =
                {"session_authorization", PGC_USERSET, UNGROUPED,
                        gettext_noop("Sets the session user name."),
                        NULL,
-                       GUC_IS_NAME | GUC_REPORT | GUC_NO_SHOW_ALL | GUC_NO_RESET_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
+                       GUC_IS_NAME | GUC_REPORT | GUC_NO_SHOW_ALL | GUC_NO_RESET_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_NOT_WHILE_SEC_DEF
                },
                &session_authorization_string,
                NULL, assign_session_authorization, show_session_authorization
@@ -4318,6 +4318,32 @@ set_config_option(const char *name, const char *value,
                        break;
        }
 
+       /*
+        * Disallow changing GUC_NOT_WHILE_SEC_DEF values if we are inside a
+        * security-definer function.  We can reject this regardless of
+        * the context or source, mainly because sources that it might be
+        * reasonable to override for won't be seen while inside a function.
+        *
+        * Note: variables marked GUC_NOT_WHILE_SEC_DEF should probably be marked
+        * GUC_NO_RESET_ALL as well, because ResetAllOptions() doesn't check this.
+        *
+        * Note: this flag is currently used for "session_authorization" and
+        * "role".  We need to prohibit this because when we exit the sec-def
+        * context, GUC won't be notified, leaving things out of sync.
+        *
+        * XXX it would be nice to allow these cases in future, with the behavior
+        * being that the SET's effects end when the security definer context is
+        * exited.
+        */
+       if ((record->flags & GUC_NOT_WHILE_SEC_DEF) && InSecurityDefinerContext())
+       {
+               ereport(elevel,
+                               (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+                                errmsg("cannot set parameter \"%s\" within security-definer function",
+                                               name)));
+               return false;
+       }
+
        /*
         * Should we set reset/stacked values?  (If so, the behavior is not
         * transactional.)      This is done either when we get a default value from
index 3d389acb2f72c04c0ea0db6385690171e7d152a9..0578ab05a8612c18c0dfd340941b85eaf621d5f6 100644 (file)
@@ -7,7 +7,7 @@
  *
  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
  *
- *       $PostgreSQL: pgsql/src/include/utils/guc_tables.h,v 1.38 2008/01/01 19:45:59 momjian Exp $
+ *       $PostgreSQL: pgsql/src/include/utils/guc_tables.h,v 1.38.2.1 2009/09/03 22:08:23 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -148,6 +148,8 @@ struct config_generic
 #define GUC_UNIT_MIN                   0x4000  /* value is in minutes */
 #define GUC_UNIT_TIME                  0x7000  /* mask for MS, S, MIN */
 
+#define GUC_NOT_WHILE_SEC_DEF  0x8000  /* can't change inside sec-def func */
+
 /* bit values in status field */
 #define GUC_IS_IN_FILE         0x0001          /* found it in config file */
 /*