Commit 927942aabbbe506bf9bc70a16dc5460ecc64c148
Committed by
James Morris
1 parent
9156235b34
KEYS: Make /proc/keys check to see if a key is possessed before security check
Make /proc/keys check to see if the calling process possesses each key before performing the security check. The possession check can be skipped if the key doesn't have the possessor-view permission bit set. This causes the keys a process possesses to show up in /proc/keys, even if they don't have matching user/group/other view permissions. Signed-off-by: David Howells <dhowells@redhat.com> Signed-off-by: James Morris <jmorris@namei.org>
Showing 3 changed files with 66 additions and 23 deletions Side-by-side Diff
security/keys/internal.h
... | ... | @@ -114,6 +114,10 @@ |
114 | 114 | const void *description, |
115 | 115 | key_match_func_t match); |
116 | 116 | |
117 | +extern key_ref_t search_my_process_keyrings(struct key_type *type, | |
118 | + const void *description, | |
119 | + key_match_func_t match, | |
120 | + const struct cred *cred); | |
117 | 121 | extern key_ref_t search_process_keyrings(struct key_type *type, |
118 | 122 | const void *description, |
119 | 123 | key_match_func_t match, |
... | ... | @@ -134,6 +138,7 @@ |
134 | 138 | struct key *dest_keyring, |
135 | 139 | unsigned long flags); |
136 | 140 | |
141 | +extern int lookup_user_key_possessed(const struct key *key, const void *target); | |
137 | 142 | extern key_ref_t lookup_user_key(key_serial_t id, unsigned long flags, |
138 | 143 | key_perm_t perm); |
139 | 144 | #define KEY_LOOKUP_CREATE 0x01 |
security/keys/proc.c
... | ... | @@ -184,20 +184,36 @@ |
184 | 184 | |
185 | 185 | static int proc_keys_show(struct seq_file *m, void *v) |
186 | 186 | { |
187 | + const struct cred *cred = current_cred(); | |
187 | 188 | struct rb_node *_p = v; |
188 | 189 | struct key *key = rb_entry(_p, struct key, serial_node); |
189 | 190 | struct timespec now; |
190 | 191 | unsigned long timo; |
192 | + key_ref_t key_ref, skey_ref; | |
191 | 193 | char xbuf[12]; |
192 | 194 | int rc; |
193 | 195 | |
196 | + key_ref = make_key_ref(key, 0); | |
197 | + | |
198 | + /* determine if the key is possessed by this process (a test we can | |
199 | + * skip if the key does not indicate the possessor can view it | |
200 | + */ | |
201 | + if (key->perm & KEY_POS_VIEW) { | |
202 | + skey_ref = search_my_process_keyrings(key->type, key, | |
203 | + lookup_user_key_possessed, | |
204 | + cred); | |
205 | + if (!IS_ERR(skey_ref)) { | |
206 | + key_ref_put(skey_ref); | |
207 | + key_ref = make_key_ref(key, 1); | |
208 | + } | |
209 | + } | |
210 | + | |
194 | 211 | /* check whether the current task is allowed to view the key (assuming |
195 | 212 | * non-possession) |
196 | 213 | * - the caller holds a spinlock, and thus the RCU read lock, making our |
197 | 214 | * access to __current_cred() safe |
198 | 215 | */ |
199 | - rc = key_task_permission(make_key_ref(key, 0), current_cred(), | |
200 | - KEY_VIEW); | |
216 | + rc = key_task_permission(key_ref, cred, KEY_VIEW); | |
201 | 217 | if (rc < 0) |
202 | 218 | return 0; |
203 | 219 |
security/keys/process_keys.c
... | ... | @@ -309,22 +309,19 @@ |
309 | 309 | |
310 | 310 | /*****************************************************************************/ |
311 | 311 | /* |
312 | - * search the process keyrings for the first matching key | |
312 | + * search only my process keyrings for the first matching key | |
313 | 313 | * - we use the supplied match function to see if the description (or other |
314 | 314 | * feature of interest) matches |
315 | 315 | * - we return -EAGAIN if we didn't find any matching key |
316 | 316 | * - we return -ENOKEY if we found only negative matching keys |
317 | 317 | */ |
318 | -key_ref_t search_process_keyrings(struct key_type *type, | |
319 | - const void *description, | |
320 | - key_match_func_t match, | |
321 | - const struct cred *cred) | |
318 | +key_ref_t search_my_process_keyrings(struct key_type *type, | |
319 | + const void *description, | |
320 | + key_match_func_t match, | |
321 | + const struct cred *cred) | |
322 | 322 | { |
323 | - struct request_key_auth *rka; | |
324 | 323 | key_ref_t key_ref, ret, err; |
325 | 324 | |
326 | - might_sleep(); | |
327 | - | |
328 | 325 | /* we want to return -EAGAIN or -ENOKEY if any of the keyrings were |
329 | 326 | * searchable, but we failed to find a key or we found a negative key; |
330 | 327 | * otherwise we want to return a sample error (probably -EACCES) if |
... | ... | @@ -424,6 +421,36 @@ |
424 | 421 | } |
425 | 422 | } |
426 | 423 | |
424 | + /* no key - decide on the error we're going to go for */ | |
425 | + key_ref = ret ? ret : err; | |
426 | + | |
427 | +found: | |
428 | + return key_ref; | |
429 | +} | |
430 | + | |
431 | +/*****************************************************************************/ | |
432 | +/* | |
433 | + * search the process keyrings for the first matching key | |
434 | + * - we use the supplied match function to see if the description (or other | |
435 | + * feature of interest) matches | |
436 | + * - we return -EAGAIN if we didn't find any matching key | |
437 | + * - we return -ENOKEY if we found only negative matching keys | |
438 | + */ | |
439 | +key_ref_t search_process_keyrings(struct key_type *type, | |
440 | + const void *description, | |
441 | + key_match_func_t match, | |
442 | + const struct cred *cred) | |
443 | +{ | |
444 | + struct request_key_auth *rka; | |
445 | + key_ref_t key_ref, ret = ERR_PTR(-EACCES), err; | |
446 | + | |
447 | + might_sleep(); | |
448 | + | |
449 | + key_ref = search_my_process_keyrings(type, description, match, cred); | |
450 | + if (!IS_ERR(key_ref)) | |
451 | + goto found; | |
452 | + err = key_ref; | |
453 | + | |
427 | 454 | /* if this process has an instantiation authorisation key, then we also |
428 | 455 | * search the keyrings of the process mentioned there |
429 | 456 | * - we don't permit access to request_key auth keys via this method |
430 | 457 | |
... | ... | @@ -446,24 +473,19 @@ |
446 | 473 | if (!IS_ERR(key_ref)) |
447 | 474 | goto found; |
448 | 475 | |
449 | - switch (PTR_ERR(key_ref)) { | |
450 | - case -EAGAIN: /* no key */ | |
451 | - if (ret) | |
452 | - break; | |
453 | - case -ENOKEY: /* negative key */ | |
454 | - ret = key_ref; | |
455 | - break; | |
456 | - default: | |
457 | - err = key_ref; | |
458 | - break; | |
459 | - } | |
476 | + ret = key_ref; | |
460 | 477 | } else { |
461 | 478 | up_read(&cred->request_key_auth->sem); |
462 | 479 | } |
463 | 480 | } |
464 | 481 | |
465 | 482 | /* no key - decide on the error we're going to go for */ |
466 | - key_ref = ret ? ret : err; | |
483 | + if (err == ERR_PTR(-ENOKEY) || ret == ERR_PTR(-ENOKEY)) | |
484 | + key_ref = ERR_PTR(-ENOKEY); | |
485 | + else if (err == ERR_PTR(-EACCES)) | |
486 | + key_ref = ret; | |
487 | + else | |
488 | + key_ref = err; | |
467 | 489 | |
468 | 490 | found: |
469 | 491 | return key_ref; |
... | ... | @@ -474,7 +496,7 @@ |
474 | 496 | /* |
475 | 497 | * see if the key we're looking at is the target key |
476 | 498 | */ |
477 | -static int lookup_user_key_possessed(const struct key *key, const void *target) | |
499 | +int lookup_user_key_possessed(const struct key *key, const void *target) | |
478 | 500 | { |
479 | 501 | return key == target; |
480 | 502 |