diff options
Diffstat (limited to 'meta-oe/recipes-support')
-rw-r--r-- | meta-oe/recipes-support/postgresql/files/0003-Shore-up-ADMIN-OPTION-restrictions.patch | 273 | ||||
-rw-r--r-- | meta-oe/recipes-support/postgresql/postgresql.inc | 1 |
2 files changed, 274 insertions, 0 deletions
diff --git a/meta-oe/recipes-support/postgresql/files/0003-Shore-up-ADMIN-OPTION-restrictions.patch b/meta-oe/recipes-support/postgresql/files/0003-Shore-up-ADMIN-OPTION-restrictions.patch new file mode 100644 index 0000000000..abbe142495 --- /dev/null +++ b/meta-oe/recipes-support/postgresql/files/0003-Shore-up-ADMIN-OPTION-restrictions.patch @@ -0,0 +1,273 @@ +From 15a8f97b9d16aaf659f58c981242b9da591cf24c Mon Sep 17 00:00:00 2001 +From: Noah Misch <noah@leadboat.com> +Date: Mon, 17 Feb 2014 09:33:31 -0500 +Subject: [PATCH] Shore up ADMIN OPTION restrictions. + +commit 15a8f97b9d16aaf659f58c981242b9da591cf24c REL9_2_STABLE + +Granting a role without ADMIN OPTION is supposed to prevent the grantee +from adding or removing members from the granted role. Issuing SET ROLE +before the GRANT bypassed that, because the role itself had an implicit +right to add or remove members. Plug that hole by recognizing that +implicit right only when the session user matches the current role. +Additionally, do not recognize it during a security-restricted operation +or during execution of a SECURITY DEFINER function. The restriction on +SECURITY DEFINER is not security-critical. However, it seems best for a +user testing his own SECURITY DEFINER function to see the same behavior +others will see. Back-patch to 8.4 (all supported versions). + +The SQL standards do not conflate roles and users as PostgreSQL does; +only SQL roles have members, and only SQL users initiate sessions. An +application using PostgreSQL users and roles as SQL users and roles will +never attempt to grant membership in the role that is the session user, +so the implicit right to add or remove members will never arise. + +The security impact was mostly that a role member could revoke access +from others, contrary to the wishes of his own grantor. Unapproved role +member additions are less notable, because the member can still largely +achieve that by creating a view or a SECURITY DEFINER function. + +Reviewed by Andres Freund and Tom Lane. Reported, independently, by +Jonas Sundman and Noah Misch. + +Security: CVE-2014-0060 + + +Upstream-Status: Backport + +Signed-off-by: Kai Kang <kai.kang@windriver.com> +--- + doc/src/sgml/ref/grant.sgml | 12 ++++--- + src/backend/commands/user.c | 11 ++++++- + src/backend/utils/adt/acl.c | 50 ++++++++++++++++++++++++------ + src/test/regress/expected/privileges.out | 36 +++++++++++++++++++++- + src/test/regress/sql/privileges.sql | 29 ++++++++++++++++- + 5 files changed, 120 insertions(+), 18 deletions(-) + +diff --git a/doc/src/sgml/ref/grant.sgml b/doc/src/sgml/ref/grant.sgml +index fb81af4..2b5a843 100644 +--- a/doc/src/sgml/ref/grant.sgml ++++ b/doc/src/sgml/ref/grant.sgml +@@ -396,11 +396,13 @@ GRANT <replaceable class="PARAMETER">role_name</replaceable> [, ...] TO <replace + <para> + If <literal>WITH ADMIN OPTION</literal> is specified, the member can + in turn grant membership in the role to others, and revoke membership +- in the role as well. Without the admin option, ordinary users cannot do +- that. However, +- database superusers can grant or revoke membership in any role to anyone. +- Roles having <literal>CREATEROLE</> privilege can grant or revoke +- membership in any role that is not a superuser. ++ in the role as well. Without the admin option, ordinary users cannot ++ do that. A role is not considered to hold <literal>WITH ADMIN ++ OPTION</literal> on itself, but it may grant or revoke membership in ++ itself from a database session where the session user matches the ++ role. Database superusers can grant or revoke membership in any role ++ to anyone. Roles having <literal>CREATEROLE</> privilege can grant ++ or revoke membership in any role that is not a superuser. + </para> + + <para> +diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c +index a22092c..39bf172 100644 +--- a/src/backend/commands/user.c ++++ b/src/backend/commands/user.c +@@ -1334,7 +1334,16 @@ AddRoleMems(const char *rolename, Oid roleid, + rolename))); + } + +- /* XXX not sure about this check */ ++ /* ++ * The role membership grantor of record has little significance at ++ * present. Nonetheless, inasmuch as users might look to it for a crude ++ * audit trail, let only superusers impute the grant to a third party. ++ * ++ * Before lifting this restriction, give the member == role case of ++ * is_admin_of_role() a fresh look. Ensure that the current role cannot ++ * use an explicit grantor specification to take advantage of the session ++ * user's self-admin right. ++ */ + if (grantorId != GetUserId() && !superuser()) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), +diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c +index 1d6ae8b..9a52edb 100644 +--- a/src/backend/utils/adt/acl.c ++++ b/src/backend/utils/adt/acl.c +@@ -4580,6 +4580,11 @@ pg_role_aclcheck(Oid role_oid, Oid roleid, AclMode mode) + { + if (mode & ACL_GRANT_OPTION_FOR(ACL_CREATE)) + { ++ /* ++ * XXX For roleid == role_oid, is_admin_of_role() also examines the ++ * session and call stack. That suits two-argument pg_has_role(), but ++ * it gives the three-argument version a lamentable whimsy. ++ */ + if (is_admin_of_role(roleid, role_oid)) + return ACLCHECK_OK; + } +@@ -4897,11 +4902,9 @@ is_member_of_role_nosuper(Oid member, Oid role) + + + /* +- * Is member an admin of role (directly or indirectly)? That is, is it +- * a member WITH ADMIN OPTION? +- * +- * We could cache the result as for is_member_of_role, but currently this +- * is not used in any performance-critical paths, so we don't. ++ * Is member an admin of role? That is, is member the role itself (subject to ++ * restrictions below), a member (directly or indirectly) WITH ADMIN OPTION, ++ * or a superuser? + */ + bool + is_admin_of_role(Oid member, Oid role) +@@ -4910,14 +4913,41 @@ is_admin_of_role(Oid member, Oid role) + List *roles_list; + ListCell *l; + +- /* Fast path for simple case */ +- if (member == role) +- return true; +- +- /* Superusers have every privilege, so are part of every role */ + if (superuser_arg(member)) + return true; + ++ if (member == role) ++ /* ++ * A role can admin itself when it matches the session user and we're ++ * outside any security-restricted operation, SECURITY DEFINER or ++ * similar context. SQL-standard roles cannot self-admin. However, ++ * SQL-standard users are distinct from roles, and they are not ++ * grantable like roles: PostgreSQL's role-user duality extends the ++ * standard. Checking for a session user match has the effect of ++ * letting a role self-admin only when it's conspicuously behaving ++ * like a user. Note that allowing self-admin under a mere SET ROLE ++ * would make WITH ADMIN OPTION largely irrelevant; any member could ++ * SET ROLE to issue the otherwise-forbidden command. ++ * ++ * Withholding self-admin in a security-restricted operation prevents ++ * object owners from harnessing the session user identity during ++ * administrative maintenance. Suppose Alice owns a database, has ++ * issued "GRANT alice TO bob", and runs a daily ANALYZE. Bob creates ++ * an alice-owned SECURITY DEFINER function that issues "REVOKE alice ++ * FROM carol". If he creates an expression index calling that ++ * function, Alice will attempt the REVOKE during each ANALYZE. ++ * Checking InSecurityRestrictedOperation() thwarts that attack. ++ * ++ * Withholding self-admin in SECURITY DEFINER functions makes their ++ * behavior independent of the calling user. There's no security or ++ * SQL-standard-conformance need for that restriction, though. ++ * ++ * A role cannot have actual WITH ADMIN OPTION on itself, because that ++ * would imply a membership loop. Therefore, we're done either way. ++ */ ++ return member == GetSessionUserId() && ++ !InLocalUserIdChange() && !InSecurityRestrictedOperation(); ++ + /* + * Find all the roles that member is a member of, including multi-level + * recursion. We build a list in the same way that is_member_of_role does +diff --git a/src/test/regress/expected/privileges.out b/src/test/regress/expected/privileges.out +index e8930cb..bc6d731 100644 +--- a/src/test/regress/expected/privileges.out ++++ b/src/test/regress/expected/privileges.out +@@ -32,7 +32,7 @@ ALTER GROUP regressgroup1 ADD USER regressuser4; + ALTER GROUP regressgroup2 ADD USER regressuser2; -- duplicate + NOTICE: role "regressuser2" is already a member of role "regressgroup2" + ALTER GROUP regressgroup2 DROP USER regressuser2; +-ALTER GROUP regressgroup2 ADD USER regressuser4; ++GRANT regressgroup2 TO regressuser4 WITH ADMIN OPTION; + -- test owner privileges + SET SESSION AUTHORIZATION regressuser1; + SELECT session_user, current_user; +@@ -929,6 +929,40 @@ SELECT has_table_privilege('regressuser1', 'atest4', 'SELECT WITH GRANT OPTION') + t + (1 row) + ++-- Admin options ++SET SESSION AUTHORIZATION regressuser4; ++CREATE FUNCTION dogrant_ok() RETURNS void LANGUAGE sql SECURITY DEFINER AS ++ 'GRANT regressgroup2 TO regressuser5'; ++GRANT regressgroup2 TO regressuser5; -- ok: had ADMIN OPTION ++SET ROLE regressgroup2; ++GRANT regressgroup2 TO regressuser5; -- fails: SET ROLE suspended privilege ++ERROR: must have admin option on role "regressgroup2" ++SET SESSION AUTHORIZATION regressuser1; ++GRANT regressgroup2 TO regressuser5; -- fails: no ADMIN OPTION ++ERROR: must have admin option on role "regressgroup2" ++SELECT dogrant_ok(); -- ok: SECURITY DEFINER conveys ADMIN ++NOTICE: role "regressuser5" is already a member of role "regressgroup2" ++CONTEXT: SQL function "dogrant_ok" statement 1 ++ dogrant_ok ++------------ ++ ++(1 row) ++ ++SET ROLE regressgroup2; ++GRANT regressgroup2 TO regressuser5; -- fails: SET ROLE did not help ++ERROR: must have admin option on role "regressgroup2" ++SET SESSION AUTHORIZATION regressgroup2; ++GRANT regressgroup2 TO regressuser5; -- ok: a role can self-admin ++NOTICE: role "regressuser5" is already a member of role "regressgroup2" ++CREATE FUNCTION dogrant_fails() RETURNS void LANGUAGE sql SECURITY DEFINER AS ++ 'GRANT regressgroup2 TO regressuser5'; ++SELECT dogrant_fails(); -- fails: no self-admin in SECURITY DEFINER ++ERROR: must have admin option on role "regressgroup2" ++CONTEXT: SQL function "dogrant_fails" statement 1 ++DROP FUNCTION dogrant_fails(); ++SET SESSION AUTHORIZATION regressuser4; ++DROP FUNCTION dogrant_ok(); ++REVOKE regressgroup2 FROM regressuser5; + -- has_sequence_privilege tests + \c - + CREATE SEQUENCE x_seq; +diff --git a/src/test/regress/sql/privileges.sql b/src/test/regress/sql/privileges.sql +index d4d328e..5f1018a 100644 +--- a/src/test/regress/sql/privileges.sql ++++ b/src/test/regress/sql/privileges.sql +@@ -37,7 +37,7 @@ ALTER GROUP regressgroup1 ADD USER regressuser4; + + ALTER GROUP regressgroup2 ADD USER regressuser2; -- duplicate + ALTER GROUP regressgroup2 DROP USER regressuser2; +-ALTER GROUP regressgroup2 ADD USER regressuser4; ++GRANT regressgroup2 TO regressuser4 WITH ADMIN OPTION; + + -- test owner privileges + +@@ -581,6 +581,33 @@ SELECT has_table_privilege('regressuser3', 'atest4', 'SELECT'); -- false + SELECT has_table_privilege('regressuser1', 'atest4', 'SELECT WITH GRANT OPTION'); -- true + + ++-- Admin options ++ ++SET SESSION AUTHORIZATION regressuser4; ++CREATE FUNCTION dogrant_ok() RETURNS void LANGUAGE sql SECURITY DEFINER AS ++ 'GRANT regressgroup2 TO regressuser5'; ++GRANT regressgroup2 TO regressuser5; -- ok: had ADMIN OPTION ++SET ROLE regressgroup2; ++GRANT regressgroup2 TO regressuser5; -- fails: SET ROLE suspended privilege ++ ++SET SESSION AUTHORIZATION regressuser1; ++GRANT regressgroup2 TO regressuser5; -- fails: no ADMIN OPTION ++SELECT dogrant_ok(); -- ok: SECURITY DEFINER conveys ADMIN ++SET ROLE regressgroup2; ++GRANT regressgroup2 TO regressuser5; -- fails: SET ROLE did not help ++ ++SET SESSION AUTHORIZATION regressgroup2; ++GRANT regressgroup2 TO regressuser5; -- ok: a role can self-admin ++CREATE FUNCTION dogrant_fails() RETURNS void LANGUAGE sql SECURITY DEFINER AS ++ 'GRANT regressgroup2 TO regressuser5'; ++SELECT dogrant_fails(); -- fails: no self-admin in SECURITY DEFINER ++DROP FUNCTION dogrant_fails(); ++ ++SET SESSION AUTHORIZATION regressuser4; ++DROP FUNCTION dogrant_ok(); ++REVOKE regressgroup2 FROM regressuser5; ++ ++ + -- has_sequence_privilege tests + \c - + +-- +1.7.5.4 + diff --git a/meta-oe/recipes-support/postgresql/postgresql.inc b/meta-oe/recipes-support/postgresql/postgresql.inc index 9b242e0476..d6a4cd781f 100644 --- a/meta-oe/recipes-support/postgresql/postgresql.inc +++ b/meta-oe/recipes-support/postgresql/postgresql.inc @@ -32,6 +32,7 @@ SRC_URI = "http://ftp.postgresql.org/pub/source/v${PV}/${BP}.tar.bz2 \ file://postgresql.service \ file://0001-Use-pkg-config-for-libxml2-detection.patch \ file://0002-Predict-integer-overflow-to-avoid-buffer-overruns.patch \ + file://0003-Shore-up-ADMIN-OPTION-restrictions.patch \ " LEAD_SONAME = "libpq.so" |