Blame view

security/keys/key.c 28.3 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"
e18b890bb   Christoph Lameter   [PATCH] slab: rem...
23
  static 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);
65f27f384   David Howells   WorkStruct: Pass ...
35
36
  static void key_cleanup(struct work_struct *work);
  static DECLARE_WORK(key_cleanup_task, key_cleanup);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37

973c9f4f4   David Howells   KEYS: Fix up comm...
38
  /* We serialise key instantiation and link */
76181c134   David Howells   KEYS: Make reques...
39
  DEFINE_MUTEX(key_construction_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
40

973c9f4f4   David Howells   KEYS: Fix up comm...
41
  /* Any key who's type gets unegistered will be re-typed to this */
1ae8f4076   Adrian Bunk   [PATCH] security/...
42
  static struct key_type key_type_dead = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43
44
45
46
47
48
49
50
51
52
53
54
  	.name		= "dead",
  };
  
  #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
55
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
56
57
   * 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
58
   */
1d1e97562   Serge E. Hallyn   keys: distinguish...
59
  struct key_user *key_user_lookup(uid_t uid, struct user_namespace *user_ns)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
60
61
62
63
  {
  	struct key_user *candidate = NULL, *user;
  	struct rb_node *parent = NULL;
  	struct rb_node **p;
973c9f4f4   David Howells   KEYS: Fix up comm...
64
  try_again:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
65
66
67
68
69
70
71
72
73
74
75
76
  	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...
77
78
79
80
  		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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
  		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...
108
  	candidate->user_ns = get_user_ns(user_ns);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
109
110
111
  	candidate->qnkeys = 0;
  	candidate->qnbytes = 0;
  	spin_lock_init(&candidate->lock);
76181c134   David Howells   KEYS: Make reques...
112
  	mutex_init(&candidate->cons_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
113
114
115
116
117
118
119
120
  
  	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...
121
  found:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
122
123
  	atomic_inc(&user->usage);
  	spin_unlock(&key_user_lock);
a7f988ba3   Jesper Juhl   [PATCH] kfree cle...
124
  	kfree(candidate);
973c9f4f4   David Howells   KEYS: Fix up comm...
125
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
126
  	return user;
a8b17ed01   David Howells   KEYS: Do some sty...
127
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
128

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
129
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
130
   * Dispose of a user structure
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
131
132
133
134
135
136
   */
  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...
137
  		put_user_ns(user->user_ns);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
138
139
140
  
  		kfree(user);
  	}
a8b17ed01   David Howells   KEYS: Do some sty...
141
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
142

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
143
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
144
145
   * 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
146
147
148
149
150
   */
  static inline void key_alloc_serial(struct key *key)
  {
  	struct rb_node *parent, **p;
  	struct key *xkey;
e51f6d343   Michael LeMay   [PATCH] keys: all...
151
  	/* propose a random serial number and look for a hole for it in the
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
152
  	 * serial number tree */
e51f6d343   Michael LeMay   [PATCH] keys: all...
153
154
155
156
157
158
159
  	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
160

9ad0830f3   David Howells   [PATCH] Keys: Fix...
161
  attempt_insertion:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
162
163
164
165
166
167
168
169
170
171
172
173
174
175
  	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...
176
177
178
179
180
181
182
  
  	/* 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
183
184
185
  
  	/* 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...
186
  serial_exists:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
187
  	for (;;) {
e51f6d343   Michael LeMay   [PATCH] keys: all...
188
  		key->serial++;
9ad0830f3   David Howells   [PATCH] Keys: Fix...
189
190
191
192
  		if (key->serial < 3) {
  			key->serial = 3;
  			goto attempt_insertion;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
193
194
195
  
  		parent = rb_next(parent);
  		if (!parent)
9ad0830f3   David Howells   [PATCH] Keys: Fix...
196
  			goto attempt_insertion;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
197
198
199
  
  		xkey = rb_entry(parent, struct key, serial_node);
  		if (key->serial < xkey->serial)
9ad0830f3   David Howells   [PATCH] Keys: Fix...
200
  			goto attempt_insertion;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
201
  	}
a8b17ed01   David Howells   KEYS: Do some sty...
202
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
203

973c9f4f4   David Howells   KEYS: Fix up comm...
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
  /**
   * 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
232
233
   */
  struct key *key_alloc(struct key_type *type, const char *desc,
d84f4f992   David Howells   CRED: Inaugurate ...
234
  		      uid_t uid, gid_t gid, const struct cred *cred,
7e047ef5f   David Howells   [PATCH] keys: sor...
235
  		      key_perm_t perm, unsigned long flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
236
237
238
239
  {
  	struct key_user *user = NULL;
  	struct key *key;
  	size_t desclen, quotalen;
29db91906   David Howells   [PATCH] Keys: Add...
240
  	int ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
241
242
243
244
  
  	key = ERR_PTR(-EINVAL);
  	if (!desc || !*desc)
  		goto error;
b9fffa387   David Howells   KEYS: Add a key t...
245
246
247
248
249
250
251
  	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
252
253
254
255
  	desclen = strlen(desc) + 1;
  	quotalen = desclen + type->def_datalen;
  
  	/* get hold of the key tracking for this user */
1d1e97562   Serge E. Hallyn   keys: distinguish...
256
  	user = key_user_lookup(uid, cred->user->user_ns);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
257
258
259
260
261
  	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...
262
  	if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) {
0b77f5bfb   David Howells   keys: make the ke...
263
264
265
266
  		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
267
  		spin_lock(&user->lock);
7e047ef5f   David Howells   [PATCH] keys: sor...
268
  		if (!(flags & KEY_ALLOC_QUOTA_OVERRUN)) {
0b77f5bfb   David Howells   keys: make the ke...
269
270
271
  			if (user->qnkeys + 1 >= maxkeys ||
  			    user->qnbytes + quotalen >= maxbytes ||
  			    user->qnbytes + quotalen < user->qnbytes)
7e047ef5f   David Howells   [PATCH] keys: sor...
272
273
  				goto no_quota;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
274
275
276
277
278
279
280
  
  		user->qnkeys++;
  		user->qnbytes += quotalen;
  		spin_unlock(&user->lock);
  	}
  
  	/* allocate and initialise the key and its description */
e94b17660   Christoph Lameter   [PATCH] slab: rem...
281
  	key = kmem_cache_alloc(key_jar, GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
282
283
284
285
  	if (!key)
  		goto no_memory_2;
  
  	if (desc) {
48ad504ee   Eric Sesterhenn   [PATCH] security/...
286
  		key->description = kmemdup(desc, desclen, GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
287
288
  		if (!key->description)
  			goto no_memory_3;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
289
290
291
  	}
  
  	atomic_set(&key->usage, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
292
293
294
295
296
297
298
299
300
301
302
  	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...
303
  	key->security = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
304

7e047ef5f   David Howells   [PATCH] keys: sor...
305
  	if (!(flags & KEY_ALLOC_NOT_IN_QUOTA))
76d8aeabf   David Howells   [PATCH] keys: Dis...
306
  		key->flags |= 1 << KEY_FLAG_IN_QUOTA;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
307
308
309
310
311
312
  
  	memset(&key->type_data, 0, sizeof(key->type_data));
  
  #ifdef KEY_DEBUGGING
  	key->magic = KEY_DEBUG_MAGIC;
  #endif
29db91906   David Howells   [PATCH] Keys: Add...
313
  	/* let the security module know about the key */
d84f4f992   David Howells   CRED: Inaugurate ...
314
  	ret = security_key_alloc(key, cred, flags);
29db91906   David Howells   [PATCH] Keys: Add...
315
316
  	if (ret < 0)
  		goto security_error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
317
318
319
  	/* publish the key by giving it a serial number */
  	atomic_inc(&user->nkeys);
  	key_alloc_serial(key);
29db91906   David Howells   [PATCH] Keys: Add...
320
  error:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
321
  	return key;
29db91906   David Howells   [PATCH] Keys: Add...
322
323
  security_error:
  	kfree(key->description);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
324
  	kmem_cache_free(key_jar, key);
7e047ef5f   David Howells   [PATCH] keys: sor...
325
  	if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
326
327
328
329
330
331
  		spin_lock(&user->lock);
  		user->qnkeys--;
  		user->qnbytes -= quotalen;
  		spin_unlock(&user->lock);
  	}
  	key_user_put(user);
29db91906   David Howells   [PATCH] Keys: Add...
332
333
334
335
336
337
  	key = ERR_PTR(ret);
  	goto error;
  
  no_memory_3:
  	kmem_cache_free(key_jar, key);
  no_memory_2:
7e047ef5f   David Howells   [PATCH] keys: sor...
338
  	if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) {
29db91906   David Howells   [PATCH] Keys: Add...
339
340
341
342
343
344
345
  		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
346
347
  	key = ERR_PTR(-ENOMEM);
  	goto error;
29db91906   David Howells   [PATCH] Keys: Add...
348
  no_quota:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
349
350
351
352
  	spin_unlock(&user->lock);
  	key_user_put(user);
  	key = ERR_PTR(-EDQUOT);
  	goto error;
a8b17ed01   David Howells   KEYS: Do some sty...
353
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
354
  EXPORT_SYMBOL(key_alloc);
973c9f4f4   David Howells   KEYS: Fix up comm...
355
356
357
358
359
360
361
362
363
364
  /**
   * 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
365
366
367
   */
  int key_payload_reserve(struct key *key, size_t datalen)
  {
c5b60b5e6   Justin P. Mattock   security: whitesp...
368
  	int delta = (int)datalen - key->datalen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
369
370
371
372
373
  	int ret = 0;
  
  	key_check(key);
  
  	/* contemplate the quota adjustment */
76d8aeabf   David Howells   [PATCH] keys: Dis...
374
  	if (delta != 0 && test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) {
0b77f5bfb   David Howells   keys: make the ke...
375
376
  		unsigned maxbytes = (key->user->uid == 0) ?
  			key_quota_root_maxbytes : key_quota_maxbytes;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
377
378
379
  		spin_lock(&key->user->lock);
  
  		if (delta > 0 &&
0b77f5bfb   David Howells   keys: make the ke...
380
381
  		    (key->user->qnbytes + delta >= maxbytes ||
  		     key->user->qnbytes + delta < key->user->qnbytes)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
382
383
384
385
386
387
388
389
390
391
392
393
394
395
  			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...
396
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
397
  EXPORT_SYMBOL(key_payload_reserve);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
398
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
399
400
401
402
   * 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
403
404
405
406
   */
  static int __key_instantiate_and_link(struct key *key,
  				      const void *data,
  				      size_t datalen,
3e30148c3   David Howells   [PATCH] Keys: Mak...
407
  				      struct key *keyring,
f70e2e061   David Howells   KEYS: Do prealloc...
408
  				      struct key *authkey,
ceb73c120   David Howells   KEYS: Fix __key_l...
409
  				      unsigned long *_prealloc)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
410
411
412
413
414
415
416
417
  {
  	int ret, awaken;
  
  	key_check(key);
  	key_check(keyring);
  
  	awaken = 0;
  	ret = -EBUSY;
76181c134   David Howells   KEYS: Make reques...
418
  	mutex_lock(&key_construction_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
419
420
  
  	/* can't instantiate twice */
76d8aeabf   David Howells   [PATCH] keys: Dis...
421
  	if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
422
423
424
425
426
  		/* 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
427
  			atomic_inc(&key->user->nikeys);
76d8aeabf   David Howells   [PATCH] keys: Dis...
428
  			set_bit(KEY_FLAG_INSTANTIATED, &key->flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
429

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

973c9f4f4   David Howells   KEYS: Fix up comm...
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
  /**
   * 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
466
467
468
469
   */
  int key_instantiate_and_link(struct key *key,
  			     const void *data,
  			     size_t datalen,
3e30148c3   David Howells   [PATCH] Keys: Mak...
470
  			     struct key *keyring,
d84f4f992   David Howells   CRED: Inaugurate ...
471
  			     struct key *authkey)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
472
  {
ceb73c120   David Howells   KEYS: Fix __key_l...
473
  	unsigned long prealloc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
474
  	int ret;
f70e2e061   David Howells   KEYS: Do prealloc...
475
476
477
478
479
480
  	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
481

f70e2e061   David Howells   KEYS: Do prealloc...
482
483
  	ret = __key_instantiate_and_link(key, data, datalen, keyring, authkey,
  					 &prealloc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
484
485
  
  	if (keyring)
f70e2e061   David Howells   KEYS: Do prealloc...
486
  		__key_link_end(keyring, key->type, prealloc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
487
488
  
  	return ret;
a8b17ed01   David Howells   KEYS: Do some sty...
489
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
490
491
  
  EXPORT_SYMBOL(key_instantiate_and_link);
973c9f4f4   David Howells   KEYS: Fix up comm...
492
  /**
fdd1b9458   David Howells   KEYS: Add a new k...
493
   * key_reject_and_link - Negatively instantiate a key and link it into the keyring.
973c9f4f4   David Howells   KEYS: Fix up comm...
494
495
   * @key: The key to instantiate.
   * @timeout: The timeout on the negative key.
fdd1b9458   David Howells   KEYS: Add a new k...
496
   * @error: The error to return when the key is hit.
973c9f4f4   David Howells   KEYS: Fix up comm...
497
498
499
500
   * @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...
501
502
503
   * 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...
504
505
   *
   * Negative keys are used to rate limit repeated request_key() calls by causing
fdd1b9458   David Howells   KEYS: Add a new k...
506
507
   * them to return the stored error code (typically ENOKEY) until the negative
   * key expires.
973c9f4f4   David Howells   KEYS: Fix up comm...
508
509
510
511
   *
   * 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
512
   */
fdd1b9458   David Howells   KEYS: Add a new k...
513
  int key_reject_and_link(struct key *key,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
514
  			unsigned timeout,
fdd1b9458   David Howells   KEYS: Add a new k...
515
  			unsigned error,
3e30148c3   David Howells   [PATCH] Keys: Mak...
516
  			struct key *keyring,
d84f4f992   David Howells   CRED: Inaugurate ...
517
  			struct key *authkey)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
518
  {
ceb73c120   David Howells   KEYS: Fix __key_l...
519
  	unsigned long prealloc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
520
  	struct timespec now;
f70e2e061   David Howells   KEYS: Do prealloc...
521
  	int ret, awaken, link_ret = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
522
523
524
525
526
527
528
529
  
  	key_check(key);
  	key_check(keyring);
  
  	awaken = 0;
  	ret = -EBUSY;
  
  	if (keyring)
f70e2e061   David Howells   KEYS: Do prealloc...
530
531
  		link_ret = __key_link_begin(keyring, key->type,
  					    key->description, &prealloc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
532

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

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

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

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

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
572
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
573
574
575
576
577
   * Garbage collect keys in process context so that we don't have to disable
   * interrupts all over the place.
   *
   * key_put() schedules this rather than trying to do the cleanup itself, which
   * means key_put() doesn't have to sleep.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
578
   */
65f27f384   David Howells   WorkStruct: Pass ...
579
  static void key_cleanup(struct work_struct *work)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
580
581
582
  {
  	struct rb_node *_n;
  	struct key *key;
973c9f4f4   David Howells   KEYS: Fix up comm...
583
  go_again:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
584
585
586
587
588
589
590
591
592
593
594
595
  	/* look for a dead key in the tree */
  	spin_lock(&key_serial_lock);
  
  	for (_n = rb_first(&key_serial_tree); _n; _n = rb_next(_n)) {
  		key = rb_entry(_n, struct key, serial_node);
  
  		if (atomic_read(&key->usage) == 0)
  			goto found_dead_key;
  	}
  
  	spin_unlock(&key_serial_lock);
  	return;
973c9f4f4   David Howells   KEYS: Fix up comm...
596
  found_dead_key:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
597
598
599
600
  	/* we found a dead key - once we've removed it from the tree, we can
  	 * drop the lock */
  	rb_erase(&key->serial_node, &key_serial_tree);
  	spin_unlock(&key_serial_lock);
76d8aeabf   David Howells   [PATCH] keys: Dis...
601
  	key_check(key);
29db91906   David Howells   [PATCH] Keys: Add...
602
  	security_key_free(key);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
603
  	/* deal with the user's key tracking and quota */
76d8aeabf   David Howells   [PATCH] keys: Dis...
604
  	if (test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
605
606
607
608
609
610
611
  		spin_lock(&key->user->lock);
  		key->user->qnkeys--;
  		key->user->qnbytes -= key->quotalen;
  		spin_unlock(&key->user->lock);
  	}
  
  	atomic_dec(&key->user->nkeys);
76d8aeabf   David Howells   [PATCH] keys: Dis...
612
  	if (test_bit(KEY_FLAG_INSTANTIATED, &key->flags))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
  		atomic_dec(&key->user->nikeys);
  
  	key_user_put(key->user);
  
  	/* now throw away the key memory */
  	if (key->type->destroy)
  		key->type->destroy(key);
  
  	kfree(key->description);
  
  #ifdef KEY_DEBUGGING
  	key->magic = KEY_DEBUG_MAGIC_X;
  #endif
  	kmem_cache_free(key_jar, key);
  
  	/* there may, of course, be more than one key to destroy */
  	goto go_again;
a8b17ed01   David Howells   KEYS: Do some sty...
630
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
631

973c9f4f4   David Howells   KEYS: Fix up comm...
632
633
634
635
636
637
638
  /**
   * 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
639
640
641
642
643
644
645
646
647
   */
  void key_put(struct key *key)
  {
  	if (key) {
  		key_check(key);
  
  		if (atomic_dec_and_test(&key->usage))
  			schedule_work(&key_cleanup_task);
  	}
a8b17ed01   David Howells   KEYS: Do some sty...
648
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
649
  EXPORT_SYMBOL(key_put);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
650
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
651
   * Find a key by its serial number.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
   */
  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...
672
  not_found:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
673
674
  	key = ERR_PTR(-ENOKEY);
  	goto error;
973c9f4f4   David Howells   KEYS: Fix up comm...
675
  found:
5593122ee   David Howells   KEYS: Deal with d...
676
677
  	/* pretend it doesn't exist if it is awaiting deletion */
  	if (atomic_read(&key->usage) == 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
678
679
680
681
682
683
  		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...
684
  error:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
685
686
  	spin_unlock(&key_serial_lock);
  	return key;
a8b17ed01   David Howells   KEYS: Do some sty...
687
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
688

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
689
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
690
691
692
693
   * 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
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
   */
  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...
710
  found_kernel_type:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
711
  	return ktype;
a8b17ed01   David Howells   KEYS: Do some sty...
712
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
713

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
714
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
715
   * Unlock a key type locked by key_type_lookup().
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
716
717
718
719
   */
  void key_type_put(struct key_type *ktype)
  {
  	up_read(&key_types_sem);
a8b17ed01   David Howells   KEYS: Do some sty...
720
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
721

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
722
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
723
724
725
726
   * 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
727
   */
664cceb00   David Howells   [PATCH] Keys: Add...
728
729
  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
730
  {
664cceb00   David Howells   [PATCH] Keys: Add...
731
  	struct key *key = key_ref_to_ptr(key_ref);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
732
733
734
  	int ret;
  
  	/* need write permission on the key to update it */
29db91906   David Howells   [PATCH] Keys: Add...
735
736
  	ret = key_permission(key_ref, KEY_WRITE);
  	if (ret < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
737
738
739
740
741
742
743
744
745
  		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...
746
  	if (ret == 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
747
  		/* updating a negative key instantiates it */
76d8aeabf   David Howells   [PATCH] keys: Dis...
748
  		clear_bit(KEY_FLAG_NEGATIVE, &key->flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
749
750
751
752
753
  
  	up_write(&key->sem);
  
  	if (ret < 0)
  		goto error;
664cceb00   David Howells   [PATCH] Keys: Add...
754
755
  out:
  	return key_ref;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
756

664cceb00   David Howells   [PATCH] Keys: Add...
757
  error:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
758
  	key_put(key);
664cceb00   David Howells   [PATCH] Keys: Add...
759
  	key_ref = ERR_PTR(ret);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
760
  	goto out;
a8b17ed01   David Howells   KEYS: Do some sty...
761
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
762

973c9f4f4   David Howells   KEYS: Fix up comm...
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
  /**
   * 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
787
   */
664cceb00   David Howells   [PATCH] Keys: Add...
788
789
790
791
792
  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...
793
  			       key_perm_t perm,
7e047ef5f   David Howells   [PATCH] keys: sor...
794
  			       unsigned long flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
795
  {
ceb73c120   David Howells   KEYS: Fix __key_l...
796
  	unsigned long prealloc;
d84f4f992   David Howells   CRED: Inaugurate ...
797
  	const struct cred *cred = current_cred();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
798
  	struct key_type *ktype;
664cceb00   David Howells   [PATCH] Keys: Add...
799
  	struct key *keyring, *key = NULL;
664cceb00   David Howells   [PATCH] Keys: Add...
800
  	key_ref_t key_ref;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
801
  	int ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
802
803
804
805
  	/* 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...
806
  		key_ref = ERR_PTR(-ENODEV);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
807
808
  		goto error;
  	}
664cceb00   David Howells   [PATCH] Keys: Add...
809
  	key_ref = ERR_PTR(-EINVAL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
810
811
  	if (!ktype->match || !ktype->instantiate)
  		goto error_2;
664cceb00   David Howells   [PATCH] Keys: Add...
812
813
814
  	keyring = key_ref_to_ptr(keyring_ref);
  
  	key_check(keyring);
c3a9d6541   David Howells   [Security] Keys: ...
815
816
817
  	key_ref = ERR_PTR(-ENOTDIR);
  	if (keyring->type != &key_type_keyring)
  		goto error_2;
f70e2e061   David Howells   KEYS: Do prealloc...
818
819
820
  	ret = __key_link_begin(keyring, ktype, description, &prealloc);
  	if (ret < 0)
  		goto error_2;
664cceb00   David Howells   [PATCH] Keys: Add...
821
822
823
  
  	/* if we're going to allocate a new key, we're going to have
  	 * to modify the keyring */
29db91906   David Howells   [PATCH] Keys: Add...
824
825
826
  	ret = key_permission(keyring_ref, KEY_WRITE);
  	if (ret < 0) {
  		key_ref = ERR_PTR(ret);
664cceb00   David Howells   [PATCH] Keys: Add...
827
  		goto error_3;
29db91906   David Howells   [PATCH] Keys: Add...
828
  	}
664cceb00   David Howells   [PATCH] Keys: Add...
829

1d9b7d97d   David Howells   [PATCH] Keys: Rep...
830
831
832
  	/* 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
833
  	 */
1d9b7d97d   David Howells   [PATCH] Keys: Rep...
834
835
836
837
838
839
  	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
840

6b79ccb51   Arun Raghavan   keys: allow clien...
841
842
843
844
  	/* 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
845

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

6b79ccb51   Arun Raghavan   keys: allow clien...
849
850
851
  		if (ktype == &key_type_keyring || ktype->update)
  			perm |= KEY_USR_WRITE;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
852
853
  
  	/* allocate a new key */
d84f4f992   David Howells   CRED: Inaugurate ...
854
855
  	key = key_alloc(ktype, description, cred->fsuid, cred->fsgid, cred,
  			perm, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
856
  	if (IS_ERR(key)) {
e231c2ee6   David Howells   Convert ERR_PTR(P...
857
  		key_ref = ERR_CAST(key);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
858
859
860
861
  		goto error_3;
  	}
  
  	/* instantiate it and link it into the target keyring */
f70e2e061   David Howells   KEYS: Do prealloc...
862
863
  	ret = __key_instantiate_and_link(key, payload, plen, keyring, NULL,
  					 &prealloc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
864
865
  	if (ret < 0) {
  		key_put(key);
664cceb00   David Howells   [PATCH] Keys: Add...
866
867
  		key_ref = ERR_PTR(ret);
  		goto error_3;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
868
  	}
664cceb00   David Howells   [PATCH] Keys: Add...
869
  	key_ref = make_key_ref(key, is_key_possessed(keyring_ref));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
870
   error_3:
f70e2e061   David Howells   KEYS: Do prealloc...
871
  	__key_link_end(keyring, ktype, prealloc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
872
873
874
   error_2:
  	key_type_put(ktype);
   error:
664cceb00   David Howells   [PATCH] Keys: Add...
875
  	return key_ref;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
876
877
878
879
880
  
   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...
881
  	__key_link_end(keyring, ktype, prealloc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
882
  	key_type_put(ktype);
664cceb00   David Howells   [PATCH] Keys: Add...
883
  	key_ref = __key_update(key_ref, payload, plen);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
884
  	goto error;
a8b17ed01   David Howells   KEYS: Do some sty...
885
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
886
  EXPORT_SYMBOL(key_create_or_update);
973c9f4f4   David Howells   KEYS: Fix up comm...
887
888
889
890
891
892
893
894
895
896
897
898
  /**
   * 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
899
   */
664cceb00   David Howells   [PATCH] Keys: Add...
900
  int key_update(key_ref_t key_ref, const void *payload, size_t plen)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
901
  {
664cceb00   David Howells   [PATCH] Keys: Add...
902
  	struct key *key = key_ref_to_ptr(key_ref);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
903
904
905
906
907
  	int ret;
  
  	key_check(key);
  
  	/* the key must be writable */
29db91906   David Howells   [PATCH] Keys: Add...
908
909
  	ret = key_permission(key_ref, KEY_WRITE);
  	if (ret < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
910
911
912
913
914
915
  		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
916

29db91906   David Howells   [PATCH] Keys: Add...
917
  		ret = key->type->update(key, payload, plen);
76d8aeabf   David Howells   [PATCH] keys: Dis...
918
  		if (ret == 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
919
  			/* updating a negative key instantiates it */
76d8aeabf   David Howells   [PATCH] keys: Dis...
920
  			clear_bit(KEY_FLAG_NEGATIVE, &key->flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
921
922
923
924
925
926
  
  		up_write(&key->sem);
  	}
  
   error:
  	return ret;
a8b17ed01   David Howells   KEYS: Do some sty...
927
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
928
  EXPORT_SYMBOL(key_update);
973c9f4f4   David Howells   KEYS: Fix up comm...
929
930
931
932
933
934
935
936
  /**
   * 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
937
938
939
   */
  void key_revoke(struct key *key)
  {
5d135440f   David Howells   KEYS: Add garbage...
940
941
  	struct timespec now;
  	time_t time;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
942
  	key_check(key);
76181c134   David Howells   KEYS: Make reques...
943
944
945
946
947
948
949
950
  	/* 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...
951
  		key->type->revoke(key);
5d135440f   David Howells   KEYS: Add garbage...
952
953
954
955
956
  	/* 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...
957
  		key_schedule_gc(key->revoked_at + key_gc_delay);
5d135440f   David Howells   KEYS: Add garbage...
958
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
959
  	up_write(&key->sem);
a8b17ed01   David Howells   KEYS: Do some sty...
960
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
961
  EXPORT_SYMBOL(key_revoke);
973c9f4f4   David Howells   KEYS: Fix up comm...
962
963
964
965
966
967
968
  /**
   * 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
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
   */
  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...
987
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
988
989
  	up_write(&key_types_sem);
  	return ret;
a8b17ed01   David Howells   KEYS: Do some sty...
990
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
991
  EXPORT_SYMBOL(register_key_type);
973c9f4f4   David Howells   KEYS: Fix up comm...
992
993
994
995
996
997
998
  /**
   * 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
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
   */
  void unregister_key_type(struct key_type *ktype)
  {
  	struct rb_node *_n;
  	struct key *key;
  
  	down_write(&key_types_sem);
  
  	/* withdraw the key type */
  	list_del_init(&ktype->link);
76d8aeabf   David Howells   [PATCH] keys: Dis...
1009
  	/* mark all the keys of this type dead */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1010
1011
1012
1013
  	spin_lock(&key_serial_lock);
  
  	for (_n = rb_first(&key_serial_tree); _n; _n = rb_next(_n)) {
  		key = rb_entry(_n, struct key, serial_node);
f041ae2f9   David Howells   KEYS: Flag dead k...
1014
  		if (key->type == ktype) {
76d8aeabf   David Howells   [PATCH] keys: Dis...
1015
  			key->type = &key_type_dead;
f041ae2f9   David Howells   KEYS: Flag dead k...
1016
1017
  			set_bit(KEY_FLAG_DEAD, &key->flags);
  		}
76d8aeabf   David Howells   [PATCH] keys: Dis...
1018
1019
1020
1021
1022
  	}
  
  	spin_unlock(&key_serial_lock);
  
  	/* make sure everyone revalidates their keys */
b2b186600   Paul E. McKenney   [PATCH] RCU: clea...
1023
  	synchronize_rcu();
76d8aeabf   David Howells   [PATCH] keys: Dis...
1024
1025
1026
1027
  
  	/* we should now be able to destroy the payloads of all the keys of
  	 * this type with impunity */
  	spin_lock(&key_serial_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1028

76d8aeabf   David Howells   [PATCH] keys: Dis...
1029
1030
  	for (_n = rb_first(&key_serial_tree); _n; _n = rb_next(_n)) {
  		key = rb_entry(_n, struct key, serial_node);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1031

76d8aeabf   David Howells   [PATCH] keys: Dis...
1032
1033
1034
  		if (key->type == ktype) {
  			if (ktype->destroy)
  				ktype->destroy(key);
a7807a32b   Randy Dunlap   [PATCH] poison: a...
1035
  			memset(&key->payload, KEY_DESTROY, sizeof(key->payload));
76d8aeabf   David Howells   [PATCH] keys: Dis...
1036
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1037
1038
1039
1040
  	}
  
  	spin_unlock(&key_serial_lock);
  	up_write(&key_types_sem);
5d135440f   David Howells   KEYS: Add garbage...
1041
  	key_schedule_gc(0);
a8b17ed01   David Howells   KEYS: Do some sty...
1042
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1043
  EXPORT_SYMBOL(unregister_key_type);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1044
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
1045
   * Initialise the key management state.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1046
1047
1048
1049
1050
   */
  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...
1051
  			0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
  
  	/* 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...
1065
  }