From 2e1689b5fe384d675043beb9df8eff49a0ff436e Mon Sep 17 00:00:00 2001 From: Joseph Koshakow Date: Sun, 9 Jul 2023 12:58:41 -0400 Subject: [PATCH 2/2] Prevent non-superusers from altering session auth Previously, if a user connected with as a role that had the superuser attribute, then they could always execute a SET SESSION AUTHORIZATION statement for the duration of their session. Even if the role was altered to set superuser to false, the user was still allowed to execute SET SESSION AUTHORIZATION. This allowed them to set their session role to some other superuser and effectively regain the superuser privileges. They could even reset their own superuser attribute to true. This commit alters the privilege checks for SET SESSION AUTHORIZATION such that a user can only execute it if the role they connected with is currently a superuser. This prevents users from regaining superuser privileges after it has been revoked. --- doc/src/sgml/ref/set_session_auth.sgml | 2 +- src/backend/utils/init/miscinit.c | 19 +++++++++---------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/doc/src/sgml/ref/set_session_auth.sgml b/doc/src/sgml/ref/set_session_auth.sgml index f8fcafc194..94adab2468 100644 --- a/doc/src/sgml/ref/set_session_auth.sgml +++ b/doc/src/sgml/ref/set_session_auth.sgml @@ -51,7 +51,7 @@ RESET SESSION AUTHORIZATION The session user identifier can be changed only if the initial session - user (the authenticated user) had the + user (the authenticated user) has the superuser privilege. Otherwise, the command is accepted only if it specifies the authenticated user name. diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c index f5548a0f47..1aa393f9fd 100644 --- a/src/backend/utils/init/miscinit.c +++ b/src/backend/utils/init/miscinit.c @@ -467,7 +467,7 @@ ChangeToDataDir(void) * AuthenticatedUserId is determined at connection start and never changes. * * SessionUserId is initially the same as AuthenticatedUserId, but can be - * changed by SET SESSION AUTHORIZATION (if AuthenticatedUserIsSuperuser). + * changed by SET SESSION AUTHORIZATION (if AuthenticatedUserId is a superuser). * This is the ID reported by the SESSION_USER SQL function. * * OuterUserId is the current user ID in effect at the "outer level" (outside @@ -492,8 +492,7 @@ static Oid OuterUserId = InvalidOid; static Oid CurrentUserId = InvalidOid; static const char *SystemUser = NULL; -/* We also have to remember the superuser state of some of these levels */ -static bool AuthenticatedUserIsSuperuser = false; +/* We also have to remember the superuser state of some of the session user */ static bool SessionUserIsSuperuser = false; static int SecurityRestrictionContext = 0; @@ -583,13 +582,13 @@ GetAuthenticatedUserId(void) } /* - * Return whether the authenticated user was superuser at connection start. + * Return whether the authenticated user is currently a superuser. */ bool GetAuthenticatedUserIsSuperuser(void) { Assert(OidIsValid(AuthenticatedUserId)); - return AuthenticatedUserIsSuperuser; + return superuser_arg(AuthenticatedUserId); } @@ -741,6 +740,7 @@ InitializeSessionUserId(const char *rolename, Oid roleid) HeapTuple roleTup; Form_pg_authid rform; char *rname; + bool is_superuser; /* * Don't do scans if we're bootstrapping, none of the system catalogs @@ -780,10 +780,10 @@ InitializeSessionUserId(const char *rolename, Oid roleid) rname = NameStr(rform->rolname); AuthenticatedUserId = roleid; - AuthenticatedUserIsSuperuser = rform->rolsuper; + is_superuser = rform->rolsuper; /* This sets OuterUserId/CurrentUserId too */ - SetSessionUserId(roleid, AuthenticatedUserIsSuperuser); + SetSessionUserId(roleid, is_superuser); /* Also mark our PGPROC entry with the authenticated user id */ /* (We assume this is an atomic store so no lock is needed) */ @@ -816,7 +816,7 @@ InitializeSessionUserId(const char *rolename, Oid roleid) * just document that the connection limit is approximate. */ if (rform->rolconnlimit >= 0 && - !AuthenticatedUserIsSuperuser && + !is_superuser && CountUserBackends(roleid) > rform->rolconnlimit) ereport(FATAL, (errcode(ERRCODE_TOO_MANY_CONNECTIONS), @@ -828,7 +828,7 @@ InitializeSessionUserId(const char *rolename, Oid roleid) SetConfigOption("session_authorization", rname, PGC_BACKEND, PGC_S_OVERRIDE); SetConfigOption("is_superuser", - AuthenticatedUserIsSuperuser ? "on" : "off", + is_superuser ? "on" : "off", PGC_INTERNAL, PGC_S_DYNAMIC_DEFAULT); ReleaseSysCache(roleTup); @@ -851,7 +851,6 @@ InitializeSessionUserIdStandalone(void) Assert(!OidIsValid(AuthenticatedUserId)); AuthenticatedUserId = BOOTSTRAP_SUPERUSERID; - AuthenticatedUserIsSuperuser = true; SetSessionUserId(BOOTSTRAP_SUPERUSERID, true); } -- 2.34.1