blob: ea55cf9acf36ac0881e642abcdf4d71bff92c34f [file] [log] [blame]
David Howells69664cf2008-04-29 01:01:31 -07001/* Management of a process's keyrings
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 *
David Howells69664cf2008-04-29 01:01:31 -07003 * Copyright (C) 2004-2005, 2008 Red Hat, Inc. All Rights Reserved.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 */
11
12#include <linux/module.h>
13#include <linux/init.h>
14#include <linux/sched.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070015#include <linux/keyctl.h>
16#include <linux/fs.h>
17#include <linux/err.h>
Ingo Molnarbb003072006-03-22 00:09:14 -080018#include <linux/mutex.h>
David Howellsee18d642009-09-02 09:14:21 +010019#include <linux/security.h>
Serge E. Hallyn1d1e9752009-02-26 18:27:38 -060020#include <linux/user_namespace.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070021#include <asm/uaccess.h>
22#include "internal.h"
23
24/* session keyring create vs join semaphore */
Ingo Molnarbb003072006-03-22 00:09:14 -080025static DEFINE_MUTEX(key_session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -070026
David Howells69664cf2008-04-29 01:01:31 -070027/* user keyring creation semaphore */
28static DEFINE_MUTEX(key_user_keyring_mutex);
29
Linus Torvalds1da177e2005-04-16 15:20:36 -070030/* the root user's tracking struct */
31struct key_user root_key_user = {
32 .usage = ATOMIC_INIT(3),
David Howells76181c12007-10-16 23:29:46 -070033 .cons_lock = __MUTEX_INITIALIZER(root_key_user.cons_lock),
Peter Zijlstra6cfd76a2006-12-06 20:37:22 -080034 .lock = __SPIN_LOCK_UNLOCKED(root_key_user.lock),
Linus Torvalds1da177e2005-04-16 15:20:36 -070035 .nkeys = ATOMIC_INIT(2),
36 .nikeys = ATOMIC_INIT(2),
37 .uid = 0,
Serge E. Hallyn1d1e9752009-02-26 18:27:38 -060038 .user_ns = &init_user_ns,
Linus Torvalds1da177e2005-04-16 15:20:36 -070039};
40
Linus Torvalds1da177e2005-04-16 15:20:36 -070041/*
David Howells69664cf2008-04-29 01:01:31 -070042 * install user and user session keyrings for a particular UID
Linus Torvalds1da177e2005-04-16 15:20:36 -070043 */
David Howells8bbf49762008-11-14 10:39:14 +110044int install_user_keyrings(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -070045{
David Howellsd84f4f92008-11-14 10:39:23 +110046 struct user_struct *user;
47 const struct cred *cred;
Linus Torvalds1da177e2005-04-16 15:20:36 -070048 struct key *uid_keyring, *session_keyring;
49 char buf[20];
50 int ret;
51
David Howellsd84f4f92008-11-14 10:39:23 +110052 cred = current_cred();
53 user = cred->user;
54
David Howells69664cf2008-04-29 01:01:31 -070055 kenter("%p{%u}", user, user->uid);
Linus Torvalds1da177e2005-04-16 15:20:36 -070056
David Howells69664cf2008-04-29 01:01:31 -070057 if (user->uid_keyring) {
58 kleave(" = 0 [exist]");
59 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070060 }
61
David Howells69664cf2008-04-29 01:01:31 -070062 mutex_lock(&key_user_keyring_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -070063 ret = 0;
64
David Howells69664cf2008-04-29 01:01:31 -070065 if (!user->uid_keyring) {
66 /* get the UID-specific keyring
67 * - there may be one in existence already as it may have been
68 * pinned by a session, but the user_struct pointing to it
69 * may have been destroyed by setuid */
70 sprintf(buf, "_uid.%u", user->uid);
Linus Torvalds1da177e2005-04-16 15:20:36 -070071
David Howells69664cf2008-04-29 01:01:31 -070072 uid_keyring = find_keyring_by_name(buf, true);
73 if (IS_ERR(uid_keyring)) {
74 uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1,
David Howellsd84f4f92008-11-14 10:39:23 +110075 cred, KEY_ALLOC_IN_QUOTA,
David Howells69664cf2008-04-29 01:01:31 -070076 NULL);
77 if (IS_ERR(uid_keyring)) {
78 ret = PTR_ERR(uid_keyring);
79 goto error;
80 }
81 }
82
83 /* get a default session keyring (which might also exist
84 * already) */
85 sprintf(buf, "_uid_ses.%u", user->uid);
86
87 session_keyring = find_keyring_by_name(buf, true);
88 if (IS_ERR(session_keyring)) {
89 session_keyring =
90 keyring_alloc(buf, user->uid, (gid_t) -1,
David Howellsd84f4f92008-11-14 10:39:23 +110091 cred, KEY_ALLOC_IN_QUOTA, NULL);
David Howells69664cf2008-04-29 01:01:31 -070092 if (IS_ERR(session_keyring)) {
93 ret = PTR_ERR(session_keyring);
94 goto error_release;
95 }
96
97 /* we install a link from the user session keyring to
98 * the user keyring */
99 ret = key_link(session_keyring, uid_keyring);
100 if (ret < 0)
101 goto error_release_both;
102 }
103
104 /* install the keyrings */
105 user->uid_keyring = uid_keyring;
106 user->session_keyring = session_keyring;
107 }
108
109 mutex_unlock(&key_user_keyring_mutex);
110 kleave(" = 0");
111 return 0;
112
113error_release_both:
114 key_put(session_keyring);
115error_release:
116 key_put(uid_keyring);
117error:
118 mutex_unlock(&key_user_keyring_mutex);
119 kleave(" = %d", ret);
120 return ret;
121}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123/*
David Howellsd84f4f92008-11-14 10:39:23 +1100124 * install a fresh thread keyring directly to new credentials
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125 */
David Howellsd84f4f92008-11-14 10:39:23 +1100126int install_thread_keyring_to_cred(struct cred *new)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127{
David Howellsd84f4f92008-11-14 10:39:23 +1100128 struct key *keyring;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129
David Howellsd84f4f92008-11-14 10:39:23 +1100130 keyring = keyring_alloc("_tid", new->uid, new->gid, new,
131 KEY_ALLOC_QUOTA_OVERRUN, NULL);
132 if (IS_ERR(keyring))
133 return PTR_ERR(keyring);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134
David Howellsd84f4f92008-11-14 10:39:23 +1100135 new->thread_keyring = keyring;
136 return 0;
137}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139/*
140 * install a fresh thread keyring, discarding the old one
141 */
David Howellsd84f4f92008-11-14 10:39:23 +1100142static int install_thread_keyring(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143{
David Howellsd84f4f92008-11-14 10:39:23 +1100144 struct cred *new;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145 int ret;
146
David Howellsd84f4f92008-11-14 10:39:23 +1100147 new = prepare_creds();
148 if (!new)
149 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150
David Howellsd84f4f92008-11-14 10:39:23 +1100151 BUG_ON(new->thread_keyring);
152
153 ret = install_thread_keyring_to_cred(new);
154 if (ret < 0) {
155 abort_creds(new);
156 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157 }
158
David Howellsd84f4f92008-11-14 10:39:23 +1100159 return commit_creds(new);
160}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161
David Howellsd84f4f92008-11-14 10:39:23 +1100162/*
163 * install a process keyring directly to a credentials struct
164 * - returns -EEXIST if there was already a process keyring, 0 if one installed,
165 * and other -ve on any other error
166 */
167int install_process_keyring_to_cred(struct cred *new)
168{
169 struct key *keyring;
170 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171
David Howellsd84f4f92008-11-14 10:39:23 +1100172 if (new->tgcred->process_keyring)
173 return -EEXIST;
174
175 keyring = keyring_alloc("_pid", new->uid, new->gid,
176 new, KEY_ALLOC_QUOTA_OVERRUN, NULL);
177 if (IS_ERR(keyring))
178 return PTR_ERR(keyring);
179
180 spin_lock_irq(&new->tgcred->lock);
181 if (!new->tgcred->process_keyring) {
182 new->tgcred->process_keyring = keyring;
183 keyring = NULL;
184 ret = 0;
185 } else {
186 ret = -EEXIST;
187 }
188 spin_unlock_irq(&new->tgcred->lock);
189 key_put(keyring);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190 return ret;
David Howellsd84f4f92008-11-14 10:39:23 +1100191}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193/*
194 * make sure a process keyring is installed
David Howellsd84f4f92008-11-14 10:39:23 +1100195 * - we
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196 */
David Howellsd84f4f92008-11-14 10:39:23 +1100197static int install_process_keyring(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198{
David Howellsd84f4f92008-11-14 10:39:23 +1100199 struct cred *new;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200 int ret;
201
David Howellsd84f4f92008-11-14 10:39:23 +1100202 new = prepare_creds();
203 if (!new)
204 return -ENOMEM;
David Howells1a26feb2006-04-10 22:54:26 -0700205
David Howellsd84f4f92008-11-14 10:39:23 +1100206 ret = install_process_keyring_to_cred(new);
207 if (ret < 0) {
208 abort_creds(new);
Andi Kleen27d63792010-10-28 13:16:13 +0100209 return ret != -EEXIST ? ret : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210 }
211
David Howellsd84f4f92008-11-14 10:39:23 +1100212 return commit_creds(new);
213}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215/*
David Howellsd84f4f92008-11-14 10:39:23 +1100216 * install a session keyring directly to a credentials struct
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217 */
Oleg Nesterov685bfd22010-05-26 14:43:00 -0700218int install_session_keyring_to_cred(struct cred *cred, struct key *keyring)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219{
David Howells7e047ef2006-06-26 00:24:50 -0700220 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 struct key *old;
David Howells1a26feb2006-04-10 22:54:26 -0700222
223 might_sleep();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224
225 /* create an empty session keyring */
226 if (!keyring) {
David Howells7e047ef2006-06-26 00:24:50 -0700227 flags = KEY_ALLOC_QUOTA_OVERRUN;
David Howellsd84f4f92008-11-14 10:39:23 +1100228 if (cred->tgcred->session_keyring)
David Howells7e047ef2006-06-26 00:24:50 -0700229 flags = KEY_ALLOC_IN_QUOTA;
230
David Howellsd84f4f92008-11-14 10:39:23 +1100231 keyring = keyring_alloc("_ses", cred->uid, cred->gid,
232 cred, flags, NULL);
David Howells1a26feb2006-04-10 22:54:26 -0700233 if (IS_ERR(keyring))
234 return PTR_ERR(keyring);
David Howellsd84f4f92008-11-14 10:39:23 +1100235 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 atomic_inc(&keyring->usage);
237 }
238
239 /* install the keyring */
David Howellsd84f4f92008-11-14 10:39:23 +1100240 spin_lock_irq(&cred->tgcred->lock);
241 old = cred->tgcred->session_keyring;
242 rcu_assign_pointer(cred->tgcred->session_keyring, keyring);
243 spin_unlock_irq(&cred->tgcred->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244
David Howells1a26feb2006-04-10 22:54:26 -0700245 /* we're using RCU on the pointer, but there's no point synchronising
246 * on it if it didn't previously point to anything */
247 if (old) {
248 synchronize_rcu();
249 key_put(old);
250 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251
David Howells1a26feb2006-04-10 22:54:26 -0700252 return 0;
David Howellsd84f4f92008-11-14 10:39:23 +1100253}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255/*
David Howellsd84f4f92008-11-14 10:39:23 +1100256 * install a session keyring, discarding the old one
257 * - if a keyring is not supplied, an empty one is invented
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 */
David Howellsd84f4f92008-11-14 10:39:23 +1100259static int install_session_keyring(struct key *keyring)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260{
David Howellsd84f4f92008-11-14 10:39:23 +1100261 struct cred *new;
262 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263
David Howellsd84f4f92008-11-14 10:39:23 +1100264 new = prepare_creds();
265 if (!new)
266 return -ENOMEM;
David Howellsb5f545c2006-01-08 01:02:47 -0800267
David Howellsd84f4f92008-11-14 10:39:23 +1100268 ret = install_session_keyring_to_cred(new, NULL);
269 if (ret < 0) {
270 abort_creds(new);
271 return ret;
272 }
David Howellsb5f545c2006-01-08 01:02:47 -0800273
David Howellsd84f4f92008-11-14 10:39:23 +1100274 return commit_creds(new);
275}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 * the filesystem user ID changed
279 */
280void key_fsuid_changed(struct task_struct *tsk)
281{
282 /* update the ownership of the thread keyring */
David Howellsb6dff3e2008-11-14 10:39:16 +1100283 BUG_ON(!tsk->cred);
284 if (tsk->cred->thread_keyring) {
285 down_write(&tsk->cred->thread_keyring->sem);
286 tsk->cred->thread_keyring->uid = tsk->cred->fsuid;
287 up_write(&tsk->cred->thread_keyring->sem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 }
David Howellsa8b17ed2011-01-20 16:38:27 +0000289}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291/*
292 * the filesystem group ID changed
293 */
294void key_fsgid_changed(struct task_struct *tsk)
295{
296 /* update the ownership of the thread keyring */
David Howellsb6dff3e2008-11-14 10:39:16 +1100297 BUG_ON(!tsk->cred);
298 if (tsk->cred->thread_keyring) {
299 down_write(&tsk->cred->thread_keyring->sem);
300 tsk->cred->thread_keyring->gid = tsk->cred->fsgid;
301 up_write(&tsk->cred->thread_keyring->sem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302 }
David Howellsa8b17ed2011-01-20 16:38:27 +0000303}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305/*
David Howells927942a2010-06-11 17:31:10 +0100306 * search only my process keyrings for the first matching key
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 * - we use the supplied match function to see if the description (or other
308 * feature of interest) matches
309 * - we return -EAGAIN if we didn't find any matching key
310 * - we return -ENOKEY if we found only negative matching keys
311 */
David Howells927942a2010-06-11 17:31:10 +0100312key_ref_t search_my_process_keyrings(struct key_type *type,
313 const void *description,
314 key_match_func_t match,
315 const struct cred *cred)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316{
David Howellsb5f545c2006-01-08 01:02:47 -0800317 key_ref_t key_ref, ret, err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318
319 /* we want to return -EAGAIN or -ENOKEY if any of the keyrings were
320 * searchable, but we failed to find a key or we found a negative key;
321 * otherwise we want to return a sample error (probably -EACCES) if
322 * none of the keyrings were searchable
323 *
324 * in terms of priority: success > -ENOKEY > -EAGAIN > other error
325 */
David Howells664cceb2005-09-28 17:03:15 +0100326 key_ref = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327 ret = NULL;
328 err = ERR_PTR(-EAGAIN);
329
330 /* search the thread keyring first */
David Howellsc69e8d92008-11-14 10:39:19 +1100331 if (cred->thread_keyring) {
David Howells664cceb2005-09-28 17:03:15 +0100332 key_ref = keyring_search_aux(
David Howellsc69e8d92008-11-14 10:39:19 +1100333 make_key_ref(cred->thread_keyring, 1),
David Howellsd84f4f92008-11-14 10:39:23 +1100334 cred, type, description, match);
David Howells664cceb2005-09-28 17:03:15 +0100335 if (!IS_ERR(key_ref))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336 goto found;
337
David Howells664cceb2005-09-28 17:03:15 +0100338 switch (PTR_ERR(key_ref)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339 case -EAGAIN: /* no key */
340 if (ret)
341 break;
342 case -ENOKEY: /* negative key */
David Howells664cceb2005-09-28 17:03:15 +0100343 ret = key_ref;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 break;
345 default:
David Howells664cceb2005-09-28 17:03:15 +0100346 err = key_ref;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 break;
348 }
349 }
350
351 /* search the process keyring second */
David Howellsbb952bb2008-11-14 10:39:20 +1100352 if (cred->tgcred->process_keyring) {
David Howells664cceb2005-09-28 17:03:15 +0100353 key_ref = keyring_search_aux(
David Howellsbb952bb2008-11-14 10:39:20 +1100354 make_key_ref(cred->tgcred->process_keyring, 1),
David Howellsd84f4f92008-11-14 10:39:23 +1100355 cred, type, description, match);
David Howells664cceb2005-09-28 17:03:15 +0100356 if (!IS_ERR(key_ref))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 goto found;
358
David Howells664cceb2005-09-28 17:03:15 +0100359 switch (PTR_ERR(key_ref)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 case -EAGAIN: /* no key */
361 if (ret)
362 break;
363 case -ENOKEY: /* negative key */
David Howells664cceb2005-09-28 17:03:15 +0100364 ret = key_ref;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 break;
366 default:
David Howells664cceb2005-09-28 17:03:15 +0100367 err = key_ref;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 break;
369 }
370 }
371
David Howells3e301482005-06-23 22:00:56 -0700372 /* search the session keyring */
David Howellsbb952bb2008-11-14 10:39:20 +1100373 if (cred->tgcred->session_keyring) {
David Howells8589b4e2005-06-23 22:00:53 -0700374 rcu_read_lock();
David Howells664cceb2005-09-28 17:03:15 +0100375 key_ref = keyring_search_aux(
376 make_key_ref(rcu_dereference(
David Howellsbb952bb2008-11-14 10:39:20 +1100377 cred->tgcred->session_keyring),
David Howells664cceb2005-09-28 17:03:15 +0100378 1),
David Howellsd84f4f92008-11-14 10:39:23 +1100379 cred, type, description, match);
David Howells8589b4e2005-06-23 22:00:53 -0700380 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381
David Howells664cceb2005-09-28 17:03:15 +0100382 if (!IS_ERR(key_ref))
David Howells3e301482005-06-23 22:00:56 -0700383 goto found;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384
David Howells664cceb2005-09-28 17:03:15 +0100385 switch (PTR_ERR(key_ref)) {
David Howells3e301482005-06-23 22:00:56 -0700386 case -EAGAIN: /* no key */
387 if (ret)
388 break;
389 case -ENOKEY: /* negative key */
David Howells664cceb2005-09-28 17:03:15 +0100390 ret = key_ref;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 break;
David Howells3e301482005-06-23 22:00:56 -0700392 default:
David Howells664cceb2005-09-28 17:03:15 +0100393 err = key_ref;
David Howells3e301482005-06-23 22:00:56 -0700394 break;
395 }
David Howells3e301482005-06-23 22:00:56 -0700396 }
397 /* or search the user-session keyring */
David Howellsc69e8d92008-11-14 10:39:19 +1100398 else if (cred->user->session_keyring) {
David Howells664cceb2005-09-28 17:03:15 +0100399 key_ref = keyring_search_aux(
David Howellsc69e8d92008-11-14 10:39:19 +1100400 make_key_ref(cred->user->session_keyring, 1),
David Howellsd84f4f92008-11-14 10:39:23 +1100401 cred, type, description, match);
David Howells664cceb2005-09-28 17:03:15 +0100402 if (!IS_ERR(key_ref))
David Howells3e301482005-06-23 22:00:56 -0700403 goto found;
404
David Howells664cceb2005-09-28 17:03:15 +0100405 switch (PTR_ERR(key_ref)) {
David Howells3e301482005-06-23 22:00:56 -0700406 case -EAGAIN: /* no key */
407 if (ret)
408 break;
409 case -ENOKEY: /* negative key */
David Howells664cceb2005-09-28 17:03:15 +0100410 ret = key_ref;
David Howells3e301482005-06-23 22:00:56 -0700411 break;
412 default:
David Howells664cceb2005-09-28 17:03:15 +0100413 err = key_ref;
David Howells3e301482005-06-23 22:00:56 -0700414 break;
415 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 }
417
David Howells927942a2010-06-11 17:31:10 +0100418 /* no key - decide on the error we're going to go for */
419 key_ref = ret ? ret : err;
420
421found:
422 return key_ref;
423}
424
David Howells927942a2010-06-11 17:31:10 +0100425/*
426 * search the process keyrings for the first matching key
427 * - we use the supplied match function to see if the description (or other
428 * feature of interest) matches
429 * - we return -EAGAIN if we didn't find any matching key
430 * - we return -ENOKEY if we found only negative matching keys
431 */
432key_ref_t search_process_keyrings(struct key_type *type,
433 const void *description,
434 key_match_func_t match,
435 const struct cred *cred)
436{
437 struct request_key_auth *rka;
438 key_ref_t key_ref, ret = ERR_PTR(-EACCES), err;
439
440 might_sleep();
441
442 key_ref = search_my_process_keyrings(type, description, match, cred);
443 if (!IS_ERR(key_ref))
444 goto found;
445 err = key_ref;
446
David Howellsb5f545c2006-01-08 01:02:47 -0800447 /* if this process has an instantiation authorisation key, then we also
448 * search the keyrings of the process mentioned there
449 * - we don't permit access to request_key auth keys via this method
450 */
David Howellsc69e8d92008-11-14 10:39:19 +1100451 if (cred->request_key_auth &&
David Howellsd84f4f92008-11-14 10:39:23 +1100452 cred == current_cred() &&
David Howells04c567d2006-06-22 14:47:18 -0700453 type != &key_type_request_key_auth
David Howellsb5f545c2006-01-08 01:02:47 -0800454 ) {
David Howells04c567d2006-06-22 14:47:18 -0700455 /* defend against the auth key being revoked */
David Howellsc69e8d92008-11-14 10:39:19 +1100456 down_read(&cred->request_key_auth->sem);
David Howells3e301482005-06-23 22:00:56 -0700457
David Howellsc69e8d92008-11-14 10:39:19 +1100458 if (key_validate(cred->request_key_auth) == 0) {
459 rka = cred->request_key_auth->payload.data;
David Howellsb5f545c2006-01-08 01:02:47 -0800460
David Howells04c567d2006-06-22 14:47:18 -0700461 key_ref = search_process_keyrings(type, description,
David Howellsd84f4f92008-11-14 10:39:23 +1100462 match, rka->cred);
David Howellsb5f545c2006-01-08 01:02:47 -0800463
David Howellsc69e8d92008-11-14 10:39:19 +1100464 up_read(&cred->request_key_auth->sem);
David Howells04c567d2006-06-22 14:47:18 -0700465
466 if (!IS_ERR(key_ref))
467 goto found;
468
David Howells927942a2010-06-11 17:31:10 +0100469 ret = key_ref;
David Howells04c567d2006-06-22 14:47:18 -0700470 } else {
David Howellsc69e8d92008-11-14 10:39:19 +1100471 up_read(&cred->request_key_auth->sem);
David Howellsb5f545c2006-01-08 01:02:47 -0800472 }
473 }
474
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475 /* no key - decide on the error we're going to go for */
David Howells927942a2010-06-11 17:31:10 +0100476 if (err == ERR_PTR(-ENOKEY) || ret == ERR_PTR(-ENOKEY))
477 key_ref = ERR_PTR(-ENOKEY);
478 else if (err == ERR_PTR(-EACCES))
479 key_ref = ret;
480 else
481 key_ref = err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482
David Howells3e301482005-06-23 22:00:56 -0700483found:
David Howells664cceb2005-09-28 17:03:15 +0100484 return key_ref;
David Howellsa8b17ed2011-01-20 16:38:27 +0000485}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487/*
David Howells664cceb2005-09-28 17:03:15 +0100488 * see if the key we're looking at is the target key
489 */
David Howells927942a2010-06-11 17:31:10 +0100490int lookup_user_key_possessed(const struct key *key, const void *target)
David Howells664cceb2005-09-28 17:03:15 +0100491{
492 return key == target;
David Howellsa8b17ed2011-01-20 16:38:27 +0000493}
David Howells664cceb2005-09-28 17:03:15 +0100494
David Howells664cceb2005-09-28 17:03:15 +0100495/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496 * lookup a key given a key ID from userspace with a given permissions mask
497 * - don't create special keyrings unless so requested
498 * - partially constructed keys aren't found unless requested
499 */
David Howells55931222009-09-02 09:13:45 +0100500key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags,
David Howells8bbf49762008-11-14 10:39:14 +1100501 key_perm_t perm)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502{
David Howells8bbf49762008-11-14 10:39:14 +1100503 struct request_key_auth *rka;
David Howellsd84f4f92008-11-14 10:39:23 +1100504 const struct cred *cred;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 struct key *key;
David Howellsb6dff3e2008-11-14 10:39:16 +1100506 key_ref_t key_ref, skey_ref;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 int ret;
508
David Howellsbb952bb2008-11-14 10:39:20 +1100509try_again:
510 cred = get_current_cred();
David Howells664cceb2005-09-28 17:03:15 +0100511 key_ref = ERR_PTR(-ENOKEY);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512
513 switch (id) {
514 case KEY_SPEC_THREAD_KEYRING:
David Howellsb6dff3e2008-11-14 10:39:16 +1100515 if (!cred->thread_keyring) {
David Howells55931222009-09-02 09:13:45 +0100516 if (!(lflags & KEY_LOOKUP_CREATE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517 goto error;
518
David Howells8bbf49762008-11-14 10:39:14 +1100519 ret = install_thread_keyring();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 if (ret < 0) {
Dan Carpenter4d09ec02010-05-17 14:42:35 +0100521 key_ref = ERR_PTR(ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 goto error;
523 }
David Howellsbb952bb2008-11-14 10:39:20 +1100524 goto reget_creds;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525 }
526
David Howellsb6dff3e2008-11-14 10:39:16 +1100527 key = cred->thread_keyring;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528 atomic_inc(&key->usage);
David Howells664cceb2005-09-28 17:03:15 +0100529 key_ref = make_key_ref(key, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 break;
531
532 case KEY_SPEC_PROCESS_KEYRING:
David Howellsbb952bb2008-11-14 10:39:20 +1100533 if (!cred->tgcred->process_keyring) {
David Howells55931222009-09-02 09:13:45 +0100534 if (!(lflags & KEY_LOOKUP_CREATE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 goto error;
536
David Howells8bbf49762008-11-14 10:39:14 +1100537 ret = install_process_keyring();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 if (ret < 0) {
Dan Carpenter4d09ec02010-05-17 14:42:35 +0100539 key_ref = ERR_PTR(ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 goto error;
541 }
David Howellsbb952bb2008-11-14 10:39:20 +1100542 goto reget_creds;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 }
544
David Howellsbb952bb2008-11-14 10:39:20 +1100545 key = cred->tgcred->process_keyring;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 atomic_inc(&key->usage);
David Howells664cceb2005-09-28 17:03:15 +0100547 key_ref = make_key_ref(key, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 break;
549
550 case KEY_SPEC_SESSION_KEYRING:
David Howellsbb952bb2008-11-14 10:39:20 +1100551 if (!cred->tgcred->session_keyring) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552 /* always install a session keyring upon access if one
553 * doesn't exist yet */
David Howells8bbf49762008-11-14 10:39:14 +1100554 ret = install_user_keyrings();
David Howells69664cf2008-04-29 01:01:31 -0700555 if (ret < 0)
556 goto error;
David Howellsb6dff3e2008-11-14 10:39:16 +1100557 ret = install_session_keyring(
558 cred->user->session_keyring);
David Howellsd84f4f92008-11-14 10:39:23 +1100559
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 if (ret < 0)
561 goto error;
David Howellsbb952bb2008-11-14 10:39:20 +1100562 goto reget_creds;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563 }
564
David Howells3e301482005-06-23 22:00:56 -0700565 rcu_read_lock();
David Howellsbb952bb2008-11-14 10:39:20 +1100566 key = rcu_dereference(cred->tgcred->session_keyring);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567 atomic_inc(&key->usage);
David Howells3e301482005-06-23 22:00:56 -0700568 rcu_read_unlock();
David Howells664cceb2005-09-28 17:03:15 +0100569 key_ref = make_key_ref(key, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 break;
571
572 case KEY_SPEC_USER_KEYRING:
David Howellsb6dff3e2008-11-14 10:39:16 +1100573 if (!cred->user->uid_keyring) {
David Howells8bbf49762008-11-14 10:39:14 +1100574 ret = install_user_keyrings();
David Howells69664cf2008-04-29 01:01:31 -0700575 if (ret < 0)
576 goto error;
577 }
578
David Howellsb6dff3e2008-11-14 10:39:16 +1100579 key = cred->user->uid_keyring;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 atomic_inc(&key->usage);
David Howells664cceb2005-09-28 17:03:15 +0100581 key_ref = make_key_ref(key, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 break;
583
584 case KEY_SPEC_USER_SESSION_KEYRING:
David Howellsb6dff3e2008-11-14 10:39:16 +1100585 if (!cred->user->session_keyring) {
David Howells8bbf49762008-11-14 10:39:14 +1100586 ret = install_user_keyrings();
David Howells69664cf2008-04-29 01:01:31 -0700587 if (ret < 0)
588 goto error;
589 }
590
David Howellsb6dff3e2008-11-14 10:39:16 +1100591 key = cred->user->session_keyring;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592 atomic_inc(&key->usage);
David Howells664cceb2005-09-28 17:03:15 +0100593 key_ref = make_key_ref(key, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594 break;
595
596 case KEY_SPEC_GROUP_KEYRING:
597 /* group keyrings are not yet supported */
Dan Carpenter4d09ec02010-05-17 14:42:35 +0100598 key_ref = ERR_PTR(-EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 goto error;
600
David Howellsb5f545c2006-01-08 01:02:47 -0800601 case KEY_SPEC_REQKEY_AUTH_KEY:
David Howellsb6dff3e2008-11-14 10:39:16 +1100602 key = cred->request_key_auth;
David Howellsb5f545c2006-01-08 01:02:47 -0800603 if (!key)
604 goto error;
605
606 atomic_inc(&key->usage);
607 key_ref = make_key_ref(key, 1);
608 break;
609
David Howells8bbf49762008-11-14 10:39:14 +1100610 case KEY_SPEC_REQUESTOR_KEYRING:
David Howellsb6dff3e2008-11-14 10:39:16 +1100611 if (!cred->request_key_auth)
David Howells8bbf49762008-11-14 10:39:14 +1100612 goto error;
613
David Howellsb6dff3e2008-11-14 10:39:16 +1100614 down_read(&cred->request_key_auth->sem);
615 if (cred->request_key_auth->flags & KEY_FLAG_REVOKED) {
David Howells8bbf49762008-11-14 10:39:14 +1100616 key_ref = ERR_PTR(-EKEYREVOKED);
617 key = NULL;
618 } else {
David Howellsb6dff3e2008-11-14 10:39:16 +1100619 rka = cred->request_key_auth->payload.data;
David Howells8bbf49762008-11-14 10:39:14 +1100620 key = rka->dest_keyring;
621 atomic_inc(&key->usage);
622 }
David Howellsb6dff3e2008-11-14 10:39:16 +1100623 up_read(&cred->request_key_auth->sem);
David Howells8bbf49762008-11-14 10:39:14 +1100624 if (!key)
625 goto error;
626 key_ref = make_key_ref(key, 1);
627 break;
628
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 default:
David Howells664cceb2005-09-28 17:03:15 +0100630 key_ref = ERR_PTR(-EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 if (id < 1)
632 goto error;
633
634 key = key_lookup(id);
David Howells664cceb2005-09-28 17:03:15 +0100635 if (IS_ERR(key)) {
David Howellse231c2e2008-02-07 00:15:26 -0800636 key_ref = ERR_CAST(key);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 goto error;
David Howells664cceb2005-09-28 17:03:15 +0100638 }
639
640 key_ref = make_key_ref(key, 0);
641
642 /* check to see if we possess the key */
643 skey_ref = search_process_keyrings(key->type, key,
644 lookup_user_key_possessed,
David Howellsd84f4f92008-11-14 10:39:23 +1100645 cred);
David Howells664cceb2005-09-28 17:03:15 +0100646
647 if (!IS_ERR(skey_ref)) {
648 key_put(key);
649 key_ref = skey_ref;
650 }
651
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 break;
653 }
654
David Howells55931222009-09-02 09:13:45 +0100655 /* unlink does not use the nominated key in any way, so can skip all
656 * the permission checks as it is only concerned with the keyring */
657 if (lflags & KEY_LOOKUP_FOR_UNLINK) {
658 ret = 0;
659 goto error;
660 }
661
662 if (!(lflags & KEY_LOOKUP_PARTIAL)) {
David Howells76181c12007-10-16 23:29:46 -0700663 ret = wait_for_key_construction(key, true);
664 switch (ret) {
665 case -ERESTARTSYS:
666 goto invalid_key;
667 default:
668 if (perm)
669 goto invalid_key;
670 case 0:
671 break;
672 }
673 } else if (perm) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 ret = key_validate(key);
675 if (ret < 0)
676 goto invalid_key;
677 }
678
679 ret = -EIO;
David Howells55931222009-09-02 09:13:45 +0100680 if (!(lflags & KEY_LOOKUP_PARTIAL) &&
681 !test_bit(KEY_FLAG_INSTANTIATED, &key->flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 goto invalid_key;
683
David Howells3e301482005-06-23 22:00:56 -0700684 /* check the permissions */
David Howellsd84f4f92008-11-14 10:39:23 +1100685 ret = key_task_permission(key_ref, cred, perm);
David Howells29db9192005-10-30 15:02:44 -0800686 if (ret < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 goto invalid_key;
688
David Howells664cceb2005-09-28 17:03:15 +0100689error:
David Howellsbb952bb2008-11-14 10:39:20 +1100690 put_cred(cred);
David Howells664cceb2005-09-28 17:03:15 +0100691 return key_ref;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692
David Howells664cceb2005-09-28 17:03:15 +0100693invalid_key:
694 key_ref_put(key_ref);
695 key_ref = ERR_PTR(ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 goto error;
697
David Howellsbb952bb2008-11-14 10:39:20 +1100698 /* if we attempted to install a keyring, then it may have caused new
699 * creds to be installed */
700reget_creds:
701 put_cred(cred);
702 goto try_again;
David Howellsa8b17ed2011-01-20 16:38:27 +0000703}
David Howellsbb952bb2008-11-14 10:39:20 +1100704
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705/*
706 * join the named keyring as the session keyring if possible, or attempt to
707 * create a new one of that name if not
708 * - if the name is NULL, an empty anonymous keyring is installed instead
709 * - named session keyring joining is done with a semaphore held
710 */
711long join_session_keyring(const char *name)
712{
David Howellsd84f4f92008-11-14 10:39:23 +1100713 const struct cred *old;
714 struct cred *new;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 struct key *keyring;
David Howellsd84f4f92008-11-14 10:39:23 +1100716 long ret, serial;
717
718 /* only permit this if there's a single thread in the thread group -
719 * this avoids us having to adjust the creds on all threads and risking
720 * ENOMEM */
Oleg Nesterov5bb459b2009-07-10 03:48:23 +0200721 if (!current_is_single_threaded())
David Howellsd84f4f92008-11-14 10:39:23 +1100722 return -EMLINK;
723
724 new = prepare_creds();
725 if (!new)
726 return -ENOMEM;
727 old = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728
729 /* if no name is provided, install an anonymous keyring */
730 if (!name) {
David Howellsd84f4f92008-11-14 10:39:23 +1100731 ret = install_session_keyring_to_cred(new, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 if (ret < 0)
733 goto error;
734
David Howellsd84f4f92008-11-14 10:39:23 +1100735 serial = new->tgcred->session_keyring->serial;
736 ret = commit_creds(new);
737 if (ret == 0)
738 ret = serial;
739 goto okay;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 }
741
742 /* allow the user to join or create a named keyring */
Ingo Molnarbb003072006-03-22 00:09:14 -0800743 mutex_lock(&key_session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744
745 /* look for an existing keyring of this name */
David Howells69664cf2008-04-29 01:01:31 -0700746 keyring = find_keyring_by_name(name, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747 if (PTR_ERR(keyring) == -ENOKEY) {
748 /* not found - try and create a new one */
David Howellsd84f4f92008-11-14 10:39:23 +1100749 keyring = keyring_alloc(name, old->uid, old->gid, old,
David Howells7e047ef2006-06-26 00:24:50 -0700750 KEY_ALLOC_IN_QUOTA, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 if (IS_ERR(keyring)) {
752 ret = PTR_ERR(keyring);
David Howellsbcf945d2005-08-04 13:07:06 -0700753 goto error2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 }
David Howellsd84f4f92008-11-14 10:39:23 +1100755 } else if (IS_ERR(keyring)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 ret = PTR_ERR(keyring);
757 goto error2;
758 }
759
760 /* we've got a keyring - now to install it */
David Howellsd84f4f92008-11-14 10:39:23 +1100761 ret = install_session_keyring_to_cred(new, keyring);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 if (ret < 0)
763 goto error2;
764
David Howellsd84f4f92008-11-14 10:39:23 +1100765 commit_creds(new);
766 mutex_unlock(&key_session_mutex);
767
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 ret = keyring->serial;
769 key_put(keyring);
David Howellsd84f4f92008-11-14 10:39:23 +1100770okay:
771 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772
David Howells664cceb2005-09-28 17:03:15 +0100773error2:
Ingo Molnarbb003072006-03-22 00:09:14 -0800774 mutex_unlock(&key_session_mutex);
David Howells664cceb2005-09-28 17:03:15 +0100775error:
David Howellsd84f4f92008-11-14 10:39:23 +1100776 abort_creds(new);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 return ret;
David Howellsd84f4f92008-11-14 10:39:23 +1100778}
David Howellsee18d642009-09-02 09:14:21 +0100779
780/*
781 * Replace a process's session keyring when that process resumes userspace on
782 * behalf of one of its children
783 */
784void key_replace_session_keyring(void)
785{
786 const struct cred *old;
787 struct cred *new;
788
789 if (!current->replacement_session_keyring)
790 return;
791
792 write_lock_irq(&tasklist_lock);
793 new = current->replacement_session_keyring;
794 current->replacement_session_keyring = NULL;
795 write_unlock_irq(&tasklist_lock);
796
797 if (!new)
798 return;
799
800 old = current_cred();
801 new-> uid = old-> uid;
802 new-> euid = old-> euid;
803 new-> suid = old-> suid;
804 new->fsuid = old->fsuid;
805 new-> gid = old-> gid;
806 new-> egid = old-> egid;
807 new-> sgid = old-> sgid;
808 new->fsgid = old->fsgid;
809 new->user = get_uid(old->user);
810 new->group_info = get_group_info(old->group_info);
811
812 new->securebits = old->securebits;
813 new->cap_inheritable = old->cap_inheritable;
814 new->cap_permitted = old->cap_permitted;
815 new->cap_effective = old->cap_effective;
816 new->cap_bset = old->cap_bset;
817
818 new->jit_keyring = old->jit_keyring;
819 new->thread_keyring = key_get(old->thread_keyring);
820 new->tgcred->tgid = old->tgcred->tgid;
821 new->tgcred->process_keyring = key_get(old->tgcred->process_keyring);
822
823 security_transfer_creds(new, old);
824
825 commit_creds(new);
826}