Blame view

security/keys/keyring.c 23.5 KB
69664cf16   David Howells   keys: don't gener...
1
  /* Keyring handling
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
15
   * 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>
  #include <linux/slab.h>
29db91906   David Howells   [PATCH] Keys: Add...
16
  #include <linux/security.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
  #include <linux/seq_file.h>
  #include <linux/err.h>
  #include <asm/uaccess.h>
  #include "internal.h"
  
  /*
   * when plumbing the depths of the key tree, this sets a hard limit set on how
   * deep we're willing to go
   */
  #define KEYRING_SEARCH_MAX_DEPTH 6
  
  /*
   * we keep all named keyrings in a hash to speed looking them up
   */
  #define KEYRING_NAME_HASH_SIZE	(1 << 5)
  
  static struct list_head	keyring_name_hash[KEYRING_NAME_HASH_SIZE];
  static DEFINE_RWLOCK(keyring_name_lock);
  
  static inline unsigned keyring_hash(const char *desc)
  {
  	unsigned bucket = 0;
  
  	for (; *desc; desc++)
  		bucket += (unsigned char) *desc;
  
  	return bucket & (KEYRING_NAME_HASH_SIZE - 1);
  }
  
  /*
   * the keyring type definition
   */
  static int keyring_instantiate(struct key *keyring,
  			       const void *data, size_t datalen);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
51
  static int keyring_match(const struct key *keyring, const void *criterion);
31204ed92   David Howells   [PATCH] keys: dis...
52
  static void keyring_revoke(struct key *keyring);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
53
54
55
56
57
58
59
60
61
  static void keyring_destroy(struct key *keyring);
  static void keyring_describe(const struct key *keyring, struct seq_file *m);
  static long keyring_read(const struct key *keyring,
  			 char __user *buffer, size_t buflen);
  
  struct key_type key_type_keyring = {
  	.name		= "keyring",
  	.def_datalen	= sizeof(struct keyring_list),
  	.instantiate	= keyring_instantiate,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62
  	.match		= keyring_match,
31204ed92   David Howells   [PATCH] keys: dis...
63
  	.revoke		= keyring_revoke,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
64
65
66
67
  	.destroy	= keyring_destroy,
  	.describe	= keyring_describe,
  	.read		= keyring_read,
  };
7318226ea   David Howells   [AF_RXRPC]: Key f...
68
  EXPORT_SYMBOL(key_type_keyring);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
69
70
71
72
  /*
   * semaphore to serialise link/link calls to prevent two link calls in parallel
   * introducing a cycle
   */
