Blame view

security/keys/keyctl.c 39.1 KB
973c9f4f4   David Howells   KEYS: Fix up comm...
1
  /* Userspace key control operations
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
   *
3e30148c3   David Howells   [PATCH] Keys: Mak...
3
   * Copyright (C) 2004-5 Red Hat, Inc. All Rights Reserved.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
   * Written by David Howells (dhowells@redhat.com)
   *
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of the GNU General Public License
   * as published by the Free Software Foundation; either version
   * 2 of the License, or (at your option) any later version.
   */
  
  #include <linux/module.h>
  #include <linux/init.h>
  #include <linux/sched.h>
  #include <linux/slab.h>
  #include <linux/syscalls.h>
  #include <linux/keyctl.h>
  #include <linux/fs.h>
c59ede7b7   Randy.Dunlap   [PATCH] move capa...
19
  #include <linux/capability.h>
0cb409d98   Davi Arnaut   [PATCH] strndup_u...
20
  #include <linux/string.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21
  #include <linux/err.h>
38bbca6b6   David Howells   keys: increase th...
22
  #include <linux/vmalloc.h>
70a5bb72b   David Howells   keys: add keyctl ...
23
  #include <linux/security.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
25
  #include <asm/uaccess.h>
  #include "internal.h"
0cb409d98   Davi Arnaut   [PATCH] strndup_u...
26
27
28
29
30
31
32
  static int key_get_type_from_user(char *type,
  				  const char __user *_type,
  				  unsigned len)
  {
  	int ret;
  
  	ret = strncpy_from_user(type, _type, len);
0cb409d98   Davi Arnaut   [PATCH] strndup_u...
33
  	if (ret < 0)
4303ef19c   Dan Carpenter   KEYS: Propagate e...
34
  		return ret;
0cb409d98   Davi Arnaut   [PATCH] strndup_u...
35
36
  	if (ret == 0 || ret >= len)
  		return -EINVAL;
0cb409d98   Davi Arnaut   [PATCH] strndup_u...
37
38
  	if (type[0] == '.')
  		return -EPERM;
0cb409d98   Davi Arnaut   [PATCH] strndup_u...
39
  	type[len - 1] = '\0';
0cb409d98   Davi Arnaut   [PATCH] strndup_u...
40
41
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
43
44
45
46
47
48
49
   * Extract the description of a new key from userspace and either add it as a
   * new key to the specified keyring or update a matching key in that keyring.
   *
   * The keyring must be writable so that we can attach the key to it.
   *
   * If successful, the new key's serial number is returned, otherwise an error
   * code is returned.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
50
   */
1e7bfb213   Heiko Carstens   [CVE-2009-0029] S...
51
52
53
54
55
  SYSCALL_DEFINE5(add_key, const char __user *, _type,
  		const char __user *, _description,
  		const void __user *, _payload,
  		size_t, plen,
  		key_serial_t, ringid)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
56
  {
664cceb00   David Howells   [PATCH] Keys: Add...
57
  	key_ref_t keyring_ref, key_ref;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58
59
  	char type[32], *description;
  	void *payload;
0cb409d98   Davi Arnaut   [PATCH] strndup_u...
60
  	long ret;
38bbca6b6   David Howells   keys: increase th...
61
  	bool vm;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62
63
  
  	ret = -EINVAL;
38bbca6b6   David Howells   keys: increase th...
64
  	if (plen > 1024 * 1024 - 1)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
65
66
67
  		goto error;
  
  	/* draw all the data into kernel space */
0cb409d98   Davi Arnaut   [PATCH] strndup_u...
68
  	ret = key_get_type_from_user(type, _type, sizeof(type));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
69
70
  	if (ret < 0)
  		goto error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
71

0cb409d98   Davi Arnaut   [PATCH] strndup_u...
72
73
74
  	description = strndup_user(_description, PAGE_SIZE);
  	if (IS_ERR(description)) {
  		ret = PTR_ERR(description);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
75
  		goto error;
0cb409d98   Davi Arnaut   [PATCH] strndup_u...
76
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
77
78
79
  
  	/* pull the payload in if one was supplied */
  	payload = NULL;
38bbca6b6   David Howells   keys: increase th...
80
  	vm = false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
81
82
83
  	if (_payload) {
  		ret = -ENOMEM;
  		payload = kmalloc(plen, GFP_KERNEL);
38bbca6b6   David Howells   keys: increase th...
84
85
86
87
88
89
90
91
  		if (!payload) {
  			if (plen <= PAGE_SIZE)
  				goto error2;
  			vm = true;
  			payload = vmalloc(plen);
  			if (!payload)
  				goto error2;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
92
93
94
95
96
97
98
  
  		ret = -EFAULT;
  		if (copy_from_user(payload, _payload, plen) != 0)
  			goto error3;
  	}
  
  	/* find the target keyring (which must be writable) */
5593122ee   David Howells   KEYS: Deal with d...
99
  	keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE);
664cceb00   David Howells   [PATCH] Keys: Add...
100
101
  	if (IS_ERR(keyring_ref)) {
  		ret = PTR_ERR(keyring_ref);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
102
103
104
105
106
  		goto error3;
  	}
  
  	/* create or update the requested key and add it to the target
  	 * keyring */
664cceb00   David Howells   [PATCH] Keys: Add...
107
  	key_ref = key_create_or_update(keyring_ref, type, description,
6b79ccb51   Arun Raghavan   keys: allow clien...
108
109
  				       payload, plen, KEY_PERM_UNDEF,
  				       KEY_ALLOC_IN_QUOTA);
664cceb00   David Howells   [PATCH] Keys: Add...
110
111
112
  	if (!IS_ERR(key_ref)) {
  		ret = key_ref_to_ptr(key_ref)->serial;
  		key_ref_put(key_ref);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
113
114
  	}
  	else {
664cceb00   David Howells   [PATCH] Keys: Add...
115
  		ret = PTR_ERR(key_ref);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
116
  	}
664cceb00   David Howells   [PATCH] Keys: Add...
117
  	key_ref_put(keyring_ref);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
118
   error3:
38bbca6b6   David Howells   keys: increase th...
119
120
121
122
  	if (!vm)
  		kfree(payload);
  	else
  		vfree(payload);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
123
124
125
126
   error2:
  	kfree(description);
   error:
  	return ret;
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
131
132
133
134
135
136
137
138
139
140
   * Search the process keyrings and keyring trees linked from those for a
   * matching key.  Keyrings must have appropriate Search permission to be
   * searched.
   *
   * If a key is found, it will be attached to the destination keyring if there's
   * one specified and the serial number of the key will be returned.
   *
   * If no key is found, /sbin/request-key will be invoked if _callout_info is
   * non-NULL in an attempt to create a key.  The _callout_info string will be
   * passed to /sbin/request-key to aid with completing the request.  If the
   * _callout_info string is "" then it will be changed to "-".
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
141
   */
1e7bfb213   Heiko Carstens   [CVE-2009-0029] S...
142
143
144
145
  SYSCALL_DEFINE4(request_key, const char __user *, _type,
  		const char __user *, _description,
  		const char __user *, _callout_info,
  		key_serial_t, destringid)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
146
147
  {
  	struct key_type *ktype;
664cceb00   David Howells   [PATCH] Keys: Add...
148
149
  	struct key *key;
  	key_ref_t dest_ref;
4a38e122e   David Howells   keys: allow the c...
150
  	size_t callout_len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
151
  	char type[32], *description, *callout_info;
0cb409d98   Davi Arnaut   [PATCH] strndup_u...
152
  	long ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
153
154
  
  	/* pull the type into kernel space */
0cb409d98   Davi Arnaut   [PATCH] strndup_u...
155
  	ret = key_get_type_from_user(type, _type, sizeof(type));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
156
157
  	if (ret < 0)
  		goto error;
1260f801b   David Howells   [PATCH] Keys: Fix...
158

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
159
  	/* pull the description into kernel space */
0cb409d98   Davi Arnaut   [PATCH] strndup_u...
160
161
162
  	description = strndup_user(_description, PAGE_SIZE);
  	if (IS_ERR(description)) {
  		ret = PTR_ERR(description);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
163
  		goto error;
0cb409d98   Davi Arnaut   [PATCH] strndup_u...
164
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
165
166
167
  
  	/* pull the callout info into kernel space */
  	callout_info = NULL;
4a38e122e   David Howells   keys: allow the c...
168
  	callout_len = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
169
  	if (_callout_info) {
0cb409d98   Davi Arnaut   [PATCH] strndup_u...
170
171
172
  		callout_info = strndup_user(_callout_info, PAGE_SIZE);
  		if (IS_ERR(callout_info)) {
  			ret = PTR_ERR(callout_info);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
173
  			goto error2;
0cb409d98   Davi Arnaut   [PATCH] strndup_u...
174
  		}
4a38e122e   David Howells   keys: allow the c...
175
  		callout_len = strlen(callout_info);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
176
177
178
  	}
  
  	/* get the destination keyring if specified */
664cceb00   David Howells   [PATCH] Keys: Add...
179
  	dest_ref = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
180
  	if (destringid) {
5593122ee   David Howells   KEYS: Deal with d...
181
182
  		dest_ref = lookup_user_key(destringid, KEY_LOOKUP_CREATE,
  					   KEY_WRITE);
664cceb00   David Howells   [PATCH] Keys: Add...
183
184
  		if (IS_ERR(dest_ref)) {
  			ret = PTR_ERR(dest_ref);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
185
186
187
188
189
190
191
192
193
194
195
196
  			goto error3;
  		}
  	}
  
  	/* find the key type */
  	ktype = key_type_lookup(type);
  	if (IS_ERR(ktype)) {
  		ret = PTR_ERR(ktype);
  		goto error4;
  	}
  
  	/* do the search */
4a38e122e   David Howells   keys: allow the c...
197
198
  	key = request_key_and_link(ktype, description, callout_info,
  				   callout_len, NULL, key_ref_to_ptr(dest_ref),
7e047ef5f   David Howells   [PATCH] keys: sor...
199
  				   KEY_ALLOC_IN_QUOTA);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
200
201
202
203
  	if (IS_ERR(key)) {
  		ret = PTR_ERR(key);
  		goto error5;
  	}
4aab1e896   David Howells   KEYS: Make reques...
204
205
206
207
  	/* wait for the key to finish being constructed */
  	ret = wait_for_key_construction(key, 1);
  	if (ret < 0)
  		goto error6;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
208
  	ret = key->serial;
4aab1e896   David Howells   KEYS: Make reques...
209
  error6:
3e30148c3   David Howells   [PATCH] Keys: Mak...
210
   	key_put(key);
c5b60b5e6   Justin P. Mattock   security: whitesp...
211
  error5:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
212
  	key_type_put(ktype);
c5b60b5e6   Justin P. Mattock   security: whitesp...
213
  error4:
664cceb00   David Howells   [PATCH] Keys: Add...
214
  	key_ref_put(dest_ref);
c5b60b5e6   Justin P. Mattock   security: whitesp...
215
  error3:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
216
  	kfree(callout_info);
c5b60b5e6   Justin P. Mattock   security: whitesp...
217
  error2:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
218
  	kfree(description);
c5b60b5e6   Justin P. Mattock   security: whitesp...
219
  error:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
220
  	return ret;
a8b17ed01   David Howells   KEYS: Do some sty...
221
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
222

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
223
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
224
225
226
227
228
   * Get the ID of the specified process keyring.
   *
   * The requested keyring must have search permission to be found.
   *
   * If successful, the ID of the requested keyring will be returned.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
229
230
231
   */
  long keyctl_get_keyring_ID(key_serial_t id, int create)
  {
664cceb00   David Howells   [PATCH] Keys: Add...
232
  	key_ref_t key_ref;
5593122ee   David Howells   KEYS: Deal with d...
233
  	unsigned long lflags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
234
  	long ret;
5593122ee   David Howells   KEYS: Deal with d...
235
236
  	lflags = create ? KEY_LOOKUP_CREATE : 0;
  	key_ref = lookup_user_key(id, lflags, KEY_SEARCH);
664cceb00   David Howells   [PATCH] Keys: Add...
237
238
  	if (IS_ERR(key_ref)) {
  		ret = PTR_ERR(key_ref);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
239
240
  		goto error;
  	}
664cceb00   David Howells   [PATCH] Keys: Add...
241
242
  	ret = key_ref_to_ptr(key_ref)->serial;
  	key_ref_put(key_ref);
c5b60b5e6   Justin P. Mattock   security: whitesp...
243
  error:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
244
  	return ret;
973c9f4f4   David Howells   KEYS: Fix up comm...
245
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
246

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
247
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
248
249
250
251
252
253
254
255
   * Join a (named) session keyring.
   *
   * Create and join an anonymous session keyring or join a named session
   * keyring, creating it if necessary.  A named session keyring must have Search
   * permission for it to be joined.  Session keyrings without this permit will
   * be skipped over.
   *
   * If successful, the ID of the joined session keyring will be returned.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
256
257
258
259
   */
  long keyctl_join_session_keyring(const char __user *_name)
  {
  	char *name;
0cb409d98   Davi Arnaut   [PATCH] strndup_u...
260
  	long ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
261
262
263
264
  
  	/* fetch the name from userspace */
  	name = NULL;
  	if (_name) {
0cb409d98   Davi Arnaut   [PATCH] strndup_u...
265
266
267
  		name = strndup_user(_name, PAGE_SIZE);
  		if (IS_ERR(name)) {
  			ret = PTR_ERR(name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
268
  			goto error;
0cb409d98   Davi Arnaut   [PATCH] strndup_u...
269
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
270
271
272
273
  	}
  
  	/* join the session */
  	ret = join_session_keyring(name);
0d54ee1c7   Vegard Nossum   security: introdu...
274
  	kfree(name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
275

c5b60b5e6   Justin P. Mattock   security: whitesp...
276
  error:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
277
  	return ret;
a8b17ed01   David Howells   KEYS: Do some sty...
278
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
279

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
280
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
281
282
283
284
285
286
287
288
   * Update a key's data payload from the given data.
   *
   * The key must grant the caller Write permission and the key type must support
   * updating for this to work.  A negative key can be positively instantiated
   * with this call.
   *
   * If successful, 0 will be returned.  If the key type does not support
   * updating, then -EOPNOTSUPP will be returned.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
289
290
291
292
293
   */
  long keyctl_update_key(key_serial_t id,
  		       const void __user *_payload,
  		       size_t plen)
  {
664cceb00   David Howells   [PATCH] Keys: Add...
294
  	key_ref_t key_ref;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
  	void *payload;
  	long ret;
  
  	ret = -EINVAL;
  	if (plen > PAGE_SIZE)
  		goto error;
  
  	/* pull the payload in if one was supplied */
  	payload = NULL;
  	if (_payload) {
  		ret = -ENOMEM;
  		payload = kmalloc(plen, GFP_KERNEL);
  		if (!payload)
  			goto error;
  
  		ret = -EFAULT;
  		if (copy_from_user(payload, _payload, plen) != 0)
  			goto error2;
  	}
  
  	/* find the target key (which must be writable) */
5593122ee   David Howells   KEYS: Deal with d...
316
  	key_ref = lookup_user_key(id, 0, KEY_WRITE);
664cceb00   David Howells   [PATCH] Keys: Add...
317
318
  	if (IS_ERR(key_ref)) {
  		ret = PTR_ERR(key_ref);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
319
320
321
322
  		goto error2;
  	}
  
  	/* update the key */
664cceb00   David Howells   [PATCH] Keys: Add...
323
  	ret = key_update(key_ref, payload, plen);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
324

664cceb00   David Howells   [PATCH] Keys: Add...
325
  	key_ref_put(key_ref);
c5b60b5e6   Justin P. Mattock   security: whitesp...
326
  error2:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
327
  	kfree(payload);
c5b60b5e6   Justin P. Mattock   security: whitesp...
328
  error:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
329
  	return ret;
a8b17ed01   David Howells   KEYS: Do some sty...
330
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
331

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
332
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
333
334
335
336
337
338
339
340
   * Revoke a key.
   *
   * The key must be grant the caller Write or Setattr permission for this to
   * work.  The key type should give up its quota claim when revoked.  The key
   * and any links to the key will be automatically garbage collected after a
   * certain amount of time (/proc/sys/kernel/keys/gc_delay).
   *
   * If successful, 0 is returned.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
341
342
343
   */
  long keyctl_revoke_key(key_serial_t id)
  {
664cceb00   David Howells   [PATCH] Keys: Add...
344
  	key_ref_t key_ref;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
345
  	long ret;
5593122ee   David Howells   KEYS: Deal with d...
346
  	key_ref = lookup_user_key(id, 0, KEY_WRITE);
664cceb00   David Howells   [PATCH] Keys: Add...
347
348
  	if (IS_ERR(key_ref)) {
  		ret = PTR_ERR(key_ref);
0c2c9a3fc   David Howells   KEYS: Allow keyct...
349
350
351
352
353
354
355
  		if (ret != -EACCES)
  			goto error;
  		key_ref = lookup_user_key(id, 0, KEY_SETATTR);
  		if (IS_ERR(key_ref)) {
  			ret = PTR_ERR(key_ref);
  			goto error;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
356
  	}
664cceb00   David Howells   [PATCH] Keys: Add...
357
  	key_revoke(key_ref_to_ptr(key_ref));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
358
  	ret = 0;
664cceb00   David Howells   [PATCH] Keys: Add...
359
  	key_ref_put(key_ref);
c5b60b5e6   Justin P. Mattock   security: whitesp...
360
  error:
1260f801b   David Howells   [PATCH] Keys: Fix...
361
  	return ret;
a8b17ed01   David Howells   KEYS: Do some sty...
362
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
363

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
364
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
365
366
367
368
369
   * Clear the specified keyring, creating an empty process keyring if one of the
   * special keyring IDs is used.
   *
   * The keyring must grant the caller Write permission for this to work.  If
   * successful, 0 will be returned.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
370
371
372
   */
  long keyctl_keyring_clear(key_serial_t ringid)
  {
664cceb00   David Howells   [PATCH] Keys: Add...
373
  	key_ref_t keyring_ref;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
374
  	long ret;
5593122ee   David Howells   KEYS: Deal with d...
375
  	keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE);
664cceb00   David Howells   [PATCH] Keys: Add...
376
377
  	if (IS_ERR(keyring_ref)) {
  		ret = PTR_ERR(keyring_ref);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
378
379
  		goto error;
  	}
664cceb00   David Howells   [PATCH] Keys: Add...
380
  	ret = keyring_clear(key_ref_to_ptr(keyring_ref));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
381

664cceb00   David Howells   [PATCH] Keys: Add...
382
  	key_ref_put(keyring_ref);
c5b60b5e6   Justin P. Mattock   security: whitesp...
383
  error:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
384
  	return ret;
a8b17ed01   David Howells   KEYS: Do some sty...
385
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
386

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
387
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
388
389
390
391
392
393
394
395
396
   * Create a link from a keyring to a key if there's no matching key in the
   * keyring, otherwise replace the link to the matching key with a link to the
   * new key.
   *
   * The key must grant the caller Link permission and the the keyring must grant
   * the caller Write permission.  Furthermore, if an additional link is created,
   * the keyring's quota will be extended.
   *
   * If successful, 0 will be returned.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
397
398
399
   */
  long keyctl_keyring_link(key_serial_t id, key_serial_t ringid)
  {
664cceb00   David Howells   [PATCH] Keys: Add...
400
  	key_ref_t keyring_ref, key_ref;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
401
  	long ret;
5593122ee   David Howells   KEYS: Deal with d...
402
  	keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE);
664cceb00   David Howells   [PATCH] Keys: Add...
403
404
  	if (IS_ERR(keyring_ref)) {
  		ret = PTR_ERR(keyring_ref);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
405
406
  		goto error;
  	}
5593122ee   David Howells   KEYS: Deal with d...
407
  	key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE, KEY_LINK);
664cceb00   David Howells   [PATCH] Keys: Add...
408
409
  	if (IS_ERR(key_ref)) {
  		ret = PTR_ERR(key_ref);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
410
411
  		goto error2;
  	}
664cceb00   David Howells   [PATCH] Keys: Add...
412
  	ret = key_link(key_ref_to_ptr(keyring_ref), key_ref_to_ptr(key_ref));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
413

664cceb00   David Howells   [PATCH] Keys: Add...
414
  	key_ref_put(key_ref);
c5b60b5e6   Justin P. Mattock   security: whitesp...
415
  error2:
664cceb00   David Howells   [PATCH] Keys: Add...
416
  	key_ref_put(keyring_ref);
c5b60b5e6   Justin P. Mattock   security: whitesp...
417
  error:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
418
  	return ret;
a8b17ed01   David Howells   KEYS: Do some sty...
419
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
420

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
421
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
422
423
424
425
426
427
428
   * Unlink a key from a keyring.
   *
   * The keyring must grant the caller Write permission for this to work; the key
   * itself need not grant the caller anything.  If the last link to a key is
   * removed then that key will be scheduled for destruction.
   *
   * If successful, 0 will be returned.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
429
430
431
   */
  long keyctl_keyring_unlink(key_serial_t id, key_serial_t ringid)
  {
664cceb00   David Howells   [PATCH] Keys: Add...
432
  	key_ref_t keyring_ref, key_ref;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
433
  	long ret;
5593122ee   David Howells   KEYS: Deal with d...
434
  	keyring_ref = lookup_user_key(ringid, 0, KEY_WRITE);
664cceb00   David Howells   [PATCH] Keys: Add...
435
436
  	if (IS_ERR(keyring_ref)) {
  		ret = PTR_ERR(keyring_ref);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
437
438
  		goto error;
  	}
5593122ee   David Howells   KEYS: Deal with d...
439
  	key_ref = lookup_user_key(id, KEY_LOOKUP_FOR_UNLINK, 0);
664cceb00   David Howells   [PATCH] Keys: Add...
440
441
  	if (IS_ERR(key_ref)) {
  		ret = PTR_ERR(key_ref);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
442
443
  		goto error2;
  	}
664cceb00   David Howells   [PATCH] Keys: Add...
444
  	ret = key_unlink(key_ref_to_ptr(keyring_ref), key_ref_to_ptr(key_ref));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
445

664cceb00   David Howells   [PATCH] Keys: Add...
446
  	key_ref_put(key_ref);
c5b60b5e6   Justin P. Mattock   security: whitesp...
447
  error2:
664cceb00   David Howells   [PATCH] Keys: Add...
448
  	key_ref_put(keyring_ref);
c5b60b5e6   Justin P. Mattock   security: whitesp...
449
  error:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
450
  	return ret;
a8b17ed01   David Howells   KEYS: Do some sty...
451
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
452

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
453
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
454
455
456
457
458
459
460
   * Return a description of a key to userspace.
   *
   * The key must grant the caller View permission for this to work.
   *
   * If there's a buffer, we place up to buflen bytes of data into it formatted
   * in the following way:
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
461
   *	type;uid;gid;perm;description<NUL>
973c9f4f4   David Howells   KEYS: Fix up comm...
462
463
464
   *
   * If successful, we return the amount of description available, irrespective
   * of how much we may have copied into the buffer.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
465
466
467
468
469
   */
  long keyctl_describe_key(key_serial_t keyid,
  			 char __user *buffer,
  			 size_t buflen)
  {
3e30148c3   David Howells   [PATCH] Keys: Mak...
470
  	struct key *key, *instkey;
664cceb00   David Howells   [PATCH] Keys: Add...
471
  	key_ref_t key_ref;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
472
473
  	char *tmpbuf;
  	long ret;
5593122ee   David Howells   KEYS: Deal with d...
474
  	key_ref = lookup_user_key(keyid, KEY_LOOKUP_PARTIAL, KEY_VIEW);
664cceb00   David Howells   [PATCH] Keys: Add...
475
  	if (IS_ERR(key_ref)) {
3e30148c3   David Howells   [PATCH] Keys: Mak...
476
477
  		/* viewing a key under construction is permitted if we have the
  		 * authorisation token handy */
664cceb00   David Howells   [PATCH] Keys: Add...
478
  		if (PTR_ERR(key_ref) == -EACCES) {
3e30148c3   David Howells   [PATCH] Keys: Mak...
479
480
481
  			instkey = key_get_instantiation_authkey(keyid);
  			if (!IS_ERR(instkey)) {
  				key_put(instkey);
8bbf4976b   David Howells   KEYS: Alter use o...
482
  				key_ref = lookup_user_key(keyid,
5593122ee   David Howells   KEYS: Deal with d...
483
484
  							  KEY_LOOKUP_PARTIAL,
  							  0);
664cceb00   David Howells   [PATCH] Keys: Add...
485
  				if (!IS_ERR(key_ref))
3e30148c3   David Howells   [PATCH] Keys: Mak...
486
487
488
  					goto okay;
  			}
  		}
664cceb00   David Howells   [PATCH] Keys: Add...
489
  		ret = PTR_ERR(key_ref);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
490
491
  		goto error;
  	}
3e30148c3   David Howells   [PATCH] Keys: Mak...
492
  okay:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
493
494
495
496
497
  	/* calculate how much description we're going to return */
  	ret = -ENOMEM;
  	tmpbuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
  	if (!tmpbuf)
  		goto error2;
664cceb00   David Howells   [PATCH] Keys: Add...
498
  	key = key_ref_to_ptr(key_ref);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
499
  	ret = snprintf(tmpbuf, PAGE_SIZE - 1,
664cceb00   David Howells   [PATCH] Keys: Add...
500
  		       "%s;%d;%d;%08x;%s",
94fd8405e   David Howells   KEYS: Use the var...
501
502
503
504
505
  		       key->type->name,
  		       key->uid,
  		       key->gid,
  		       key->perm,
  		       key->description ?: "");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
  
  	/* include a NUL char at the end of the data */
  	if (ret > PAGE_SIZE - 1)
  		ret = PAGE_SIZE - 1;
  	tmpbuf[ret] = 0;
  	ret++;
  
  	/* consider returning the data */
  	if (buffer && buflen > 0) {
  		if (buflen > ret)
  			buflen = ret;
  
  		if (copy_to_user(buffer, tmpbuf, buflen) != 0)
  			ret = -EFAULT;
  	}
  
  	kfree(tmpbuf);
c5b60b5e6   Justin P. Mattock   security: whitesp...
523
  error2:
664cceb00   David Howells   [PATCH] Keys: Add...
524
  	key_ref_put(key_ref);
c5b60b5e6   Justin P. Mattock   security: whitesp...
525
  error:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
526
  	return ret;
a8b17ed01   David Howells   KEYS: Do some sty...
527
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
528

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
529
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
530
531
532
533
534
535
536
537
   * Search the specified keyring and any keyrings it links to for a matching
   * key.  Only keyrings that grant the caller Search permission will be searched
   * (this includes the starting keyring).  Only keys with Search permission can
   * be found.
   *
   * If successful, the found key will be linked to the destination keyring if
   * supplied and the key has Link permission, and the found key ID will be
   * returned.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
538
539
540
541
542
543
544
   */
  long keyctl_keyring_search(key_serial_t ringid,
  			   const char __user *_type,
  			   const char __user *_description,
  			   key_serial_t destringid)
  {
  	struct key_type *ktype;
664cceb00   David Howells   [PATCH] Keys: Add...
545
  	key_ref_t keyring_ref, key_ref, dest_ref;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
546
  	char type[32], *description;
0cb409d98   Davi Arnaut   [PATCH] strndup_u...
547
  	long ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
548
549
  
  	/* pull the type and description into kernel space */
0cb409d98   Davi Arnaut   [PATCH] strndup_u...
550
  	ret = key_get_type_from_user(type, _type, sizeof(type));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
551
552
  	if (ret < 0)
  		goto error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
553

0cb409d98   Davi Arnaut   [PATCH] strndup_u...
554
555
556
  	description = strndup_user(_description, PAGE_SIZE);
  	if (IS_ERR(description)) {
  		ret = PTR_ERR(description);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
557
  		goto error;
0cb409d98   Davi Arnaut   [PATCH] strndup_u...
558
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
559
560
  
  	/* get the keyring at which to begin the search */
5593122ee   David Howells   KEYS: Deal with d...
561
  	keyring_ref = lookup_user_key(ringid, 0, KEY_SEARCH);
664cceb00   David Howells   [PATCH] Keys: Add...
562
563
  	if (IS_ERR(keyring_ref)) {
  		ret = PTR_ERR(keyring_ref);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
564
565
566
567
  		goto error2;
  	}
  
  	/* get the destination keyring if specified */
664cceb00   David Howells   [PATCH] Keys: Add...
568
  	dest_ref = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
569
  	if (destringid) {
5593122ee   David Howells   KEYS: Deal with d...
570
571
  		dest_ref = lookup_user_key(destringid, KEY_LOOKUP_CREATE,
  					   KEY_WRITE);
664cceb00   David Howells   [PATCH] Keys: Add...
572
573
  		if (IS_ERR(dest_ref)) {
  			ret = PTR_ERR(dest_ref);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
574
575
576
577
578
579
580
581
582
583
584
585
  			goto error3;
  		}
  	}
  
  	/* find the key type */
  	ktype = key_type_lookup(type);
  	if (IS_ERR(ktype)) {
  		ret = PTR_ERR(ktype);
  		goto error4;
  	}
  
  	/* do the search */
664cceb00   David Howells   [PATCH] Keys: Add...
586
587
588
  	key_ref = keyring_search(keyring_ref, ktype, description);
  	if (IS_ERR(key_ref)) {
  		ret = PTR_ERR(key_ref);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
589
590
591
592
593
594
595
596
  
  		/* treat lack or presence of a negative key the same */
  		if (ret == -EAGAIN)
  			ret = -ENOKEY;
  		goto error5;
  	}
  
  	/* link the resulting key to the destination keyring if we can */
664cceb00   David Howells   [PATCH] Keys: Add...
597
  	if (dest_ref) {
29db91906   David Howells   [PATCH] Keys: Add...
598
599
  		ret = key_permission(key_ref, KEY_LINK);
  		if (ret < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
600
  			goto error6;
664cceb00   David Howells   [PATCH] Keys: Add...
601
  		ret = key_link(key_ref_to_ptr(dest_ref), key_ref_to_ptr(key_ref));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
602
603
604
  		if (ret < 0)
  			goto error6;
  	}
664cceb00   David Howells   [PATCH] Keys: Add...
605
  	ret = key_ref_to_ptr(key_ref)->serial;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
606

c5b60b5e6   Justin P. Mattock   security: whitesp...
607
  error6:
664cceb00   David Howells   [PATCH] Keys: Add...
608
  	key_ref_put(key_ref);
c5b60b5e6   Justin P. Mattock   security: whitesp...
609
  error5:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
610
  	key_type_put(ktype);
c5b60b5e6   Justin P. Mattock   security: whitesp...
611
  error4:
664cceb00   David Howells   [PATCH] Keys: Add...
612
  	key_ref_put(dest_ref);
c5b60b5e6   Justin P. Mattock   security: whitesp...
613
  error3:
664cceb00   David Howells   [PATCH] Keys: Add...
614
  	key_ref_put(keyring_ref);
c5b60b5e6   Justin P. Mattock   security: whitesp...
615
  error2:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
616
  	kfree(description);
c5b60b5e6   Justin P. Mattock   security: whitesp...
617
  error:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
618
  	return ret;
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
626
627
628
629
   * Read a key's payload.
   *
   * The key must either grant the caller Read permission, or it must grant the
   * caller Search permission when searched for from the process keyrings.
   *
   * If successful, we place up to buflen bytes of data into the buffer, if one
   * is provided, and return the amount of data that is available in the key,
   * irrespective of how much we copied into the buffer.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
630
631
632
   */
  long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen)
  {
664cceb00   David Howells   [PATCH] Keys: Add...
633
634
  	struct key *key;
  	key_ref_t key_ref;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
635
636
637
  	long ret;
  
  	/* find the key first */
5593122ee   David Howells   KEYS: Deal with d...
638
  	key_ref = lookup_user_key(keyid, 0, 0);
664cceb00   David Howells   [PATCH] Keys: Add...
639
640
641
  	if (IS_ERR(key_ref)) {
  		ret = -ENOKEY;
  		goto error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
642
  	}
664cceb00   David Howells   [PATCH] Keys: Add...
643
644
645
  	key = key_ref_to_ptr(key_ref);
  
  	/* see if we can read it directly */
29db91906   David Howells   [PATCH] Keys: Add...
646
647
  	ret = key_permission(key_ref, KEY_READ);
  	if (ret == 0)
664cceb00   David Howells   [PATCH] Keys: Add...
648
  		goto can_read_key;
29db91906   David Howells   [PATCH] Keys: Add...
649
650
  	if (ret != -EACCES)
  		goto error;
664cceb00   David Howells   [PATCH] Keys: Add...
651
652
653
654
655
656
657
658
659
  
  	/* we can't; see if it's searchable from this process's keyrings
  	 * - we automatically take account of the fact that it may be
  	 *   dangling off an instantiation key
  	 */
  	if (!is_key_possessed(key_ref)) {
  		ret = -EACCES;
  		goto error2;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
660
661
  
  	/* the key is probably readable - now try to read it */
c5b60b5e6   Justin P. Mattock   security: whitesp...
662
  can_read_key:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
663
664
665
666
667
668
669
670
671
672
673
  	ret = key_validate(key);
  	if (ret == 0) {
  		ret = -EOPNOTSUPP;
  		if (key->type->read) {
  			/* read the data with the semaphore held (since we
  			 * might sleep) */
  			down_read(&key->sem);
  			ret = key->type->read(key, buffer, buflen);
  			up_read(&key->sem);
  		}
  	}
c5b60b5e6   Justin P. Mattock   security: whitesp...
674
  error2:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
675
  	key_put(key);
c5b60b5e6   Justin P. Mattock   security: whitesp...
676
  error:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
677
  	return ret;
a8b17ed01   David Howells   KEYS: Do some sty...
678
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
679

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
680
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
681
682
683
684
685
686
687
688
689
690
691
692
693
   * Change the ownership of a key
   *
   * The key must grant the caller Setattr permission for this to work, though
   * the key need not be fully instantiated yet.  For the UID to be changed, or
   * for the GID to be changed to a group the caller is not a member of, the
   * caller must have sysadmin capability.  If either uid or gid is -1 then that
   * attribute is not changed.
   *
   * If the UID is to be changed, the new user must have sufficient quota to
   * accept the key.  The quota deduction will be removed from the old user to
   * the new user should the attribute be changed.
   *
   * If successful, 0 will be returned.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
694
695
696
   */
  long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid)
  {
5801649d8   Fredrik Tolf   [PATCH] keys: let...
697
  	struct key_user *newowner, *zapowner = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
698
  	struct key *key;
664cceb00   David Howells   [PATCH] Keys: Add...
699
  	key_ref_t key_ref;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
700
701
702
703
704
  	long ret;
  
  	ret = 0;
  	if (uid == (uid_t) -1 && gid == (gid_t) -1)
  		goto error;
5593122ee   David Howells   KEYS: Deal with d...
705
706
  	key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL,
  				  KEY_SETATTR);
664cceb00   David Howells   [PATCH] Keys: Add...
707
708
  	if (IS_ERR(key_ref)) {
  		ret = PTR_ERR(key_ref);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
709
710
  		goto error;
  	}
664cceb00   David Howells   [PATCH] Keys: Add...
711
  	key = key_ref_to_ptr(key_ref);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
712
713
714
  	/* make the changes with the locks held to prevent chown/chown races */
  	ret = -EACCES;
  	down_write(&key->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
715
716
717
718
  
  	if (!capable(CAP_SYS_ADMIN)) {
  		/* only the sysadmin can chown a key to some other UID */
  		if (uid != (uid_t) -1 && key->uid != uid)
5801649d8   Fredrik Tolf   [PATCH] keys: let...
719
  			goto error_put;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
720
721
722
723
  
  		/* only the sysadmin can set the key's GID to a group other
  		 * than one of those that the current process subscribes to */
  		if (gid != (gid_t) -1 && gid != key->gid && !in_group_p(gid))
5801649d8   Fredrik Tolf   [PATCH] keys: let...
724
  			goto error_put;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
725
  	}
5801649d8   Fredrik Tolf   [PATCH] keys: let...
726
  	/* change the UID */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
727
  	if (uid != (uid_t) -1 && uid != key->uid) {
5801649d8   Fredrik Tolf   [PATCH] keys: let...
728
  		ret = -ENOMEM;
1d1e97562   Serge E. Hallyn   keys: distinguish...
729
  		newowner = key_user_lookup(uid, current_user_ns());
5801649d8   Fredrik Tolf   [PATCH] keys: let...
730
731
732
733
734
  		if (!newowner)
  			goto error_put;
  
  		/* transfer the quota burden to the new user */
  		if (test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) {
0b77f5bfb   David Howells   keys: make the ke...
735
736
737
738
  			unsigned maxkeys = (uid == 0) ?
  				key_quota_root_maxkeys : key_quota_maxkeys;
  			unsigned maxbytes = (uid == 0) ?
  				key_quota_root_maxbytes : key_quota_maxbytes;
5801649d8   Fredrik Tolf   [PATCH] keys: let...
739
  			spin_lock(&newowner->lock);
0b77f5bfb   David Howells   keys: make the ke...
740
741
742
743
  			if (newowner->qnkeys + 1 >= maxkeys ||
  			    newowner->qnbytes + key->quotalen >= maxbytes ||
  			    newowner->qnbytes + key->quotalen <
  			    newowner->qnbytes)
5801649d8   Fredrik Tolf   [PATCH] keys: let...
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
  				goto quota_overrun;
  
  			newowner->qnkeys++;
  			newowner->qnbytes += key->quotalen;
  			spin_unlock(&newowner->lock);
  
  			spin_lock(&key->user->lock);
  			key->user->qnkeys--;
  			key->user->qnbytes -= key->quotalen;
  			spin_unlock(&key->user->lock);
  		}
  
  		atomic_dec(&key->user->nkeys);
  		atomic_inc(&newowner->nkeys);
  
  		if (test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) {
  			atomic_dec(&key->user->nikeys);
  			atomic_inc(&newowner->nikeys);
  		}
  
  		zapowner = key->user;
  		key->user = newowner;
  		key->uid = uid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
767
768
769
770
771
772
773
  	}
  
  	/* change the GID */
  	if (gid != (gid_t) -1)
  		key->gid = gid;
  
  	ret = 0;
5801649d8   Fredrik Tolf   [PATCH] keys: let...
774
  error_put:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
775
776
  	up_write(&key->sem);
  	key_put(key);
5801649d8   Fredrik Tolf   [PATCH] keys: let...
777
778
779
  	if (zapowner)
  		key_user_put(zapowner);
  error:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
780
  	return ret;
5801649d8   Fredrik Tolf   [PATCH] keys: let...
781
782
783
784
785
  quota_overrun:
  	spin_unlock(&newowner->lock);
  	zapowner = newowner;
  	ret = -EDQUOT;
  	goto error_put;
a8b17ed01   David Howells   KEYS: Do some sty...
786
  }
5801649d8   Fredrik Tolf   [PATCH] keys: let...
787

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
788
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
789
790
791
792
793
   * Change the permission mask on a key.
   *
   * The key must grant the caller Setattr permission for this to work, though
   * the key need not be fully instantiated yet.  If the caller does not have
   * sysadmin capability, it may only change the permission on keys that it owns.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
794
795
796
797
   */
  long keyctl_setperm_key(key_serial_t id, key_perm_t perm)
  {
  	struct key *key;
664cceb00   David Howells   [PATCH] Keys: Add...
798
  	key_ref_t key_ref;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
799
800
801
  	long ret;
  
  	ret = -EINVAL;
664cceb00   David Howells   [PATCH] Keys: Add...
802
  	if (perm & ~(KEY_POS_ALL | KEY_USR_ALL | KEY_GRP_ALL | KEY_OTH_ALL))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
803
  		goto error;
5593122ee   David Howells   KEYS: Deal with d...
804
805
  	key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL,
  				  KEY_SETATTR);
664cceb00   David Howells   [PATCH] Keys: Add...
806
807
  	if (IS_ERR(key_ref)) {
  		ret = PTR_ERR(key_ref);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
808
809
  		goto error;
  	}
664cceb00   David Howells   [PATCH] Keys: Add...
810
  	key = key_ref_to_ptr(key_ref);
76d8aeabf   David Howells   [PATCH] keys: Dis...
811
  	/* make the changes with the locks held to prevent chown/chmod races */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
812
813
  	ret = -EACCES;
  	down_write(&key->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
814

76d8aeabf   David Howells   [PATCH] keys: Dis...
815
  	/* if we're not the sysadmin, we can only change a key that we own */
47d804bfa   David Howells   CRED: Wrap task c...
816
  	if (capable(CAP_SYS_ADMIN) || key->uid == current_fsuid()) {
76d8aeabf   David Howells   [PATCH] keys: Dis...
817
818
819
  		key->perm = perm;
  		ret = 0;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
820

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
821
822
  	up_write(&key->sem);
  	key_put(key);
76d8aeabf   David Howells   [PATCH] keys: Dis...
823
  error:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
824
  	return ret;
a8b17ed01   David Howells   KEYS: Do some sty...
825
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
826

8bbf4976b   David Howells   KEYS: Alter use o...
827
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
828
829
   * Get the destination keyring for instantiation and check that the caller has
   * Write permission on it.
8bbf4976b   David Howells   KEYS: Alter use o...
830
831
832
833
834
835
   */
  static long get_instantiation_keyring(key_serial_t ringid,
  				      struct request_key_auth *rka,
  				      struct key **_dest_keyring)
  {
  	key_ref_t dkref;
eca1bf5b4   David Howells   KEYS: Fix variabl...
836
  	*_dest_keyring = NULL;
8bbf4976b   David Howells   KEYS: Alter use o...
837
  	/* just return a NULL pointer if we weren't asked to make a link */
eca1bf5b4   David Howells   KEYS: Fix variabl...
838
  	if (ringid == 0)
8bbf4976b   David Howells   KEYS: Alter use o...
839
  		return 0;
8bbf4976b   David Howells   KEYS: Alter use o...
840
841
842
  
  	/* if a specific keyring is nominated by ID, then use that */
  	if (ringid > 0) {
5593122ee   David Howells   KEYS: Deal with d...
843
  		dkref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE);
8bbf4976b   David Howells   KEYS: Alter use o...
844
845
846
847
848
849
850
851
852
853
854
855
  		if (IS_ERR(dkref))
  			return PTR_ERR(dkref);
  		*_dest_keyring = key_ref_to_ptr(dkref);
  		return 0;
  	}
  
  	if (ringid == KEY_SPEC_REQKEY_AUTH_KEY)
  		return -EINVAL;
  
  	/* otherwise specify the destination keyring recorded in the
  	 * authorisation key (any KEY_SPEC_*_KEYRING) */
  	if (ringid >= KEY_SPEC_REQUESTOR_KEYRING) {
21279cfa1   David Howells   KEYS: get_instant...
856
  		*_dest_keyring = key_get(rka->dest_keyring);
8bbf4976b   David Howells   KEYS: Alter use o...
857
858
859
860
861
  		return 0;
  	}
  
  	return -ENOKEY;
  }
d84f4f992   David Howells   CRED: Inaugurate ...
862
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
863
   * Change the request_key authorisation key on the current process.
d84f4f992   David Howells   CRED: Inaugurate ...
864
865
866
867
868
869
870
871
872
873
874
875
876
877
   */
  static int keyctl_change_reqkey_auth(struct key *key)
  {
  	struct cred *new;
  
  	new = prepare_creds();
  	if (!new)
  		return -ENOMEM;
  
  	key_put(new->request_key_auth);
  	new->request_key_auth = key_get(key);
  
  	return commit_creds(new);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
878
  /*
ee009e4a0   David Howells   KEYS: Add an iove...
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
   * Copy the iovec data from userspace
   */
  static long copy_from_user_iovec(void *buffer, const struct iovec *iov,
  				 unsigned ioc)
  {
  	for (; ioc > 0; ioc--) {
  		if (copy_from_user(buffer, iov->iov_base, iov->iov_len) != 0)
  			return -EFAULT;
  		buffer += iov->iov_len;
  		iov++;
  	}
  	return 0;
  }
  
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
894
895
896
897
898
899
900
   * Instantiate a key with the specified payload and link the key into the
   * destination keyring if one is given.
   *
   * The caller must have the appropriate instantiation permit set for this to
   * work (see keyctl_assume_authority).  No other permissions are required.
   *
   * If successful, 0 will be returned.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
901
   */
ee009e4a0   David Howells   KEYS: Add an iove...
902
903
904
905
906
  long keyctl_instantiate_key_common(key_serial_t id,
  				   const struct iovec *payload_iov,
  				   unsigned ioc,
  				   size_t plen,
  				   key_serial_t ringid)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
907
  {
d84f4f992   David Howells   CRED: Inaugurate ...
908
  	const struct cred *cred = current_cred();
3e30148c3   David Howells   [PATCH] Keys: Mak...
909
  	struct request_key_auth *rka;
8bbf4976b   David Howells   KEYS: Alter use o...
910
  	struct key *instkey, *dest_keyring;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
911
912
  	void *payload;
  	long ret;
38bbca6b6   David Howells   keys: increase th...
913
  	bool vm = false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
914

d84f4f992   David Howells   CRED: Inaugurate ...
915
  	kenter("%d,,%zu,%d", id, plen, ringid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
916
  	ret = -EINVAL;
38bbca6b6   David Howells   keys: increase th...
917
  	if (plen > 1024 * 1024 - 1)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
918
  		goto error;
b5f545c88   David Howells   [PATCH] keys: Per...
919
920
921
  	/* the appropriate instantiation authorisation key must have been
  	 * assumed before calling this */
  	ret = -EPERM;
d84f4f992   David Howells   CRED: Inaugurate ...
922
  	instkey = cred->request_key_auth;
b5f545c88   David Howells   [PATCH] keys: Per...
923
924
925
926
927
928
  	if (!instkey)
  		goto error;
  
  	rka = instkey->payload.data;
  	if (rka->target_key->serial != id)
  		goto error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
929
930
  	/* pull the payload in if one was supplied */
  	payload = NULL;
ee009e4a0   David Howells   KEYS: Add an iove...
931
  	if (payload_iov) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
932
933
  		ret = -ENOMEM;
  		payload = kmalloc(plen, GFP_KERNEL);
38bbca6b6   David Howells   keys: increase th...
934
935
936
937
938
939
940
941
  		if (!payload) {
  			if (plen <= PAGE_SIZE)
  				goto error;
  			vm = true;
  			payload = vmalloc(plen);
  			if (!payload)
  				goto error;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
942

ee009e4a0   David Howells   KEYS: Add an iove...
943
944
  		ret = copy_from_user_iovec(payload, payload_iov, ioc);
  		if (ret < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
945
946
  			goto error2;
  	}
3e30148c3   David Howells   [PATCH] Keys: Mak...
947
948
  	/* find the destination keyring amongst those belonging to the
  	 * requesting task */
8bbf4976b   David Howells   KEYS: Alter use o...
949
950
951
  	ret = get_instantiation_keyring(ringid, rka, &dest_keyring);
  	if (ret < 0)
  		goto error2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
952
953
  
  	/* instantiate the key and link it into a keyring */
3e30148c3   David Howells   [PATCH] Keys: Mak...
954
  	ret = key_instantiate_and_link(rka->target_key, payload, plen,
8bbf4976b   David Howells   KEYS: Alter use o...
955
  				       dest_keyring, instkey);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
956

8bbf4976b   David Howells   KEYS: Alter use o...
957
  	key_put(dest_keyring);
b5f545c88   David Howells   [PATCH] keys: Per...
958
959
960
  
  	/* discard the assumed authority if it's just been disabled by
  	 * instantiation of the key */
d84f4f992   David Howells   CRED: Inaugurate ...
961
962
  	if (ret == 0)
  		keyctl_change_reqkey_auth(NULL);
b5f545c88   David Howells   [PATCH] keys: Per...
963
964
  
  error2:
38bbca6b6   David Howells   keys: increase th...
965
966
967
968
  	if (!vm)
  		kfree(payload);
  	else
  		vfree(payload);
b5f545c88   David Howells   [PATCH] keys: Per...
969
  error:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
970
  	return ret;
a8b17ed01   David Howells   KEYS: Do some sty...
971
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
972

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
973
  /*
ee009e4a0   David Howells   KEYS: Add an iove...
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
   * Instantiate a key with the specified payload and link the key into the
   * destination keyring if one is given.
   *
   * The caller must have the appropriate instantiation permit set for this to
   * work (see keyctl_assume_authority).  No other permissions are required.
   *
   * If successful, 0 will be returned.
   */
  long keyctl_instantiate_key(key_serial_t id,
  			    const void __user *_payload,
  			    size_t plen,
  			    key_serial_t ringid)
  {
  	if (_payload && plen) {
  		struct iovec iov[1] = {
  			[0].iov_base = (void __user *)_payload,
  			[0].iov_len  = plen
  		};
  
  		return keyctl_instantiate_key_common(id, iov, 1, plen, ringid);
  	}
  
  	return keyctl_instantiate_key_common(id, NULL, 0, 0, ringid);
  }
  
  /*
   * Instantiate a key with the specified multipart payload and link the key into
   * the destination keyring if one is given.
   *
   * The caller must have the appropriate instantiation permit set for this to
   * work (see keyctl_assume_authority).  No other permissions are required.
   *
   * If successful, 0 will be returned.
   */
  long keyctl_instantiate_key_iov(key_serial_t id,
  				const struct iovec __user *_payload_iov,
  				unsigned ioc,
  				key_serial_t ringid)
  {
  	struct iovec iovstack[UIO_FASTIOV], *iov = iovstack;
  	long ret;
  
  	if (_payload_iov == 0 || ioc == 0)
  		goto no_payload;
  
  	ret = rw_copy_check_uvector(WRITE, _payload_iov, ioc,
fcf634098   Christopher Yeoh   Cross Memory Attach
1020
  				    ARRAY_SIZE(iovstack), iovstack, &iov, 1);
ee009e4a0   David Howells   KEYS: Add an iove...
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
  	if (ret < 0)
  		return ret;
  	if (ret == 0)
  		goto no_payload_free;
  
  	ret = keyctl_instantiate_key_common(id, iov, ioc, ret, ringid);
  
  	if (iov != iovstack)
  		kfree(iov);
  	return ret;
  
  no_payload_free:
  	if (iov != iovstack)
  		kfree(iov);
  no_payload:
  	return keyctl_instantiate_key_common(id, NULL, 0, 0, ringid);
  }
  
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
   * Negatively instantiate the key with the given timeout (in seconds) and link
   * the key into the destination keyring if one is given.
   *
   * The caller must have the appropriate instantiation permit set for this to
   * work (see keyctl_assume_authority).  No other permissions are required.
   *
   * The key and any links to the key will be automatically garbage collected
   * after the timeout expires.
   *
   * Negative keys are used to rate limit repeated request_key() calls by causing
   * them to return -ENOKEY until the negative key expires.
   *
   * If successful, 0 will be returned.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1053
1054
1055
   */
  long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid)
  {
fdd1b9458   David Howells   KEYS: Add a new k...
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
  	return keyctl_reject_key(id, timeout, ENOKEY, ringid);
  }
  
  /*
   * Negatively instantiate the key with the given timeout (in seconds) and error
   * code and link the key into the destination keyring if one is given.
   *
   * The caller must have the appropriate instantiation permit set for this to
   * work (see keyctl_assume_authority).  No other permissions are required.
   *
   * The key and any links to the key will be automatically garbage collected
   * after the timeout expires.
   *
   * Negative keys are used to rate limit repeated request_key() calls by causing
   * them to return the specified error code until the negative key expires.
   *
   * If successful, 0 will be returned.
   */
  long keyctl_reject_key(key_serial_t id, unsigned timeout, unsigned error,
  		       key_serial_t ringid)
  {
d84f4f992   David Howells   CRED: Inaugurate ...
1077
  	const struct cred *cred = current_cred();
3e30148c3   David Howells   [PATCH] Keys: Mak...
1078
  	struct request_key_auth *rka;
8bbf4976b   David Howells   KEYS: Alter use o...
1079
  	struct key *instkey, *dest_keyring;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1080
  	long ret;
fdd1b9458   David Howells   KEYS: Add a new k...
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
  	kenter("%d,%u,%u,%d", id, timeout, error, ringid);
  
  	/* must be a valid error code and mustn't be a kernel special */
  	if (error <= 0 ||
  	    error >= MAX_ERRNO ||
  	    error == ERESTARTSYS ||
  	    error == ERESTARTNOINTR ||
  	    error == ERESTARTNOHAND ||
  	    error == ERESTART_RESTARTBLOCK)
  		return -EINVAL;
d84f4f992   David Howells   CRED: Inaugurate ...
1091

b5f545c88   David Howells   [PATCH] keys: Per...
1092
1093
1094
  	/* the appropriate instantiation authorisation key must have been
  	 * assumed before calling this */
  	ret = -EPERM;
d84f4f992   David Howells   CRED: Inaugurate ...
1095
  	instkey = cred->request_key_auth;
b5f545c88   David Howells   [PATCH] keys: Per...
1096
  	if (!instkey)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1097
  		goto error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1098

3e30148c3   David Howells   [PATCH] Keys: Mak...
1099
  	rka = instkey->payload.data;
b5f545c88   David Howells   [PATCH] keys: Per...
1100
1101
  	if (rka->target_key->serial != id)
  		goto error;
3e30148c3   David Howells   [PATCH] Keys: Mak...
1102

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1103
1104
  	/* find the destination keyring if present (which must also be
  	 * writable) */
8bbf4976b   David Howells   KEYS: Alter use o...
1105
1106
1107
  	ret = get_instantiation_keyring(ringid, rka, &dest_keyring);
  	if (ret < 0)
  		goto error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1108
1109
  
  	/* instantiate the key and link it into a keyring */
fdd1b9458   David Howells   KEYS: Add a new k...
1110
  	ret = key_reject_and_link(rka->target_key, timeout, error,
8bbf4976b   David Howells   KEYS: Alter use o...
1111
  				  dest_keyring, instkey);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1112

8bbf4976b   David Howells   KEYS: Alter use o...
1113
  	key_put(dest_keyring);
b5f545c88   David Howells   [PATCH] keys: Per...
1114
1115
1116
  
  	/* discard the assumed authority if it's just been disabled by
  	 * instantiation of the key */
d84f4f992   David Howells   CRED: Inaugurate ...
1117
1118
  	if (ret == 0)
  		keyctl_change_reqkey_auth(NULL);
b5f545c88   David Howells   [PATCH] keys: Per...
1119
1120
  
  error:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1121
  	return ret;
a8b17ed01   David Howells   KEYS: Do some sty...
1122
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1123

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1124
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
1125
1126
1127
1128
1129
   * Read or set the default keyring in which request_key() will cache keys and
   * return the old setting.
   *
   * If a process keyring is specified then this will be created if it doesn't
   * yet exist.  The old setting will be returned if successful.
3e30148c3   David Howells   [PATCH] Keys: Mak...
1130
1131
1132
   */
  long keyctl_set_reqkey_keyring(int reqkey_defl)
  {
d84f4f992   David Howells   CRED: Inaugurate ...
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
  	struct cred *new;
  	int ret, old_setting;
  
  	old_setting = current_cred_xxx(jit_keyring);
  
  	if (reqkey_defl == KEY_REQKEY_DEFL_NO_CHANGE)
  		return old_setting;
  
  	new = prepare_creds();
  	if (!new)
  		return -ENOMEM;
3e30148c3   David Howells   [PATCH] Keys: Mak...
1144
1145
1146
  
  	switch (reqkey_defl) {
  	case KEY_REQKEY_DEFL_THREAD_KEYRING:
d84f4f992   David Howells   CRED: Inaugurate ...
1147
  		ret = install_thread_keyring_to_cred(new);
3e30148c3   David Howells   [PATCH] Keys: Mak...
1148
  		if (ret < 0)
d84f4f992   David Howells   CRED: Inaugurate ...
1149
  			goto error;
3e30148c3   David Howells   [PATCH] Keys: Mak...
1150
1151
1152
  		goto set;
  
  	case KEY_REQKEY_DEFL_PROCESS_KEYRING:
d84f4f992   David Howells   CRED: Inaugurate ...
1153
1154
1155
1156
1157
1158
1159
  		ret = install_process_keyring_to_cred(new);
  		if (ret < 0) {
  			if (ret != -EEXIST)
  				goto error;
  			ret = 0;
  		}
  		goto set;
3e30148c3   David Howells   [PATCH] Keys: Mak...
1160
1161
1162
1163
1164
  
  	case KEY_REQKEY_DEFL_DEFAULT:
  	case KEY_REQKEY_DEFL_SESSION_KEYRING:
  	case KEY_REQKEY_DEFL_USER_KEYRING:
  	case KEY_REQKEY_DEFL_USER_SESSION_KEYRING:
d84f4f992   David Howells   CRED: Inaugurate ...
1165
1166
  	case KEY_REQKEY_DEFL_REQUESTOR_KEYRING:
  		goto set;
3e30148c3   David Howells   [PATCH] Keys: Mak...
1167
1168
  
  	case KEY_REQKEY_DEFL_NO_CHANGE:
3e30148c3   David Howells   [PATCH] Keys: Mak...
1169
1170
  	case KEY_REQKEY_DEFL_GROUP_KEYRING:
  	default:
d84f4f992   David Howells   CRED: Inaugurate ...
1171
1172
  		ret = -EINVAL;
  		goto error;
3e30148c3   David Howells   [PATCH] Keys: Mak...
1173
  	}
d84f4f992   David Howells   CRED: Inaugurate ...
1174
1175
1176
1177
1178
1179
  set:
  	new->jit_keyring = reqkey_defl;
  	commit_creds(new);
  	return old_setting;
  error:
  	abort_creds(new);
4303ef19c   Dan Carpenter   KEYS: Propagate e...
1180
  	return ret;
a8b17ed01   David Howells   KEYS: Do some sty...
1181
  }
d84f4f992   David Howells   CRED: Inaugurate ...
1182

3e30148c3   David Howells   [PATCH] Keys: Mak...
1183
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
   * Set or clear the timeout on a key.
   *
   * Either the key must grant the caller Setattr permission or else the caller
   * must hold an instantiation authorisation token for the key.
   *
   * The timeout is either 0 to clear the timeout, or a number of seconds from
   * the current time.  The key and any links to the key will be automatically
   * garbage collected after the timeout expires.
   *
   * If successful, 0 is returned.
017679c4d   David Howells   [PATCH] keys: Per...
1194
1195
1196
1197
   */
  long keyctl_set_timeout(key_serial_t id, unsigned timeout)
  {
  	struct timespec now;
9156235b3   David Howells   KEYS: Authorise k...
1198
  	struct key *key, *instkey;
017679c4d   David Howells   [PATCH] keys: Per...
1199
1200
1201
  	key_ref_t key_ref;
  	time_t expiry;
  	long ret;
5593122ee   David Howells   KEYS: Deal with d...
1202
1203
  	key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL,
  				  KEY_SETATTR);
017679c4d   David Howells   [PATCH] keys: Per...
1204
  	if (IS_ERR(key_ref)) {
9156235b3   David Howells   KEYS: Authorise k...
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
  		/* setting the timeout on a key under construction is permitted
  		 * if we have the authorisation token handy */
  		if (PTR_ERR(key_ref) == -EACCES) {
  			instkey = key_get_instantiation_authkey(id);
  			if (!IS_ERR(instkey)) {
  				key_put(instkey);
  				key_ref = lookup_user_key(id,
  							  KEY_LOOKUP_PARTIAL,
  							  0);
  				if (!IS_ERR(key_ref))
  					goto okay;
  			}
  		}
017679c4d   David Howells   [PATCH] keys: Per...
1218
1219
1220
  		ret = PTR_ERR(key_ref);
  		goto error;
  	}
9156235b3   David Howells   KEYS: Authorise k...
1221
  okay:
017679c4d   David Howells   [PATCH] keys: Per...
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
  	key = key_ref_to_ptr(key_ref);
  
  	/* make the changes with the locks held to prevent races */
  	down_write(&key->sem);
  
  	expiry = 0;
  	if (timeout > 0) {
  		now = current_kernel_time();
  		expiry = now.tv_sec + timeout;
  	}
  
  	key->expiry = expiry;
c08ef808e   David Howells   KEYS: Fix garbage...
1234
  	key_schedule_gc(key->expiry + key_gc_delay);
017679c4d   David Howells   [PATCH] keys: Per...
1235
1236
1237
1238
1239
1240
1241
  
  	up_write(&key->sem);
  	key_put(key);
  
  	ret = 0;
  error:
  	return ret;
a8b17ed01   David Howells   KEYS: Do some sty...
1242
  }
017679c4d   David Howells   [PATCH] keys: Per...
1243

017679c4d   David Howells   [PATCH] keys: Per...
1244
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
   * Assume (or clear) the authority to instantiate the specified key.
   *
   * This sets the authoritative token currently in force for key instantiation.
   * This must be done for a key to be instantiated.  It has the effect of making
   * available all the keys from the caller of the request_key() that created a
   * key to request_key() calls made by the caller of this function.
   *
   * The caller must have the instantiation key in their process keyrings with a
   * Search permission grant available to the caller.
   *
   * If the ID given is 0, then the setting will be cleared and 0 returned.
   *
   * If the ID given has a matching an authorisation key, then that key will be
   * set and its ID will be returned.  The authorisation key can be read to get
   * the callout information passed to request_key().
b5f545c88   David Howells   [PATCH] keys: Per...
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
   */
  long keyctl_assume_authority(key_serial_t id)
  {
  	struct key *authkey;
  	long ret;
  
  	/* special key IDs aren't permitted */
  	ret = -EINVAL;
  	if (id < 0)
  		goto error;
  
  	/* we divest ourselves of authority if given an ID of 0 */
  	if (id == 0) {
d84f4f992   David Howells   CRED: Inaugurate ...
1273
  		ret = keyctl_change_reqkey_auth(NULL);
b5f545c88   David Howells   [PATCH] keys: Per...
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
  		goto error;
  	}
  
  	/* attempt to assume the authority temporarily granted to us whilst we
  	 * instantiate the specified key
  	 * - the authorisation key must be in the current task's keyrings
  	 *   somewhere
  	 */
  	authkey = key_get_instantiation_authkey(id);
  	if (IS_ERR(authkey)) {
  		ret = PTR_ERR(authkey);
  		goto error;
  	}
d84f4f992   David Howells   CRED: Inaugurate ...
1287
1288
1289
1290
  	ret = keyctl_change_reqkey_auth(authkey);
  	if (ret < 0)
  		goto error;
  	key_put(authkey);
b5f545c88   David Howells   [PATCH] keys: Per...
1291

d84f4f992   David Howells   CRED: Inaugurate ...
1292
  	ret = authkey->serial;
b5f545c88   David Howells   [PATCH] keys: Per...
1293
1294
  error:
  	return ret;
a8b17ed01   David Howells   KEYS: Do some sty...
1295
  }
b5f545c88   David Howells   [PATCH] keys: Per...
1296

70a5bb72b   David Howells   keys: add keyctl ...
1297
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
1298
1299
1300
1301
1302
1303
1304
1305
   * Get a key's the LSM security label.
   *
   * The key must grant the caller View permission for this to work.
   *
   * If there's a buffer, then up to buflen bytes of data will be placed into it.
   *
   * If successful, the amount of information available will be returned,
   * irrespective of how much was copied (including the terminal NUL).
70a5bb72b   David Howells   keys: add keyctl ...
1306
1307
1308
1309
1310
1311
1312
1313
1314
   */
  long keyctl_get_security(key_serial_t keyid,
  			 char __user *buffer,
  			 size_t buflen)
  {
  	struct key *key, *instkey;
  	key_ref_t key_ref;
  	char *context;
  	long ret;
5593122ee   David Howells   KEYS: Deal with d...
1315
  	key_ref = lookup_user_key(keyid, KEY_LOOKUP_PARTIAL, KEY_VIEW);
70a5bb72b   David Howells   keys: add keyctl ...
1316
1317
1318
1319
1320
1321
1322
1323
  	if (IS_ERR(key_ref)) {
  		if (PTR_ERR(key_ref) != -EACCES)
  			return PTR_ERR(key_ref);
  
  		/* viewing a key under construction is also permitted if we
  		 * have the authorisation token handy */
  		instkey = key_get_instantiation_authkey(keyid);
  		if (IS_ERR(instkey))
fa1cc7b5a   Roel Kluin   keys: PTR_ERR ret...
1324
  			return PTR_ERR(instkey);
70a5bb72b   David Howells   keys: add keyctl ...
1325
  		key_put(instkey);
5593122ee   David Howells   KEYS: Deal with d...
1326
  		key_ref = lookup_user_key(keyid, KEY_LOOKUP_PARTIAL, 0);
70a5bb72b   David Howells   keys: add keyctl ...
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
  		if (IS_ERR(key_ref))
  			return PTR_ERR(key_ref);
  	}
  
  	key = key_ref_to_ptr(key_ref);
  	ret = security_key_getsecurity(key, &context);
  	if (ret == 0) {
  		/* if no information was returned, give userspace an empty
  		 * string */
  		ret = 1;
  		if (buffer && buflen > 0 &&
  		    copy_to_user(buffer, "", 1) != 0)
  			ret = -EFAULT;
  	} else if (ret > 0) {
  		/* return as much data as there's room for */
  		if (buffer && buflen > 0) {
  			if (buflen > ret)
  				buflen = ret;
  
  			if (copy_to_user(buffer, context, buflen) != 0)
  				ret = -EFAULT;
  		}
  
  		kfree(context);
  	}
  
  	key_ref_put(key_ref);
  	return ret;
  }
ee18d64c1   David Howells   KEYS: Add a keyct...
1356
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
   * Attempt to install the calling process's session keyring on the process's
   * parent process.
   *
   * The keyring must exist and must grant the caller LINK permission, and the
   * parent process must be single-threaded and must have the same effective
   * ownership as this process and mustn't be SUID/SGID.
   *
   * The keyring will be emplaced on the parent when it next resumes userspace.
   *
   * If successful, 0 will be returned.
ee18d64c1   David Howells   KEYS: Add a keyct...
1367
1368
1369
   */
  long keyctl_session_to_parent(void)
  {
a00ae4d21   Geert Uytterhoeven   Keys: KEYCTL_SESS...
1370
  #ifdef TIF_NOTIFY_RESUME
ee18d64c1   David Howells   KEYS: Add a keyct...
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
  	struct task_struct *me, *parent;
  	const struct cred *mycred, *pcred;
  	struct cred *cred, *oldcred;
  	key_ref_t keyring_r;
  	int ret;
  
  	keyring_r = lookup_user_key(KEY_SPEC_SESSION_KEYRING, 0, KEY_LINK);
  	if (IS_ERR(keyring_r))
  		return PTR_ERR(keyring_r);
  
  	/* our parent is going to need a new cred struct, a new tgcred struct
  	 * and new security data, so we allocate them here to prevent ENOMEM in
  	 * our parent */
  	ret = -ENOMEM;
  	cred = cred_alloc_blank();
  	if (!cred)
  		goto error_keyring;
  
  	cred->tgcred->session_keyring = key_ref_to_ptr(keyring_r);
  	keyring_r = NULL;
  
  	me = current;
9d1ac65a9   David Howells   KEYS: Fix RCU no-...
1393
  	rcu_read_lock();
ee18d64c1   David Howells   KEYS: Add a keyct...
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
  	write_lock_irq(&tasklist_lock);
  
  	parent = me->real_parent;
  	ret = -EPERM;
  
  	/* the parent mustn't be init and mustn't be a kernel thread */
  	if (parent->pid <= 1 || !parent->mm)
  		goto not_permitted;
  
  	/* the parent must be single threaded */
dd98acf74   Oleg Nesterov   keyctl_session_to...
1404
  	if (!thread_group_empty(parent))
ee18d64c1   David Howells   KEYS: Add a keyct...
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
  		goto not_permitted;
  
  	/* the parent and the child must have different session keyrings or
  	 * there's no point */
  	mycred = current_cred();
  	pcred = __task_cred(parent);
  	if (mycred == pcred ||
  	    mycred->tgcred->session_keyring == pcred->tgcred->session_keyring)
  		goto already_same;
  
  	/* the parent must have the same effective ownership and mustn't be
  	 * SUID/SGID */
c5b60b5e6   Justin P. Mattock   security: whitesp...
1417
  	if (pcred->uid	!= mycred->euid	||
ee18d64c1   David Howells   KEYS: Add a keyct...
1418
1419
  	    pcred->euid	!= mycred->euid	||
  	    pcred->suid	!= mycred->euid	||
c5b60b5e6   Justin P. Mattock   security: whitesp...
1420
  	    pcred->gid	!= mycred->egid	||
ee18d64c1   David Howells   KEYS: Add a keyct...
1421
1422
1423
1424
1425
  	    pcred->egid	!= mycred->egid	||
  	    pcred->sgid	!= mycred->egid)
  		goto not_permitted;
  
  	/* the keyrings must have the same UID */
3d96406c7   David Howells   KEYS: Fix bug in ...
1426
1427
  	if ((pcred->tgcred->session_keyring &&
  	     pcred->tgcred->session_keyring->uid != mycred->euid) ||
ee18d64c1   David Howells   KEYS: Add a keyct...
1428
1429
  	    mycred->tgcred->session_keyring->uid != mycred->euid)
  		goto not_permitted;
ee18d64c1   David Howells   KEYS: Add a keyct...
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
  	/* if there's an already pending keyring replacement, then we replace
  	 * that */
  	oldcred = parent->replacement_session_keyring;
  
  	/* the replacement session keyring is applied just prior to userspace
  	 * restarting */
  	parent->replacement_session_keyring = cred;
  	cred = NULL;
  	set_ti_thread_flag(task_thread_info(parent), TIF_NOTIFY_RESUME);
  
  	write_unlock_irq(&tasklist_lock);
9d1ac65a9   David Howells   KEYS: Fix RCU no-...
1441
  	rcu_read_unlock();
ee18d64c1   David Howells   KEYS: Add a keyct...
1442
1443
1444
1445
1446
1447
1448
  	if (oldcred)
  		put_cred(oldcred);
  	return 0;
  
  already_same:
  	ret = 0;
  not_permitted:
5c84342a3   Marc Dionne   KEYS: Unlock task...
1449
  	write_unlock_irq(&tasklist_lock);
9d1ac65a9   David Howells   KEYS: Fix RCU no-...
1450
  	rcu_read_unlock();
ee18d64c1   David Howells   KEYS: Add a keyct...
1451
1452
1453
1454
1455
1456
  	put_cred(cred);
  	return ret;
  
  error_keyring:
  	key_ref_put(keyring_r);
  	return ret;
a00ae4d21   Geert Uytterhoeven   Keys: KEYCTL_SESS...
1457
1458
1459
1460
1461
1462
1463
1464
1465
  
  #else /* !TIF_NOTIFY_RESUME */
  	/*
  	 * To be removed when TIF_NOTIFY_RESUME has been implemented on
  	 * m68k/xtensa
  	 */
  #warning TIF_NOTIFY_RESUME not implemented
  	return -EOPNOTSUPP;
  #endif /* !TIF_NOTIFY_RESUME */
ee18d64c1   David Howells   KEYS: Add a keyct...
1466
  }
b5f545c88   David Howells   [PATCH] keys: Per...
1467
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
1468
   * The key control system call
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1469
   */
938bb9f5e   Heiko Carstens   [CVE-2009-0029] S...
1470
1471
  SYSCALL_DEFINE5(keyctl, int, option, unsigned long, arg2, unsigned long, arg3,
  		unsigned long, arg4, unsigned long, arg5)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
  {
  	switch (option) {
  	case KEYCTL_GET_KEYRING_ID:
  		return keyctl_get_keyring_ID((key_serial_t) arg2,
  					     (int) arg3);
  
  	case KEYCTL_JOIN_SESSION_KEYRING:
  		return keyctl_join_session_keyring((const char __user *) arg2);
  
  	case KEYCTL_UPDATE:
  		return keyctl_update_key((key_serial_t) arg2,
  					 (const void __user *) arg3,
  					 (size_t) arg4);
  
  	case KEYCTL_REVOKE:
  		return keyctl_revoke_key((key_serial_t) arg2);
  
  	case KEYCTL_DESCRIBE:
  		return keyctl_describe_key((key_serial_t) arg2,
  					   (char __user *) arg3,
  					   (unsigned) arg4);
  
  	case KEYCTL_CLEAR:
  		return keyctl_keyring_clear((key_serial_t) arg2);
  
  	case KEYCTL_LINK:
  		return keyctl_keyring_link((key_serial_t) arg2,
  					   (key_serial_t) arg3);
  
  	case KEYCTL_UNLINK:
  		return keyctl_keyring_unlink((key_serial_t) arg2,
  					     (key_serial_t) arg3);
  
  	case KEYCTL_SEARCH:
  		return keyctl_keyring_search((key_serial_t) arg2,
  					     (const char __user *) arg3,
  					     (const char __user *) arg4,
  					     (key_serial_t) arg5);
  
  	case KEYCTL_READ:
  		return keyctl_read_key((key_serial_t) arg2,
  				       (char __user *) arg3,
  				       (size_t) arg4);
  
  	case KEYCTL_CHOWN:
  		return keyctl_chown_key((key_serial_t) arg2,
  					(uid_t) arg3,
  					(gid_t) arg4);
  
  	case KEYCTL_SETPERM:
  		return keyctl_setperm_key((key_serial_t) arg2,
  					  (key_perm_t) arg3);
  
  	case KEYCTL_INSTANTIATE:
  		return keyctl_instantiate_key((key_serial_t) arg2,
  					      (const void __user *) arg3,
  					      (size_t) arg4,
  					      (key_serial_t) arg5);
  
  	case KEYCTL_NEGATE:
  		return keyctl_negate_key((key_serial_t) arg2,
  					 (unsigned) arg3,
  					 (key_serial_t) arg4);
3e30148c3   David Howells   [PATCH] Keys: Mak...
1535
1536
  	case KEYCTL_SET_REQKEY_KEYRING:
  		return keyctl_set_reqkey_keyring(arg2);
017679c4d   David Howells   [PATCH] keys: Per...
1537
1538
1539
  	case KEYCTL_SET_TIMEOUT:
  		return keyctl_set_timeout((key_serial_t) arg2,
  					  (unsigned) arg3);
b5f545c88   David Howells   [PATCH] keys: Per...
1540
1541
  	case KEYCTL_ASSUME_AUTHORITY:
  		return keyctl_assume_authority((key_serial_t) arg2);
70a5bb72b   David Howells   keys: add keyctl ...
1542
1543
  	case KEYCTL_GET_SECURITY:
  		return keyctl_get_security((key_serial_t) arg2,
90bd49ab6   James Morris   keys: fix sparse ...
1544
  					   (char __user *) arg3,
70a5bb72b   David Howells   keys: add keyctl ...
1545
  					   (size_t) arg4);
ee18d64c1   David Howells   KEYS: Add a keyct...
1546
1547
  	case KEYCTL_SESSION_TO_PARENT:
  		return keyctl_session_to_parent();
fdd1b9458   David Howells   KEYS: Add a new k...
1548
1549
1550
1551
1552
  	case KEYCTL_REJECT:
  		return keyctl_reject_key((key_serial_t) arg2,
  					 (unsigned) arg3,
  					 (unsigned) arg4,
  					 (key_serial_t) arg5);
ee009e4a0   David Howells   KEYS: Add an iove...
1553
1554
1555
1556
1557
1558
  	case KEYCTL_INSTANTIATE_IOV:
  		return keyctl_instantiate_key_iov(
  			(key_serial_t) arg2,
  			(const struct iovec __user *) arg3,
  			(unsigned) arg4,
  			(key_serial_t) arg5);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1559
1560
1561
  	default:
  		return -EOPNOTSUPP;
  	}
a8b17ed01   David Howells   KEYS: Do some sty...
1562
  }