Blame view

security/keys/keyring.c 30.1 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
  #include <linux/seq_file.h>
  #include <linux/err.h>
e9e349b05   David Howells   KEYS: Disperse li...
19
  #include <keys/keyring-type.h>
512ea3bc3   Chihau Chau   Security: key: ke...
20
  #include <linux/uaccess.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21
  #include "internal.h"
f0641cba7   David Howells   KEYS: Use RCU der...
22
23
24
25
  #define rcu_dereference_locked_keyring(keyring)				\
  	(rcu_dereference_protected(					\
  		(keyring)->payload.subscriptions,			\
  		rwsem_is_locked((struct rw_semaphore *)&(keyring)->sem)))
ceb73c120   David Howells   KEYS: Fix __key_l...
26
  #define KEY_LINK_FIXQUOTA 1UL
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
28
29
   * When plumbing the depths of the key tree, this sets a hard limit
   * set on how deep we're willing to go.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
30
31
32
33
   */
  #define KEYRING_SEARCH_MAX_DEPTH 6
  
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
34
   * We keep all named keyrings in a hash to speed looking them up.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35
36
37
38
39
40
41
42
43
44
45
   */
  #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++)
c5b60b5e6   Justin P. Mattock   security: whitesp...
46
  		bucket += (unsigned char)*desc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47
48
49
50
51
  
  	return bucket & (KEYRING_NAME_HASH_SIZE - 1);
  }
  
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
52
53
54
   * The keyring key type definition.  Keyrings are simply keys of this type and
   * can be treated as ordinary keys in addition to having their own special
   * operations.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55
56
57
   */
  static int keyring_instantiate(struct key *keyring,
  			       const void *data, size_t datalen);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58
  static int keyring_match(const struct key *keyring, const void *criterion);
31204ed92   David Howells   [PATCH] keys: dis...
59
  static void keyring_revoke(struct key *keyring);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
60
61
62
63
64
65
66
67
68
  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
69
  	.match		= keyring_match,
31204ed92   David Howells   [PATCH] keys: dis...
70
  	.revoke		= keyring_revoke,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
71
72
73
74
  	.destroy	= keyring_destroy,
  	.describe	= keyring_describe,
  	.read		= keyring_read,
  };
7318226ea   David Howells   [AF_RXRPC]: Key f...
75
  EXPORT_SYMBOL(key_type_keyring);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
76
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
77
78
   * Semaphore to serialise link/link calls to prevent two link calls in parallel
   * introducing a cycle.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
79
   */
1ae8f4076   Adrian Bunk   [PATCH] security/...
80
  static DECLARE_RWSEM(keyring_serialise_link_sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
81

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
82
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
83
84
   * Publish the name of a keyring so that it can be found by name (if it has
   * one).
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
85
   */
69664cf16   David Howells   keys: don't gener...
86
  static void keyring_publish_name(struct key *keyring)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
  {
  	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);
  	}
a8b17ed01   David Howells   KEYS: Do some sty...
103
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
104

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
105
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
106
107
108
   * Initialise a keyring.
   *
   * Returns 0 on success, -EINVAL if given any data.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
109
110
111
112
113
114
115
116
117
118
119
120
121
122
   */
  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;
a8b17ed01   David Howells   KEYS: Do some sty...
123
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
124

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
125
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
126
   * Match keyrings on their name
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
127
128
129
130
131
   */
  static int keyring_match(const struct key *keyring, const void *description)
  {
  	return keyring->description &&
  		strcmp(keyring->description, description) == 0;
a8b17ed01   David Howells   KEYS: Do some sty...
132
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
133

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
134
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
135
136
   * Clean up a keyring when it is destroyed.  Unpublish its name if it had one
   * and dispose of its data.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
137
138
139
140
141
142
143
144
   */
  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...
145
146
147
148
  
  		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
149
150
  		write_unlock(&keyring_name_lock);
  	}
e7b0a61b7   Paul E. McKenney   security: Apply l...
151
  	klist = rcu_dereference_check(keyring->payload.subscriptions,
e7b0a61b7   Paul E. McKenney   security: Apply l...
152
  				      atomic_read(&keyring->usage) == 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
153
154
155
156
157
  	if (klist) {
  		for (loop = klist->nkeys - 1; loop >= 0; loop--)
  			key_put(klist->keys[loop]);
  		kfree(klist);
  	}
a8b17ed01   David Howells   KEYS: Do some sty...
158
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
159

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
160
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
161
   * Describe a keyring for /proc.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
162
163
164
165
   */
  static void keyring_describe(const struct key *keyring, struct seq_file *m)
  {
  	struct keyring_list *klist;
c8563473c   wzt.wzt@gmail.com   Security: Fix som...
166
  	if (keyring->description)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
167
  		seq_puts(m, keyring->description);
c8563473c   wzt.wzt@gmail.com   Security: Fix som...
168
  	else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
169
  		seq_puts(m, "[anon]");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
170

78b7280cc   David Howells   KEYS: Improve /pr...
171
172
173
174
175
176
177
178
179
  	if (key_is_instantiated(keyring)) {
  		rcu_read_lock();
  		klist = rcu_dereference(keyring->payload.subscriptions);
  		if (klist)
  			seq_printf(m, ": %u/%u", klist->nkeys, klist->maxkeys);
  		else
  			seq_puts(m, ": empty");
  		rcu_read_unlock();
  	}
a8b17ed01   David Howells   KEYS: Do some sty...
180
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
181

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
182
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
183
184
185
   * Read a list of key IDs from the keyring's contents in binary form
   *
   * The keyring's semaphore is read-locked by the caller.
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;
f0641cba7   David Howells   KEYS: Use RCU der...
196
  	klist = rcu_dereference_locked_keyring(keyring);
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
  	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;
  	}
c5b60b5e6   Justin P. Mattock   security: whitesp...
230
  error:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
231
  	return ret;
a8b17ed01   David Howells   KEYS: Do some sty...
232
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
233

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
234
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
235
   * Allocate a keyring and link into the destination keyring.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
236
237
   */
  struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,
d84f4f992   David Howells   CRED: Inaugurate ...
238
  			  const struct cred *cred, unsigned long flags,
d720024e9   Michael LeMay   [PATCH] selinux: ...
239
  			  struct key *dest)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