1ae8f4076   Adrian Bunk   [PATCH] security/...
73
  static DECLARE_RWSEM(keyring_serialise_link_sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
74
75
76
77
78
79
  
  /*****************************************************************************/
  /*
   * publish the name of a keyring so that it can be found by name (if it has
   * one)
   */
69664cf16   David Howells   keys: don't gener...
80
  static void keyring_publish_name(struct key *keyring)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
  {
  	int bucket;
  
  	if (keyring->description) {
  		bucket = keyring_hash(keyring->description);
  
  		write_lock(&keyring_name_lock);
  
  		if (!keyring_name_hash[bucket].next)
  			INIT_LIST_HEAD(&keyring_name_hash[bucket]);
  
  		list_add_tail(&keyring->type_data.link,
  			      &keyring_name_hash[bucket]);
  
  		write_unlock(&keyring_name_lock);
  	}
  
  } /* end keyring_publish_name() */
  
  /*****************************************************************************/
  /*
   * initialise a keyring
   * - we object if we were given any data
   */
  static int keyring_instantiate(struct key *keyring,
  			       const void *data, size_t datalen)
  {
  	int ret;
  
  	ret = -EINVAL;
  	if (datalen == 0) {
  		/* make the keyring available by name if it has one */
  		keyring_publish_name(keyring);
  		ret = 0;
  	}
  
  	return ret;
  
  } /* end keyring_instantiate() */
  
  /*****************************************************************************/
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
   * match keyrings on their name
   */
  static int keyring_match(const struct key *keyring, const void *description)
  {
  	return keyring->description &&
  		strcmp(keyring->description, description) == 0;
  
  } /* end keyring_match() */
  
  /*****************************************************************************/
  /*
   * dispose of the data dangling from the corpse of a keyring
   */
  static void keyring_destroy(struct key *keyring)
  {
  	struct keyring_list *klist;
  	int loop;
  
  	if (keyring->description) {
  		write_lock(&keyring_name_lock);
94efe72f7   David Howells   [PATCH] Destructi...
143
144
145
146
  
  		if (keyring->type_data.link.next != NULL &&
  		    !list_empty(&keyring->type_data.link))
  			list_del(&keyring->type_data.link);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
147
148
  		write_unlock(&keyring_name_lock);
  	}
76d8aeabf   David Howells   [PATCH] keys: Dis...
149
  	klist = rcu_dereference(keyring->payload.subscriptions);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
  	if (klist) {
  		for (loop = klist->nkeys - 1; loop >= 0; loop--)
  			key_put(klist->keys[loop]);
  		kfree(klist);
  	}
  
  } /* end keyring_destroy() */
  
  /*****************************************************************************/
  /*
   * describe the keyring
   */
  static void keyring_describe(const struct key *keyring, struct seq_file *m)
  {
  	struct keyring_list *klist;
  
  	if (keyring->description) {
  		seq_puts(m, keyring->description);
  	}
  	else {
  		seq_puts(m, "[anon]");
  	}
76d8aeabf   David Howells   [PATCH] keys: Dis...
172
173
  	rcu_read_lock();
  	klist = rcu_dereference(keyring->payload.subscriptions);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
174
175
176
177
  	if (klist)
  		seq_printf(m, ": %u/%u", klist->nkeys, klist->maxkeys);
  	else
  		seq_puts(m, ": empty");
76d8aeabf   David Howells   [PATCH] keys: Dis...
178
  	rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
179
180
181
182
183
184
  
  } /* end keyring_describe() */
  
  /*****************************************************************************/
  /*
   * read a list of key IDs from the keyring's contents
76d8aeabf   David Howells   [PATCH] keys: Dis...
185
   * - the keyring's semaphore is read-locked
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
186
187
188
189
190
191
192
193
194
195
   */
  static long keyring_read(const struct key *keyring,
  			 char __user *buffer, size_t buflen)
  {
  	struct keyring_list *klist;
  	struct key *key;
  	size_t qty, tmp;
  	int loop, ret;
  
  	ret = 0;
76d8aeabf   David Howells   [PATCH] keys: Dis...
196
  	klist = rcu_dereference(keyring->payload.subscriptions);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
  
  	if (klist) {
  		/* calculate how much data we could return */
  		qty = klist->nkeys * sizeof(key_serial_t);
  
  		if (buffer && buflen > 0) {
  			if (buflen > qty)
  				buflen = qty;
  
  			/* copy the IDs of the subscribed keys into the
  			 * buffer */
  			ret = -EFAULT;
  
  			for (loop = 0; loop < klist->nkeys; loop++) {
  				key = klist->keys[loop];
  
  				tmp = sizeof(key_serial_t);
  				if (tmp > buflen)
  					tmp = buflen;
  
  				if (copy_to_user(buffer,
  						 &key->serial,
  						 tmp) != 0)
  					goto error;
  
  				buflen -= tmp;
  				if (buflen == 0)
  					break;
  				buffer += tmp;
  			}
  		}
  
  		ret = qty;
  	}
  
   error:
  	return ret;
  
  } /* end keyring_read() */
  
  /*****************************************************************************/
  /*
   * allocate a keyring and link into the destination keyring
   */
  struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,
7e047ef5f   David Howells   [PATCH] keys: sor...
242
  			  struct task_struct *ctx, unsigned long flags,
d720024e9   Michael LeMay   [PATCH] selinux: ...
243
  			  struct key *dest)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
