Blame view

security/keys/process_keys.c 20.6 KB
973c9f4f4   David Howells   KEYS: Fix up comm...
1
  /* Manage a process's keyrings
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
   *
69664cf16   David Howells   keys: don't gener...
3
   * Copyright (C) 2004-2005, 2008 Red Hat, Inc. All Rights Reserved.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4
5
6
7
8
9
10
11
12
13
14
   * Written by David Howells (dhowells@redhat.com)
   *
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of the GNU General Public License
   * as published by the Free Software Foundation; either version
   * 2 of the License, or (at your option) any later version.
   */
  
  #include <linux/module.h>
  #include <linux/init.h>
  #include <linux/sched.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15
16
17
  #include <linux/keyctl.h>
  #include <linux/fs.h>
  #include <linux/err.h>
bb0030797   Ingo Molnar   [PATCH] sem2mutex...
18
  #include <linux/mutex.h>
ee18d64c1   David Howells   KEYS: Add a keyct...
19
  #include <linux/security.h>
1d1e97562   Serge E. Hallyn   keys: distinguish...
20
  #include <linux/user_namespace.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21
22
  #include <asm/uaccess.h>
  #include "internal.h"
973c9f4f4   David Howells   KEYS: Fix up comm...
23
  /* Session keyring create vs join semaphore */
