Blame view

security/keys/key.c 25.7 KB
76181c134   David Howells   KEYS: Make reques...
1
  /* Basic authentication token and access key management
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
   *
69664cf16   David Howells   keys: don't gener...
3
   * Copyright (C) 2004-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
   * 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>
a7807a32b   Randy Dunlap   [PATCH] poison: a...
14
  #include <linux/poison.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15
16
  #include <linux/sched.h>
  #include <linux/slab.h>
29db91906   David Howells   [PATCH] Keys: Add...
17
  #include <linux/security.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
18
  #include <linux/workqueue.h>
e51f6d343   Michael LeMay   [PATCH] keys: all...
19
  #include <linux/random.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
20
  #include <linux/err.h>
1d1e97562   Serge E. Hallyn   keys: distinguish...
21
  #include <linux/user_namespace.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
  #include "internal.h"
8bc16deab   David Howells   KEYS: Move the un...
23
  struct kmem_cache *key_jar;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
25
26
27
28
  struct rb_root		key_serial_tree; /* tree of keys indexed by serial */
  DEFINE_SPINLOCK(key_serial_lock);
  
  struct rb_root	key_user_tree; /* tree of quota records indexed by UID */
  DEFINE_SPINLOCK(key_user_lock);
0b77f5bfb   David Howells   keys: make the ke...
29
30
31
32
  unsigned int key_quota_root_maxkeys = 200;	/* root's key count quota */
  unsigned int key_quota_root_maxbytes = 20000;	/* root's key space quota */
  unsigned int key_quota_maxkeys = 200;		/* general key count quota */
  unsigned int key_quota_maxbytes = 20000;	/* general key space quota */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
33
34
  static LIST_HEAD(key_types_list);
  static DECLARE_RWSEM(key_types_sem);
973c9f4f4   David Howells   KEYS: Fix up comm...
35
  /* We serialise key instantiation and link */
