X-Git-Url: http://git.rot13.org/?a=blobdiff_plain;f=security%2Fkeys%2Fkeyctl.c;h=3d2ebae029c1775b49722314b2def71bc4aabe9d;hb=0a3a98f6dd4e8f4d928a09302c0d1c56f2192ac3;hp=a6516a64b297898923ca760e2e3b779880021c30;hpb=1d492eb41371d9a5145651e8eb64bea1042a4057;p=powerpc.git diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index a6516a64b2..3d2ebae029 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c @@ -34,7 +34,7 @@ asmlinkage long sys_add_key(const char __user *_type, size_t plen, key_serial_t ringid) { - struct key *keyring, *key; + key_ref_t keyring_ref, key_ref; char type[32], *description; void *payload; long dlen, ret; @@ -86,25 +86,25 @@ asmlinkage long sys_add_key(const char __user *_type, } /* find the target keyring (which must be writable) */ - keyring = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE); - if (IS_ERR(keyring)) { - ret = PTR_ERR(keyring); + keyring_ref = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE); + if (IS_ERR(keyring_ref)) { + ret = PTR_ERR(keyring_ref); goto error3; } /* create or update the requested key and add it to the target * keyring */ - key = key_create_or_update(keyring, type, description, - payload, plen, 0); - if (!IS_ERR(key)) { - ret = key->serial; - key_put(key); + key_ref = key_create_or_update(keyring_ref, type, description, + payload, plen, 0); + if (!IS_ERR(key_ref)) { + ret = key_ref_to_ptr(key_ref)->serial; + key_ref_put(key_ref); } else { - ret = PTR_ERR(key); + ret = PTR_ERR(key_ref); } - key_put(keyring); + key_ref_put(keyring_ref); error3: kfree(payload); error2: @@ -131,7 +131,8 @@ asmlinkage long sys_request_key(const char __user *_type, key_serial_t destringid) { struct key_type *ktype; - struct key *key, *dest; + struct key *key; + key_ref_t dest_ref; char type[32], *description, *callout_info; long dlen, ret; @@ -187,11 +188,11 @@ asmlinkage long sys_request_key(const char __user *_type, } /* get the destination keyring if specified */ - dest = NULL; + dest_ref = NULL; if (destringid) { - dest = lookup_user_key(NULL, destringid, 1, 0, KEY_WRITE); - if (IS_ERR(dest)) { - ret = PTR_ERR(dest); + dest_ref = lookup_user_key(NULL, destringid, 1, 0, KEY_WRITE); + if (IS_ERR(dest_ref)) { + ret = PTR_ERR(dest_ref); goto error3; } } @@ -204,7 +205,8 @@ asmlinkage long sys_request_key(const char __user *_type, } /* do the search */ - key = request_key_and_link(ktype, description, callout_info, dest); + key = request_key_and_link(ktype, description, callout_info, + key_ref_to_ptr(dest_ref)); if (IS_ERR(key)) { ret = PTR_ERR(key); goto error5; @@ -216,7 +218,7 @@ asmlinkage long sys_request_key(const char __user *_type, error5: key_type_put(ktype); error4: - key_put(dest); + key_ref_put(dest_ref); error3: kfree(callout_info); error2: @@ -234,17 +236,17 @@ asmlinkage long sys_request_key(const char __user *_type, */ long keyctl_get_keyring_ID(key_serial_t id, int create) { - struct key *key; + key_ref_t key_ref; long ret; - key = lookup_user_key(NULL, id, create, 0, KEY_SEARCH); - if (IS_ERR(key)) { - ret = PTR_ERR(key); + key_ref = lookup_user_key(NULL, id, create, 0, KEY_SEARCH); + if (IS_ERR(key_ref)) { + ret = PTR_ERR(key_ref); goto error; } - ret = key->serial; - key_put(key); + ret = key_ref_to_ptr(key_ref)->serial; + key_ref_put(key_ref); error: return ret; @@ -302,7 +304,7 @@ long keyctl_update_key(key_serial_t id, const void __user *_payload, size_t plen) { - struct key *key; + key_ref_t key_ref; void *payload; long ret; @@ -324,16 +326,16 @@ long keyctl_update_key(key_serial_t id, } /* find the target key (which must be writable) */ - key = lookup_user_key(NULL, id, 0, 0, KEY_WRITE); - if (IS_ERR(key)) { - ret = PTR_ERR(key); + key_ref = lookup_user_key(NULL, id, 0, 0, KEY_WRITE); + if (IS_ERR(key_ref)) { + ret = PTR_ERR(key_ref); goto error2; } /* update the key */ - ret = key_update(key, payload, plen); + ret = key_update(key_ref, payload, plen); - key_put(key); + key_ref_put(key_ref); error2: kfree(payload); error: @@ -349,19 +351,19 @@ long keyctl_update_key(key_serial_t id, */ long keyctl_revoke_key(key_serial_t id) { - struct key *key; + key_ref_t key_ref; long ret; - key = lookup_user_key(NULL, id, 0, 0, KEY_WRITE); - if (IS_ERR(key)) { - ret = PTR_ERR(key); + key_ref = lookup_user_key(NULL, id, 0, 0, KEY_WRITE); + if (IS_ERR(key_ref)) { + ret = PTR_ERR(key_ref); goto error; } - key_revoke(key); + key_revoke(key_ref_to_ptr(key_ref)); ret = 0; - key_put(key); + key_ref_put(key_ref); error: return ret; @@ -375,18 +377,18 @@ long keyctl_revoke_key(key_serial_t id) */ long keyctl_keyring_clear(key_serial_t ringid) { - struct key *keyring; + key_ref_t keyring_ref; long ret; - keyring = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE); - if (IS_ERR(keyring)) { - ret = PTR_ERR(keyring); + keyring_ref = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE); + if (IS_ERR(keyring_ref)) { + ret = PTR_ERR(keyring_ref); goto error; } - ret = keyring_clear(keyring); + ret = keyring_clear(key_ref_to_ptr(keyring_ref)); - key_put(keyring); + key_ref_put(keyring_ref); error: return ret; @@ -401,26 +403,26 @@ long keyctl_keyring_clear(key_serial_t ringid) */ long keyctl_keyring_link(key_serial_t id, key_serial_t ringid) { - struct key *keyring, *key; + key_ref_t keyring_ref, key_ref; long ret; - keyring = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE); - if (IS_ERR(keyring)) { - ret = PTR_ERR(keyring); + keyring_ref = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE); + if (IS_ERR(keyring_ref)) { + ret = PTR_ERR(keyring_ref); goto error; } - key = lookup_user_key(NULL, id, 1, 0, KEY_LINK); - if (IS_ERR(key)) { - ret = PTR_ERR(key); + key_ref = lookup_user_key(NULL, id, 1, 0, KEY_LINK); + if (IS_ERR(key_ref)) { + ret = PTR_ERR(key_ref); goto error2; } - ret = key_link(keyring, key); + ret = key_link(key_ref_to_ptr(keyring_ref), key_ref_to_ptr(key_ref)); - key_put(key); + key_ref_put(key_ref); error2: - key_put(keyring); + key_ref_put(keyring_ref); error: return ret; @@ -435,26 +437,26 @@ long keyctl_keyring_link(key_serial_t id, key_serial_t ringid) */ long keyctl_keyring_unlink(key_serial_t id, key_serial_t ringid) { - struct key *keyring, *key; + key_ref_t keyring_ref, key_ref; long ret; - keyring = lookup_user_key(NULL, ringid, 0, 0, KEY_WRITE); - if (IS_ERR(keyring)) { - ret = PTR_ERR(keyring); + keyring_ref = lookup_user_key(NULL, ringid, 0, 0, KEY_WRITE); + if (IS_ERR(keyring_ref)) { + ret = PTR_ERR(keyring_ref); goto error; } - key = lookup_user_key(NULL, id, 0, 0, 0); - if (IS_ERR(key)) { - ret = PTR_ERR(key); + key_ref = lookup_user_key(NULL, id, 0, 0, 0); + if (IS_ERR(key_ref)) { + ret = PTR_ERR(key_ref); goto error2; } - ret = key_unlink(keyring, key); + ret = key_unlink(key_ref_to_ptr(keyring_ref), key_ref_to_ptr(key_ref)); - key_put(key); + key_ref_put(key_ref); error2: - key_put(keyring); + key_ref_put(keyring_ref); error: return ret; @@ -476,24 +478,26 @@ long keyctl_describe_key(key_serial_t keyid, size_t buflen) { struct key *key, *instkey; + key_ref_t key_ref; char *tmpbuf; long ret; - key = lookup_user_key(NULL, keyid, 0, 1, KEY_VIEW); - if (IS_ERR(key)) { + key_ref = lookup_user_key(NULL, keyid, 0, 1, KEY_VIEW); + if (IS_ERR(key_ref)) { /* viewing a key under construction is permitted if we have the * authorisation token handy */ - if (PTR_ERR(key) == -EACCES) { + if (PTR_ERR(key_ref) == -EACCES) { instkey = key_get_instantiation_authkey(keyid); if (!IS_ERR(instkey)) { key_put(instkey); - key = lookup_user_key(NULL, keyid, 0, 1, 0); - if (!IS_ERR(key)) + key_ref = lookup_user_key(NULL, keyid, + 0, 1, 0); + if (!IS_ERR(key_ref)) goto okay; } } - ret = PTR_ERR(key); + ret = PTR_ERR(key_ref); goto error; } @@ -504,13 +508,16 @@ okay: if (!tmpbuf) goto error2; + key = key_ref_to_ptr(key_ref); + ret = snprintf(tmpbuf, PAGE_SIZE - 1, - "%s;%d;%d;%06x;%s", - key->type->name, - key->uid, - key->gid, - key->perm, - key->description ? key->description :"" + "%s;%d;%d;%08x;%s", + key_ref_to_ptr(key_ref)->type->name, + key_ref_to_ptr(key_ref)->uid, + key_ref_to_ptr(key_ref)->gid, + key_ref_to_ptr(key_ref)->perm, + key_ref_to_ptr(key_ref)->description ? + key_ref_to_ptr(key_ref)->description : "" ); /* include a NUL char at the end of the data */ @@ -530,7 +537,7 @@ okay: kfree(tmpbuf); error2: - key_put(key); + key_ref_put(key_ref); error: return ret; @@ -552,7 +559,7 @@ long keyctl_keyring_search(key_serial_t ringid, key_serial_t destringid) { struct key_type *ktype; - struct key *keyring, *key, *dest; + key_ref_t keyring_ref, key_ref, dest_ref; char type[32], *description; long dlen, ret; @@ -581,18 +588,18 @@ long keyctl_keyring_search(key_serial_t ringid, goto error2; /* get the keyring at which to begin the search */ - keyring = lookup_user_key(NULL, ringid, 0, 0, KEY_SEARCH); - if (IS_ERR(keyring)) { - ret = PTR_ERR(keyring); + keyring_ref = lookup_user_key(NULL, ringid, 0, 0, KEY_SEARCH); + if (IS_ERR(keyring_ref)) { + ret = PTR_ERR(keyring_ref); goto error2; } /* get the destination keyring if specified */ - dest = NULL; + dest_ref = NULL; if (destringid) { - dest = lookup_user_key(NULL, destringid, 1, 0, KEY_WRITE); - if (IS_ERR(dest)) { - ret = PTR_ERR(dest); + dest_ref = lookup_user_key(NULL, destringid, 1, 0, KEY_WRITE); + if (IS_ERR(dest_ref)) { + ret = PTR_ERR(dest_ref); goto error3; } } @@ -605,9 +612,9 @@ long keyctl_keyring_search(key_serial_t ringid, } /* do the search */ - key = keyring_search(keyring, ktype, description); - if (IS_ERR(key)) { - ret = PTR_ERR(key); + key_ref = keyring_search(keyring_ref, ktype, description); + if (IS_ERR(key_ref)) { + ret = PTR_ERR(key_ref); /* treat lack or presence of a negative key the same */ if (ret == -EAGAIN) @@ -616,26 +623,26 @@ long keyctl_keyring_search(key_serial_t ringid, } /* link the resulting key to the destination keyring if we can */ - if (dest) { - ret = -EACCES; - if (!key_permission(key, KEY_LINK)) + if (dest_ref) { + ret = key_permission(key_ref, KEY_LINK); + if (ret < 0) goto error6; - ret = key_link(dest, key); + ret = key_link(key_ref_to_ptr(dest_ref), key_ref_to_ptr(key_ref)); if (ret < 0) goto error6; } - ret = key->serial; + ret = key_ref_to_ptr(key_ref)->serial; error6: - key_put(key); + key_ref_put(key_ref); error5: key_type_put(ktype); error4: - key_put(dest); + key_ref_put(dest_ref); error3: - key_put(keyring); + key_ref_put(keyring_ref); error2: kfree(description); error: @@ -643,16 +650,6 @@ long keyctl_keyring_search(key_serial_t ringid, } /* end keyctl_keyring_search() */ -/*****************************************************************************/ -/* - * see if the key we're looking at is the target key - */ -static int keyctl_read_key_same(const struct key *key, const void *target) -{ - return key == target; - -} /* end keyctl_read_key_same() */ - /*****************************************************************************/ /* * read a user key's payload @@ -665,38 +662,36 @@ static int keyctl_read_key_same(const struct key *key, const void *target) */ long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen) { - struct key *key, *skey; + struct key *key; + key_ref_t key_ref; long ret; /* find the key first */ - key = lookup_user_key(NULL, keyid, 0, 0, 0); - if (!IS_ERR(key)) { - /* see if we can read it directly */ - if (key_permission(key, KEY_READ)) - goto can_read_key; - - /* 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 - */ - skey = search_process_keyrings(key->type, key, - keyctl_read_key_same, current); - if (!IS_ERR(skey)) - goto can_read_key2; - - ret = PTR_ERR(skey); - if (ret == -EAGAIN) - ret = -EACCES; - goto error2; + key_ref = lookup_user_key(NULL, keyid, 0, 0, 0); + if (IS_ERR(key_ref)) { + ret = -ENOKEY; + goto error; } - ret = -ENOKEY; - goto error; + key = key_ref_to_ptr(key_ref); + + /* see if we can read it directly */ + ret = key_permission(key_ref, KEY_READ); + if (ret == 0) + goto can_read_key; + if (ret != -EACCES) + goto error; + + /* 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; + } /* the key is probably readable - now try to read it */ - can_read_key2: - key_put(skey); can_read_key: ret = key_validate(key); if (ret == 0) { @@ -727,18 +722,21 @@ long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen) long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid) { struct key *key; + key_ref_t key_ref; long ret; ret = 0; if (uid == (uid_t) -1 && gid == (gid_t) -1) goto error; - key = lookup_user_key(NULL, id, 1, 1, 0); - if (IS_ERR(key)) { - ret = PTR_ERR(key); + key_ref = lookup_user_key(NULL, id, 1, 1, KEY_SETATTR); + if (IS_ERR(key_ref)) { + ret = PTR_ERR(key_ref); goto error; } + key = key_ref_to_ptr(key_ref); + /* make the changes with the locks held to prevent chown/chown races */ ret = -EACCES; down_write(&key->sem); @@ -784,18 +782,21 @@ long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid) long keyctl_setperm_key(key_serial_t id, key_perm_t perm) { struct key *key; + key_ref_t key_ref; long ret; ret = -EINVAL; - if (perm & ~(KEY_USR_ALL | KEY_GRP_ALL | KEY_OTH_ALL)) + if (perm & ~(KEY_POS_ALL | KEY_USR_ALL | KEY_GRP_ALL | KEY_OTH_ALL)) goto error; - key = lookup_user_key(NULL, id, 1, 1, 0); - if (IS_ERR(key)) { - ret = PTR_ERR(key); + key_ref = lookup_user_key(NULL, id, 1, 1, KEY_SETATTR); + if (IS_ERR(key_ref)) { + ret = PTR_ERR(key_ref); goto error; } + key = key_ref_to_ptr(key_ref); + /* make the changes with the locks held to prevent chown/chmod races */ ret = -EACCES; down_write(&key->sem); @@ -824,7 +825,8 @@ long keyctl_instantiate_key(key_serial_t id, key_serial_t ringid) { struct request_key_auth *rka; - struct key *instkey, *keyring; + struct key *instkey; + key_ref_t keyring_ref; void *payload; long ret; @@ -832,6 +834,17 @@ long keyctl_instantiate_key(key_serial_t id, if (plen > 32767) goto error; + /* the appropriate instantiation authorisation key must have been + * assumed before calling this */ + ret = -EPERM; + instkey = current->request_key_auth; + if (!instkey) + goto error; + + rka = instkey->payload.data; + if (rka->target_key->serial != id) + goto error; + /* pull the payload in if one was supplied */ payload = NULL; @@ -846,37 +859,34 @@ long keyctl_instantiate_key(key_serial_t id, goto error2; } - /* find the instantiation authorisation key */ - instkey = key_get_instantiation_authkey(id); - if (IS_ERR(instkey)) { - ret = PTR_ERR(instkey); - goto error2; - } - - rka = instkey->payload.data; - /* find the destination keyring amongst those belonging to the * requesting task */ - keyring = NULL; + keyring_ref = NULL; if (ringid) { - keyring = lookup_user_key(rka->context, ringid, 1, 0, - KEY_WRITE); - if (IS_ERR(keyring)) { - ret = PTR_ERR(keyring); - goto error3; + keyring_ref = lookup_user_key(rka->context, ringid, 1, 0, + KEY_WRITE); + if (IS_ERR(keyring_ref)) { + ret = PTR_ERR(keyring_ref); + goto error2; } } /* instantiate the key and link it into a keyring */ ret = key_instantiate_and_link(rka->target_key, payload, plen, - keyring, instkey); + key_ref_to_ptr(keyring_ref), instkey); - key_put(keyring); - error3: - key_put(instkey); - error2: + key_ref_put(keyring_ref); + + /* discard the assumed authority if it's just been disabled by + * instantiation of the key */ + if (ret == 0) { + key_put(current->request_key_auth); + current->request_key_auth = NULL; + } + +error2: kfree(payload); - error: +error: return ret; } /* end keyctl_instantiate_key() */ @@ -889,36 +899,46 @@ long keyctl_instantiate_key(key_serial_t id, long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid) { struct request_key_auth *rka; - struct key *instkey, *keyring; + struct key *instkey; + key_ref_t keyring_ref; long ret; - /* find the instantiation authorisation key */ - instkey = key_get_instantiation_authkey(id); - if (IS_ERR(instkey)) { - ret = PTR_ERR(instkey); + /* the appropriate instantiation authorisation key must have been + * assumed before calling this */ + ret = -EPERM; + instkey = current->request_key_auth; + if (!instkey) goto error; - } rka = instkey->payload.data; + if (rka->target_key->serial != id) + goto error; /* find the destination keyring if present (which must also be * writable) */ - keyring = NULL; + keyring_ref = NULL; if (ringid) { - keyring = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE); - if (IS_ERR(keyring)) { - ret = PTR_ERR(keyring); - goto error2; + keyring_ref = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE); + if (IS_ERR(keyring_ref)) { + ret = PTR_ERR(keyring_ref); + goto error; } } /* instantiate the key and link it into a keyring */ - ret = key_negate_and_link(rka->target_key, timeout, keyring, instkey); + ret = key_negate_and_link(rka->target_key, timeout, + key_ref_to_ptr(keyring_ref), instkey); - key_put(keyring); - error2: - key_put(instkey); - error: + key_ref_put(keyring_ref); + + /* discard the assumed authority if it's just been disabled by + * instantiation of the key */ + if (ret == 0) { + key_put(current->request_key_auth); + current->request_key_auth = NULL; + } + +error: return ret; } /* end keyctl_negate_key() */ @@ -961,6 +981,88 @@ long keyctl_set_reqkey_keyring(int reqkey_defl) } /* end keyctl_set_reqkey_keyring() */ +/*****************************************************************************/ +/* + * set or clear the timeout for a key + */ +long keyctl_set_timeout(key_serial_t id, unsigned timeout) +{ + struct timespec now; + struct key *key; + key_ref_t key_ref; + time_t expiry; + long ret; + + key_ref = lookup_user_key(NULL, id, 1, 1, KEY_SETATTR); + if (IS_ERR(key_ref)) { + ret = PTR_ERR(key_ref); + goto error; + } + + 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; + + up_write(&key->sem); + key_put(key); + + ret = 0; +error: + return ret; + +} /* end keyctl_set_timeout() */ + +/*****************************************************************************/ +/* + * assume the authority to instantiate the specified key + */ +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) { + key_put(current->request_key_auth); + current->request_key_auth = NULL; + ret = 0; + 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; + } + + key_put(current->request_key_auth); + current->request_key_auth = authkey; + ret = authkey->serial; + +error: + return ret; + +} /* end keyctl_assume_authority() */ + /*****************************************************************************/ /* * the key control system call @@ -1034,6 +1136,13 @@ asmlinkage long sys_keyctl(int option, unsigned long arg2, unsigned long arg3, case KEYCTL_SET_REQKEY_KEYRING: return keyctl_set_reqkey_keyring(arg2); + case KEYCTL_SET_TIMEOUT: + return keyctl_set_timeout((key_serial_t) arg2, + (unsigned) arg3); + + case KEYCTL_ASSUME_AUTHORITY: + return keyctl_assume_authority((key_serial_t) arg2); + default: return -EOPNOTSUPP; }