aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Biggers <ebiggers@google.com>2017-04-18 10:31:09 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-04-27 03:10:37 -0400
commit174a74dbca2ddc7269c265598399c000e5b9b870 (patch)
tree44e4e9f9bf0fbf1ffd5f8fadf5211d614d9655fb
parentb2dd90e812f3f733b55f0bf4487032e53b487665 (diff)
KEYS: fix keyctl_set_reqkey_keyring() to not leak thread keyrings
commit c9f838d104fed6f2f61d68164712e3204bf5271b upstream. This fixes CVE-2017-7472. Running the following program as an unprivileged user exhausts kernel memory by leaking thread keyrings: #include <keyutils.h> int main() { for (;;) keyctl_set_reqkey_keyring(KEY_REQKEY_DEFL_THREAD_KEYRING); } Fix it by only creating a new thread keyring if there wasn't one before. To make things more consistent, make install_thread_keyring_to_cred() and install_process_keyring_to_cred() both return 0 if the corresponding keyring is already present. Fixes: d84f4f992cbd ("CRED: Inaugurate COW credentials") Signed-off-by: Eric Biggers <ebiggers@google.com> Signed-off-by: David Howells <dhowells@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--security/keys/keyctl.c11
-rw-r--r--security/keys/process_keys.c44
2 files changed, 31 insertions, 24 deletions
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index 7cdd5b550693..dbbfd7735ce5 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -1256,8 +1256,8 @@ error:
1256 * Read or set the default keyring in which request_key() will cache keys and 1256 * Read or set the default keyring in which request_key() will cache keys and
1257 * return the old setting. 1257 * return the old setting.
1258 * 1258 *
1259 * If a process keyring is specified then this will be created if it doesn't 1259 * If a thread or process keyring is specified then it will be created if it
1260 * yet exist. The old setting will be returned if successful. 1260 * doesn't yet exist. The old setting will be returned if successful.
1261 */ 1261 */
1262long keyctl_set_reqkey_keyring(int reqkey_defl) 1262long keyctl_set_reqkey_keyring(int reqkey_defl)
1263{ 1263{
@@ -1282,11 +1282,8 @@ long keyctl_set_reqkey_keyring(int reqkey_defl)
1282 1282
1283 case KEY_REQKEY_DEFL_PROCESS_KEYRING: 1283 case KEY_REQKEY_DEFL_PROCESS_KEYRING:
1284 ret = install_process_keyring_to_cred(new); 1284 ret = install_process_keyring_to_cred(new);
1285 if (ret < 0) { 1285 if (ret < 0)
1286 if (ret != -EEXIST) 1286 goto error;
1287 goto error;
1288 ret = 0;
1289 }
1290 goto set; 1287 goto set;
1291 1288
1292 case KEY_REQKEY_DEFL_DEFAULT: 1289 case KEY_REQKEY_DEFL_DEFAULT:
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
index 40a885239782..45536c677b05 100644
--- a/security/keys/process_keys.c
+++ b/security/keys/process_keys.c
@@ -127,13 +127,18 @@ error:
127} 127}
128 128
129/* 129/*
130 * Install a fresh thread keyring directly to new credentials. This keyring is 130 * Install a thread keyring to the given credentials struct if it didn't have
131 * allowed to overrun the quota. 131 * one already. This is allowed to overrun the quota.
132 *
133 * Return: 0 if a thread keyring is now present; -errno on failure.
132 */ 134 */
133int install_thread_keyring_to_cred(struct cred *new) 135int install_thread_keyring_to_cred(struct cred *new)
134{ 136{
135 struct key *keyring; 137 struct key *keyring;
136 138
139 if (new->thread_keyring)
140 return 0;
141
137 keyring = keyring_alloc("_tid", new->uid, new->gid, new, 142 keyring = keyring_alloc("_tid", new->uid, new->gid, new,
138 KEY_POS_ALL | KEY_USR_VIEW, 143 KEY_POS_ALL | KEY_USR_VIEW,
139 KEY_ALLOC_QUOTA_OVERRUN, 144 KEY_ALLOC_QUOTA_OVERRUN,
@@ -146,7 +151,9 @@ int install_thread_keyring_to_cred(struct cred *new)
146} 151}
147 152
148/* 153/*
149 * Install a fresh thread keyring, discarding the old one. 154 * Install a thread keyring to the current task if it didn't have one already.
155 *
156 * Return: 0 if a thread keyring is now present; -errno on failure.
150 */ 157 */
151static int install_thread_keyring(void) 158static int install_thread_keyring(void)
152{ 159{
@@ -157,8 +164,6 @@ static int install_thread_keyring(void)
157 if (!new) 164 if (!new)
158 return -ENOMEM; 165 return -ENOMEM;
159 166
160 BUG_ON(new->thread_keyring);
161
162 ret = install_thread_keyring_to_cred(new); 167 ret = install_thread_keyring_to_cred(new);
163 if (ret < 0) { 168 if (ret < 0) {
164 abort_creds(new); 169 abort_creds(new);
@@ -169,17 +174,17 @@ static int install_thread_keyring(void)
169} 174}
170 175
171/* 176/*
172 * Install a process keyring directly to a credentials struct. 177 * Install a process keyring to the given credentials struct if it didn't have
178 * one already. This is allowed to overrun the quota.
173 * 179 *
174 * Returns -EEXIST if there was already a process keyring, 0 if one installed, 180 * Return: 0 if a process keyring is now present; -errno on failure.
175 * and other value on any other error
176 */ 181 */
177int install_process_keyring_to_cred(struct cred *new) 182int install_process_keyring_to_cred(struct cred *new)
178{ 183{
179 struct key *keyring; 184 struct key *keyring;
180 185
181 if (new->process_keyring) 186 if (new->process_keyring)
182 return -EEXIST; 187 return 0;
183 188
184 keyring = keyring_alloc("_pid", new->uid, new->gid, new, 189 keyring = keyring_alloc("_pid", new->uid, new->gid, new,
185 KEY_POS_ALL | KEY_USR_VIEW, 190 KEY_POS_ALL | KEY_USR_VIEW,
@@ -193,11 +198,9 @@ int install_process_keyring_to_cred(struct cred *new)
193} 198}
194 199
195/* 200/*
196 * Make sure a process keyring is installed for the current process. The 201 * Install a process keyring to the current task if it didn't have one already.
197 * existing process keyring is not replaced.
198 * 202 *
199 * Returns 0 if there is a process keyring by the end of this function, some 203 * Return: 0 if a process keyring is now present; -errno on failure.
200 * error otherwise.
201 */ 204 */
202static int install_process_keyring(void) 205static int install_process_keyring(void)
203{ 206{
@@ -211,14 +214,18 @@ static int install_process_keyring(void)
211 ret = install_process_keyring_to_cred(new); 214 ret = install_process_keyring_to_cred(new);
212 if (ret < 0) { 215 if (ret < 0) {
213 abort_creds(new); 216 abort_creds(new);
214 return ret != -EEXIST ? ret : 0; 217 return ret;
215 } 218 }
216 219
217 return commit_creds(new); 220 return commit_creds(new);
218} 221}
219 222
220/* 223/*
221 * Install a session keyring directly to a credentials struct. 224 * Install the given keyring as the session keyring of the given credentials
225 * struct, replacing the existing one if any. If the given keyring is NULL,
226 * then install a new anonymous session keyring.
227 *
228 * Return: 0 on success; -errno on failure.
222 */ 229 */
223int install_session_keyring_to_cred(struct cred *cred, struct key *keyring) 230int install_session_keyring_to_cred(struct cred *cred, struct key *keyring)
224{ 231{
@@ -253,8 +260,11 @@ int install_session_keyring_to_cred(struct cred *cred, struct key *keyring)
253} 260}
254 261
255/* 262/*
256 * Install a session keyring, discarding the old one. If a keyring is not 263 * Install the given keyring as the session keyring of the current task,
257 * supplied, an empty one is invented. 264 * replacing the existing one if any. If the given keyring is NULL, then
265 * install a new anonymous session keyring.
266 *
267 * Return: 0 on success; -errno on failure.
258 */ 268 */
259static int install_session_keyring(struct key *keyring) 269static int install_session_keyring(struct key *keyring)
260{ 270{