240
241
242
243
244
  {
  	struct key *keyring;
  	int ret;
  
  	keyring = key_alloc(&key_type_keyring, description,
d84f4f992   David Howells   CRED: Inaugurate ...
245
  			    uid, gid, cred,
29db91906   David Howells   [PATCH] Keys: Add...
246
  			    (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_ALL,
7e047ef5f   David Howells   [PATCH] keys: sor...
247
  			    flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
248
249
  
  	if (!IS_ERR(keyring)) {
3e30148c3   David Howells   [PATCH] Keys: Mak...
250
  		ret = key_instantiate_and_link(keyring, NULL, 0, dest, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
251
252
253
254
255
256
257
  		if (ret < 0) {
  			key_put(keyring);
  			keyring = ERR_PTR(ret);
  		}
  	}
  
  	return keyring;
a8b17ed01   David Howells   KEYS: Do some sty...
258
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
259

973c9f4f4   David Howells   KEYS: Fix up comm...
260
261
262
263
264
265
266
  /**
   * keyring_search_aux - Search a keyring tree for a key matching some criteria
   * @keyring_ref: A pointer to the keyring with possession indicator.
   * @cred: The credentials to use for permissions checks.
   * @type: The type of key to search for.
   * @description: Parameter for @match.
   * @match: Function to rule on whether or not a key is the one required.
78b7280cc   David Howells   KEYS: Improve /pr...
267
   * @no_state_check: Don't check if a matching key is bad
973c9f4f4   David Howells   KEYS: Fix up comm...
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
   *
   * Search the supplied keyring tree for a key that matches the criteria given.
   * The root keyring and any linked keyrings must grant Search permission to the
   * caller to be searchable and keys can only be found if they too grant Search
   * to the caller. The possession flag on the root keyring pointer controls use
   * of the possessor bits in permissions checking of the entire tree.  In
   * addition, the LSM gets to forbid keyring searches and key matches.
   *
   * The search is performed as a breadth-then-depth search up to the prescribed
   * limit (KEYRING_SEARCH_MAX_DEPTH).
   *
   * Keys are matched to the type provided and are then filtered by the match
   * function, which is given the description to use in any way it sees fit.  The
   * match function may use any attributes of a key that it wishes to to
   * determine the match.  Normally the match function from the key type would be
   * used.
   *
   * RCU is used to prevent the keyring key lists from disappearing without the
   * need to take lots of locks.
   *
   * Returns a pointer to the found key and increments the key usage count if
   * successful; -EAGAIN if no matching keys were found, or if expired or revoked
   * keys were found; -ENOKEY if only negative keys were found; -ENOTDIR if the
   * specified keyring wasn't a keyring.
   *
   * In the case of a successful return, the possession attribute from
   * @keyring_ref is propagated to the returned key reference.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
295
   */
664cceb00   David Howells   [PATCH] Keys: Add...
296
  key_ref_t keyring_search_aux(key_ref_t keyring_ref,
d84f4f992   David Howells   CRED: Inaugurate ...
297
  			     const struct cred *cred,
664cceb00   David Howells   [PATCH] Keys: Add...
298
299
  			     struct key_type *type,
  			     const void *description,
78b7280cc   David Howells   KEYS: Improve /pr...
300
301
  			     key_match_func_t match,
  			     bool no_state_check)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
302
303
  {
  	struct {
76d8aeabf   David Howells   [PATCH] keys: Dis...
304
  		struct keyring_list *keylist;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
305
306
307
308
309
  		int kix;
  	} stack[KEYRING_SEARCH_MAX_DEPTH];
  
  	struct keyring_list *keylist;
  	struct timespec now;
dceba9944   Kevin Coffman   keys: check start...
310
  	unsigned long possessed, kflags;
664cceb00   David Howells   [PATCH] Keys: Add...
311
312
  	struct key *keyring, *key;
  	key_ref_t key_ref;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
313
  	long err;
76d8aeabf   David Howells   [PATCH] keys: Dis...
314
  	int sp, kix;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
315

664cceb00   David Howells   [PATCH] Keys: Add...
316
317
  	keyring = key_ref_to_ptr(keyring_ref);
  	possessed = is_key_possessed(keyring_ref);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
318
319
320
  	key_check(keyring);
  
  	/* top keyring must have search permission to begin the search */
512ea3bc3   Chihau Chau   Security: key: ke...
321
  	err = key_task_permission(keyring_ref, cred, KEY_SEARCH);
29db91906   David Howells   [PATCH] Keys: Add...
322
323
  	if (err < 0) {
  		key_ref = ERR_PTR(err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
324
  		goto error;
29db91906   David Howells   [PATCH] Keys: Add...
325
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
326

664cceb00   David Howells   [PATCH] Keys: Add...
327
  	key_ref = ERR_PTR(-ENOTDIR);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
328
329
  	if (keyring->type != &key_type_keyring)
  		goto error;
664cceb00   David Howells   [PATCH] Keys: Add...
330
  	rcu_read_lock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
331
332
333
  	now = current_kernel_time();
  	err = -EAGAIN;
  	sp = 0;
dceba9944   Kevin Coffman   keys: check start...
334
335
336
337
338
339
  	/* 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;
78b7280cc   David Howells   KEYS: Improve /pr...
340
341
  		if (no_state_check)
  			goto found;
dceba9944   Kevin Coffman   keys: check start...
342
343
344
345
346
347
348
  
  		/* 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;
fdd1b9458   David Howells   KEYS: Add a new k...
349
  		key_ref = ERR_PTR(key->type_data.reject_error);
dceba9944   Kevin Coffman   keys: check start...
350
351
352
353
354
355
356
357
358
359
360
  		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
361
  	/* start processing a new keyring */
664cceb00   David Howells   [PATCH] Keys: Add...
362
  descend:
76d8aeabf   David Howells   [PATCH] keys: Dis...
363
  	if (test_bit(KEY_FLAG_REVOKED, &keyring->flags))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
364
  		goto not_this_keyring;
76d8aeabf   David Howells   [PATCH] keys: Dis...
365
  	keylist = rcu_dereference(keyring->payload.subscriptions);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
366
367
368
369
370
371
  	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...
372
  		kflags = key->flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
373
374
375
376
377
378
  
  		/* ignore keys not of this type */
  		if (key->type != type)
  			continue;
  
  		/* skip revoked keys and expired keys */
78b7280cc   David Howells   KEYS: Improve /pr...
379
380
381
  		if (!no_state_check) {
  			if (kflags & (1 << KEY_FLAG_REVOKED))
  				continue;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
382

78b7280cc   David Howells   KEYS: Improve /pr...
383
384
385
  			if (key->expiry && now.tv_sec >= key->expiry)
  				continue;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
386
387
388
389
390
391
  
  		/* keys that don't match */
  		if (!match(key, description))
  			continue;
  
  		/* key must have search permissions */
29db91906   David Howells   [PATCH] Keys: Add...
392
  		if (key_task_permission(make_key_ref(key, possessed),
d84f4f992   David Howells   CRED: Inaugurate ...
393
  					cred, KEY_SEARCH) < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
394
  			continue;
78b7280cc   David Howells   KEYS: Improve /pr...
395
396
  		if (no_state_check)
  			goto found;
dceba9944   Kevin Coffman   keys: check start...
397
398
  		/* we set a different error code if we pass a negative key */
  		if (kflags & (1 << KEY_FLAG_NEGATIVE)) {
fdd1b9458   David Howells   KEYS: Add a new k...
399
  			err = key->type_data.reject_error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
400
401
402
403
404
405
406
407
  			continue;
  		}
  
  		goto found;
  	}
  
  	/* search through the keyrings nested in this one */
  	kix = 0;
664cceb00   David Howells   [PATCH] Keys: Add...
408
  ascend:
76d8aeabf   David Howells   [PATCH] keys: Dis...
409
  	for (; kix < keylist->nkeys; kix++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
410
411
  		key = keylist->keys[kix];
  		if (key->type != &key_type_keyring)
76d8aeabf   David Howells   [PATCH] keys: Dis...
412
  			continue;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
413
414
415
416
417
  
  		/* 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...
418
  			continue;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
419

0f6ed7c26   David Howells   [PATCH] Keys: Rem...
420
  		if (key_task_permission(make_key_ref(key, possessed),
d84f4f992   David Howells   CRED: Inaugurate ...
421
  					cred, KEY_SEARCH) < 0)
76d8aeabf   David Howells   [PATCH] keys: Dis...
422
  			continue;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
423
424
  
  		/* stack the current position */
76d8aeabf   David Howells   [PATCH] keys: Dis...
425
  		stack[sp].keylist = keylist;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
426
427
428
429
430
431
  		stack[sp].kix = kix;
  		sp++;
  
  		/* begin again with the new keyring */
  		keyring = key;
  		goto descend;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
432
433
434
435
  	}
  
  	/* the keyring we're looking at was disqualified or didn't contain a
  	 * matching key */
664cceb00   David Howells   [PATCH] Keys: Add...
436
  not_this_keyring:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
437
438
439
  	if (sp > 0) {
  		/* resume the processing of a keyring higher up in the tree */
  		sp--;
76d8aeabf   David Howells   [PATCH] keys: Dis...
440
  		keylist = stack[sp].keylist;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
441
442
443
  		kix = stack[sp].kix + 1;
  		goto ascend;
  	}
664cceb00   David Howells   [PATCH] Keys: Add...
444
445
  	key_ref = ERR_PTR(err);
  	goto error_2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
446
447
  
  	/* we found a viable match */
664cceb00   David Howells   [PATCH] Keys: Add...
448
  found:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
449
  	atomic_inc(&key->usage);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
450
  	key_check(key);
664cceb00   David Howells   [PATCH] Keys: Add...
451
452
  	key_ref = make_key_ref(key, possessed);
  error_2:
76d8aeabf   David Howells   [PATCH] keys: Dis...
453
  	rcu_read_unlock();
664cceb00   David Howells   [PATCH] Keys: Add...
454
455
  error:
  	return key_ref;
a8b17ed01   David Howells   KEYS: Do some sty...
456
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
457

973c9f4f4   David Howells   KEYS: Fix up comm...
458
459
460
461
462
463
464
465
  /**
   * keyring_search - Search the supplied keyring tree for a matching key
   * @keyring: The root of the keyring tree to be searched.
   * @type: The type of keyring we want to find.
   * @description: The name of the keyring we want to find.
   *
   * As keyring_search_aux() above, but using the current task's credentials and
   * type's default matching function.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
466
   */
664cceb00   David Howells   [PATCH] Keys: Add...
467
468
469
  key_ref_t keyring_search(key_ref_t keyring,
  			 struct key_type *type,
  			 const char *description)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
470
  {
3e30148c3   David Howells   [PATCH] Keys: Mak...
471
472
  	if (!type->match)
  		return ERR_PTR(-ENOKEY);
d84f4f992   David Howells   CRED: Inaugurate ...
473
  	return keyring_search_aux(keyring, current->cred,
78b7280cc   David Howells   KEYS: Improve /pr...
474
  				  type, description, type->match, false);
a8b17ed01   David Howells   KEYS: Do some sty...
475
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
476
  EXPORT_SYMBOL(keyring_search);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
477
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
478
479
480
481
482
483
484
485
486
487
488
489
490
   * Search the given keyring only (no recursion).
   *
   * The caller must guarantee that the keyring is a keyring and that the
   * permission is granted to search the keyring as no check is made here.
   *
   * RCU is used to make it unnecessary to lock the keyring key list here.
   *
   * Returns a pointer to the found key with usage count incremented if
   * successful and returns -ENOKEY if not found.  Revoked keys and keys not
   * providing the requested permission are skipped over.
   *
   * If successful, the possession indicator is propagated from the keyring ref
   * to the returned key reference.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
491
   */
664cceb00   David Howells   [PATCH] Keys: Add...
492
493
494
495
  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
496
497
  {
  	struct keyring_list *klist;
664cceb00   David Howells   [PATCH] Keys: Add...
498
499
  	unsigned long possessed;
  	struct key *keyring, *key;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
500
  	int loop;
664cceb00   David Howells   [PATCH] Keys: Add...
501
502
  	keyring = key_ref_to_ptr(keyring_ref);
  	possessed = is_key_possessed(keyring_ref);
76d8aeabf   David Howells   [PATCH] keys: Dis...
503
504
505
  	rcu_read_lock();
  
  	klist = rcu_dereference(keyring->payload.subscriptions);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
506
507
508
509
510
  	if (klist) {
  		for (loop = 0; loop < klist->nkeys; loop++) {
  			key = klist->keys[loop];
  
  			if (key->type == ktype &&
3e30148c3   David Howells   [PATCH] Keys: Mak...
511
512
  			    (!key->type->match ||
  			     key->type->match(key, description)) &&
664cceb00   David Howells   [PATCH] Keys: Add...
513
  			    key_permission(make_key_ref(key, possessed),
db1d1d57e   David Howells   [PATCH] Keys: Fix...
514
  					   perm) == 0 &&
76d8aeabf   David Howells   [PATCH] keys: Dis...
515
  			    !test_bit(KEY_FLAG_REVOKED, &key->flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
516
517
518
519
  			    )
  				goto found;
  		}
  	}
664cceb00   David Howells   [PATCH] Keys: Add...
520
521
  	rcu_read_unlock();
  	return ERR_PTR(-ENOKEY);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
522

c5b60b5e6   Justin P. Mattock   security: whitesp...
523
  found:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
524
  	atomic_inc(&key->usage);
76d8aeabf   David Howells   [PATCH] keys: Dis...
525
  	rcu_read_unlock();
664cceb00   David Howells   [PATCH] Keys: Add...
526
  	return make_key_ref(key, possessed);
a8b17ed01   David Howells   KEYS: Do some sty...
527
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
528

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
529
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
530
531
532
533
534
535
536
537
538
   * Find a keyring with the specified name.
   *
   * All named keyrings in the current user namespace are searched, provided they
   * grant Search permission directly to the caller (unless this check is
   * skipped).  Keyrings whose usage points have reached zero or who have been
   * revoked are skipped.
   *
   * Returns a pointer to the keyring with the keyring's refcount having being
   * incremented on success.  -ENOKEY is returned if a key could not be found.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
539
   */
69664cf16   David Howells   keys: don't gener...
540
  struct key *find_keyring_by_name(const char *name, bool skip_perm_check)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
541
542
543
  {
  	struct key *keyring;
  	int bucket;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
544
  	if (!name)
cea7daa35   Toshiyuki Okajima   KEYS: find_keyrin...
545
  		return ERR_PTR(-EINVAL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
546
547
548
549
550
551
552
553
554
555
556
557
  
  	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
  				    ) {
2ea190d0a   Serge E. Hallyn   keys: skip keys f...
558
559
  			if (keyring->user->user_ns != current_user_ns())
  				continue;
76d8aeabf   David Howells   [PATCH] keys: Dis...
560
  			if (test_bit(KEY_FLAG_REVOKED, &keyring->flags))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
561
562
563
564
  				continue;
  
  			if (strcmp(keyring->description, name) != 0)
  				continue;
69664cf16   David Howells   keys: don't gener...
565
566
  			if (!skip_perm_check &&
  			    key_permission(make_key_ref(keyring, 0),
0f6ed7c26   David Howells   [PATCH] Keys: Rem...
567
  					   KEY_SEARCH) < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
568
  				continue;
cea7daa35   Toshiyuki Okajima   KEYS: find_keyrin...
569
570
571
572
573
574
  			/* we've got a match but we might end up racing with
  			 * key_cleanup() if the keyring is currently 'dead'
  			 * (ie. it has a zero usage count) */
  			if (!atomic_inc_not_zero(&keyring->usage))
  				continue;
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
575
576
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
577
  	keyring = ERR_PTR(-ENOKEY);
cea7daa35   Toshiyuki Okajima   KEYS: find_keyrin...
578
579
  out:
  	read_unlock(&keyring_name_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
580
  	return keyring;
a8b17ed01   David Howells   KEYS: Do some sty...
581
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
582

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
583
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
584
585
586
587
588
   * 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.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
589
590
591
592
   */
  static int keyring_detect_cycle(struct key *A, struct key *B)
  {
  	struct {
76d8aeabf   David Howells   [PATCH] keys: Dis...
593
  		struct keyring_list *keylist;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
594
595
596
597
598
599
  		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...
600
  	rcu_read_lock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
601
602
  	ret = -EDEADLK;
  	if (A == B)
76d8aeabf   David Howells   [PATCH] keys: Dis...
603
  		goto cycle_detected;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
604
605
606
607
608
  
  	subtree = B;
  	sp = 0;
  
  	/* start processing a new keyring */
c5b60b5e6   Justin P. Mattock   security: whitesp...
609
  descend:
76d8aeabf   David Howells   [PATCH] keys: Dis...
610
  	if (test_bit(KEY_FLAG_REVOKED, &subtree->flags))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
611
  		goto not_this_keyring;
76d8aeabf   David Howells   [PATCH] keys: Dis...
612
  	keylist = rcu_dereference(subtree->payload.subscriptions);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
613
614
615
  	if (!keylist)
  		goto not_this_keyring;
  	kix = 0;
c5b60b5e6   Justin P. Mattock   security: whitesp...
616
  ascend:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
617
618
619
620
621
622
623
624
625
626
627
628
629
  	/* 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...
630
  			stack[sp].keylist = keylist;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
631
632
633
634
635
636
637
638
639
640
641
  			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 */
c5b60b5e6   Justin P. Mattock   security: whitesp...
642
  not_this_keyring:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
643
644
645
  	if (sp > 0) {
  		/* resume the checking of a keyring higher up in the tree */
  		sp--;
76d8aeabf   David Howells   [PATCH] keys: Dis...
646
  		keylist = stack[sp].keylist;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
647
648
649
650
651
  		kix = stack[sp].kix + 1;
  		goto ascend;
  	}
  
  	ret = 0; /* no cycles detected */
c5b60b5e6   Justin P. Mattock   security: whitesp...
652
  error:
76d8aeabf   David Howells   [PATCH] keys: Dis...
653
  	rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
654
  	return ret;
c5b60b5e6   Justin P. Mattock   security: whitesp...
655
  too_deep:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
656
  	ret = -ELOOP;
76d8aeabf   David Howells   [PATCH] keys: Dis...
657
  	goto error;
c5b60b5e6   Justin P. Mattock   security: whitesp...
658
  cycle_detected:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
659
  	ret = -EDEADLK;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
660
  	goto error;
a8b17ed01   David Howells   KEYS: Do some sty...
661
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
662

76d8aeabf   David Howells   [PATCH] keys: Dis...
663
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
664
   * Dispose of a keyring list after the RCU grace period, freeing the unlinked
cab8eb594   David Howells   [PATCH] keys: Dis...
665
666
667
668
669
670
   * key
   */
  static void keyring_unlink_rcu_disposal(struct rcu_head *rcu)
  {
  	struct keyring_list *klist =
  		container_of(rcu, struct keyring_list, rcu);
4be929be3   Alexey Dobriyan   kernel-wide: repl...
671
  	if (klist->delkey != USHRT_MAX)
f70e2e061   David Howells   KEYS: Do prealloc...
672
  		key_put(klist->keys[klist->delkey]);
cab8eb594   David Howells   [PATCH] keys: Dis...
673
  	kfree(klist);
f70e2e061   David Howells   KEYS: Do prealloc...
674
  }
cab8eb594   David Howells   [PATCH] keys: Dis...
675

cab8eb594   David Howells   [PATCH] keys: Dis...
676
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
677
   * Preallocate memory so that a key can be linked into to a keyring.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
678
   */
f70e2e061   David Howells   KEYS: Do prealloc...
679
  int __key_link_begin(struct key *keyring, const struct key_type *type,
ceb73c120   David Howells   KEYS: Fix __key_l...
680
  		     const char *description, unsigned long *_prealloc)
f70e2e061   David Howells   KEYS: Do prealloc...
681
  	__acquires(&keyring->sem)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
682
683
  {
  	struct keyring_list *klist, *nklist;
ceb73c120   David Howells   KEYS: Fix __key_l...
684
  	unsigned long prealloc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
685
686
  	unsigned max;
  	size_t size;
cab8eb594   David Howells   [PATCH] keys: Dis...
687
  	int loop, ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
688

f70e2e061   David Howells   KEYS: Do prealloc...
689
  	kenter("%d,%s,%s,", key_serial(keyring), type->name, description);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
690

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
691
  	if (keyring->type != &key_type_keyring)
f70e2e061   David Howells   KEYS: Do prealloc...
692
693
694
695
696
697
698
  		return -ENOTDIR;
  
  	down_write(&keyring->sem);
  
  	ret = -EKEYREVOKED;
  	if (test_bit(KEY_FLAG_REVOKED, &keyring->flags))
  		goto error_krsem;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
699

f70e2e061   David Howells   KEYS: Do prealloc...
700
701
702
  	/* serialise link/link calls to prevent parallel calls causing a cycle
  	 * when linking two keyring in opposite orders */
  	if (type == &key_type_keyring)
553d603c8   David Howells   KEYS: keyring_ser...
703
  		down_write(&keyring_serialise_link_sem);
f70e2e061   David Howells   KEYS: Do prealloc...
704
  	klist = rcu_dereference_locked_keyring(keyring);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
705

cab8eb594   David Howells   [PATCH] keys: Dis...
706
  	/* see if there's a matching key we can displace */
cab8eb594   David Howells   [PATCH] keys: Dis...
707
  	if (klist && klist->nkeys > 0) {
cab8eb594   David Howells   [PATCH] keys: Dis...
708
709
710
  		for (loop = klist->nkeys - 1; loop >= 0; loop--) {
  			if (klist->keys[loop]->type == type &&
  			    strcmp(klist->keys[loop]->description,
f70e2e061   David Howells   KEYS: Do prealloc...
711
  				   description) == 0
cab8eb594   David Howells   [PATCH] keys: Dis...
712
  			    ) {
f70e2e061   David Howells   KEYS: Do prealloc...
713
714
  				/* found a match - we'll replace this one with
  				 * the new key */
cab8eb594   David Howells   [PATCH] keys: Dis...
715
716
717
718
719
  				size = sizeof(struct key *) * klist->maxkeys;
  				size += sizeof(*klist);
  				BUG_ON(size > PAGE_SIZE);
  
  				ret = -ENOMEM;
48ad504ee   Eric Sesterhenn   [PATCH] security/...
720
  				nklist = kmemdup(klist, size, GFP_KERNEL);
cab8eb594   David Howells   [PATCH] keys: Dis...
721
  				if (!nklist)
f70e2e061   David Howells   KEYS: Do prealloc...
722
  					goto error_sem;
cab8eb594   David Howells   [PATCH] keys: Dis...
723

f70e2e061   David Howells   KEYS: Do prealloc...
724
725
  				/* note replacement slot */
  				klist->delkey = nklist->delkey = loop;
ceb73c120   David Howells   KEYS: Fix __key_l...
726
  				prealloc = (unsigned long)nklist;
cab8eb594   David Howells   [PATCH] keys: Dis...
727
728
729
730
  				goto done;
  			}
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
731
732
733
734
  	/* 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)
f70e2e061   David Howells   KEYS: Do prealloc...
735
  		goto error_sem;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
736

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
737
  	if (klist && klist->nkeys < klist->maxkeys) {
f70e2e061   David Howells   KEYS: Do prealloc...
738
739
  		/* there's sufficient slack space to append directly */
  		nklist = NULL;
ceb73c120   David Howells   KEYS: Fix __key_l...
740
  		prealloc = KEY_LINK_FIXQUOTA;
512ea3bc3   Chihau Chau   Security: key: ke...
741
  	} else {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
742
743
744
745
746
747
  		/* grow the key list */
  		max = 4;
  		if (klist)
  			max += klist->maxkeys;
  
  		ret = -ENFILE;
4be929be3   Alexey Dobriyan   kernel-wide: repl...
748
  		if (max > USHRT_MAX - 1)
f70e2e061   David Howells   KEYS: Do prealloc...
749
  			goto error_quota;
a4014d8f6   David Howells   [PATCH] Keys: Bas...
750
  		size = sizeof(*klist) + sizeof(struct key *) * max;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
751
  		if (size > PAGE_SIZE)
f70e2e061   David Howells   KEYS: Do prealloc...
752
  			goto error_quota;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
753
754
755
756
  
  		ret = -ENOMEM;
  		nklist = kmalloc(size, GFP_KERNEL);
  		if (!nklist)
f70e2e061   David Howells   KEYS: Do prealloc...
757
  			goto error_quota;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
758

f70e2e061   David Howells   KEYS: Do prealloc...
759
  		nklist->maxkeys = max;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
760
  		if (klist) {
f70e2e061   David Howells   KEYS: Do prealloc...
761
  			memcpy(nklist->keys, klist->keys,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
762
  			       sizeof(struct key *) * klist->nkeys);
f70e2e061   David Howells   KEYS: Do prealloc...
763
764
  			nklist->delkey = klist->nkeys;
  			nklist->nkeys = klist->nkeys + 1;
4be929be3   Alexey Dobriyan   kernel-wide: repl...
765
  			klist->delkey = USHRT_MAX;
f70e2e061   David Howells   KEYS: Do prealloc...
766
767
768
  		} else {
  			nklist->nkeys = 1;
  			nklist->delkey = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
769
770
771
  		}
  
  		/* add the key into the new space */
f70e2e061   David Howells   KEYS: Do prealloc...
772
  		nklist->keys[nklist->delkey] = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
773
  	}
ceb73c120   David Howells   KEYS: Fix __key_l...
774
  	prealloc = (unsigned long)nklist | KEY_LINK_FIXQUOTA;
cab8eb594   David Howells   [PATCH] keys: Dis...
775
  done:
ceb73c120   David Howells   KEYS: Fix __key_l...
776
  	*_prealloc = prealloc;
f70e2e061   David Howells   KEYS: Do prealloc...
777
778
  	kleave(" = 0");
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
779

f70e2e061   David Howells   KEYS: Do prealloc...
780
  error_quota:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
781
782
783
  	/* undo the quota changes */
  	key_payload_reserve(keyring,
  			    keyring->datalen - KEYQUOTA_LINK_BYTES);
f70e2e061   David Howells   KEYS: Do prealloc...
784
785
786
787
788
789
790
791
  error_sem:
  	if (type == &key_type_keyring)
  		up_write(&keyring_serialise_link_sem);
  error_krsem:
  	up_write(&keyring->sem);
  	kleave(" = %d", ret);
  	return ret;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
792

f70e2e061   David Howells   KEYS: Do prealloc...
793
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
794
795
796
797
   * Check already instantiated keys aren't going to be a problem.
   *
   * The caller must have called __key_link_begin(). Don't need to call this for
   * keys that were created since __key_link_begin() was called.
f70e2e061   David Howells   KEYS: Do prealloc...
798
799
800
801
802
803
804
805
806
807
808
   */
  int __key_link_check_live_key(struct key *keyring, struct key *key)
  {
  	if (key->type == &key_type_keyring)
  		/* check that we aren't going to create a cycle by linking one
  		 * keyring to another */
  		return keyring_detect_cycle(keyring, key);
  	return 0;
  }
  
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
809
810
811
812
813
814
   * Link a key into to a keyring.
   *
   * Must be called with __key_link_begin() having being called.  Discards any
   * already extant link to matching key if there is one, so that each keyring
   * holds at most one link to any given key of a particular type+description
   * combination.
f70e2e061   David Howells   KEYS: Do prealloc...
815
816
   */
  void __key_link(struct key *keyring, struct key *key,
ceb73c120   David Howells   KEYS: Fix __key_l...
817
  		unsigned long *_prealloc)
f70e2e061   David Howells   KEYS: Do prealloc...
818
819
  {
  	struct keyring_list *klist, *nklist;
ceb73c120   David Howells   KEYS: Fix __key_l...
820
821
  	nklist = (struct keyring_list *)(*_prealloc & ~KEY_LINK_FIXQUOTA);
  	*_prealloc = 0;
f70e2e061   David Howells   KEYS: Do prealloc...
822
823
  
  	kenter("%d,%d,%p", keyring->serial, key->serial, nklist);
6d528b082   David Howells   KEYS: __key_link(...
824
  	klist = rcu_dereference_locked_keyring(keyring);
f70e2e061   David Howells   KEYS: Do prealloc...
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
  
  	atomic_inc(&key->usage);
  
  	/* there's a matching key we can displace or an empty slot in a newly
  	 * allocated list we can fill */
  	if (nklist) {
  		kdebug("replace %hu/%hu/%hu",
  		       nklist->delkey, nklist->nkeys, nklist->maxkeys);
  
  		nklist->keys[nklist->delkey] = key;
  
  		rcu_assign_pointer(keyring->payload.subscriptions, nklist);
  
  		/* dispose of the old keyring list and, if there was one, the
  		 * displaced key */
  		if (klist) {
  			kdebug("dispose %hu/%hu/%hu",
  			       klist->delkey, klist->nkeys, klist->maxkeys);
  			call_rcu(&klist->rcu, keyring_unlink_rcu_disposal);
  		}
  	} else {
  		/* there's sufficient slack space to append directly */
  		klist->keys[klist->nkeys] = key;
  		smp_wmb();
  		klist->nkeys++;
  	}
  }
  
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
854
855
856
   * Finish linking a key into to a keyring.
   *
   * Must be called with __key_link_begin() having being called.
f70e2e061   David Howells   KEYS: Do prealloc...
857
858
   */
  void __key_link_end(struct key *keyring, struct key_type *type,
ceb73c120   David Howells   KEYS: Fix __key_l...
859
  		    unsigned long prealloc)
f70e2e061   David Howells   KEYS: Do prealloc...
860
861
862
863
  	__releases(&keyring->sem)
  {
  	BUG_ON(type == NULL);
  	BUG_ON(type->name == NULL);
ceb73c120   David Howells   KEYS: Fix __key_l...
864
  	kenter("%d,%s,%lx", keyring->serial, type->name, prealloc);
f70e2e061   David Howells   KEYS: Do prealloc...
865
866
867
868
869
  
  	if (type == &key_type_keyring)
  		up_write(&keyring_serialise_link_sem);
  
  	if (prealloc) {
ceb73c120   David Howells   KEYS: Fix __key_l...
870
871
872
873
874
  		if (prealloc & KEY_LINK_FIXQUOTA)
  			key_payload_reserve(keyring,
  					    keyring->datalen -
  					    KEYQUOTA_LINK_BYTES);
  		kfree((struct keyring_list *)(prealloc & ~KEY_LINK_FIXQUOTA));
f70e2e061   David Howells   KEYS: Do prealloc...
875
876
877
  	}
  	up_write(&keyring->sem);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
878

973c9f4f4   David Howells   KEYS: Fix up comm...
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
  /**
   * key_link - Link a key to a keyring
   * @keyring: The keyring to make the link in.
   * @key: The key to link to.
   *
   * Make a link in a keyring to a key, such that the keyring holds a reference
   * on that key and the key can potentially be found by searching that keyring.
   *
   * This function will write-lock the keyring's semaphore and will consume some
   * of the user's key data quota to hold the link.
   *
   * Returns 0 if successful, -ENOTDIR if the keyring isn't a keyring,
   * -EKEYREVOKED if the keyring has been revoked, -ENFILE if the keyring is
   * full, -EDQUOT if there is insufficient key data quota remaining to add
   * another link or -ENOMEM if there's insufficient memory.
   *
   * It is assumed that the caller has checked that it is permitted for a link to
   * be made (the keyring should have Write permission and the key Link
   * permission).
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
898
899
900
   */
  int key_link(struct key *keyring, struct key *key)
  {
ceb73c120   David Howells   KEYS: Fix __key_l...
901
  	unsigned long prealloc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
902
903
904
905
  	int ret;
  
  	key_check(keyring);
  	key_check(key);
f70e2e061   David Howells   KEYS: Do prealloc...
906
907
908
909
910
911
912
  	ret = __key_link_begin(keyring, key->type, key->description, &prealloc);
  	if (ret == 0) {
  		ret = __key_link_check_live_key(keyring, key);
  		if (ret == 0)
  			__key_link(keyring, key, &prealloc);
  		__key_link_end(keyring, key->type, prealloc);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
913
914
  
  	return ret;
f70e2e061   David Howells   KEYS: Do prealloc...
915
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
916
  EXPORT_SYMBOL(key_link);
973c9f4f4   David Howells   KEYS: Fix up comm...
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
  /**
   * key_unlink - Unlink the first link to a key from a keyring.
   * @keyring: The keyring to remove the link from.
   * @key: The key the link is to.
   *
   * Remove a link from a keyring to a key.
   *
   * This function will write-lock the keyring's semaphore.
   *
   * Returns 0 if successful, -ENOTDIR if the keyring isn't a keyring, -ENOENT if
   * the key isn't linked to by the keyring or -ENOMEM if there's insufficient
   * memory.
   *
   * It is assumed that the caller has checked that it is permitted for a link to
   * be removed (the keyring should have Write permission; no permissions are
   * required on the key).
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
933
934
935
   */
  int key_unlink(struct key *keyring, struct key *key)
  {
76d8aeabf   David Howells   [PATCH] keys: Dis...
936
  	struct keyring_list *klist, *nklist;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
937
938
939
940
941
942
943
944
945
946
  	int loop, ret;
  
  	key_check(keyring);
  	key_check(key);
  
  	ret = -ENOTDIR;
  	if (keyring->type != &key_type_keyring)
  		goto error;
  
  	down_write(&keyring->sem);
f0641cba7   David Howells   KEYS: Use RCU der...
947
  	klist = rcu_dereference_locked_keyring(keyring);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
948
949
950
951
952
953
954
955
956
957
  	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...
958
959
  key_is_present:
  	/* we need to copy the key list for RCU purposes */
a4014d8f6   David Howells   [PATCH] Keys: Bas...
960
961
  	nklist = kmalloc(sizeof(*klist) +
  			 sizeof(struct key *) * klist->maxkeys,
76d8aeabf   David Howells   [PATCH] keys: Dis...
962
963
964
965
966
967
968
969
970
  			 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...
971
  		       loop * sizeof(struct key *));
76d8aeabf   David Howells   [PATCH] keys: Dis...
972
973
974
975
  
  	if (loop < nklist->nkeys)
  		memcpy(&nklist->keys[loop],
  		       &klist->keys[loop + 1],
a4014d8f6   David Howells   [PATCH] Keys: Bas...
976
  		       (nklist->nkeys - loop) * sizeof(struct key *));
76d8aeabf   David Howells   [PATCH] keys: Dis...
977

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

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

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

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
989
  	ret = 0;
76d8aeabf   David Howells   [PATCH] keys: Dis...
990
  error:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
991
  	return ret;
76d8aeabf   David Howells   [PATCH] keys: Dis...
992
993
994
995
  nomem:
  	ret = -ENOMEM;
  	up_write(&keyring->sem);
  	goto error;
a8b17ed01   David Howells   KEYS: Do some sty...
996
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
997
  EXPORT_SYMBOL(key_unlink);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
998
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
999
1000
   * Dispose of a keyring list after the RCU grace period, releasing the keys it
   * links to.
76d8aeabf   David Howells   [PATCH] keys: Dis...
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
   */
  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);
a8b17ed01   David Howells   KEYS: Do some sty...
1013
  }
76d8aeabf   David Howells   [PATCH] keys: Dis...
1014

973c9f4f4   David Howells   KEYS: Fix up comm...
1015
1016
1017
1018
1019
1020
1021
  /**
   * keyring_clear - Clear a keyring
   * @keyring: The keyring to clear.
   *
   * Clear the contents of the specified keyring.
   *
   * Returns 0 if successful or -ENOTDIR if the keyring isn't a keyring.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1022
1023
1024
1025
   */
  int keyring_clear(struct key *keyring)
  {
  	struct keyring_list *klist;
76d8aeabf   David Howells   [PATCH] keys: Dis...
1026
  	int ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1027
1028
1029
1030
1031
  
  	ret = -ENOTDIR;
  	if (keyring->type == &key_type_keyring) {
  		/* detach the pointer block with the locks held */
  		down_write(&keyring->sem);
f0641cba7   David Howells   KEYS: Use RCU der...
1032
  		klist = rcu_dereference_locked_keyring(keyring);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1033
1034
1035
1036
  		if (klist) {
  			/* adjust the quota */
  			key_payload_reserve(keyring,
  					    sizeof(struct keyring_list));
76d8aeabf   David Howells   [PATCH] keys: Dis...
1037
1038
  			rcu_assign_pointer(keyring->payload.subscriptions,
  					   NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1039
1040
1041
1042
1043
  		}
  
  		up_write(&keyring->sem);
  
  		/* free the keys after the locks have been dropped */
76d8aeabf   David Howells   [PATCH] keys: Dis...
1044
1045
  		if (klist)
  			call_rcu(&klist->rcu, keyring_clear_rcu_disposal);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1046
1047
1048
1049
1050
  
  		ret = 0;
  	}
  
  	return ret;
a8b17ed01   David Howells   KEYS: Do some sty...
1051
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1052
  EXPORT_SYMBOL(keyring_clear);
31204ed92   David Howells   [PATCH] keys: dis...
1053

31204ed92   David Howells   [PATCH] keys: dis...
1054
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
1055
1056
1057
   * Dispose of the links from a revoked keyring.
   *
   * This is called with the key sem write-locked.
31204ed92   David Howells   [PATCH] keys: dis...
1058
1059
1060
   */
  static void keyring_revoke(struct key *keyring)
  {
f0641cba7   David Howells   KEYS: Use RCU der...
1061
1062
1063
  	struct keyring_list *klist;
  
  	klist = rcu_dereference_locked_keyring(keyring);
31204ed92   David Howells   [PATCH] keys: dis...
1064
1065
1066
1067
1068
1069
1070
1071
  
  	/* 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);
  	}
a8b17ed01   David Howells   KEYS: Do some sty...
1072
  }
5d135440f   David Howells   KEYS: Add garbage...
1073
1074
  
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
1075
   * Determine whether a key is dead.
5d135440f   David Howells   KEYS: Add garbage...
1076
1077
1078
1079
1080
1081
1082
1083
   */
  static bool key_is_dead(struct key *key, time_t limit)
  {
  	return test_bit(KEY_FLAG_DEAD, &key->flags) ||
  		(key->expiry > 0 && key->expiry <= limit);
  }
  
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
1084
1085
1086
1087
1088
1089
   * Collect garbage from the contents of a keyring, replacing the old list with
   * a new one with the pointers all shuffled down.
   *
   * Dead keys are classed as oned that are flagged as being dead or are revoked,
   * expired or negative keys that were revoked or expired before the specified
   * limit.
5d135440f   David Howells   KEYS: Add garbage...
1090
1091
1092
1093
1094
1095
   */
  void keyring_gc(struct key *keyring, time_t limit)
  {
  	struct keyring_list *klist, *new;
  	struct key *key;
  	int loop, keep, max;
c08ef808e   David Howells   KEYS: Fix garbage...
1096
  	kenter("{%x,%s}", key_serial(keyring), keyring->description);
5d135440f   David Howells   KEYS: Add garbage...
1097
1098
  
  	down_write(&keyring->sem);
f0641cba7   David Howells   KEYS: Use RCU der...
1099
  	klist = rcu_dereference_locked_keyring(keyring);
5d135440f   David Howells   KEYS: Add garbage...
1100
  	if (!klist)
c08ef808e   David Howells   KEYS: Fix garbage...
1101
  		goto no_klist;
5d135440f   David Howells   KEYS: Add garbage...
1102
1103
1104
1105
  
  	/* work out how many subscriptions we're keeping */
  	keep = 0;
  	for (loop = klist->nkeys - 1; loop >= 0; loop--)
c08ef808e   David Howells   KEYS: Fix garbage...
1106
  		if (!key_is_dead(klist->keys[loop], limit))
5d135440f   David Howells   KEYS: Add garbage...
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
  			keep++;
  
  	if (keep == klist->nkeys)
  		goto just_return;
  
  	/* allocate a new keyring payload */
  	max = roundup(keep, 4);
  	new = kmalloc(sizeof(struct keyring_list) + max * sizeof(struct key *),
  		      GFP_KERNEL);
  	if (!new)
c08ef808e   David Howells   KEYS: Fix garbage...
1117
  		goto nomem;
5d135440f   David Howells   KEYS: Add garbage...
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
  	new->maxkeys = max;
  	new->nkeys = 0;
  	new->delkey = 0;
  
  	/* install the live keys
  	 * - must take care as expired keys may be updated back to life
  	 */
  	keep = 0;
  	for (loop = klist->nkeys - 1; loop >= 0; loop--) {
  		key = klist->keys[loop];
  		if (!key_is_dead(key, limit)) {
  			if (keep >= max)
  				goto discard_new;
  			new->keys[keep++] = key_get(key);
  		}
  	}
  	new->nkeys = keep;
  
  	/* adjust the quota */
  	key_payload_reserve(keyring,
  			    sizeof(struct keyring_list) +
  			    KEYQUOTA_LINK_BYTES * keep);
  
  	if (keep == 0) {
  		rcu_assign_pointer(keyring->payload.subscriptions, NULL);
  		kfree(new);
  	} else {
  		rcu_assign_pointer(keyring->payload.subscriptions, new);
  	}
  
  	up_write(&keyring->sem);
  
  	call_rcu(&klist->rcu, keyring_clear_rcu_disposal);
  	kleave(" [yes]");
  	return;
  
  discard_new:
  	new->nkeys = keep;
  	keyring_clear_rcu_disposal(&new->rcu);
c08ef808e   David Howells   KEYS: Fix garbage...
1157
1158
1159
  	up_write(&keyring->sem);
  	kleave(" [discard]");
  	return;
5d135440f   David Howells   KEYS: Add garbage...
1160
1161
  just_return:
  	up_write(&keyring->sem);
c08ef808e   David Howells   KEYS: Fix garbage...
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
  	kleave(" [no dead]");
  	return;
  
  no_klist:
  	up_write(&keyring->sem);
  	kleave(" [no_klist]");
  	return;
  
  nomem:
  	up_write(&keyring->sem);
  	kleave(" [oom]");
5d135440f   David Howells   KEYS: Add garbage...
1173
  }