76181c134   David Howells   KEYS: Make reques...
36
  DEFINE_MUTEX(key_construction_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
38
39
40
41
42
43
44
45
46
  #ifdef KEY_DEBUGGING
  void __key_check(const struct key *key)
  {
  	printk("__key_check: key %p {%08x} should be {%08x}
  ",
  	       key, key->magic, KEY_DEBUG_MAGIC);
  	BUG();
  }
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
48
49
   * Get the key quota record for a user, allocating a new record if one doesn't
   * already exist.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
50
   */
1d1e97562   Serge E. Hallyn   keys: distinguish...
51
  struct key_user *key_user_lookup(uid_t uid, struct user_namespace *user_ns)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52
53
54
55
  {
  	struct key_user *candidate = NULL, *user;
  	struct rb_node *parent = NULL;
  	struct rb_node **p;
973c9f4f4   David Howells   KEYS: Fix up comm...
56
  try_again:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
57
58
59
60
61
62
63
64
65
66
67
68
  	p = &key_user_tree.rb_node;
  	spin_lock(&key_user_lock);
  
  	/* search the tree for a user record with a matching UID */
  	while (*p) {
  		parent = *p;
  		user = rb_entry(parent, struct key_user, node);
  
  		if (uid < user->uid)
  			p = &(*p)->rb_left;
  		else if (uid > user->uid)
  			p = &(*p)->rb_right;
1d1e97562   Serge E. Hallyn   keys: distinguish...
69
70
71
72
  		else if (user_ns < user->user_ns)
  			p = &(*p)->rb_left;
  		else if (user_ns > user->user_ns)
  			p = &(*p)->rb_right;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
  		else
  			goto found;
  	}
  
  	/* if we get here, we failed to find a match in the tree */
  	if (!candidate) {
  		/* allocate a candidate user record if we don't already have
  		 * one */
  		spin_unlock(&key_user_lock);
  
  		user = NULL;
  		candidate = kmalloc(sizeof(struct key_user), GFP_KERNEL);
  		if (unlikely(!candidate))
  			goto out;
  
  		/* the allocation may have scheduled, so we need to repeat the
  		 * search lest someone else added the record whilst we were
  		 * asleep */
  		goto try_again;
  	}
  
  	/* if we get here, then the user record still hadn't appeared on the
  	 * second pass - so we use the candidate record */
  	atomic_set(&candidate->usage, 1);
  	atomic_set(&candidate->nkeys, 0);
  	atomic_set(&candidate->nikeys, 0);
  	candidate->uid = uid;
1d1e97562   Serge E. Hallyn   keys: distinguish...
100
  	candidate->user_ns = get_user_ns(user_ns);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
101
102
103
  	candidate->qnkeys = 0;
  	candidate->qnbytes = 0;
  	spin_lock_init(&candidate->lock);
76181c134   David Howells   KEYS: Make reques...
104
  	mutex_init(&candidate->cons_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
105
106
107
108
109
110
111
112
  
  	rb_link_node(&candidate->node, parent, p);
  	rb_insert_color(&candidate->node, &key_user_tree);
  	spin_unlock(&key_user_lock);
  	user = candidate;
  	goto out;
  
  	/* okay - we found a user record for this UID */
973c9f4f4   David Howells   KEYS: Fix up comm...
113
  found:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
114
115
  	atomic_inc(&user->usage);
  	spin_unlock(&key_user_lock);
a7f988ba3   Jesper Juhl   [PATCH] kfree cle...
116
  	kfree(candidate);
973c9f4f4   David Howells   KEYS: Fix up comm...
117
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
118
  	return user;
a8b17ed01   David Howells   KEYS: Do some sty...
119
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
120

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
121
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
122
   * Dispose of a user structure
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
123
124
125
126
127
128
   */
  void key_user_put(struct key_user *user)
  {
  	if (atomic_dec_and_lock(&user->usage, &key_user_lock)) {
  		rb_erase(&user->node, &key_user_tree);
  		spin_unlock(&key_user_lock);
1d1e97562   Serge E. Hallyn   keys: distinguish...
129
  		put_user_ns(user->user_ns);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
130
131
132
  
  		kfree(user);
  	}
a8b17ed01   David Howells   KEYS: Do some sty...
133
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
134

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
135
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
136
137
   * Allocate a serial number for a key.  These are assigned randomly to avoid
   * security issues through covert channel problems.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
138
139
140
141
142
   */
  static inline void key_alloc_serial(struct key *key)
  {
  	struct rb_node *parent, **p;
  	struct key *xkey;
e51f6d343   Michael LeMay   [PATCH] keys: all...
143
  	/* propose a random serial number and look for a hole for it in the
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
144
  	 * serial number tree */
e51f6d343   Michael LeMay   [PATCH] keys: all...
145
146
147
148
149
150
151
  	do {
  		get_random_bytes(&key->serial, sizeof(key->serial));
  
  		key->serial >>= 1; /* negative numbers are not permitted */
  	} while (key->serial < 3);
  
  	spin_lock(&key_serial_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
152

9ad0830f3   David Howells   [PATCH] Keys: Fix...
153
  attempt_insertion:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
154
155
156
157
158
159
160
161
162
163
164
165
166
167
  	parent = NULL;
  	p = &key_serial_tree.rb_node;
  
  	while (*p) {
  		parent = *p;
  		xkey = rb_entry(parent, struct key, serial_node);
  
  		if (key->serial < xkey->serial)
  			p = &(*p)->rb_left;
  		else if (key->serial > xkey->serial)
  			p = &(*p)->rb_right;
  		else
  			goto serial_exists;
  	}
9ad0830f3   David Howells   [PATCH] Keys: Fix...
168
169
170
171
172
173
174
  
  	/* we've found a suitable hole - arrange for this key to occupy it */
  	rb_link_node(&key->serial_node, parent, p);
  	rb_insert_color(&key->serial_node, &key_serial_tree);
  
  	spin_unlock(&key_serial_lock);
  	return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
175
176
177
  
  	/* we found a key with the proposed serial number - walk the tree from
  	 * that point looking for the next unused serial number */
e51f6d343   Michael LeMay   [PATCH] keys: all...
178
  serial_exists:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
179
  	for (;;) {
e51f6d343   Michael LeMay   [PATCH] keys: all...
180
  		key->serial++;
9ad0830f3   David Howells   [PATCH] Keys: Fix...
181
182
183
184
  		if (key->serial < 3) {
  			key->serial = 3;
  			goto attempt_insertion;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
185
186
187
  
  		parent = rb_next(parent);
  		if (!parent)
9ad0830f3   David Howells   [PATCH] Keys: Fix...
188
  			goto attempt_insertion;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
189
190
191
  
  		xkey = rb_entry(parent, struct key, serial_node);
  		if (key->serial < xkey->serial)
9ad0830f3   David Howells   [PATCH] Keys: Fix...
192
  			goto attempt_insertion;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
193
  	}
a8b17ed01   David Howells   KEYS: Do some sty...
194
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
195

973c9f4f4   David Howells   KEYS: Fix up comm...
196
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
  /**
   * key_alloc - Allocate a key of the specified type.
   * @type: The type of key to allocate.
   * @desc: The key description to allow the key to be searched out.
   * @uid: The owner of the new key.
   * @gid: The group ID for the new key's group permissions.
   * @cred: The credentials specifying UID namespace.
   * @perm: The permissions mask of the new key.
   * @flags: Flags specifying quota properties.
   *
   * Allocate a key of the specified type with the attributes given.  The key is
   * returned in an uninstantiated state and the caller needs to instantiate the
   * key before returning.
   *
   * The user's key count quota is updated to reflect the creation of the key and
   * the user's key data quota has the default for the key type reserved.  The
   * instantiation function should amend this as necessary.  If insufficient
   * quota is available, -EDQUOT will be returned.
   *
   * The LSM security modules can prevent a key being created, in which case
   * -EACCES will be returned.
   *
   * Returns a pointer to the new key if successful and an error code otherwise.
   *
   * Note that the caller needs to ensure the key type isn't uninstantiated.
   * Internally this can be done by locking key_types_sem.  Externally, this can
   * be done by either never unregistering the key type, or making sure
   * key_alloc() calls don't race with module unloading.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
224
225
   */
  struct key *key_alloc(struct key_type *type, const char *desc,
d84f4f992   David Howells   CRED: Inaugurate ...
226
  		      uid_t uid, gid_t gid, const struct cred *cred,
7e047ef5f   David Howells   [PATCH] keys: sor...
227
  		      key_perm_t perm, unsigned long flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
228
229
230
231
  {
  	struct key_user *user = NULL;
  	struct key *key;
  	size_t desclen, quotalen;
29db91906   David Howells   [PATCH] Keys: Add...
232
  	int ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
233
234
235
236
  
  	key = ERR_PTR(-EINVAL);
  	if (!desc || !*desc)
  		goto error;
b9fffa387   David Howells   KEYS: Add a key t...
237
238
239
240
241
242
243
  	if (type->vet_description) {
  		ret = type->vet_description(desc);
  		if (ret < 0) {
  			key = ERR_PTR(ret);
  			goto error;
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
244
245
246
247
  	desclen = strlen(desc) + 1;
  	quotalen = desclen + type->def_datalen;
  
  	/* get hold of the key tracking for this user */
1d1e97562   Serge E. Hallyn   keys: distinguish...
248
  	user = key_user_lookup(uid, cred->user->user_ns);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
249
250
251
252
253
  	if (!user)
  		goto no_memory_1;
  
  	/* check that the user's quota permits allocation of another key and
  	 * its description */
7e047ef5f   David Howells   [PATCH] keys: sor...
254
  	if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) {
0b77f5bfb   David Howells   keys: make the ke...
255
256
257
258
  		unsigned maxkeys = (uid == 0) ?
  			key_quota_root_maxkeys : key_quota_maxkeys;
  		unsigned maxbytes = (uid == 0) ?
  			key_quota_root_maxbytes : key_quota_maxbytes;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
259
  		spin_lock(&user->lock);
7e047ef5f   David Howells   [PATCH] keys: sor...
260
  		if (!(flags & KEY_ALLOC_QUOTA_OVERRUN)) {
0b77f5bfb   David Howells   keys: make the ke...
261
262
263
  			if (user->qnkeys + 1 >= maxkeys ||
  			    user->qnbytes + quotalen >= maxbytes ||
  			    user->qnbytes + quotalen < user->qnbytes)
7e047ef5f   David Howells   [PATCH] keys: sor...
264
265
  				goto no_quota;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
266
267
268
269
270
271
272
  
  		user->qnkeys++;
  		user->qnbytes += quotalen;
  		spin_unlock(&user->lock);
  	}
  
  	/* allocate and initialise the key and its description */
e94b17660   Christoph Lameter   [PATCH] slab: rem...
273
  	key = kmem_cache_alloc(key_jar, GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
274
275
276
277
  	if (!key)
  		goto no_memory_2;
  
  	if (desc) {
48ad504ee   Eric Sesterhenn   [PATCH] security/...
278
  		key->description = kmemdup(desc, desclen, GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
279
280
  		if (!key->description)
  			goto no_memory_3;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
281
282
283
  	}
  
  	atomic_set(&key->usage, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
284
285
286
287
288
289
290
291
292
293
294
  	init_rwsem(&key->sem);
  	key->type = type;
  	key->user = user;
  	key->quotalen = quotalen;
  	key->datalen = type->def_datalen;
  	key->uid = uid;
  	key->gid = gid;
  	key->perm = perm;
  	key->flags = 0;
  	key->expiry = 0;
  	key->payload.data = NULL;
29db91906   David Howells   [PATCH] Keys: Add...
295
  	key->security = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
296

7e047ef5f   David Howells   [PATCH] keys: sor...
297
  	if (!(flags & KEY_ALLOC_NOT_IN_QUOTA))
76d8aeabf   David Howells   [PATCH] keys: Dis...
298
  		key->flags |= 1 << KEY_FLAG_IN_QUOTA;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
299
300
301
302
303
304
  
  	memset(&key->type_data, 0, sizeof(key->type_data));
  
  #ifdef KEY_DEBUGGING
  	key->magic = KEY_DEBUG_MAGIC;
  #endif
29db91906   David Howells   [PATCH] Keys: Add...
305
  	/* let the security module know about the key */
d84f4f992   David Howells   CRED: Inaugurate ...
306
  	ret = security_key_alloc(key, cred, flags);
29db91906   David Howells   [PATCH] Keys: Add...
307
308
  	if (ret < 0)
  		goto security_error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
309
310
311
  	/* publish the key by giving it a serial number */
  	atomic_inc(&user->nkeys);
  	key_alloc_serial(key);
29db91906   David Howells   [PATCH] Keys: Add...
312
  error:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
313
  	return key;
29db91906   David Howells   [PATCH] Keys: Add...
314
315
  security_error:
  	kfree(key->description);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
316
  	kmem_cache_free(key_jar, key);
7e047ef5f   David Howells   [PATCH] keys: sor...
317
  	if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
318
319
320
321
322
323
  		spin_lock(&user->lock);
  		user->qnkeys--;
  		user->qnbytes -= quotalen;
  		spin_unlock(&user->lock);
  	}
  	key_user_put(user);
29db91906   David Howells   [PATCH] Keys: Add...
324
325
326
327
328
329
  	key = ERR_PTR(ret);
  	goto error;
  
  no_memory_3:
  	kmem_cache_free(key_jar, key);
  no_memory_2:
7e047ef5f   David Howells   [PATCH] keys: sor...
330
  	if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) {
29db91906   David Howells   [PATCH] Keys: Add...
331
332
333
334
335
336
337
  		spin_lock(&user->lock);
  		user->qnkeys--;
  		user->qnbytes -= quotalen;
  		spin_unlock(&user->lock);
  	}
  	key_user_put(user);
  no_memory_1:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
338
339
  	key = ERR_PTR(-ENOMEM);
  	goto error;
29db91906   David Howells   [PATCH] Keys: Add...
340
  no_quota:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
341
342
343
344
  	spin_unlock(&user->lock);
  	key_user_put(user);
  	key = ERR_PTR(-EDQUOT);
  	goto error;
a8b17ed01   David Howells   KEYS: Do some sty...
345
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
346
  EXPORT_SYMBOL(key_alloc);
973c9f4f4   David Howells   KEYS: Fix up comm...
347
348
349
350
351
352
353
354
355
356
  /**
   * key_payload_reserve - Adjust data quota reservation for the key's payload
   * @key: The key to make the reservation for.
   * @datalen: The amount of data payload the caller now wants.
   *
   * Adjust the amount of the owning user's key data quota that a key reserves.
   * If the amount is increased, then -EDQUOT may be returned if there isn't
   * enough free quota available.
   *
   * If successful, 0 is returned.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
357
358
359
   */
  int key_payload_reserve(struct key *key, size_t datalen)
  {
c5b60b5e6   Justin P. Mattock   security: whitesp...
360
  	int delta = (int)datalen - key->datalen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
361
362
363
364
365
  	int ret = 0;
  
  	key_check(key);
  
  	/* contemplate the quota adjustment */
76d8aeabf   David Howells   [PATCH] keys: Dis...
366
  	if (delta != 0 && test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) {
0b77f5bfb   David Howells   keys: make the ke...
367
368
  		unsigned maxbytes = (key->user->uid == 0) ?
  			key_quota_root_maxbytes : key_quota_maxbytes;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
369
370
371
  		spin_lock(&key->user->lock);
  
  		if (delta > 0 &&
0b77f5bfb   David Howells   keys: make the ke...
372
373
  		    (key->user->qnbytes + delta >= maxbytes ||
  		     key->user->qnbytes + delta < key->user->qnbytes)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
374
375
376
377
378
379
380
381
382
383
384
385
386
387
  			ret = -EDQUOT;
  		}
  		else {
  			key->user->qnbytes += delta;
  			key->quotalen += delta;
  		}
  		spin_unlock(&key->user->lock);
  	}
  
  	/* change the recorded data length if that didn't generate an error */
  	if (ret == 0)
  		key->datalen = datalen;
  
  	return ret;
a8b17ed01   David Howells   KEYS: Do some sty...
388
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
389
  EXPORT_SYMBOL(key_payload_reserve);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
390
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
391
392
393
394
   * Instantiate a key and link it into the target keyring atomically.  Must be
   * called with the target keyring's semaphore writelocked.  The target key's
   * semaphore need not be locked as instantiation is serialised by
   * key_construction_mutex.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
395
396
397
398
   */
  static int __key_instantiate_and_link(struct key *key,
  				      const void *data,
  				      size_t datalen,
3e30148c3   David Howells   [PATCH] Keys: Mak...
399
  				      struct key *keyring,
f70e2e061   David Howells   KEYS: Do prealloc...
400
  				      struct key *authkey,
ceb73c120   David Howells   KEYS: Fix __key_l...
401
  				      unsigned long *_prealloc)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
402
403
404
405
406
407
408
409
  {
  	int ret, awaken;
  
  	key_check(key);
  	key_check(keyring);
  
  	awaken = 0;
  	ret = -EBUSY;
76181c134   David Howells   KEYS: Make reques...
410
  	mutex_lock(&key_construction_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
411
412
  
  	/* can't instantiate twice */
76d8aeabf   David Howells   [PATCH] keys: Dis...
413
  	if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
414
415
416
417
418
  		/* instantiate the key */
  		ret = key->type->instantiate(key, data, datalen);
  
  		if (ret == 0) {
  			/* mark the key as being instantiated */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
419
  			atomic_inc(&key->user->nikeys);
76d8aeabf   David Howells   [PATCH] keys: Dis...
420
  			set_bit(KEY_FLAG_INSTANTIATED, &key->flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
421

76d8aeabf   David Howells   [PATCH] keys: Dis...
422
  			if (test_and_clear_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
423
  				awaken = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
424
425
426
  
  			/* and link it into the destination keyring */
  			if (keyring)
f70e2e061   David Howells   KEYS: Do prealloc...
427
  				__key_link(keyring, key, _prealloc);
3e30148c3   David Howells   [PATCH] Keys: Mak...
428
429
  
  			/* disable the authorisation key */
d84f4f992   David Howells   CRED: Inaugurate ...
430
431
  			if (authkey)
  				key_revoke(authkey);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
432
433
  		}
  	}
76181c134   David Howells   KEYS: Make reques...
434
  	mutex_unlock(&key_construction_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
435
436
437
  
  	/* wake up anyone waiting for a key to be constructed */
  	if (awaken)
76181c134   David Howells   KEYS: Make reques...
438
  		wake_up_bit(&key->flags, KEY_FLAG_USER_CONSTRUCT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
439
440
  
  	return ret;
a8b17ed01   David Howells   KEYS: Do some sty...
441
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
442

973c9f4f4   David Howells   KEYS: Fix up comm...
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
  /**
   * key_instantiate_and_link - Instantiate a key and link it into the keyring.
   * @key: The key to instantiate.
   * @data: The data to use to instantiate the keyring.
   * @datalen: The length of @data.
   * @keyring: Keyring to create a link in on success (or NULL).
   * @authkey: The authorisation token permitting instantiation.
   *
   * Instantiate a key that's in the uninstantiated state using the provided data
   * and, if successful, link it in to the destination keyring if one is
   * supplied.
   *
   * If successful, 0 is returned, the authorisation token is revoked and anyone
   * waiting for the key is woken up.  If the key was already instantiated,
   * -EBUSY will be returned.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
458
459
460
461
   */
  int key_instantiate_and_link(struct key *key,
  			     const void *data,
  			     size_t datalen,
3e30148c3   David Howells   [PATCH] Keys: Mak...
462
  			     struct key *keyring,
d84f4f992   David Howells   CRED: Inaugurate ...
463
  			     struct key *authkey)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
464
  {
ceb73c120   David Howells   KEYS: Fix __key_l...
465
  	unsigned long prealloc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
466
  	int ret;
f70e2e061   David Howells   KEYS: Do prealloc...
467
468
469
470
471
472
  	if (keyring) {
  		ret = __key_link_begin(keyring, key->type, key->description,
  				       &prealloc);
  		if (ret < 0)
  			return ret;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
473

f70e2e061   David Howells   KEYS: Do prealloc...
474
475
  	ret = __key_instantiate_and_link(key, data, datalen, keyring, authkey,
  					 &prealloc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
476
477
  
  	if (keyring)
f70e2e061   David Howells   KEYS: Do prealloc...
478
  		__key_link_end(keyring, key->type, prealloc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
479
480
  
  	return ret;
a8b17ed01   David Howells   KEYS: Do some sty...
481
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
482
483
  
  EXPORT_SYMBOL(key_instantiate_and_link);
973c9f4f4   David Howells   KEYS: Fix up comm...
484
  /**
fdd1b9458   David Howells   KEYS: Add a new k...
485
   * key_reject_and_link - Negatively instantiate a key and link it into the keyring.
973c9f4f4   David Howells   KEYS: Fix up comm...
486
487
   * @key: The key to instantiate.
   * @timeout: The timeout on the negative key.
fdd1b9458   David Howells   KEYS: Add a new k...
488
   * @error: The error to return when the key is hit.
973c9f4f4   David Howells   KEYS: Fix up comm...
489
490
491
492
   * @keyring: Keyring to create a link in on success (or NULL).
   * @authkey: The authorisation token permitting instantiation.
   *
   * Negatively instantiate a key that's in the uninstantiated state and, if
fdd1b9458   David Howells   KEYS: Add a new k...
493
494
495
   * successful, set its timeout and stored error and link it in to the
   * destination keyring if one is supplied.  The key and any links to the key
   * will be automatically garbage collected after the timeout expires.
973c9f4f4   David Howells   KEYS: Fix up comm...
496
497
   *
   * Negative keys are used to rate limit repeated request_key() calls by causing
fdd1b9458   David Howells   KEYS: Add a new k...
498
499
   * them to return the stored error code (typically ENOKEY) until the negative
   * key expires.
973c9f4f4   David Howells   KEYS: Fix up comm...
500
501
502
503
   *
   * If successful, 0 is returned, the authorisation token is revoked and anyone
   * waiting for the key is woken up.  If the key was already instantiated,
   * -EBUSY will be returned.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
504
   */
fdd1b9458   David Howells   KEYS: Add a new k...
505
  int key_reject_and_link(struct key *key,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
506
  			unsigned timeout,
fdd1b9458   David Howells   KEYS: Add a new k...
507
  			unsigned error,
3e30148c3   David Howells   [PATCH] Keys: Mak...
508
  			struct key *keyring,
d84f4f992   David Howells   CRED: Inaugurate ...
509
  			struct key *authkey)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
510
  {
ceb73c120   David Howells   KEYS: Fix __key_l...
511
  	unsigned long prealloc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
512
  	struct timespec now;
f70e2e061   David Howells   KEYS: Do prealloc...
513
  	int ret, awaken, link_ret = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
514
515
516
517
518
519
520
521
  
  	key_check(key);
  	key_check(keyring);
  
  	awaken = 0;
  	ret = -EBUSY;
  
  	if (keyring)
f70e2e061   David Howells   KEYS: Do prealloc...
522
523
  		link_ret = __key_link_begin(keyring, key->type,
  					    key->description, &prealloc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
524

76181c134   David Howells   KEYS: Make reques...
525
  	mutex_lock(&key_construction_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
526
527
  
  	/* can't instantiate twice */
76d8aeabf   David Howells   [PATCH] keys: Dis...
528
  	if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
529
  		/* mark the key as being negatively instantiated */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
530
  		atomic_inc(&key->user->nikeys);
76d8aeabf   David Howells   [PATCH] keys: Dis...
531
532
  		set_bit(KEY_FLAG_NEGATIVE, &key->flags);
  		set_bit(KEY_FLAG_INSTANTIATED, &key->flags);
fdd1b9458   David Howells   KEYS: Add a new k...
533
  		key->type_data.reject_error = -error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
534
535
  		now = current_kernel_time();
  		key->expiry = now.tv_sec + timeout;
c08ef808e   David Howells   KEYS: Fix garbage...
536
  		key_schedule_gc(key->expiry + key_gc_delay);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
537

76d8aeabf   David Howells   [PATCH] keys: Dis...
538
  		if (test_and_clear_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
539
  			awaken = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
540

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
541
542
543
  		ret = 0;
  
  		/* and link it into the destination keyring */
f70e2e061   David Howells   KEYS: Do prealloc...
544
545
  		if (keyring && link_ret == 0)
  			__key_link(keyring, key, &prealloc);
3e30148c3   David Howells   [PATCH] Keys: Mak...
546
547
  
  		/* disable the authorisation key */
d84f4f992   David Howells   CRED: Inaugurate ...
548
549
  		if (authkey)
  			key_revoke(authkey);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
550
  	}
76181c134   David Howells   KEYS: Make reques...
551
  	mutex_unlock(&key_construction_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
552
553
  
  	if (keyring)
f70e2e061   David Howells   KEYS: Do prealloc...
554
  		__key_link_end(keyring, key->type, prealloc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
555
556
557
  
  	/* wake up anyone waiting for a key to be constructed */
  	if (awaken)
76181c134   David Howells   KEYS: Make reques...
558
  		wake_up_bit(&key->flags, KEY_FLAG_USER_CONSTRUCT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
559

f70e2e061   David Howells   KEYS: Do prealloc...
560
  	return ret == 0 ? link_ret : ret;
a8b17ed01   David Howells   KEYS: Do some sty...
561
  }
fdd1b9458   David Howells   KEYS: Add a new k...
562
  EXPORT_SYMBOL(key_reject_and_link);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
563

973c9f4f4   David Howells   KEYS: Fix up comm...
564
565
566
567
568
569
570
  /**
   * key_put - Discard a reference to a key.
   * @key: The key to discard a reference from.
   *
   * Discard a reference to a key, and when all the references are gone, we
   * schedule the cleanup task to come and pull it out of the tree in process
   * context at some later time.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
571
572
573
574
575
576
577
   */
  void key_put(struct key *key)
  {
  	if (key) {
  		key_check(key);
  
  		if (atomic_dec_and_test(&key->usage))
0c061b570   David Howells   KEYS: Correctly d...
578
  			queue_work(system_nrt_wq, &key_gc_work);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
579
  	}
a8b17ed01   David Howells   KEYS: Do some sty...
580
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
581
  EXPORT_SYMBOL(key_put);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
582
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
583
   * Find a key by its serial number.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
   */
  struct key *key_lookup(key_serial_t id)
  {
  	struct rb_node *n;
  	struct key *key;
  
  	spin_lock(&key_serial_lock);
  
  	/* search the tree for the specified key */
  	n = key_serial_tree.rb_node;
  	while (n) {
  		key = rb_entry(n, struct key, serial_node);
  
  		if (id < key->serial)
  			n = n->rb_left;
  		else if (id > key->serial)
  			n = n->rb_right;
  		else
  			goto found;
  	}
973c9f4f4   David Howells   KEYS: Fix up comm...
604
  not_found:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
605
606
  	key = ERR_PTR(-ENOKEY);
  	goto error;
973c9f4f4   David Howells   KEYS: Fix up comm...
607
  found:
5593122ee   David Howells   KEYS: Deal with d...
608
609
  	/* pretend it doesn't exist if it is awaiting deletion */
  	if (atomic_read(&key->usage) == 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
610
611
612
613
614
615
  		goto not_found;
  
  	/* this races with key_put(), but that doesn't matter since key_put()
  	 * doesn't actually change the key
  	 */
  	atomic_inc(&key->usage);
973c9f4f4   David Howells   KEYS: Fix up comm...
616
  error:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
617
618
  	spin_unlock(&key_serial_lock);
  	return key;
a8b17ed01   David Howells   KEYS: Do some sty...
619
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
620

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
621
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
622
623
624
625
   * Find and lock the specified key type against removal.
   *
   * We return with the sem read-locked if successful.  If the type wasn't
   * available -ENOKEY is returned instead.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
   */
  struct key_type *key_type_lookup(const char *type)
  {
  	struct key_type *ktype;
  
  	down_read(&key_types_sem);
  
  	/* look up the key type to see if it's one of the registered kernel
  	 * types */
  	list_for_each_entry(ktype, &key_types_list, link) {
  		if (strcmp(ktype->name, type) == 0)
  			goto found_kernel_type;
  	}
  
  	up_read(&key_types_sem);
  	ktype = ERR_PTR(-ENOKEY);
973c9f4f4   David Howells   KEYS: Fix up comm...
642
  found_kernel_type:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
643
  	return ktype;
a8b17ed01   David Howells   KEYS: Do some sty...
644
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
645

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
646
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
647
   * Unlock a key type locked by key_type_lookup().
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
648
649
650
651
   */
  void key_type_put(struct key_type *ktype)
  {
  	up_read(&key_types_sem);
a8b17ed01   David Howells   KEYS: Do some sty...
652
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
653

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
654
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
655
656
657
658
   * Attempt to update an existing key.
   *
   * The key is given to us with an incremented refcount that we need to discard
   * if we get an error.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
659
   */
664cceb00   David Howells   [PATCH] Keys: Add...
660
661
  static inline key_ref_t __key_update(key_ref_t key_ref,
  				     const void *payload, size_t plen)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
662
  {
664cceb00   David Howells   [PATCH] Keys: Add...
663
  	struct key *key = key_ref_to_ptr(key_ref);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
664
665
666
  	int ret;
  
  	/* need write permission on the key to update it */
29db91906   David Howells   [PATCH] Keys: Add...
667
668
  	ret = key_permission(key_ref, KEY_WRITE);
  	if (ret < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
669
670
671
672
673
674
675
676
677
  		goto error;
  
  	ret = -EEXIST;
  	if (!key->type->update)
  		goto error;
  
  	down_write(&key->sem);
  
  	ret = key->type->update(key, payload, plen);
76d8aeabf   David Howells   [PATCH] keys: Dis...
678
  	if (ret == 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
679
  		/* updating a negative key instantiates it */
76d8aeabf   David Howells   [PATCH] keys: Dis...
680
  		clear_bit(KEY_FLAG_NEGATIVE, &key->flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
681
682
683
684
685
  
  	up_write(&key->sem);
  
  	if (ret < 0)
  		goto error;
664cceb00   David Howells   [PATCH] Keys: Add...
686
687
  out:
  	return key_ref;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
688

664cceb00   David Howells   [PATCH] Keys: Add...
689
  error:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
690
  	key_put(key);
664cceb00   David Howells   [PATCH] Keys: Add...
691
  	key_ref = ERR_PTR(ret);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
692
  	goto out;
a8b17ed01   David Howells   KEYS: Do some sty...
693
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
694

973c9f4f4   David Howells   KEYS: Fix up comm...
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
  /**
   * key_create_or_update - Update or create and instantiate a key.
   * @keyring_ref: A pointer to the destination keyring with possession flag.
   * @type: The type of key.
   * @description: The searchable description for the key.
   * @payload: The data to use to instantiate or update the key.
   * @plen: The length of @payload.
   * @perm: The permissions mask for a new key.
   * @flags: The quota flags for a new key.
   *
   * Search the destination keyring for a key of the same description and if one
   * is found, update it, otherwise create and instantiate a new one and create a
   * link to it from that keyring.
   *
   * If perm is KEY_PERM_UNDEF then an appropriate key permissions mask will be
   * concocted.
   *
   * Returns a pointer to the new key if successful, -ENODEV if the key type
   * wasn't available, -ENOTDIR if the keyring wasn't a keyring, -EACCES if the
   * caller isn't permitted to modify the keyring or the LSM did not permit
   * creation of the key.
   *
   * On success, the possession flag from the keyring ref will be tacked on to
   * the key ref before it is returned.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
719
   */
664cceb00   David Howells   [PATCH] Keys: Add...
720
721
722
723
724
  key_ref_t key_create_or_update(key_ref_t keyring_ref,
  			       const char *type,
  			       const char *description,
  			       const void *payload,
  			       size_t plen,
6b79ccb51   Arun Raghavan   keys: allow clien...
725
  			       key_perm_t perm,
7e047ef5f   David Howells   [PATCH] keys: sor...
726
  			       unsigned long flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
727
  {
ceb73c120   David Howells   KEYS: Fix __key_l...
728
  	unsigned long prealloc;
d84f4f992   David Howells   CRED: Inaugurate ...
729
  	const struct cred *cred = current_cred();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
730
  	struct key_type *ktype;
664cceb00   David Howells   [PATCH] Keys: Add...
731
  	struct key *keyring, *key = NULL;
664cceb00   David Howells   [PATCH] Keys: Add...
732
  	key_ref_t key_ref;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
733
  	int ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
734
735
736
737
  	/* look up the key type to see if it's one of the registered kernel
  	 * types */
  	ktype = key_type_lookup(type);
  	if (IS_ERR(ktype)) {
664cceb00   David Howells   [PATCH] Keys: Add...
738
  		key_ref = ERR_PTR(-ENODEV);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
739
740
  		goto error;
  	}
664cceb00   David Howells   [PATCH] Keys: Add...
741
  	key_ref = ERR_PTR(-EINVAL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
742
743
  	if (!ktype->match || !ktype->instantiate)
  		goto error_2;
664cceb00   David Howells   [PATCH] Keys: Add...
744
745
746
  	keyring = key_ref_to_ptr(keyring_ref);
  
  	key_check(keyring);
c3a9d6541   David Howells   [Security] Keys: ...
747
748
749
  	key_ref = ERR_PTR(-ENOTDIR);
  	if (keyring->type != &key_type_keyring)
  		goto error_2;
f70e2e061   David Howells   KEYS: Do prealloc...
750
751
752
  	ret = __key_link_begin(keyring, ktype, description, &prealloc);
  	if (ret < 0)
  		goto error_2;
664cceb00   David Howells   [PATCH] Keys: Add...
753
754
755
  
  	/* if we're going to allocate a new key, we're going to have
  	 * to modify the keyring */
29db91906   David Howells   [PATCH] Keys: Add...
756
757
758
  	ret = key_permission(keyring_ref, KEY_WRITE);
  	if (ret < 0) {
  		key_ref = ERR_PTR(ret);
664cceb00   David Howells   [PATCH] Keys: Add...
759
  		goto error_3;
29db91906   David Howells   [PATCH] Keys: Add...
760
  	}
664cceb00   David Howells   [PATCH] Keys: Add...
761

1d9b7d97d   David Howells   [PATCH] Keys: Rep...
762
763
764
  	/* if it's possible to update this type of key, search for an existing
  	 * key of the same type and description in the destination keyring and
  	 * update that instead if possible
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
765
  	 */
1d9b7d97d   David Howells   [PATCH] Keys: Rep...
766
767
768
769
770
771
  	if (ktype->update) {
  		key_ref = __keyring_search_one(keyring_ref, ktype, description,
  					       0);
  		if (!IS_ERR(key_ref))
  			goto found_matching_key;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
772

6b79ccb51   Arun Raghavan   keys: allow clien...
773
774
775
776
  	/* if the client doesn't provide, decide on the permissions we want */
  	if (perm == KEY_PERM_UNDEF) {
  		perm = KEY_POS_VIEW | KEY_POS_SEARCH | KEY_POS_LINK | KEY_POS_SETATTR;
  		perm |= KEY_USR_VIEW | KEY_USR_SEARCH | KEY_USR_LINK | KEY_USR_SETATTR;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
777

6b79ccb51   Arun Raghavan   keys: allow clien...
778
779
  		if (ktype->read)
  			perm |= KEY_POS_READ | KEY_USR_READ;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
780

6b79ccb51   Arun Raghavan   keys: allow clien...
781
782
783
  		if (ktype == &key_type_keyring || ktype->update)
  			perm |= KEY_USR_WRITE;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
784
785
  
  	/* allocate a new key */
d84f4f992   David Howells   CRED: Inaugurate ...
786
787
  	key = key_alloc(ktype, description, cred->fsuid, cred->fsgid, cred,
  			perm, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
788
  	if (IS_ERR(key)) {
e231c2ee6   David Howells   Convert ERR_PTR(P...
789
  		key_ref = ERR_CAST(key);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
790
791
792
793
  		goto error_3;
  	}
  
  	/* instantiate it and link it into the target keyring */
f70e2e061   David Howells   KEYS: Do prealloc...
794
795
  	ret = __key_instantiate_and_link(key, payload, plen, keyring, NULL,
  					 &prealloc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
796
797
  	if (ret < 0) {
  		key_put(key);
664cceb00   David Howells   [PATCH] Keys: Add...
798
799
  		key_ref = ERR_PTR(ret);
  		goto error_3;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
800
  	}
664cceb00   David Howells   [PATCH] Keys: Add...
801
  	key_ref = make_key_ref(key, is_key_possessed(keyring_ref));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
802
   error_3:
f70e2e061   David Howells   KEYS: Do prealloc...
803
  	__key_link_end(keyring, ktype, prealloc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
804
805
806
   error_2:
  	key_type_put(ktype);
   error:
664cceb00   David Howells   [PATCH] Keys: Add...
807
  	return key_ref;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
808
809
810
811
812
  
   found_matching_key:
  	/* we found a matching key, so we're going to try to update it
  	 * - we can drop the locks first as we have the key pinned
  	 */
f70e2e061   David Howells   KEYS: Do prealloc...
813
  	__key_link_end(keyring, ktype, prealloc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
814
  	key_type_put(ktype);
664cceb00   David Howells   [PATCH] Keys: Add...
815
  	key_ref = __key_update(key_ref, payload, plen);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
816
  	goto error;
a8b17ed01   David Howells   KEYS: Do some sty...
817
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
818
  EXPORT_SYMBOL(key_create_or_update);
973c9f4f4   David Howells   KEYS: Fix up comm...
819
820
821
822
823
824
825
826
827
828
829
830
  /**
   * key_update - Update a key's contents.
   * @key_ref: The pointer (plus possession flag) to the key.
   * @payload: The data to be used to update the key.
   * @plen: The length of @payload.
   *
   * Attempt to update the contents of a key with the given payload data.  The
   * caller must be granted Write permission on the key.  Negative keys can be
   * instantiated by this method.
   *
   * Returns 0 on success, -EACCES if not permitted and -EOPNOTSUPP if the key
   * type does not support updating.  The key type may return other errors.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
831
   */
664cceb00   David Howells   [PATCH] Keys: Add...
832
  int key_update(key_ref_t key_ref, const void *payload, size_t plen)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
833
  {
664cceb00   David Howells   [PATCH] Keys: Add...
834
  	struct key *key = key_ref_to_ptr(key_ref);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
835
836
837
838
839
  	int ret;
  
  	key_check(key);
  
  	/* the key must be writable */
29db91906   David Howells   [PATCH] Keys: Add...
840
841
  	ret = key_permission(key_ref, KEY_WRITE);
  	if (ret < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
842
843
844
845
846
847
  		goto error;
  
  	/* attempt to update it if supported */
  	ret = -EOPNOTSUPP;
  	if (key->type->update) {
  		down_write(&key->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
848

29db91906   David Howells   [PATCH] Keys: Add...
849
  		ret = key->type->update(key, payload, plen);
76d8aeabf   David Howells   [PATCH] keys: Dis...
850
  		if (ret == 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
851
  			/* updating a negative key instantiates it */
76d8aeabf   David Howells   [PATCH] keys: Dis...
852
  			clear_bit(KEY_FLAG_NEGATIVE, &key->flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
853
854
855
856
857
858
  
  		up_write(&key->sem);
  	}
  
   error:
  	return ret;
a8b17ed01   David Howells   KEYS: Do some sty...
859
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
860
  EXPORT_SYMBOL(key_update);
973c9f4f4   David Howells   KEYS: Fix up comm...
861
862
863
864
865
866
867
868
  /**
   * key_revoke - Revoke a key.
   * @key: The key to be revoked.
   *
   * Mark a key as being revoked and ask the type to free up its resources.  The
   * revocation timeout is set and the key and all its links will be
   * automatically garbage collected after key_gc_delay amount of time if they
   * are not manually dealt with first.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
869
870
871
   */
  void key_revoke(struct key *key)
  {
5d135440f   David Howells   KEYS: Add garbage...
872
873
  	struct timespec now;
  	time_t time;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
874
  	key_check(key);
76181c134   David Howells   KEYS: Make reques...
875
876
877
878
879
880
881
882
  	/* make sure no one's trying to change or use the key when we mark it
  	 * - we tell lockdep that we might nest because we might be revoking an
  	 *   authorisation key whilst holding the sem on a key we've just
  	 *   instantiated
  	 */
  	down_write_nested(&key->sem, 1);
  	if (!test_and_set_bit(KEY_FLAG_REVOKED, &key->flags) &&
  	    key->type->revoke)
04c567d93   David Howells   [PATCH] Keys: Fix...
883
  		key->type->revoke(key);
5d135440f   David Howells   KEYS: Add garbage...
884
885
886
887
888
  	/* set the death time to no more than the expiry time */
  	now = current_kernel_time();
  	time = now.tv_sec;
  	if (key->revoked_at == 0 || key->revoked_at > time) {
  		key->revoked_at = time;
c08ef808e   David Howells   KEYS: Fix garbage...
889
  		key_schedule_gc(key->revoked_at + key_gc_delay);
5d135440f   David Howells   KEYS: Add garbage...
890
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
891
  	up_write(&key->sem);
a8b17ed01   David Howells   KEYS: Do some sty...
892
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
893
  EXPORT_SYMBOL(key_revoke);
973c9f4f4   David Howells   KEYS: Fix up comm...
894
895
896
897
898
899
900
  /**
   * register_key_type - Register a type of key.
   * @ktype: The new key type.
   *
   * Register a new key type.
   *
   * Returns 0 on success or -EEXIST if a type of this name already exists.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
   */
  int register_key_type(struct key_type *ktype)
  {
  	struct key_type *p;
  	int ret;
  
  	ret = -EEXIST;
  	down_write(&key_types_sem);
  
  	/* disallow key types with the same name */
  	list_for_each_entry(p, &key_types_list, link) {
  		if (strcmp(p->name, ktype->name) == 0)
  			goto out;
  	}
  
  	/* store the type */
  	list_add(&ktype->link, &key_types_list);
  	ret = 0;
973c9f4f4   David Howells   KEYS: Fix up comm...
919
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
920
921
  	up_write(&key_types_sem);
  	return ret;
a8b17ed01   David Howells   KEYS: Do some sty...
922
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
923
  EXPORT_SYMBOL(register_key_type);
973c9f4f4   David Howells   KEYS: Fix up comm...
924
925
926
927
928
929
930
  /**
   * unregister_key_type - Unregister a type of key.
   * @ktype: The key type.
   *
   * Unregister a key type and mark all the extant keys of this type as dead.
   * Those keys of this type are then destroyed to get rid of their payloads and
   * they and their links will be garbage collected as soon as possible.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
931
932
933
   */
  void unregister_key_type(struct key_type *ktype)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
934
  	down_write(&key_types_sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
935
  	list_del_init(&ktype->link);
0c061b570   David Howells   KEYS: Correctly d...
936
937
938
  	downgrade_write(&key_types_sem);
  	key_gc_keytype(ktype);
  	up_read(&key_types_sem);
a8b17ed01   David Howells   KEYS: Do some sty...
939
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
940
  EXPORT_SYMBOL(unregister_key_type);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
941
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
942
   * Initialise the key management state.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
943
944
945
946
947
   */
  void __init key_init(void)
  {
  	/* allocate a slab in which we can store keys */
  	key_jar = kmem_cache_create("key_jar", sizeof(struct key),
20c2df83d   Paul Mundt   mm: Remove slab d...
948
  			0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
949
950
951
952
953
954
955
956
957
958
959
960
961
  
  	/* add the special key types */
  	list_add_tail(&key_type_keyring.link, &key_types_list);
  	list_add_tail(&key_type_dead.link, &key_types_list);
  	list_add_tail(&key_type_user.link, &key_types_list);
  
  	/* record the root user tracking */
  	rb_link_node(&root_key_user.node,
  		     NULL,
  		     &key_user_tree.rb_node);
  
  	rb_insert_color(&root_key_user.node,
  			&key_user_tree);
a8b17ed01   David Howells   KEYS: Do some sty...
962
  }