summaryrefslogtreecommitdiffstats
path: root/meta-oe/recipes-support/postgresql/files/0003-Shore-up-ADMIN-OPTION-restrictions.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta-oe/recipes-support/postgresql/files/0003-Shore-up-ADMIN-OPTION-restrictions.patch')
-rw-r--r--meta-oe/recipes-support/postgresql/files/0003-Shore-up-ADMIN-OPTION-restrictions.patch273
1 files changed, 273 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 000000000..abbe14249
--- /dev/null
+++ b/meta-oe/recipes-support/postgresql/files/0003-Shore-up-ADMIN-OPTION-restrictions.patch
@@ -0,0 +1,273 @@
1From 15a8f97b9d16aaf659f58c981242b9da591cf24c Mon Sep 17 00:00:00 2001
2From: Noah Misch <noah@leadboat.com>
3Date: Mon, 17 Feb 2014 09:33:31 -0500
4Subject: [PATCH] Shore up ADMIN OPTION restrictions.
5
6commit 15a8f97b9d16aaf659f58c981242b9da591cf24c REL9_2_STABLE
7
8Granting a role without ADMIN OPTION is supposed to prevent the grantee
9from adding or removing members from the granted role. Issuing SET ROLE
10before the GRANT bypassed that, because the role itself had an implicit
11right to add or remove members. Plug that hole by recognizing that
12implicit right only when the session user matches the current role.
13Additionally, do not recognize it during a security-restricted operation
14or during execution of a SECURITY DEFINER function. The restriction on
15SECURITY DEFINER is not security-critical. However, it seems best for a
16user testing his own SECURITY DEFINER function to see the same behavior
17others will see. Back-patch to 8.4 (all supported versions).
18
19The SQL standards do not conflate roles and users as PostgreSQL does;
20only SQL roles have members, and only SQL users initiate sessions. An
21application using PostgreSQL users and roles as SQL users and roles will
22never attempt to grant membership in the role that is the session user,
23so the implicit right to add or remove members will never arise.
24
25The security impact was mostly that a role member could revoke access
26from others, contrary to the wishes of his own grantor. Unapproved role
27member additions are less notable, because the member can still largely
28achieve that by creating a view or a SECURITY DEFINER function.
29
30Reviewed by Andres Freund and Tom Lane. Reported, independently, by
31Jonas Sundman and Noah Misch.
32
33Security: CVE-2014-0060
34
35
36Upstream-Status: Backport
37
38Signed-off-by: Kai Kang <kai.kang@windriver.com>
39---
40 doc/src/sgml/ref/grant.sgml | 12 ++++---
41 src/backend/commands/user.c | 11 ++++++-
42 src/backend/utils/adt/acl.c | 50 ++++++++++++++++++++++++------
43 src/test/regress/expected/privileges.out | 36 +++++++++++++++++++++-
44 src/test/regress/sql/privileges.sql | 29 ++++++++++++++++-
45 5 files changed, 120 insertions(+), 18 deletions(-)
46
47diff --git a/doc/src/sgml/ref/grant.sgml b/doc/src/sgml/ref/grant.sgml
48index fb81af4..2b5a843 100644
49--- a/doc/src/sgml/ref/grant.sgml
50+++ b/doc/src/sgml/ref/grant.sgml
51@@ -396,11 +396,13 @@ GRANT <replaceable class="PARAMETER">role_name</replaceable> [, ...] TO <replace
52 <para>
53 If <literal>WITH ADMIN OPTION</literal> is specified, the member can
54 in turn grant membership in the role to others, and revoke membership
55- in the role as well. Without the admin option, ordinary users cannot do
56- that. However,
57- database superusers can grant or revoke membership in any role to anyone.
58- Roles having <literal>CREATEROLE</> privilege can grant or revoke
59- membership in any role that is not a superuser.
60+ in the role as well. Without the admin option, ordinary users cannot
61+ do that. A role is not considered to hold <literal>WITH ADMIN
62+ OPTION</literal> on itself, but it may grant or revoke membership in
63+ itself from a database session where the session user matches the
64+ role. Database superusers can grant or revoke membership in any role
65+ to anyone. Roles having <literal>CREATEROLE</> privilege can grant
66+ or revoke membership in any role that is not a superuser.
67 </para>
68
69 <para>
70diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c
71index a22092c..39bf172 100644
72--- a/src/backend/commands/user.c
73+++ b/src/backend/commands/user.c
74@@ -1334,7 +1334,16 @@ AddRoleMems(const char *rolename, Oid roleid,
75 rolename)));
76 }
77
78- /* XXX not sure about this check */
79+ /*
80+ * The role membership grantor of record has little significance at
81+ * present. Nonetheless, inasmuch as users might look to it for a crude
82+ * audit trail, let only superusers impute the grant to a third party.
83+ *
84+ * Before lifting this restriction, give the member == role case of
85+ * is_admin_of_role() a fresh look. Ensure that the current role cannot
86+ * use an explicit grantor specification to take advantage of the session
87+ * user's self-admin right.
88+ */
89 if (grantorId != GetUserId() && !superuser())
90 ereport(ERROR,
91 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
92diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
93index 1d6ae8b..9a52edb 100644
94--- a/src/backend/utils/adt/acl.c
95+++ b/src/backend/utils/adt/acl.c
96@@ -4580,6 +4580,11 @@ pg_role_aclcheck(Oid role_oid, Oid roleid, AclMode mode)
97 {
98 if (mode & ACL_GRANT_OPTION_FOR(ACL_CREATE))
99 {
100+ /*
101+ * XXX For roleid == role_oid, is_admin_of_role() also examines the
102+ * session and call stack. That suits two-argument pg_has_role(), but
103+ * it gives the three-argument version a lamentable whimsy.
104+ */
105 if (is_admin_of_role(roleid, role_oid))
106 return ACLCHECK_OK;
107 }
108@@ -4897,11 +4902,9 @@ is_member_of_role_nosuper(Oid member, Oid role)
109
110
111 /*
112- * Is member an admin of role (directly or indirectly)? That is, is it
113- * a member WITH ADMIN OPTION?
114- *
115- * We could cache the result as for is_member_of_role, but currently this
116- * is not used in any performance-critical paths, so we don't.
117+ * Is member an admin of role? That is, is member the role itself (subject to
118+ * restrictions below), a member (directly or indirectly) WITH ADMIN OPTION,
119+ * or a superuser?
120 */
121 bool
122 is_admin_of_role(Oid member, Oid role)
123@@ -4910,14 +4913,41 @@ is_admin_of_role(Oid member, Oid role)
124 List *roles_list;
125 ListCell *l;
126
127- /* Fast path for simple case */
128- if (member == role)
129- return true;
130-
131- /* Superusers have every privilege, so are part of every role */
132 if (superuser_arg(member))
133 return true;
134
135+ if (member == role)
136+ /*
137+ * A role can admin itself when it matches the session user and we're
138+ * outside any security-restricted operation, SECURITY DEFINER or
139+ * similar context. SQL-standard roles cannot self-admin. However,
140+ * SQL-standard users are distinct from roles, and they are not
141+ * grantable like roles: PostgreSQL's role-user duality extends the
142+ * standard. Checking for a session user match has the effect of
143+ * letting a role self-admin only when it's conspicuously behaving
144+ * like a user. Note that allowing self-admin under a mere SET ROLE
145+ * would make WITH ADMIN OPTION largely irrelevant; any member could
146+ * SET ROLE to issue the otherwise-forbidden command.
147+ *
148+ * Withholding self-admin in a security-restricted operation prevents
149+ * object owners from harnessing the session user identity during
150+ * administrative maintenance. Suppose Alice owns a database, has
151+ * issued "GRANT alice TO bob", and runs a daily ANALYZE. Bob creates
152+ * an alice-owned SECURITY DEFINER function that issues "REVOKE alice
153+ * FROM carol". If he creates an expression index calling that
154+ * function, Alice will attempt the REVOKE during each ANALYZE.
155+ * Checking InSecurityRestrictedOperation() thwarts that attack.
156+ *
157+ * Withholding self-admin in SECURITY DEFINER functions makes their
158+ * behavior independent of the calling user. There's no security or
159+ * SQL-standard-conformance need for that restriction, though.
160+ *
161+ * A role cannot have actual WITH ADMIN OPTION on itself, because that
162+ * would imply a membership loop. Therefore, we're done either way.
163+ */
164+ return member == GetSessionUserId() &&
165+ !InLocalUserIdChange() && !InSecurityRestrictedOperation();
166+
167 /*
168 * Find all the roles that member is a member of, including multi-level
169 * recursion. We build a list in the same way that is_member_of_role does
170diff --git a/src/test/regress/expected/privileges.out b/src/test/regress/expected/privileges.out
171index e8930cb..bc6d731 100644
172--- a/src/test/regress/expected/privileges.out
173+++ b/src/test/regress/expected/privileges.out
174@@ -32,7 +32,7 @@ ALTER GROUP regressgroup1 ADD USER regressuser4;
175 ALTER GROUP regressgroup2 ADD USER regressuser2; -- duplicate
176 NOTICE: role "regressuser2" is already a member of role "regressgroup2"
177 ALTER GROUP regressgroup2 DROP USER regressuser2;
178-ALTER GROUP regressgroup2 ADD USER regressuser4;
179+GRANT regressgroup2 TO regressuser4 WITH ADMIN OPTION;
180 -- test owner privileges
181 SET SESSION AUTHORIZATION regressuser1;
182 SELECT session_user, current_user;
183@@ -929,6 +929,40 @@ SELECT has_table_privilege('regressuser1', 'atest4', 'SELECT WITH GRANT OPTION')
184 t
185 (1 row)
186
187+-- Admin options
188+SET SESSION AUTHORIZATION regressuser4;
189+CREATE FUNCTION dogrant_ok() RETURNS void LANGUAGE sql SECURITY DEFINER AS
190+ 'GRANT regressgroup2 TO regressuser5';
191+GRANT regressgroup2 TO regressuser5; -- ok: had ADMIN OPTION
192+SET ROLE regressgroup2;
193+GRANT regressgroup2 TO regressuser5; -- fails: SET ROLE suspended privilege
194+ERROR: must have admin option on role "regressgroup2"
195+SET SESSION AUTHORIZATION regressuser1;
196+GRANT regressgroup2 TO regressuser5; -- fails: no ADMIN OPTION
197+ERROR: must have admin option on role "regressgroup2"
198+SELECT dogrant_ok(); -- ok: SECURITY DEFINER conveys ADMIN
199+NOTICE: role "regressuser5" is already a member of role "regressgroup2"
200+CONTEXT: SQL function "dogrant_ok" statement 1
201+ dogrant_ok
202+------------
203+
204+(1 row)
205+
206+SET ROLE regressgroup2;
207+GRANT regressgroup2 TO regressuser5; -- fails: SET ROLE did not help
208+ERROR: must have admin option on role "regressgroup2"
209+SET SESSION AUTHORIZATION regressgroup2;
210+GRANT regressgroup2 TO regressuser5; -- ok: a role can self-admin
211+NOTICE: role "regressuser5" is already a member of role "regressgroup2"
212+CREATE FUNCTION dogrant_fails() RETURNS void LANGUAGE sql SECURITY DEFINER AS
213+ 'GRANT regressgroup2 TO regressuser5';
214+SELECT dogrant_fails(); -- fails: no self-admin in SECURITY DEFINER
215+ERROR: must have admin option on role "regressgroup2"
216+CONTEXT: SQL function "dogrant_fails" statement 1
217+DROP FUNCTION dogrant_fails();
218+SET SESSION AUTHORIZATION regressuser4;
219+DROP FUNCTION dogrant_ok();
220+REVOKE regressgroup2 FROM regressuser5;
221 -- has_sequence_privilege tests
222 \c -
223 CREATE SEQUENCE x_seq;
224diff --git a/src/test/regress/sql/privileges.sql b/src/test/regress/sql/privileges.sql
225index d4d328e..5f1018a 100644
226--- a/src/test/regress/sql/privileges.sql
227+++ b/src/test/regress/sql/privileges.sql
228@@ -37,7 +37,7 @@ ALTER GROUP regressgroup1 ADD USER regressuser4;
229
230 ALTER GROUP regressgroup2 ADD USER regressuser2; -- duplicate
231 ALTER GROUP regressgroup2 DROP USER regressuser2;
232-ALTER GROUP regressgroup2 ADD USER regressuser4;
233+GRANT regressgroup2 TO regressuser4 WITH ADMIN OPTION;
234
235 -- test owner privileges
236
237@@ -581,6 +581,33 @@ SELECT has_table_privilege('regressuser3', 'atest4', 'SELECT'); -- false
238 SELECT has_table_privilege('regressuser1', 'atest4', 'SELECT WITH GRANT OPTION'); -- true
239
240
241+-- Admin options
242+
243+SET SESSION AUTHORIZATION regressuser4;
244+CREATE FUNCTION dogrant_ok() RETURNS void LANGUAGE sql SECURITY DEFINER AS
245+ 'GRANT regressgroup2 TO regressuser5';
246+GRANT regressgroup2 TO regressuser5; -- ok: had ADMIN OPTION
247+SET ROLE regressgroup2;
248+GRANT regressgroup2 TO regressuser5; -- fails: SET ROLE suspended privilege
249+
250+SET SESSION AUTHORIZATION regressuser1;
251+GRANT regressgroup2 TO regressuser5; -- fails: no ADMIN OPTION
252+SELECT dogrant_ok(); -- ok: SECURITY DEFINER conveys ADMIN
253+SET ROLE regressgroup2;
254+GRANT regressgroup2 TO regressuser5; -- fails: SET ROLE did not help
255+
256+SET SESSION AUTHORIZATION regressgroup2;
257+GRANT regressgroup2 TO regressuser5; -- ok: a role can self-admin
258+CREATE FUNCTION dogrant_fails() RETURNS void LANGUAGE sql SECURITY DEFINER AS
259+ 'GRANT regressgroup2 TO regressuser5';
260+SELECT dogrant_fails(); -- fails: no self-admin in SECURITY DEFINER
261+DROP FUNCTION dogrant_fails();
262+
263+SET SESSION AUTHORIZATION regressuser4;
264+DROP FUNCTION dogrant_ok();
265+REVOKE regressgroup2 FROM regressuser5;
266+
267+
268 -- has_sequence_privilege tests
269 \c -
270
271--
2721.7.5.4
273