bb0030797   Ingo Molnar   [PATCH] sem2mutex...
24
  static DEFINE_MUTEX(key_session_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
25

973c9f4f4   David Howells   KEYS: Fix up comm...
26
  /* User keyring creation semaphore */
69664cf16   David Howells   keys: don't gener...
27
  static DEFINE_MUTEX(key_user_keyring_mutex);
973c9f4f4   David Howells   KEYS: Fix up comm...
28
  /* The root user's tracking struct */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29
30
  struct key_user root_key_user = {
  	.usage		= ATOMIC_INIT(3),
76181c134   David Howells   KEYS: Make reques...
31
  	.cons_lock	= __MUTEX_INITIALIZER(root_key_user.cons_lock),
6cfd76a26   Peter Zijlstra   [PATCH] lockdep: ...
32
  	.lock		= __SPIN_LOCK_UNLOCKED(root_key_user.lock),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
33
34
35
  	.nkeys		= ATOMIC_INIT(2),
  	.nikeys		= ATOMIC_INIT(2),
  	.uid		= 0,
1d1e97562   Serge E. Hallyn   keys: distinguish...
36
  	.user_ns	= &init_user_ns,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
38
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
39
   * Install the user and user session keyrings for the current process's UID.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
40
   */
8bbf4976b   David Howells   KEYS: Alter use o...
41
  int install_user_keyrings(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42
  {
d84f4f992   David Howells   CRED: Inaugurate ...
43
44
  	struct user_struct *user;
  	const struct cred *cred;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45
46
47
  	struct key *uid_keyring, *session_keyring;
  	char buf[20];
  	int ret;
d84f4f992   David Howells   CRED: Inaugurate ...
48
49
  	cred = current_cred();
  	user = cred->user;
69664cf16   David Howells   keys: don't gener...
50
  	kenter("%p{%u}", user, user->uid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
51

69664cf16   David Howells   keys: don't gener...
52
53
54
  	if (user->uid_keyring) {
  		kleave(" = 0 [exist]");
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55
  	}
69664cf16   David Howells   keys: don't gener...
56
57
  	mutex_lock(&key_user_keyring_mutex);
  	ret = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58

69664cf16   David Howells   keys: don't gener...
59
60
61
62
63
64
65
66
67
68
  	if (!user->uid_keyring) {
  		/* get the UID-specific keyring
  		 * - there may be one in existence already as it may have been
  		 *   pinned by a session, but the user_struct pointing to it
  		 *   may have been destroyed by setuid */
  		sprintf(buf, "_uid.%u", user->uid);
  
  		uid_keyring = find_keyring_by_name(buf, true);
  		if (IS_ERR(uid_keyring)) {
  			uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1,
d84f4f992   David Howells   CRED: Inaugurate ...
69
  						    cred, KEY_ALLOC_IN_QUOTA,
69664cf16   David Howells   keys: don't gener...
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
  						    NULL);
  			if (IS_ERR(uid_keyring)) {
  				ret = PTR_ERR(uid_keyring);
  				goto error;
  			}
  		}
  
  		/* get a default session keyring (which might also exist
  		 * already) */
  		sprintf(buf, "_uid_ses.%u", user->uid);
  
  		session_keyring = find_keyring_by_name(buf, true);
  		if (IS_ERR(session_keyring)) {
  			session_keyring =
  				keyring_alloc(buf, user->uid, (gid_t) -1,
d84f4f992   David Howells   CRED: Inaugurate ...
85
  					      cred, KEY_ALLOC_IN_QUOTA, NULL);
69664cf16   David Howells   keys: don't gener...
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
  			if (IS_ERR(session_keyring)) {
  				ret = PTR_ERR(session_keyring);
  				goto error_release;
  			}
  
  			/* we install a link from the user session keyring to
  			 * the user keyring */
  			ret = key_link(session_keyring, uid_keyring);
  			if (ret < 0)
  				goto error_release_both;
  		}
  
  		/* install the keyrings */
  		user->uid_keyring = uid_keyring;
  		user->session_keyring = session_keyring;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
101
  	}
69664cf16   David Howells   keys: don't gener...
102
103
104
  	mutex_unlock(&key_user_keyring_mutex);
  	kleave(" = 0");
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
105

69664cf16   David Howells   keys: don't gener...
106
107
108
109
  error_release_both:
  	key_put(session_keyring);
  error_release:
  	key_put(uid_keyring);
664cceb00   David Howells   [PATCH] Keys: Add...
110
  error:
69664cf16   David Howells   keys: don't gener...
111
112
  	mutex_unlock(&key_user_keyring_mutex);
  	kleave(" = %d", ret);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
113
  	return ret;
69664cf16   David Howells   keys: don't gener...
114
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
115

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
116
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
117
118
   * Install a fresh thread keyring directly to new credentials.  This keyring is
   * allowed to overrun the quota.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
119
   */
d84f4f992   David Howells   CRED: Inaugurate ...
120
  int install_thread_keyring_to_cred(struct cred *new)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
121
  {
d84f4f992   David Howells   CRED: Inaugurate ...
122
  	struct key *keyring;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
123

d84f4f992   David Howells   CRED: Inaugurate ...
124
125
126
127
  	keyring = keyring_alloc("_tid", new->uid, new->gid, new,
  				KEY_ALLOC_QUOTA_OVERRUN, NULL);
  	if (IS_ERR(keyring))
  		return PTR_ERR(keyring);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
128

d84f4f992   David Howells   CRED: Inaugurate ...
129
130
131
  	new->thread_keyring = keyring;
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
132

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
133
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
134
   * Install a fresh thread keyring, discarding the old one.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
135
   */
d84f4f992   David Howells   CRED: Inaugurate ...
136
  static int install_thread_keyring(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
137
  {
d84f4f992   David Howells   CRED: Inaugurate ...
138
  	struct cred *new;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
139
  	int ret;
d84f4f992   David Howells   CRED: Inaugurate ...
140
141
142
  	new = prepare_creds();
  	if (!new)
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
143

d84f4f992   David Howells   CRED: Inaugurate ...
144
145
146
147
148
149
  	BUG_ON(new->thread_keyring);
  
  	ret = install_thread_keyring_to_cred(new);
  	if (ret < 0) {
  		abort_creds(new);
  		return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
150
  	}
d84f4f992   David Howells   CRED: Inaugurate ...
151
152
  	return commit_creds(new);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
153

d84f4f992   David Howells   CRED: Inaugurate ...
154
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
155
156
157
158
   * Install a process keyring directly to a credentials struct.
   *
   * Returns -EEXIST if there was already a process keyring, 0 if one installed,
   * and other value on any other error
d84f4f992   David Howells   CRED: Inaugurate ...
159
160
161
162
163
   */
  int install_process_keyring_to_cred(struct cred *new)
  {
  	struct key *keyring;
  	int ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
164

d84f4f992   David Howells   CRED: Inaugurate ...
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
  	if (new->tgcred->process_keyring)
  		return -EEXIST;
  
  	keyring = keyring_alloc("_pid", new->uid, new->gid,
  				new, KEY_ALLOC_QUOTA_OVERRUN, NULL);
  	if (IS_ERR(keyring))
  		return PTR_ERR(keyring);
  
  	spin_lock_irq(&new->tgcred->lock);
  	if (!new->tgcred->process_keyring) {
  		new->tgcred->process_keyring = keyring;
  		keyring = NULL;
  		ret = 0;
  	} else {
  		ret = -EEXIST;
  	}
  	spin_unlock_irq(&new->tgcred->lock);
  	key_put(keyring);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
183
  	return ret;
d84f4f992   David Howells   CRED: Inaugurate ...
184
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
185

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
186
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
187
188
189
190
191
   * Make sure a process keyring is installed for the current process.  The
   * existing process keyring is not replaced.
   *
   * Returns 0 if there is a process keyring by the end of this function, some
   * error otherwise.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
192
   */
d84f4f992   David Howells   CRED: Inaugurate ...
193
  static int install_process_keyring(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
194
  {
d84f4f992   David Howells   CRED: Inaugurate ...
195
  	struct cred *new;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
196
  	int ret;
d84f4f992   David Howells   CRED: Inaugurate ...
197
198
199
  	new = prepare_creds();
  	if (!new)
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
200

d84f4f992   David Howells   CRED: Inaugurate ...
201
202
203
  	ret = install_process_keyring_to_cred(new);
  	if (ret < 0) {
  		abort_creds(new);
27d637989   Andi Kleen   Fix install_proce...
204
  		return ret != -EEXIST ? ret : 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
205
  	}
d84f4f992   David Howells   CRED: Inaugurate ...
206
207
  	return commit_creds(new);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
208

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
209
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
210
   * Install a session keyring directly to a credentials struct.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
211
   */
685bfd2c4   Oleg Nesterov   umh: creds: conve...
212
  int install_session_keyring_to_cred(struct cred *cred, struct key *keyring)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
213
  {
7e047ef5f   David Howells   [PATCH] keys: sor...
214
  	unsigned long flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
215
  	struct key *old;
1a26feb96   David Howells   [PATCH] Keys: Imp...
216
217
  
  	might_sleep();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
218
219
220
  
  	/* create an empty session keyring */
  	if (!keyring) {
7e047ef5f   David Howells   [PATCH] keys: sor...
221
  		flags = KEY_ALLOC_QUOTA_OVERRUN;
d84f4f992   David Howells   CRED: Inaugurate ...
222
  		if (cred->tgcred->session_keyring)
7e047ef5f   David Howells   [PATCH] keys: sor...
223
  			flags = KEY_ALLOC_IN_QUOTA;
d84f4f992   David Howells   CRED: Inaugurate ...
224
225
  		keyring = keyring_alloc("_ses", cred->uid, cred->gid,
  					cred, flags, NULL);
1a26feb96   David Howells   [PATCH] Keys: Imp...
226
227
  		if (IS_ERR(keyring))
  			return PTR_ERR(keyring);
d84f4f992   David Howells   CRED: Inaugurate ...
228
  	} else {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
229
230
231
232
  		atomic_inc(&keyring->usage);
  	}
  
  	/* install the keyring */
d84f4f992   David Howells   CRED: Inaugurate ...
233
234
235
236
  	spin_lock_irq(&cred->tgcred->lock);
  	old = cred->tgcred->session_keyring;
  	rcu_assign_pointer(cred->tgcred->session_keyring, keyring);
  	spin_unlock_irq(&cred->tgcred->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
237

1a26feb96   David Howells   [PATCH] Keys: Imp...
238
239
240
241
242
243
  	/* we're using RCU on the pointer, but there's no point synchronising
  	 * on it if it didn't previously point to anything */
  	if (old) {
  		synchronize_rcu();
  		key_put(old);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
244

1a26feb96   David Howells   [PATCH] Keys: Imp...
245
  	return 0;
d84f4f992   David Howells   CRED: Inaugurate ...
246
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
247

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
248
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
249
250
   * Install a session keyring, discarding the old one.  If a keyring is not
   * supplied, an empty one is invented.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
251
   */
d84f4f992   David Howells   CRED: Inaugurate ...
252
  static int install_session_keyring(struct key *keyring)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
253
  {
d84f4f992   David Howells   CRED: Inaugurate ...
254
255
  	struct cred *new;
  	int ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
256

d84f4f992   David Howells   CRED: Inaugurate ...
257
258
259
  	new = prepare_creds();
  	if (!new)
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
260

995995378   David Howells   KEYS: If install_...
261
  	ret = install_session_keyring_to_cred(new, keyring);
d84f4f992   David Howells   CRED: Inaugurate ...
262
263
264
265
  	if (ret < 0) {
  		abort_creds(new);
  		return ret;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
266

d84f4f992   David Howells   CRED: Inaugurate ...
267
268
  	return commit_creds(new);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
269

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
270
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
271
   * Handle the fsuid changing.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
272
273
274
275
   */
  void key_fsuid_changed(struct task_struct *tsk)
  {
  	/* update the ownership of the thread keyring */
b6dff3ec5   David Howells   CRED: Separate ta...
276
277
278
279
280
  	BUG_ON(!tsk->cred);
  	if (tsk->cred->thread_keyring) {
  		down_write(&tsk->cred->thread_keyring->sem);
  		tsk->cred->thread_keyring->uid = tsk->cred->fsuid;
  		up_write(&tsk->cred->thread_keyring->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
281
  	}
a8b17ed01   David Howells   KEYS: Do some sty...
282
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
283

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
284
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
285
   * Handle the fsgid changing.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
286
287
288
289
   */
  void key_fsgid_changed(struct task_struct *tsk)
  {
  	/* update the ownership of the thread keyring */
b6dff3ec5   David Howells   CRED: Separate ta...
290
291
292
293
294
  	BUG_ON(!tsk->cred);
  	if (tsk->cred->thread_keyring) {
  		down_write(&tsk->cred->thread_keyring->sem);
  		tsk->cred->thread_keyring->gid = tsk->cred->fsgid;
  		up_write(&tsk->cred->thread_keyring->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
295
  	}
a8b17ed01   David Howells   KEYS: Do some sty...
296
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
297

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
298
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
   * Search the process keyrings attached to the supplied cred for the first
   * matching key.
   *
   * The search criteria are the type and the match function.  The description is
   * given to the match function as a parameter, but doesn't otherwise influence
   * the search.  Typically the match function will compare the description
   * parameter to the key's description.
   *
   * This can only search keyrings that grant Search permission to the supplied
   * credentials.  Keyrings linked to searched keyrings will also be searched if
   * they grant Search permission too.  Keys can only be found if they grant
   * Search permission to the credentials.
   *
   * Returns a pointer to the key with the key usage count incremented if
   * successful, -EAGAIN if we didn't find any matching key or -ENOKEY if we only
   * matched negative keys.
   *
   * In the case of a successful return, the possession attribute is set on the
   * returned key reference.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
318
   */
927942aab   David Howells   KEYS: Make /proc/...
319
320
321
  key_ref_t search_my_process_keyrings(struct key_type *type,
  				     const void *description,
  				     key_match_func_t match,
78b7280cc   David Howells   KEYS: Improve /pr...
322
  				     bool no_state_check,
927942aab   David Howells   KEYS: Make /proc/...
323
  				     const struct cred *cred)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
324
  {
b5f545c88   David Howells   [PATCH] keys: Per...
325
  	key_ref_t key_ref, ret, err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
326
327
328
329
330
331
332
333
  
  	/* we want to return -EAGAIN or -ENOKEY if any of the keyrings were
  	 * searchable, but we failed to find a key or we found a negative key;
  	 * otherwise we want to return a sample error (probably -EACCES) if
  	 * none of the keyrings were searchable
  	 *
  	 * in terms of priority: success > -ENOKEY > -EAGAIN > other error
  	 */
664cceb00   David Howells   [PATCH] Keys: Add...
334
  	key_ref = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
335
336
337
338
  	ret = NULL;
  	err = ERR_PTR(-EAGAIN);
  
  	/* search the thread keyring first */
c69e8d9c0   David Howells   CRED: Use RCU to ...
339
  	if (cred->thread_keyring) {
664cceb00   David Howells   [PATCH] Keys: Add...
340
  		key_ref = keyring_search_aux(
c69e8d9c0   David Howells   CRED: Use RCU to ...
341
  			make_key_ref(cred->thread_keyring, 1),
78b7280cc   David Howells   KEYS: Improve /pr...
342
  			cred, type, description, match, no_state_check);
664cceb00   David Howells   [PATCH] Keys: Add...
343
  		if (!IS_ERR(key_ref))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
344
  			goto found;
664cceb00   David Howells   [PATCH] Keys: Add...
345
  		switch (PTR_ERR(key_ref)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
346
347
348
349
  		case -EAGAIN: /* no key */
  			if (ret)
  				break;
  		case -ENOKEY: /* negative key */
664cceb00   David Howells   [PATCH] Keys: Add...
350
  			ret = key_ref;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
351
352
  			break;
  		default:
664cceb00   David Howells   [PATCH] Keys: Add...
353
  			err = key_ref;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
354
355
356
357
358
  			break;
  		}
  	}
  
  	/* search the process keyring second */
bb952bb98   David Howells   CRED: Separate pe...
359
  	if (cred->tgcred->process_keyring) {
664cceb00   David Howells   [PATCH] Keys: Add...
360
  		key_ref = keyring_search_aux(
bb952bb98   David Howells   CRED: Separate pe...
361
  			make_key_ref(cred->tgcred->process_keyring, 1),
78b7280cc   David Howells   KEYS: Improve /pr...
362
  			cred, type, description, match, no_state_check);
664cceb00   David Howells   [PATCH] Keys: Add...
363
  		if (!IS_ERR(key_ref))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
364
  			goto found;
664cceb00   David Howells   [PATCH] Keys: Add...
365
  		switch (PTR_ERR(key_ref)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
366
367
368
369
  		case -EAGAIN: /* no key */
  			if (ret)
  				break;
  		case -ENOKEY: /* negative key */
664cceb00   David Howells   [PATCH] Keys: Add...
370
  			ret = key_ref;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
371
372
  			break;
  		default:
664cceb00   David Howells   [PATCH] Keys: Add...
373
  			err = key_ref;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
374
375
376
  			break;
  		}
  	}
3e30148c3   David Howells   [PATCH] Keys: Mak...
377
  	/* search the session keyring */
bb952bb98   David Howells   CRED: Separate pe...
378
  	if (cred->tgcred->session_keyring) {
8589b4e00   David Howells   [PATCH] Keys: Use...
379
  		rcu_read_lock();
664cceb00   David Howells   [PATCH] Keys: Add...
380
381
  		key_ref = keyring_search_aux(
  			make_key_ref(rcu_dereference(
bb952bb98   David Howells   CRED: Separate pe...
382
  					     cred->tgcred->session_keyring),
664cceb00   David Howells   [PATCH] Keys: Add...
383
  				     1),
78b7280cc   David Howells   KEYS: Improve /pr...
384
  			cred, type, description, match, no_state_check);
8589b4e00   David Howells   [PATCH] Keys: Use...
385
  		rcu_read_unlock();
3e30148c3   David Howells   [PATCH] Keys: Mak...
386

664cceb00   David Howells   [PATCH] Keys: Add...
387
  		if (!IS_ERR(key_ref))
3e30148c3   David Howells   [PATCH] Keys: Mak...
388
  			goto found;
664cceb00   David Howells   [PATCH] Keys: Add...
389
  		switch (PTR_ERR(key_ref)) {
3e30148c3   David Howells   [PATCH] Keys: Mak...
390
391
392
393
  		case -EAGAIN: /* no key */
  			if (ret)
  				break;
  		case -ENOKEY: /* negative key */
664cceb00   David Howells   [PATCH] Keys: Add...
394
  			ret = key_ref;
3e30148c3   David Howells   [PATCH] Keys: Mak...
395
396
  			break;
  		default:
664cceb00   David Howells   [PATCH] Keys: Add...
397
  			err = key_ref;
3e30148c3   David Howells   [PATCH] Keys: Mak...
398
399
  			break;
  		}
b5f545c88   David Howells   [PATCH] keys: Per...
400
401
  	}
  	/* or search the user-session keyring */
c69e8d9c0   David Howells   CRED: Use RCU to ...
402
  	else if (cred->user->session_keyring) {
b5f545c88   David Howells   [PATCH] keys: Per...
403
  		key_ref = keyring_search_aux(
c69e8d9c0   David Howells   CRED: Use RCU to ...
404
  			make_key_ref(cred->user->session_keyring, 1),
78b7280cc   David Howells   KEYS: Improve /pr...
405
  			cred, type, description, match, no_state_check);
664cceb00   David Howells   [PATCH] Keys: Add...
406
  		if (!IS_ERR(key_ref))
3e30148c3   David Howells   [PATCH] Keys: Mak...
407
  			goto found;
664cceb00   David Howells   [PATCH] Keys: Add...
408
  		switch (PTR_ERR(key_ref)) {
3e30148c3   David Howells   [PATCH] Keys: Mak...
409
410
411
412
  		case -EAGAIN: /* no key */
  			if (ret)
  				break;
  		case -ENOKEY: /* negative key */
664cceb00   David Howells   [PATCH] Keys: Add...
413
  			ret = key_ref;
3e30148c3   David Howells   [PATCH] Keys: Mak...
414
415
  			break;
  		default:
664cceb00   David Howells   [PATCH] Keys: Add...
416
  			err = key_ref;
3e30148c3   David Howells   [PATCH] Keys: Mak...
417
418
  			break;
  		}
8589b4e00   David Howells   [PATCH] Keys: Use...
419
  	}
b5f545c88   David Howells   [PATCH] keys: Per...
420

927942aab   David Howells   KEYS: Make /proc/...
421
422
423
424
425
426
  	/* no key - decide on the error we're going to go for */
  	key_ref = ret ? ret : err;
  
  found:
  	return key_ref;
  }
927942aab   David Howells   KEYS: Make /proc/...
427
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
428
429
430
431
432
433
   * Search the process keyrings attached to the supplied cred for the first
   * matching key in the manner of search_my_process_keyrings(), but also search
   * the keys attached to the assumed authorisation key using its credentials if
   * one is available.
   *
   * Return same as search_my_process_keyrings().
927942aab   David Howells   KEYS: Make /proc/...
434
435
436
437
438
439
440
441
442
443
   */
  key_ref_t search_process_keyrings(struct key_type *type,
  				  const void *description,
  				  key_match_func_t match,
  				  const struct cred *cred)
  {
  	struct request_key_auth *rka;
  	key_ref_t key_ref, ret = ERR_PTR(-EACCES), err;
  
  	might_sleep();
78b7280cc   David Howells   KEYS: Improve /pr...
444
445
  	key_ref = search_my_process_keyrings(type, description, match,
  					     false, cred);
927942aab   David Howells   KEYS: Make /proc/...
446
447
448
  	if (!IS_ERR(key_ref))
  		goto found;
  	err = key_ref;
b5f545c88   David Howells   [PATCH] keys: Per...
449
450
451
452
  	/* if this process has an instantiation authorisation key, then we also
  	 * search the keyrings of the process mentioned there
  	 * - we don't permit access to request_key auth keys via this method
  	 */
c69e8d9c0   David Howells   CRED: Use RCU to ...
453
  	if (cred->request_key_auth &&
d84f4f992   David Howells   CRED: Inaugurate ...
454
  	    cred == current_cred() &&
04c567d93   David Howells   [PATCH] Keys: Fix...
455
  	    type != &key_type_request_key_auth
b5f545c88   David Howells   [PATCH] keys: Per...
456
  	    ) {
04c567d93   David Howells   [PATCH] Keys: Fix...
457
  		/* defend against the auth key being revoked */
c69e8d9c0   David Howells   CRED: Use RCU to ...
458
  		down_read(&cred->request_key_auth->sem);
b5f545c88   David Howells   [PATCH] keys: Per...
459

c69e8d9c0   David Howells   CRED: Use RCU to ...
460
461
  		if (key_validate(cred->request_key_auth) == 0) {
  			rka = cred->request_key_auth->payload.data;
b5f545c88   David Howells   [PATCH] keys: Per...
462

04c567d93   David Howells   [PATCH] Keys: Fix...
463
  			key_ref = search_process_keyrings(type, description,
d84f4f992   David Howells   CRED: Inaugurate ...
464
  							  match, rka->cred);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
465

c69e8d9c0   David Howells   CRED: Use RCU to ...
466
  			up_read(&cred->request_key_auth->sem);
04c567d93   David Howells   [PATCH] Keys: Fix...
467
468
469
  
  			if (!IS_ERR(key_ref))
  				goto found;
927942aab   David Howells   KEYS: Make /proc/...
470
  			ret = key_ref;
04c567d93   David Howells   [PATCH] Keys: Fix...
471
  		} else {
c69e8d9c0   David Howells   CRED: Use RCU to ...
472
  			up_read(&cred->request_key_auth->sem);
3e30148c3   David Howells   [PATCH] Keys: Mak...
473
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
474
475
476
  	}
  
  	/* no key - decide on the error we're going to go for */
927942aab   David Howells   KEYS: Make /proc/...
477
478
479
480
481
482
  	if (err == ERR_PTR(-ENOKEY) || ret == ERR_PTR(-ENOKEY))
  		key_ref = ERR_PTR(-ENOKEY);
  	else if (err == ERR_PTR(-EACCES))
  		key_ref = ret;
  	else
  		key_ref = err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
483

3e30148c3   David Howells   [PATCH] Keys: Mak...
484
  found:
664cceb00   David Howells   [PATCH] Keys: Add...
485
  	return key_ref;
a8b17ed01   David Howells   KEYS: Do some sty...
486
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
487

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
488
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
489
   * See if the key we're looking at is the target key.
664cceb00   David Howells   [PATCH] Keys: Add...
490
   */
927942aab   David Howells   KEYS: Make /proc/...
491
  int lookup_user_key_possessed(const struct key *key, const void *target)
664cceb00   David Howells   [PATCH] Keys: Add...
492
493
  {
  	return key == target;
a8b17ed01   David Howells   KEYS: Do some sty...
494
  }
664cceb00   David Howells   [PATCH] Keys: Add...
495

664cceb00   David Howells   [PATCH] Keys: Add...
496
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
   * Look up a key ID given us by userspace with a given permissions mask to get
   * the key it refers to.
   *
   * Flags can be passed to request that special keyrings be created if referred
   * to directly, to permit partially constructed keys to be found and to skip
   * validity and permission checks on the found key.
   *
   * Returns a pointer to the key with an incremented usage count if successful;
   * -EINVAL if the key ID is invalid; -ENOKEY if the key ID does not correspond
   * to a key or the best found key was a negative key; -EKEYREVOKED or
   * -EKEYEXPIRED if the best found key was revoked or expired; -EACCES if the
   * found key doesn't grant the requested permit or the LSM denied access to it;
   * or -ENOMEM if a special keyring couldn't be created.
   *
   * In the case of a successful return, the possession attribute is set on the
   * returned key reference.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
513
   */
5593122ee   David Howells   KEYS: Deal with d...
514
  key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags,
8bbf4976b   David Howells   KEYS: Alter use o...
515
  			  key_perm_t perm)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
516
  {
8bbf4976b   David Howells   KEYS: Alter use o...
517
  	struct request_key_auth *rka;
d84f4f992   David Howells   CRED: Inaugurate ...
518
  	const struct cred *cred;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
519
  	struct key *key;
b6dff3ec5   David Howells   CRED: Separate ta...
520
  	key_ref_t key_ref, skey_ref;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
521
  	int ret;
bb952bb98   David Howells   CRED: Separate pe...
522
523
  try_again:
  	cred = get_current_cred();
664cceb00   David Howells   [PATCH] Keys: Add...
524
  	key_ref = ERR_PTR(-ENOKEY);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
525
526
527
  
  	switch (id) {
  	case KEY_SPEC_THREAD_KEYRING:
b6dff3ec5   David Howells   CRED: Separate ta...
528
  		if (!cred->thread_keyring) {
5593122ee   David Howells   KEYS: Deal with d...
529
  			if (!(lflags & KEY_LOOKUP_CREATE))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
530
  				goto error;
8bbf4976b   David Howells   KEYS: Alter use o...
531
  			ret = install_thread_keyring();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
532
  			if (ret < 0) {
4d09ec0f7   Dan Carpenter   KEYS: Return more...
533
  				key_ref = ERR_PTR(ret);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
534
535
  				goto error;
  			}
bb952bb98   David Howells   CRED: Separate pe...
536
  			goto reget_creds;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
537
  		}
b6dff3ec5   David Howells   CRED: Separate ta...
538
  		key = cred->thread_keyring;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
539
  		atomic_inc(&key->usage);
664cceb00   David Howells   [PATCH] Keys: Add...
540
  		key_ref = make_key_ref(key, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
541
542
543
  		break;
  
  	case KEY_SPEC_PROCESS_KEYRING:
bb952bb98   David Howells   CRED: Separate pe...
544
  		if (!cred->tgcred->process_keyring) {
5593122ee   David Howells   KEYS: Deal with d...
545
  			if (!(lflags & KEY_LOOKUP_CREATE))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
546
  				goto error;
8bbf4976b   David Howells   KEYS: Alter use o...
547
  			ret = install_process_keyring();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
548
  			if (ret < 0) {
4d09ec0f7   Dan Carpenter   KEYS: Return more...
549
  				key_ref = ERR_PTR(ret);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
550
551
  				goto error;
  			}
bb952bb98   David Howells   CRED: Separate pe...
552
  			goto reget_creds;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
553
  		}
bb952bb98   David Howells   CRED: Separate pe...
554
  		key = cred->tgcred->process_keyring;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
555
  		atomic_inc(&key->usage);
664cceb00   David Howells   [PATCH] Keys: Add...
556
  		key_ref = make_key_ref(key, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
557
558
559
  		break;
  
  	case KEY_SPEC_SESSION_KEYRING:
bb952bb98   David Howells   CRED: Separate pe...
560
  		if (!cred->tgcred->session_keyring) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
561
562
  			/* always install a session keyring upon access if one
  			 * doesn't exist yet */
8bbf4976b   David Howells   KEYS: Alter use o...
563
  			ret = install_user_keyrings();
69664cf16   David Howells   keys: don't gener...
564
565
  			if (ret < 0)
  				goto error;
3ecf1b4f3   David Howells   KEYS: keyctl_get_...
566
567
568
569
570
  			if (lflags & KEY_LOOKUP_CREATE)
  				ret = join_session_keyring(NULL);
  			else
  				ret = install_session_keyring(
  					cred->user->session_keyring);
d84f4f992   David Howells   CRED: Inaugurate ...
571

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
572
573
  			if (ret < 0)
  				goto error;
bb952bb98   David Howells   CRED: Separate pe...
574
  			goto reget_creds;
3ecf1b4f3   David Howells   KEYS: keyctl_get_...
575
576
577
578
579
580
581
  		} else if (cred->tgcred->session_keyring ==
  			   cred->user->session_keyring &&
  			   lflags & KEY_LOOKUP_CREATE) {
  			ret = join_session_keyring(NULL);
  			if (ret < 0)
  				goto error;
  			goto reget_creds;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
582
  		}
3e30148c3   David Howells   [PATCH] Keys: Mak...
583
  		rcu_read_lock();
bb952bb98   David Howells   CRED: Separate pe...
584
  		key = rcu_dereference(cred->tgcred->session_keyring);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
585
  		atomic_inc(&key->usage);
3e30148c3   David Howells   [PATCH] Keys: Mak...
586
  		rcu_read_unlock();
664cceb00   David Howells   [PATCH] Keys: Add...
587
  		key_ref = make_key_ref(key, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
588
589
590
  		break;
  
  	case KEY_SPEC_USER_KEYRING:
b6dff3ec5   David Howells   CRED: Separate ta...
591
  		if (!cred->user->uid_keyring) {
8bbf4976b   David Howells   KEYS: Alter use o...
592
  			ret = install_user_keyrings();
69664cf16   David Howells   keys: don't gener...
593
594
595
  			if (ret < 0)
  				goto error;
  		}
b6dff3ec5   David Howells   CRED: Separate ta...
596
  		key = cred->user->uid_keyring;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
597
  		atomic_inc(&key->usage);
664cceb00   David Howells   [PATCH] Keys: Add...
598
  		key_ref = make_key_ref(key, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
599
600
601
  		break;
  
  	case KEY_SPEC_USER_SESSION_KEYRING:
b6dff3ec5   David Howells   CRED: Separate ta...
602
  		if (!cred->user->session_keyring) {
8bbf4976b   David Howells   KEYS: Alter use o...
603
  			ret = install_user_keyrings();
69664cf16   David Howells   keys: don't gener...
604
605
606
  			if (ret < 0)
  				goto error;
  		}
b6dff3ec5   David Howells   CRED: Separate ta...
607
  		key = cred->user->session_keyring;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
608
  		atomic_inc(&key->usage);
664cceb00   David Howells   [PATCH] Keys: Add...
609
  		key_ref = make_key_ref(key, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
610
611
612
613
  		break;
  
  	case KEY_SPEC_GROUP_KEYRING:
  		/* group keyrings are not yet supported */
4d09ec0f7   Dan Carpenter   KEYS: Return more...
614
  		key_ref = ERR_PTR(-EINVAL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
615
  		goto error;
b5f545c88   David Howells   [PATCH] keys: Per...
616
  	case KEY_SPEC_REQKEY_AUTH_KEY:
b6dff3ec5   David Howells   CRED: Separate ta...
617
  		key = cred->request_key_auth;
b5f545c88   David Howells   [PATCH] keys: Per...
618
619
620
621
622
623
  		if (!key)
  			goto error;
  
  		atomic_inc(&key->usage);
  		key_ref = make_key_ref(key, 1);
  		break;
8bbf4976b   David Howells   KEYS: Alter use o...
624
  	case KEY_SPEC_REQUESTOR_KEYRING:
b6dff3ec5   David Howells   CRED: Separate ta...
625
  		if (!cred->request_key_auth)
8bbf4976b   David Howells   KEYS: Alter use o...
626
  			goto error;
b6dff3ec5   David Howells   CRED: Separate ta...
627
628
  		down_read(&cred->request_key_auth->sem);
  		if (cred->request_key_auth->flags & KEY_FLAG_REVOKED) {
8bbf4976b   David Howells   KEYS: Alter use o...
629
630
631
  			key_ref = ERR_PTR(-EKEYREVOKED);
  			key = NULL;
  		} else {
b6dff3ec5   David Howells   CRED: Separate ta...
632
  			rka = cred->request_key_auth->payload.data;
8bbf4976b   David Howells   KEYS: Alter use o...
633
634
635
  			key = rka->dest_keyring;
  			atomic_inc(&key->usage);
  		}
b6dff3ec5   David Howells   CRED: Separate ta...
636
  		up_read(&cred->request_key_auth->sem);
8bbf4976b   David Howells   KEYS: Alter use o...
637
638
639
640
  		if (!key)
  			goto error;
  		key_ref = make_key_ref(key, 1);
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
641
  	default:
664cceb00   David Howells   [PATCH] Keys: Add...
642
  		key_ref = ERR_PTR(-EINVAL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
643
644
645
646
  		if (id < 1)
  			goto error;
  
  		key = key_lookup(id);
664cceb00   David Howells   [PATCH] Keys: Add...
647
  		if (IS_ERR(key)) {
e231c2ee6   David Howells   Convert ERR_PTR(P...
648
  			key_ref = ERR_CAST(key);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
649
  			goto error;
664cceb00   David Howells   [PATCH] Keys: Add...
650
651
652
653
654
655
656
  		}
  
  		key_ref = make_key_ref(key, 0);
  
  		/* check to see if we possess the key */
  		skey_ref = search_process_keyrings(key->type, key,
  						   lookup_user_key_possessed,
d84f4f992   David Howells   CRED: Inaugurate ...
657
  						   cred);
664cceb00   David Howells   [PATCH] Keys: Add...
658
659
660
661
662
  
  		if (!IS_ERR(skey_ref)) {
  			key_put(key);
  			key_ref = skey_ref;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
663
664
  		break;
  	}
5593122ee   David Howells   KEYS: Deal with d...
665
666
667
668
669
670
671
672
  	/* unlink does not use the nominated key in any way, so can skip all
  	 * the permission checks as it is only concerned with the keyring */
  	if (lflags & KEY_LOOKUP_FOR_UNLINK) {
  		ret = 0;
  		goto error;
  	}
  
  	if (!(lflags & KEY_LOOKUP_PARTIAL)) {
76181c134   David Howells   KEYS: Make reques...
673
674
675
676
677
678
679
680
681
682
683
  		ret = wait_for_key_construction(key, true);
  		switch (ret) {
  		case -ERESTARTSYS:
  			goto invalid_key;
  		default:
  			if (perm)
  				goto invalid_key;
  		case 0:
  			break;
  		}
  	} else if (perm) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
684
685
686
687
688
689
  		ret = key_validate(key);
  		if (ret < 0)
  			goto invalid_key;
  	}
  
  	ret = -EIO;
5593122ee   David Howells   KEYS: Deal with d...
690
691
  	if (!(lflags & KEY_LOOKUP_PARTIAL) &&
  	    !test_bit(KEY_FLAG_INSTANTIATED, &key->flags))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
692
  		goto invalid_key;
3e30148c3   David Howells   [PATCH] Keys: Mak...
693
  	/* check the permissions */
d84f4f992   David Howells   CRED: Inaugurate ...
694
  	ret = key_task_permission(key_ref, cred, perm);
29db91906   David Howells   [PATCH] Keys: Add...
695
  	if (ret < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
696
  		goto invalid_key;
664cceb00   David Howells   [PATCH] Keys: Add...
697
  error:
bb952bb98   David Howells   CRED: Separate pe...
698
  	put_cred(cred);
664cceb00   David Howells   [PATCH] Keys: Add...
699
  	return key_ref;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
700

664cceb00   David Howells   [PATCH] Keys: Add...
701
702
703
  invalid_key:
  	key_ref_put(key_ref);
  	key_ref = ERR_PTR(ret);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
704
  	goto error;
bb952bb98   David Howells   CRED: Separate pe...
705
706
707
708
709
  	/* if we attempted to install a keyring, then it may have caused new
  	 * creds to be installed */
  reget_creds:
  	put_cred(cred);
  	goto try_again;
a8b17ed01   David Howells   KEYS: Do some sty...
710
  }
bb952bb98   David Howells   CRED: Separate pe...
711

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
712
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
713
714
715
716
717
718
719
720
721
   * Join the named keyring as the session keyring if possible else attempt to
   * create a new one of that name and join that.
   *
   * If the name is NULL, an empty anonymous keyring will be installed as the
   * session keyring.
   *
   * Named session keyrings are joined with a semaphore held to prevent the
   * keyrings from going away whilst the attempt is made to going them and also
   * to prevent a race in creating compatible session keyrings.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
722
723
724
   */
  long join_session_keyring(const char *name)
  {
d84f4f992   David Howells   CRED: Inaugurate ...
725
726
  	const struct cred *old;
  	struct cred *new;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
727
  	struct key *keyring;
d84f4f992   David Howells   CRED: Inaugurate ...
728
729
730
731
732
  	long ret, serial;
  
  	/* only permit this if there's a single thread in the thread group -
  	 * this avoids us having to adjust the creds on all threads and risking
  	 * ENOMEM */
5bb459bb4   Oleg Nesterov   kernel: rename is...
733
  	if (!current_is_single_threaded())
d84f4f992   David Howells   CRED: Inaugurate ...
734
735
736
737
738
739
  		return -EMLINK;
  
  	new = prepare_creds();
  	if (!new)
  		return -ENOMEM;
  	old = current_cred();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
740
741
742
  
  	/* if no name is provided, install an anonymous keyring */
  	if (!name) {
d84f4f992   David Howells   CRED: Inaugurate ...
743
  		ret = install_session_keyring_to_cred(new, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
744
745
  		if (ret < 0)
  			goto error;
d84f4f992   David Howells   CRED: Inaugurate ...
746
747
748
749
750
  		serial = new->tgcred->session_keyring->serial;
  		ret = commit_creds(new);
  		if (ret == 0)
  			ret = serial;
  		goto okay;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
751
752
753
  	}
  
  	/* allow the user to join or create a named keyring */
bb0030797   Ingo Molnar   [PATCH] sem2mutex...
754
  	mutex_lock(&key_session_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
755
756
  
  	/* look for an existing keyring of this name */
69664cf16   David Howells   keys: don't gener...
757
  	keyring = find_keyring_by_name(name, false);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
758
759
  	if (PTR_ERR(keyring) == -ENOKEY) {
  		/* not found - try and create a new one */
d84f4f992   David Howells   CRED: Inaugurate ...
760
  		keyring = keyring_alloc(name, old->uid, old->gid, old,
7e047ef5f   David Howells   [PATCH] keys: sor...
761
  					KEY_ALLOC_IN_QUOTA, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
762
763
  		if (IS_ERR(keyring)) {
  			ret = PTR_ERR(keyring);
bcf945d36   David Howells   [PATCH] Error dur...
764
  			goto error2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
765
  		}
d84f4f992   David Howells   CRED: Inaugurate ...
766
  	} else if (IS_ERR(keyring)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
767
768
769
770
771
  		ret = PTR_ERR(keyring);
  		goto error2;
  	}
  
  	/* we've got a keyring - now to install it */
d84f4f992   David Howells   CRED: Inaugurate ...
772
  	ret = install_session_keyring_to_cred(new, keyring);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
773
774
  	if (ret < 0)
  		goto error2;
d84f4f992   David Howells   CRED: Inaugurate ...
775
776
  	commit_creds(new);
  	mutex_unlock(&key_session_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
777
778
  	ret = keyring->serial;
  	key_put(keyring);
d84f4f992   David Howells   CRED: Inaugurate ...
779
780
  okay:
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
781

664cceb00   David Howells   [PATCH] Keys: Add...
782
  error2:
bb0030797   Ingo Molnar   [PATCH] sem2mutex...
783
  	mutex_unlock(&key_session_mutex);
664cceb00   David Howells   [PATCH] Keys: Add...
784
  error:
d84f4f992   David Howells   CRED: Inaugurate ...
785
  	abort_creds(new);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
786
  	return ret;
d84f4f992   David Howells   CRED: Inaugurate ...
787
  }
ee18d64c1   David Howells   KEYS: Add a keyct...
788
789
  
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
790
791
   * Replace a process's session keyring on behalf of one of its children when
   * the target  process is about to resume userspace execution.
ee18d64c1   David Howells   KEYS: Add a keyct...
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
   */
  void key_replace_session_keyring(void)
  {
  	const struct cred *old;
  	struct cred *new;
  
  	if (!current->replacement_session_keyring)
  		return;
  
  	write_lock_irq(&tasklist_lock);
  	new = current->replacement_session_keyring;
  	current->replacement_session_keyring = NULL;
  	write_unlock_irq(&tasklist_lock);
  
  	if (!new)
  		return;
  
  	old = current_cred();
  	new->  uid	= old->  uid;
  	new-> euid	= old-> euid;
  	new-> suid	= old-> suid;
  	new->fsuid	= old->fsuid;
  	new->  gid	= old->  gid;
  	new-> egid	= old-> egid;
  	new-> sgid	= old-> sgid;
  	new->fsgid	= old->fsgid;
  	new->user	= get_uid(old->user);
f7285b5d6   Serge E. Hallyn   Set cred->user_ns...
819
  	new->user_ns	= new->user->user_ns;
ee18d64c1   David Howells   KEYS: Add a keyct...
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
  	new->group_info	= get_group_info(old->group_info);
  
  	new->securebits	= old->securebits;
  	new->cap_inheritable	= old->cap_inheritable;
  	new->cap_permitted	= old->cap_permitted;
  	new->cap_effective	= old->cap_effective;
  	new->cap_bset		= old->cap_bset;
  
  	new->jit_keyring	= old->jit_keyring;
  	new->thread_keyring	= key_get(old->thread_keyring);
  	new->tgcred->tgid	= old->tgcred->tgid;
  	new->tgcred->process_keyring = key_get(old->tgcred->process_keyring);
  
  	security_transfer_creds(new, old);
  
  	commit_creds(new);
  }