diff options
-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 000000000..abbe14249 --- /dev/null +++ b/meta-oe/recipes-support/postgresql/files/0003-Shore-up-ADMIN-OPTION-restrictions.patch | |||
@@ -0,0 +1,273 @@ | |||
1 | From 15a8f97b9d16aaf659f58c981242b9da591cf24c Mon Sep 17 00:00:00 2001 | ||
2 | From: Noah Misch <noah@leadboat.com> | ||
3 | Date: Mon, 17 Feb 2014 09:33:31 -0500 | ||
4 | Subject: [PATCH] Shore up ADMIN OPTION restrictions. | ||
5 | |||
6 | commit 15a8f97b9d16aaf659f58c981242b9da591cf24c REL9_2_STABLE | ||
7 | |||
8 | Granting a role without ADMIN OPTION is supposed to prevent the grantee | ||
9 | from adding or removing members from the granted role. Issuing SET ROLE | ||
10 | before the GRANT bypassed that, because the role itself had an implicit | ||
11 | right to add or remove members. Plug that hole by recognizing that | ||
12 | implicit right only when the session user matches the current role. | ||
13 | Additionally, do not recognize it during a security-restricted operation | ||
14 | or during execution of a SECURITY DEFINER function. The restriction on | ||
15 | SECURITY DEFINER is not security-critical. However, it seems best for a | ||
16 | user testing his own SECURITY DEFINER function to see the same behavior | ||
17 | others will see. Back-patch to 8.4 (all supported versions). | ||
18 | |||
19 | The SQL standards do not conflate roles and users as PostgreSQL does; | ||
20 | only SQL roles have members, and only SQL users initiate sessions. An | ||
21 | application using PostgreSQL users and roles as SQL users and roles will | ||
22 | never attempt to grant membership in the role that is the session user, | ||
23 | so the implicit right to add or remove members will never arise. | ||
24 | |||
25 | The security impact was mostly that a role member could revoke access | ||
26 | from others, contrary to the wishes of his own grantor. Unapproved role | ||
27 | member additions are less notable, because the member can still largely | ||
28 | achieve that by creating a view or a SECURITY DEFINER function. | ||
29 | |||
30 | Reviewed by Andres Freund and Tom Lane. Reported, independently, by | ||
31 | Jonas Sundman and Noah Misch. | ||
32 | |||
33 | Security: CVE-2014-0060 | ||
34 | |||
35 | |||
36 | Upstream-Status: Backport | ||
37 | |||
38 | Signed-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 | |||
47 | diff --git a/doc/src/sgml/ref/grant.sgml b/doc/src/sgml/ref/grant.sgml | ||
48 | index 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> | ||
70 | diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c | ||
71 | index 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), | ||
92 | diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c | ||
93 | index 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 | ||
170 | diff --git a/src/test/regress/expected/privileges.out b/src/test/regress/expected/privileges.out | ||
171 | index 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; | ||
224 | diff --git a/src/test/regress/sql/privileges.sql b/src/test/regress/sql/privileges.sql | ||
225 | index 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 | -- | ||
272 | 1.7.5.4 | ||
273 | |||
diff --git a/meta-oe/recipes-support/postgresql/postgresql.inc b/meta-oe/recipes-support/postgresql/postgresql.inc index 9b242e047..d6a4cd781 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 \ | |||
32 | file://postgresql.service \ | 32 | file://postgresql.service \ |
33 | file://0001-Use-pkg-config-for-libxml2-detection.patch \ | 33 | file://0001-Use-pkg-config-for-libxml2-detection.patch \ |
34 | file://0002-Predict-integer-overflow-to-avoid-buffer-overruns.patch \ | 34 | file://0002-Predict-integer-overflow-to-avoid-buffer-overruns.patch \ |
35 | file://0003-Shore-up-ADMIN-OPTION-restrictions.patch \ | ||
35 | " | 36 | " |
36 | 37 | ||
37 | LEAD_SONAME = "libpq.so" | 38 | LEAD_SONAME = "libpq.so" |