244
245
246
247
248
  {
  	struct key *keyring;
  	int ret;
  
  	keyring = key_alloc(&key_type_keyring, description,
d720024e9   Michael LeMay   [PATCH] selinux: ...
249
  			    uid, gid, ctx,
29db91906   David Howells   [PATCH] Keys: Add...
250
  			    (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_ALL,
7e047ef5f   David Howells   [PATCH] keys: sor...
251
  			    flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
252
253
  
  	if (!IS_ERR(keyring)) {
3e30148c3   David Howells   [PATCH] Keys: Mak...
254
  		ret = key_instantiate_and_link(keyring, NULL, 0, dest, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
  		if (ret < 0) {
  			key_put(keyring);
  			keyring = ERR_PTR(ret);
  		}
  	}
  
  	return keyring;
  
  } /* end keyring_alloc() */
  
  /*****************************************************************************/
  /*
   * search the supplied keyring tree for a key that matches the criterion
   * - perform a breadth-then-depth search up to the prescribed limit
   * - we only find keys on which we have search permission
   * - we use the supplied match function to see if the description (or other
   *   feature of interest) matches
3e30148c3   David Howells   [PATCH] Keys: Mak...
272
   * - we rely on RCU to prevent the keyring lists from disappearing on us
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
273
274
   * - we return -EAGAIN if we didn't find any matching key
   * - we return -ENOKEY if we only found negative matching keys
664cceb00   David Howells   [PATCH] Keys: Add...
275
   * - we propagate the possession attribute from the keyring ref to the key ref
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
276
   */
664cceb00   David Howells   [PATCH] Keys: Add...
277
278
279
280
281
  key_ref_t keyring_search_aux(key_ref_t keyring_ref,
  			     struct task_struct *context,
  			     struct key_type *type,
  			     const void *description,
  			     key_match_func_t match)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
282
283
  {
  	struct {
76d8aeabf   David Howells   [PATCH] keys: Dis...
284
  		struct keyring_list *keylist;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
285
286
287
288
289
  		int kix;
  	} stack[KEYRING_SEARCH_MAX_DEPTH];
  
  	struct keyring_list *keylist;
  	struct timespec now;
dceba9944   Kevin Coffman   keys: check start...
290
  	unsigned long possessed, kflags;
664cceb00   David Howells   [PATCH] Keys: Add...
291
292
  	struct key *keyring, *key;
  	key_ref_t key_ref;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
293
  	long err;
76d8aeabf   David Howells   [PATCH] keys: Dis...
294
  	int sp, kix;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
295

664cceb00   David Howells   [PATCH] Keys: Add...
296
297
  	keyring = key_ref_to_ptr(keyring_ref);
  	possessed = is_key_possessed(keyring_ref);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
298
299
300
  	key_check(keyring);
  
  	/* top keyring must have search permission to begin the search */
29db91906   David Howells   [PATCH] Keys: Add...
301
302
303
          err = key_task_permission(keyring_ref, context, KEY_SEARCH);
  	if (err < 0) {
  		key_ref = ERR_PTR(err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
304
  		goto error;
29db91906   David Howells   [PATCH] Keys: Add...
305
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
306

664cceb00   David Howells   [PATCH] Keys: Add...
307
  	key_ref = ERR_PTR(-ENOTDIR);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
308
309
  	if (keyring->type != &key_type_keyring)
  		goto error;
664cceb00   David Howells   [PATCH] Keys: Add...
310
  	rcu_read_lock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
311
312
313
  	now = current_kernel_time();
  	err = -EAGAIN;
  	sp = 0;
dceba9944   Kevin Coffman   keys: check start...
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
  	/* firstly we should check to see if this top-level keyring is what we
  	 * are looking for */
  	key_ref = ERR_PTR(-EAGAIN);
  	kflags = keyring->flags;
  	if (keyring->type == type && match(keyring, description)) {
  		key = keyring;
  
  		/* check it isn't negative and hasn't expired or been
  		 * revoked */
  		if (kflags & (1 << KEY_FLAG_REVOKED))
  			goto error_2;
  		if (key->expiry && now.tv_sec >= key->expiry)
  			goto error_2;
  		key_ref = ERR_PTR(-ENOKEY);
  		if (kflags & (1 << KEY_FLAG_NEGATIVE))
  			goto error_2;
  		goto found;
  	}
  
  	/* otherwise, the top keyring must not be revoked, expired, or
  	 * negatively instantiated if we are to search it */
  	key_ref = ERR_PTR(-EAGAIN);
  	if (kflags & ((1 << KEY_FLAG_REVOKED) | (1 << KEY_FLAG_NEGATIVE)) ||
  	    (keyring->expiry && now.tv_sec >= keyring->expiry))
  		goto error_2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
339
  	/* start processing a new keyring */
664cceb00   David Howells   [PATCH] Keys: Add...
340
  descend:
76d8aeabf   David Howells   [PATCH] keys: Dis...
341
  	if (test_bit(KEY_FLAG_REVOKED, &keyring->flags))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
342
  		goto not_this_keyring;
76d8aeabf   David Howells   [PATCH] keys: Dis...
343
  	keylist = rcu_dereference(keyring->payload.subscriptions);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
344
345
346
347
348
349
  	if (!keylist)
  		goto not_this_keyring;
  
  	/* iterate through the keys in this keyring first */
  	for (kix = 0; kix < keylist->nkeys; kix++) {
  		key = keylist->keys[kix];
dceba9944   Kevin Coffman   keys: check start...
350
  		kflags = key->flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
351
352
353
354
355
356
  
  		/* ignore keys not of this type */
  		if (key->type != type)
  			continue;
  
  		/* skip revoked keys and expired keys */
dceba9944   Kevin Coffman   keys: check start...
357
  		if (kflags & (1 << KEY_FLAG_REVOKED))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
358
359
360
361
362
363
364
365
366
367
  			continue;
  
  		if (key->expiry && now.tv_sec >= key->expiry)
  			continue;
  
  		/* keys that don't match */
  		if (!match(key, description))
  			continue;
  
  		/* key must have search permissions */
29db91906   David Howells   [PATCH] Keys: Add...
368
369
  		if (key_task_permission(make_key_ref(key, possessed),
  					context, KEY_SEARCH) < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
370
  			continue;
dceba9944   Kevin Coffman   keys: check start...
371
372
  		/* we set a different error code if we pass a negative key */
  		if (kflags & (1 << KEY_FLAG_NEGATIVE)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
373
374
375
376
377
378
379
380
381
  			err = -ENOKEY;
  			continue;
  		}
  
  		goto found;
  	}
  
  	/* search through the keyrings nested in this one */
  	kix = 0;
664cceb00   David Howells   [PATCH] Keys: Add...
382
  ascend:
76d8aeabf   David Howells   [PATCH] keys: Dis...
383
  	for (; kix < keylist->nkeys; kix++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
384
385
  		key = keylist->keys[kix];
  		if (key->type != &key_type_keyring)
76d8aeabf   David Howells   [PATCH] keys: Dis...
386
  			continue;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
387
388
389
390
391
  
  		/* recursively search nested keyrings
  		 * - only search keyrings for which we have search permission
  		 */
  		if (sp >= KEYRING_SEARCH_MAX_DEPTH)
76d8aeabf   David Howells   [PATCH] keys: Dis...
392
  			continue;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
393

0f6ed7c26   David Howells   [PATCH] Keys: Rem...
394
395
  		if (key_task_permission(make_key_ref(key, possessed),
  					context, KEY_SEARCH) < 0)
76d8aeabf   David Howells   [PATCH] keys: Dis...
396
  			continue;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
397
398
  
  		/* stack the current position */
76d8aeabf   David Howells   [PATCH] keys: Dis...
399
  		stack[sp].keylist = keylist;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
400
401
402
403
404
405
  		stack[sp].kix = kix;
  		sp++;
  
  		/* begin again with the new keyring */
  		keyring = key;
  		goto descend;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
406
407
408
409
  	}
  
  	/* the keyring we're looking at was disqualified or didn't contain a
  	 * matching key */
664cceb00   David Howells   [PATCH] Keys: Add...
410
  not_this_keyring:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
411
412
413
  	if (sp > 0) {
  		/* resume the processing of a keyring higher up in the tree */
  		sp--;
76d8aeabf   David Howells   [PATCH] keys: Dis...
414
  		keylist = stack[sp].keylist;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
415
416
417
  		kix = stack[sp].kix + 1;
  		goto ascend;
  	}
664cceb00   David Howells   [PATCH] Keys: Add...
418
419
  	key_ref = ERR_PTR(err);
  	goto error_2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
420
421
  
  	/* we found a viable match */
664cceb00   David Howells   [PATCH] Keys: Add...
422
  found:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
423
  	atomic_inc(&key->usage);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
424
  	key_check(key);
664cceb00   David Howells   [PATCH] Keys: Add...
425
426
  	key_ref = make_key_ref(key, possessed);
  error_2:
76d8aeabf   David Howells   [PATCH] keys: Dis...
427
  	rcu_read_unlock();
664cceb00   David Howells   [PATCH] Keys: Add...
428
429
  error:
  	return key_ref;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
430
431
432
433
434
435
436
437
438
439
440
441
  
  } /* end keyring_search_aux() */
  
  /*****************************************************************************/
  /*
   * search the supplied keyring tree for a key that matches the criterion
   * - perform a breadth-then-depth search up to the prescribed limit
   * - we only find keys on which we have search permission
   * - we readlock the keyrings as we search down the tree
   * - we return -EAGAIN if we didn't find any matching key
   * - we return -ENOKEY if we only found negative matching keys
   */
664cceb00   David Howells   [PATCH] Keys: Add...
442
443
444
  key_ref_t keyring_search(key_ref_t keyring,
  			 struct key_type *type,
  			 const char *description)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
445
  {
3e30148c3   David Howells   [PATCH] Keys: Mak...
446
447
448
449
450
  	if (!type->match)
  		return ERR_PTR(-ENOKEY);
  
  	return keyring_search_aux(keyring, current,
  				  type, description, type->match);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
451
452
453
454
455
456
457
458
459
  
  } /* end keyring_search() */
  
  EXPORT_SYMBOL(keyring_search);
  
  /*****************************************************************************/
  /*
   * search the given keyring only (no recursion)
   * - keyring must be locked by caller
c3a9d6541   David Howells   [Security] Keys: ...
460
   * - caller must guarantee that the keyring is a keyring
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
461
   */
664cceb00   David Howells   [PATCH] Keys: Add...
462
463
464
465
  key_ref_t __keyring_search_one(key_ref_t keyring_ref,
  			       const struct key_type *ktype,
  			       const char *description,
  			       key_perm_t perm)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
466
467
  {
  	struct keyring_list *klist;
664cceb00   David Howells   [PATCH] Keys: Add...
468
469
  	unsigned long possessed;
  	struct key *keyring, *key;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
470
  	int loop;
664cceb00   David Howells   [PATCH] Keys: Add...
471
472
  	keyring = key_ref_to_ptr(keyring_ref);
  	possessed = is_key_possessed(keyring_ref);
76d8aeabf   David Howells   [PATCH] keys: Dis...
473
474
475
  	rcu_read_lock();
  
  	klist = rcu_dereference(keyring->payload.subscriptions);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
476
477
478
479
480
  	if (klist) {
  		for (loop = 0; loop < klist->nkeys; loop++) {
  			key = klist->keys[loop];
  
  			if (key->type == ktype &&
3e30148c3   David Howells   [PATCH] Keys: Mak...
481
482
  			    (!key->type->match ||
  			     key->type->match(key, description)) &&
664cceb00   David Howells   [PATCH] Keys: Add...
483
  			    key_permission(make_key_ref(key, possessed),
db1d1d57e   David Howells   [PATCH] Keys: Fix...
484
  					   perm) == 0 &&
76d8aeabf   David Howells   [PATCH] keys: Dis...
485
  			    !test_bit(KEY_FLAG_REVOKED, &key->flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
486
487
488
489
  			    )
  				goto found;
  		}
  	}
664cceb00   David Howells   [PATCH] Keys: Add...
490
491
  	rcu_read_unlock();
  	return ERR_PTR(-ENOKEY);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
492
493
494
  
   found:
  	atomic_inc(&key->usage);
76d8aeabf   David Howells   [PATCH] keys: Dis...
495
  	rcu_read_unlock();
664cceb00   David Howells   [PATCH] Keys: Add...
496
  	return make_key_ref(key, possessed);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
497
498
499
500
501
502
503
  
  } /* end __keyring_search_one() */
  
  /*****************************************************************************/
  /*
   * find a keyring with the specified name
   * - all named keyrings are searched
69664cf16   David Howells   keys: don't gener...
504
   * - normally only finds keyrings with search permission for the current process
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
505
   */
69664cf16   David Howells   keys: don't gener...
506
  struct key *find_keyring_by_name(const char *name, bool skip_perm_check)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
  {
  	struct key *keyring;
  	int bucket;
  
  	keyring = ERR_PTR(-EINVAL);
  	if (!name)
  		goto error;
  
  	bucket = keyring_hash(name);
  
  	read_lock(&keyring_name_lock);
  
  	if (keyring_name_hash[bucket].next) {
  		/* search this hash bucket for a keyring with a matching name
  		 * that's readable and that hasn't been revoked */
  		list_for_each_entry(keyring,
  				    &keyring_name_hash[bucket],
  				    type_data.link
  				    ) {
76d8aeabf   David Howells   [PATCH] keys: Dis...
526
  			if (test_bit(KEY_FLAG_REVOKED, &keyring->flags))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
527
528
529
530
  				continue;
  
  			if (strcmp(keyring->description, name) != 0)
  				continue;
69664cf16   David Howells   keys: don't gener...
531
532
  			if (!skip_perm_check &&
  			    key_permission(make_key_ref(keyring, 0),
0f6ed7c26   David Howells   [PATCH] Keys: Rem...
533
  					   KEY_SEARCH) < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
534
  				continue;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
  			/* we've got a match */
  			atomic_inc(&keyring->usage);
  			read_unlock(&keyring_name_lock);
  			goto error;
  		}
  	}
  
  	read_unlock(&keyring_name_lock);
  	keyring = ERR_PTR(-ENOKEY);
  
   error:
  	return keyring;
  
  } /* end find_keyring_by_name() */
  
  /*****************************************************************************/
  /*
   * see if a cycle will will be created by inserting acyclic tree B in acyclic
   * tree A at the topmost level (ie: as a direct child of A)
   * - since we are adding B to A at the top level, checking for cycles should
   *   just be a matter of seeing if node A is somewhere in tree B
   */
  static int keyring_detect_cycle(struct key *A, struct key *B)
  {
  	struct {
76d8aeabf   David Howells   [PATCH] keys: Dis...
560
  		struct keyring_list *keylist;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
561
562
563
564
565
566
  		int kix;
  	} stack[KEYRING_SEARCH_MAX_DEPTH];
  
  	struct keyring_list *keylist;
  	struct key *subtree, *key;
  	int sp, kix, ret;
76d8aeabf   David Howells   [PATCH] keys: Dis...
567
  	rcu_read_lock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
568
569
  	ret = -EDEADLK;
  	if (A == B)
76d8aeabf   David Howells   [PATCH] keys: Dis...
570
  		goto cycle_detected;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
571
572
573
574
575
576
  
  	subtree = B;
  	sp = 0;
  
  	/* start processing a new keyring */
   descend:
76d8aeabf   David Howells   [PATCH] keys: Dis...
577
  	if (test_bit(KEY_FLAG_REVOKED, &subtree->flags))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
578
  		goto not_this_keyring;
76d8aeabf   David Howells   [PATCH] keys: Dis...
579
  	keylist = rcu_dereference(subtree->payload.subscriptions);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
  	if (!keylist)
  		goto not_this_keyring;
  	kix = 0;
  
   ascend:
  	/* iterate through the remaining keys in this keyring */
  	for (; kix < keylist->nkeys; kix++) {
  		key = keylist->keys[kix];
  
  		if (key == A)
  			goto cycle_detected;
  
  		/* recursively check nested keyrings */
  		if (key->type == &key_type_keyring) {
  			if (sp >= KEYRING_SEARCH_MAX_DEPTH)
  				goto too_deep;
  
  			/* stack the current position */
76d8aeabf   David Howells   [PATCH] keys: Dis...
598
  			stack[sp].keylist = keylist;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
599
600
601
602
603
604
605
606
607
608
609
610
  			stack[sp].kix = kix;
  			sp++;
  
  			/* begin again with the new keyring */
  			subtree = key;
  			goto descend;
  		}
  	}
  
  	/* the keyring we're looking at was disqualified or didn't contain a
  	 * matching key */
   not_this_keyring:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
611
612
613
  	if (sp > 0) {
  		/* resume the checking of a keyring higher up in the tree */
  		sp--;
76d8aeabf   David Howells   [PATCH] keys: Dis...
614
  		keylist = stack[sp].keylist;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
615
616
617
618
619
620
621
  		kix = stack[sp].kix + 1;
  		goto ascend;
  	}
  
  	ret = 0; /* no cycles detected */
  
   error:
76d8aeabf   David Howells   [PATCH] keys: Dis...
622
  	rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
623
624
625
626
  	return ret;
  
   too_deep:
  	ret = -ELOOP;
76d8aeabf   David Howells   [PATCH] keys: Dis...
627
  	goto error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
628
629
   cycle_detected:
  	ret = -EDEADLK;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
630
631
632
633
634
635
  	goto error;
  
  } /* end keyring_detect_cycle() */
  
  /*****************************************************************************/
  /*
76d8aeabf   David Howells   [PATCH] keys: Dis...
636
637
638
639
640
641
642
643
644
645
646
647
648
   * dispose of a keyring list after the RCU grace period
   */
  static void keyring_link_rcu_disposal(struct rcu_head *rcu)
  {
  	struct keyring_list *klist =
  		container_of(rcu, struct keyring_list, rcu);
  
  	kfree(klist);
  
  } /* end keyring_link_rcu_disposal() */
  
  /*****************************************************************************/
  /*
cab8eb594   David Howells   [PATCH] keys: Dis...
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
   * dispose of a keyring list after the RCU grace period, freeing the unlinked
   * key
   */
  static void keyring_unlink_rcu_disposal(struct rcu_head *rcu)
  {
  	struct keyring_list *klist =
  		container_of(rcu, struct keyring_list, rcu);
  
  	key_put(klist->keys[klist->delkey]);
  	kfree(klist);
  
  } /* end keyring_unlink_rcu_disposal() */
  
  /*****************************************************************************/
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
664
   * link a key into to a keyring
76d8aeabf   David Howells   [PATCH] keys: Dis...
665
   * - must be called with the keyring's semaphore write-locked
cab8eb594   David Howells   [PATCH] keys: Dis...
666
   * - discard already extant link to matching key if there is one
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
667
668
669
670
671
672
   */
  int __key_link(struct key *keyring, struct key *key)
  {
  	struct keyring_list *klist, *nklist;
  	unsigned max;
  	size_t size;
cab8eb594   David Howells   [PATCH] keys: Dis...
673
  	int loop, ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
674
675
  
  	ret = -EKEYREVOKED;
76d8aeabf   David Howells   [PATCH] keys: Dis...
676
  	if (test_bit(KEY_FLAG_REVOKED, &keyring->flags))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
  		goto error;
  
  	ret = -ENOTDIR;
  	if (keyring->type != &key_type_keyring)
  		goto error;
  
  	/* serialise link/link calls to prevent parallel calls causing a
  	 * cycle when applied to two keyring in opposite orders */
  	down_write(&keyring_serialise_link_sem);
  
  	/* check that we aren't going to create a cycle adding one keyring to
  	 * another */
  	if (key->type == &key_type_keyring) {
  		ret = keyring_detect_cycle(keyring, key);
  		if (ret < 0)
  			goto error2;
  	}
cab8eb594   David Howells   [PATCH] keys: Dis...
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
  	/* see if there's a matching key we can displace */
  	klist = keyring->payload.subscriptions;
  
  	if (klist && klist->nkeys > 0) {
  		struct key_type *type = key->type;
  
  		for (loop = klist->nkeys - 1; loop >= 0; loop--) {
  			if (klist->keys[loop]->type == type &&
  			    strcmp(klist->keys[loop]->description,
  				   key->description) == 0
  			    ) {
  				/* found a match - replace with new key */
  				size = sizeof(struct key *) * klist->maxkeys;
  				size += sizeof(*klist);
  				BUG_ON(size > PAGE_SIZE);
  
  				ret = -ENOMEM;
48ad504ee   Eric Sesterhenn   [PATCH] security/...
711
  				nklist = kmemdup(klist, size, GFP_KERNEL);
cab8eb594   David Howells   [PATCH] keys: Dis...
712
713
  				if (!nklist)
  					goto error2;
cab8eb594   David Howells   [PATCH] keys: Dis...
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
  				/* replace matched key */
  				atomic_inc(&key->usage);
  				nklist->keys[loop] = key;
  
  				rcu_assign_pointer(
  					keyring->payload.subscriptions,
  					nklist);
  
  				/* dispose of the old keyring list and the
  				 * displaced key */
  				klist->delkey = loop;
  				call_rcu(&klist->rcu,
  					 keyring_unlink_rcu_disposal);
  
  				goto done;
  			}
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
732
733
734
735
736
737
738
739
740
741
742
  	/* check that we aren't going to overrun the user's quota */
  	ret = key_payload_reserve(keyring,
  				  keyring->datalen + KEYQUOTA_LINK_BYTES);
  	if (ret < 0)
  		goto error2;
  
  	klist = keyring->payload.subscriptions;
  
  	if (klist && klist->nkeys < klist->maxkeys) {
  		/* there's sufficient slack space to add directly */
  		atomic_inc(&key->usage);
76d8aeabf   David Howells   [PATCH] keys: Dis...
743
744
745
746
  		klist->keys[klist->nkeys] = key;
  		smp_wmb();
  		klist->nkeys++;
  		smp_wmb();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
747
748
749
750
751
752
753
754
  	}
  	else {
  		/* grow the key list */
  		max = 4;
  		if (klist)
  			max += klist->maxkeys;
  
  		ret = -ENFILE;
76d8aeabf   David Howells   [PATCH] keys: Dis...
755
756
  		if (max > 65535)
  			goto error3;
a4014d8f6   David Howells   [PATCH] Keys: Bas...
757
  		size = sizeof(*klist) + sizeof(struct key *) * max;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
  		if (size > PAGE_SIZE)
  			goto error3;
  
  		ret = -ENOMEM;
  		nklist = kmalloc(size, GFP_KERNEL);
  		if (!nklist)
  			goto error3;
  		nklist->maxkeys = max;
  		nklist->nkeys = 0;
  
  		if (klist) {
  			nklist->nkeys = klist->nkeys;
  			memcpy(nklist->keys,
  			       klist->keys,
  			       sizeof(struct key *) * klist->nkeys);
  		}
  
  		/* add the key into the new space */
  		atomic_inc(&key->usage);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
777
  		nklist->keys[nklist->nkeys++] = key;
76d8aeabf   David Howells   [PATCH] keys: Dis...
778
779
  
  		rcu_assign_pointer(keyring->payload.subscriptions, nklist);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
780
781
  
  		/* dispose of the old keyring list */
76d8aeabf   David Howells   [PATCH] keys: Dis...
782
783
  		if (klist)
  			call_rcu(&klist->rcu, keyring_link_rcu_disposal);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
784
  	}
cab8eb594   David Howells   [PATCH] keys: Dis...
785
786
787
  done:
  	ret = 0;
  error2:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
788
  	up_write(&keyring_serialise_link_sem);
cab8eb594   David Howells   [PATCH] keys: Dis...
789
  error:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
790
  	return ret;
cab8eb594   David Howells   [PATCH] keys: Dis...
791
  error3:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
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
819
820
821
822
823
824
825
  	/* undo the quota changes */
  	key_payload_reserve(keyring,
  			    keyring->datalen - KEYQUOTA_LINK_BYTES);
  	goto error2;
  
  } /* end __key_link() */
  
  /*****************************************************************************/
  /*
   * link a key to a keyring
   */
  int key_link(struct key *keyring, struct key *key)
  {
  	int ret;
  
  	key_check(keyring);
  	key_check(key);
  
  	down_write(&keyring->sem);
  	ret = __key_link(keyring, key);
  	up_write(&keyring->sem);
  
  	return ret;
  
  } /* end key_link() */
  
  EXPORT_SYMBOL(key_link);
  
  /*****************************************************************************/
  /*
   * unlink the first link to a key from a keyring
   */
  int key_unlink(struct key *keyring, struct key *key)
  {
76d8aeabf   David Howells   [PATCH] keys: Dis...
826
  	struct keyring_list *klist, *nklist;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
  	int loop, ret;
  
  	key_check(keyring);
  	key_check(key);
  
  	ret = -ENOTDIR;
  	if (keyring->type != &key_type_keyring)
  		goto error;
  
  	down_write(&keyring->sem);
  
  	klist = keyring->payload.subscriptions;
  	if (klist) {
  		/* search the keyring for the key */
  		for (loop = 0; loop < klist->nkeys; loop++)
  			if (klist->keys[loop] == key)
  				goto key_is_present;
  	}
  
  	up_write(&keyring->sem);
  	ret = -ENOENT;
  	goto error;
76d8aeabf   David Howells   [PATCH] keys: Dis...
849
850
  key_is_present:
  	/* we need to copy the key list for RCU purposes */
a4014d8f6   David Howells   [PATCH] Keys: Bas...
851
852
  	nklist = kmalloc(sizeof(*klist) +
  			 sizeof(struct key *) * klist->maxkeys,
76d8aeabf   David Howells   [PATCH] keys: Dis...
853
854
855
856
857
858
859
860
861
  			 GFP_KERNEL);
  	if (!nklist)
  		goto nomem;
  	nklist->maxkeys = klist->maxkeys;
  	nklist->nkeys = klist->nkeys - 1;
  
  	if (loop > 0)
  		memcpy(&nklist->keys[0],
  		       &klist->keys[0],
a4014d8f6   David Howells   [PATCH] Keys: Bas...
862
  		       loop * sizeof(struct key *));
76d8aeabf   David Howells   [PATCH] keys: Dis...
863
864
865
866
  
  	if (loop < nklist->nkeys)
  		memcpy(&nklist->keys[loop],
  		       &klist->keys[loop + 1],
a4014d8f6   David Howells   [PATCH] Keys: Bas...
867
  		       (nklist->nkeys - loop) * sizeof(struct key *));
76d8aeabf   David Howells   [PATCH] keys: Dis...
868

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
869
870
871
  	/* adjust the user's quota */
  	key_payload_reserve(keyring,
  			    keyring->datalen - KEYQUOTA_LINK_BYTES);
76d8aeabf   David Howells   [PATCH] keys: Dis...
872
  	rcu_assign_pointer(keyring->payload.subscriptions, nklist);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
873

76d8aeabf   David Howells   [PATCH] keys: Dis...
874
  	up_write(&keyring->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
875

76d8aeabf   David Howells   [PATCH] keys: Dis...
876
877
878
  	/* schedule for later cleanup */
  	klist->delkey = loop;
  	call_rcu(&klist->rcu, keyring_unlink_rcu_disposal);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
879

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
880
  	ret = 0;
76d8aeabf   David Howells   [PATCH] keys: Dis...
881
  error:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
882
  	return ret;
76d8aeabf   David Howells   [PATCH] keys: Dis...
883
884
885
886
  nomem:
  	ret = -ENOMEM;
  	up_write(&keyring->sem);
  	goto error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
887
888
889
890
891
892
893
  
  } /* end key_unlink() */
  
  EXPORT_SYMBOL(key_unlink);
  
  /*****************************************************************************/
  /*
76d8aeabf   David Howells   [PATCH] keys: Dis...
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
   * dispose of a keyring list after the RCU grace period, releasing the keys it
   * links to
   */
  static void keyring_clear_rcu_disposal(struct rcu_head *rcu)
  {
  	struct keyring_list *klist;
  	int loop;
  
  	klist = container_of(rcu, struct keyring_list, rcu);
  
  	for (loop = klist->nkeys - 1; loop >= 0; loop--)
  		key_put(klist->keys[loop]);
  
  	kfree(klist);
  
  } /* end keyring_clear_rcu_disposal() */
  
  /*****************************************************************************/
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
913
914
915
916
917
918
   * clear the specified process keyring
   * - implements keyctl(KEYCTL_CLEAR)
   */
  int keyring_clear(struct key *keyring)
  {
  	struct keyring_list *klist;
76d8aeabf   David Howells   [PATCH] keys: Dis...
919
  	int ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
920
921
922
923
924
925
926
927
928
929
930
  
  	ret = -ENOTDIR;
  	if (keyring->type == &key_type_keyring) {
  		/* detach the pointer block with the locks held */
  		down_write(&keyring->sem);
  
  		klist = keyring->payload.subscriptions;
  		if (klist) {
  			/* adjust the quota */
  			key_payload_reserve(keyring,
  					    sizeof(struct keyring_list));
76d8aeabf   David Howells   [PATCH] keys: Dis...
931
932
  			rcu_assign_pointer(keyring->payload.subscriptions,
  					   NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
933
934
935
936
937
  		}
  
  		up_write(&keyring->sem);
  
  		/* free the keys after the locks have been dropped */
76d8aeabf   David Howells   [PATCH] keys: Dis...
938
939
  		if (klist)
  			call_rcu(&klist->rcu, keyring_clear_rcu_disposal);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
940
941
942
943
944
945
946
947
948
  
  		ret = 0;
  	}
  
  	return ret;
  
  } /* end keyring_clear() */
  
  EXPORT_SYMBOL(keyring_clear);
31204ed92   David Howells   [PATCH] keys: dis...
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
  
  /*****************************************************************************/
  /*
   * dispose of the links from a revoked keyring
   * - called with the key sem write-locked
   */
  static void keyring_revoke(struct key *keyring)
  {
  	struct keyring_list *klist = keyring->payload.subscriptions;
  
  	/* adjust the quota */
  	key_payload_reserve(keyring, 0);
  
  	if (klist) {
  		rcu_assign_pointer(keyring->payload.subscriptions, NULL);
  		call_rcu(&klist->rcu, keyring_clear_rcu_disposal);
  	}
  
  } /* end keyring_revoke() */