/* * unlink the first attachment of a key from a keyring * - the keyring must be writable * - we don't need any permissions on the key * - implements keyctl(KEYCTL_UNLINK) */ long keyctl_keyring_unlink(key_serial_t id, key_serial_t ringid) { key_ref_t keyring_ref, key_ref; long ret; keyring_ref = lookup_user_key(NULL, ringid, 0, 0, KEY_WRITE); if (IS_ERR(keyring_ref)) { ret = PTR_ERR(keyring_ref); goto error; } 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(key_ref_to_ptr(keyring_ref), key_ref_to_ptr(key_ref)); key_ref_put(key_ref); error2: key_ref_put(keyring_ref); error: return ret; } /* end keyctl_keyring_unlink() */
/* * Load the compiled-in list of X.509 certificates. */ static __init int load_system_certificate_list(void) { key_ref_t key; const u8 *p, *end; size_t plen; pr_notice("Loading compiled-in X.509 certificates\n"); p = system_certificate_list; end = p + system_certificate_list_size; while (p < end) { /* Each cert begins with an ASN.1 SEQUENCE tag and must be more * than 256 bytes in size. */ if (end - p < 4) goto dodgy_cert; if (p[0] != 0x30 && p[1] != 0x82) goto dodgy_cert; plen = (p[2] << 8) | p[3]; plen += 4; if (plen > end - p) goto dodgy_cert; key = key_create_or_update(make_key_ref(system_trusted_keyring, 1), "asymmetric", NULL, p, plen, ((KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_VIEW | KEY_USR_READ), KEY_ALLOC_NOT_IN_QUOTA | KEY_ALLOC_TRUSTED); if (IS_ERR(key)) { pr_err("Problem loading in-kernel X.509 certificate (%ld)\n", PTR_ERR(key)); } else { set_bit(KEY_FLAG_BUILTIN, &key_ref_to_ptr(key)->flags); pr_notice("Loaded X.509 cert '%s'\n", key_ref_to_ptr(key)->description); key_ref_put(key); } p += plen; } return 0; dodgy_cert: pr_err("Problem parsing in-kernel X.509 certificate list\n"); return 0; }
/* * Get the persistent keyring for a specific UID and link it to the nominated * keyring. */ static long key_get_persistent(struct user_namespace *ns, kuid_t uid, key_ref_t dest_ref) { struct keyring_index_key index_key; struct key *persistent; key_ref_t reg_ref, persistent_ref; char buf[32]; long ret; /* Look in the register if it exists */ index_key.type = &key_type_keyring; index_key.description = buf; index_key.desc_len = sprintf(buf, "_persistent.%u", from_kuid(ns, uid)); if (ns->persistent_keyring_register) { reg_ref = make_key_ref(ns->persistent_keyring_register, true); down_read(&ns->persistent_keyring_register_sem); persistent_ref = find_key_to_update(reg_ref, &index_key); up_read(&ns->persistent_keyring_register_sem); if (persistent_ref) goto found; } /* It wasn't in the register, so we'll need to create it. We might * also need to create the register. */ down_write(&ns->persistent_keyring_register_sem); persistent_ref = key_create_persistent(ns, uid, &index_key); up_write(&ns->persistent_keyring_register_sem); if (!IS_ERR(persistent_ref)) goto found; return PTR_ERR(persistent_ref); found: ret = key_task_permission(persistent_ref, current_cred(), KEY_NEED_LINK); if (ret == 0) { persistent = key_ref_to_ptr(persistent_ref); ret = key_link(key_ref_to_ptr(dest_ref), persistent); if (ret == 0) { key_set_timeout(persistent, persistent_keyring_expiry); ret = persistent->serial; } } key_ref_put(persistent_ref); return ret; }
/* * get the ID of the specified process keyring * - the keyring must have search permission to be found * - implements keyctl(KEYCTL_GET_KEYRING_ID) */ long keyctl_get_keyring_ID(key_serial_t id, int create) { key_ref_t key_ref; long ret; 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_ref_to_ptr(key_ref)->serial; key_ref_put(key_ref); error: return ret; } /* end keyctl_get_keyring_ID() */
/* * 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. */ long keyctl_get_keyring_ID(key_serial_t id, int create) { key_ref_t key_ref; unsigned long lflags; long ret; lflags = create ? KEY_LOOKUP_CREATE : 0; key_ref = lookup_user_key(id, lflags, KEY_SEARCH); if (IS_ERR(key_ref)) { ret = PTR_ERR(key_ref); goto error; } ret = key_ref_to_ptr(key_ref)->serial; key_ref_put(key_ref); error: return ret; }
/* * clear the specified process keyring * - the keyring must be writable * - implements keyctl(KEYCTL_CLEAR) */ long keyctl_keyring_clear(key_serial_t ringid) { key_ref_t keyring_ref; long ret; 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(key_ref_to_ptr(keyring_ref)); key_ref_put(keyring_ref); error: return ret; } /* end keyctl_keyring_clear() */
/* * revoke a key * - the key must be writable * - implements keyctl(KEYCTL_REVOKE) */ long keyctl_revoke_key(key_serial_t id) { key_ref_t key_ref; long ret; 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_ref_to_ptr(key_ref)); ret = 0; key_ref_put(key_ref); error: return ret; } /* end keyctl_revoke_key() */
/* * update a key's data payload * - the key must be writable * - implements keyctl(KEYCTL_UPDATE) */ long keyctl_update_key(key_serial_t id, const void __user *_payload, size_t plen) { key_ref_t key_ref; 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) */ 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_ref, payload, plen); key_ref_put(key_ref); error2: kfree(payload); error: return ret; } /* end keyctl_update_key() */
/* * Get the persistent keyring for a specific UID and link it to the nominated * keyring. */ long keyctl_get_persistent(uid_t _uid, key_serial_t destid) { struct user_namespace *ns = current_user_ns(); key_ref_t dest_ref; kuid_t uid; long ret; /* -1 indicates the current user */ if (_uid == (uid_t)-1) { uid = current_uid(); } else { uid = make_kuid(ns, _uid); if (!uid_valid(uid)) return -EINVAL; /* You can only see your own persistent cache if you're not * sufficiently privileged. */ if (!uid_eq(uid, current_uid()) && !uid_eq(uid, current_euid()) && !ns_capable(ns, CAP_SETUID)) return -EPERM; } /* There must be a destination keyring */ dest_ref = lookup_user_key(destid, KEY_LOOKUP_CREATE, KEY_NEED_WRITE); if (IS_ERR(dest_ref)) return PTR_ERR(dest_ref); if (key_ref_to_ptr(dest_ref)->type != &key_type_keyring) { ret = -ENOTDIR; goto out_put_dest; } ret = key_get_persistent(ns, uid, dest_ref); out_put_dest: key_ref_put(dest_ref); return ret; }
/* * negatively instantiate the key with the given timeout (in seconds), and, if * one is given, link the key into the keyring */ long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid) { struct request_key_auth *rka; 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); goto error; } rka = instkey->payload.data; /* find the destination keyring if present (which must also be * writable) */ keyring_ref = NULL; if (ringid) { keyring_ref = lookup_user_key(NULL, 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_negate_and_link(rka->target_key, timeout, key_ref_to_ptr(keyring_ref), instkey); key_ref_put(keyring_ref); error2: key_put(instkey); error: return ret; } /* end keyctl_negate_key() */
int __init integrity_add_key(const unsigned int id, const void *data, off_t size, key_perm_t perm) { key_ref_t key; int rc = 0; if (!keyring[id]) return -EINVAL; key = key_create_or_update(make_key_ref(keyring[id], 1), "asymmetric", NULL, data, size, perm, KEY_ALLOC_NOT_IN_QUOTA); if (IS_ERR(key)) { rc = PTR_ERR(key); pr_err("Problem loading X.509 certificate %d\n", rc); } else { pr_notice("Loaded X.509 cert '%s'\n", key_ref_to_ptr(key)->description); key_ref_put(key); } return rc; }
/* * instantiate the key with the specified payload, and, if one is given, link * the key into the keyring */ long keyctl_instantiate_key(key_serial_t id, const void __user *_payload, size_t plen, key_serial_t ringid) { struct request_key_auth *rka; struct key *instkey; key_ref_t keyring_ref; void *payload; long ret; ret = -EINVAL; if (plen > 32767) 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 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_ref = NULL; if (ringid) { keyring_ref = lookup_user_key(rka->context, ringid, 1, 0, KEY_WRITE); if (IS_ERR(keyring_ref)) { ret = PTR_ERR(keyring_ref); goto error3; } } /* instantiate the key and link it into a keyring */ ret = key_instantiate_and_link(rka->target_key, payload, plen, key_ref_to_ptr(keyring_ref), instkey); key_ref_put(keyring_ref); error3: key_put(instkey); error2: kfree(payload); error: return ret; } /* end keyctl_instantiate_key() */
/* * 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 * - returns the new key's serial number * - implements add_key() */ asmlinkage long sys_add_key(const char __user *_type, const char __user *_description, const void __user *_payload, size_t plen, key_serial_t ringid) { key_ref_t keyring_ref, key_ref; char type[32], *description; void *payload; long dlen, ret; ret = -EINVAL; if (plen > 32767) goto error; /* draw all the data into kernel space */ ret = strncpy_from_user(type, _type, sizeof(type) - 1); if (ret < 0) goto error; type[31] = '\0'; ret = -EPERM; if (type[0] == '.') goto error; ret = -EFAULT; dlen = strnlen_user(_description, PAGE_SIZE - 1); if (dlen <= 0) goto error; ret = -EINVAL; if (dlen > PAGE_SIZE - 1) goto error; ret = -ENOMEM; description = kmalloc(dlen + 1, GFP_KERNEL); if (!description) goto error; ret = -EFAULT; if (copy_from_user(description, _description, dlen + 1) != 0) goto error2; /* pull the payload in if one was supplied */ payload = NULL; if (_payload) { ret = -ENOMEM; payload = kmalloc(plen, GFP_KERNEL); if (!payload) goto error2; ret = -EFAULT; if (copy_from_user(payload, _payload, plen) != 0) goto error3; } /* find the target keyring (which must be writable) */ 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_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_ref); } key_ref_put(keyring_ref); error3: kfree(payload); error2: kfree(description); error: return ret; } /* end sys_add_key() */
/* * 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. * * If the description is NULL or an empty string, the key type is asked to * generate one from the payload. * * 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. */ SYSCALL_DEFINE5(add_key, const char __user *, _type, const char __user *, _description, const void __user *, _payload, size_t, plen, key_serial_t, ringid) { key_ref_t keyring_ref, key_ref; char type[32], *description; void *payload; long ret; bool vm; ret = -EINVAL; if (plen > 1024 * 1024 - 1) goto error; /* draw all the data into kernel space */ ret = key_get_type_from_user(type, _type, sizeof(type)); if (ret < 0) goto error; description = NULL; if (_description) { description = strndup_user(_description, PAGE_SIZE); if (IS_ERR(description)) { ret = PTR_ERR(description); goto error; } if (!*description) { kfree(description); description = NULL; } } /* pull the payload in if one was supplied */ payload = NULL; vm = false; if (_payload) { ret = -ENOMEM; payload = kmalloc(plen, GFP_KERNEL | __GFP_NOWARN); if (!payload) { if (plen <= PAGE_SIZE) goto error2; vm = true; payload = vmalloc(plen); if (!payload) goto error2; } ret = -EFAULT; if (copy_from_user(payload, _payload, plen) != 0) goto error3; } /* find the target keyring (which must be writable) */ keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, 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_ref = key_create_or_update(keyring_ref, type, description, payload, plen, KEY_PERM_UNDEF, KEY_ALLOC_IN_QUOTA); if (!IS_ERR(key_ref)) { ret = key_ref_to_ptr(key_ref)->serial; key_ref_put(key_ref); } else { ret = PTR_ERR(key_ref); } key_ref_put(keyring_ref); error3: if (!vm) kfree(payload); else vfree(payload); error2: kfree(description); error: return ret; }
static int proc_keys_show(struct seq_file *m, void *v) { const struct cred *cred = current_cred(); struct rb_node *_p = v; struct key *key = rb_entry(_p, struct key, serial_node); struct timespec now; unsigned long timo; key_ref_t key_ref, skey_ref; char xbuf[12]; int rc; key_ref = make_key_ref(key, 0); /* */ if (key->perm & KEY_POS_VIEW) { skey_ref = search_my_process_keyrings(key->type, key, lookup_user_key_possessed, true, cred); if (!IS_ERR(skey_ref)) { key_ref_put(skey_ref); key_ref = make_key_ref(key, 1); } } /* */ rc = key_task_permission(key_ref, cred, KEY_VIEW); if (rc < 0) return 0; now = current_kernel_time(); rcu_read_lock(); /* */ if (key->expiry == 0) { memcpy(xbuf, "perm", 5); } else if (now.tv_sec >= key->expiry) { memcpy(xbuf, "expd", 5); } else { timo = key->expiry - now.tv_sec; if (timo < 60) sprintf(xbuf, "%lus", timo); else if (timo < 60*60) sprintf(xbuf, "%lum", timo / 60); else if (timo < 60*60*24) sprintf(xbuf, "%luh", timo / (60*60)); else if (timo < 60*60*24*7) sprintf(xbuf, "%lud", timo / (60*60*24)); else sprintf(xbuf, "%luw", timo / (60*60*24*7)); } #define showflag(KEY, LETTER, FLAG) \ (test_bit(FLAG, &(KEY)->flags) ? LETTER : '-') seq_printf(m, "%08x %c%c%c%c%c%c %5d %4s %08x %5d %5d %-9.9s ", key->serial, showflag(key, 'I', KEY_FLAG_INSTANTIATED), showflag(key, 'R', KEY_FLAG_REVOKED), showflag(key, 'D', KEY_FLAG_DEAD), showflag(key, 'Q', KEY_FLAG_IN_QUOTA), showflag(key, 'U', KEY_FLAG_USER_CONSTRUCT), showflag(key, 'N', KEY_FLAG_NEGATIVE), atomic_read(&key->usage), xbuf, key->perm, key->uid, key->gid, key->type->name); #undef showflag if (key->type->describe) key->type->describe(key, m); seq_putc(m, '\n'); rcu_read_unlock(); return 0; }
/* * describe a user key * - the key must have view permission * - if there's a buffer, we place up to buflen bytes of data into it * - unless there's an error, we return the amount of description available, * irrespective of how much we may have copied * - the description is formatted thus: * type;uid;gid;perm;description<NUL> * - implements keyctl(KEYCTL_DESCRIBE) */ long keyctl_describe_key(key_serial_t keyid, char __user *buffer, size_t buflen) { struct key *key, *instkey; key_ref_t key_ref; char *tmpbuf; long ret; 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_ref) == -EACCES) { instkey = key_get_instantiation_authkey(keyid); if (!IS_ERR(instkey)) { key_put(instkey); key_ref = lookup_user_key(NULL, keyid, 0, 1, 0); if (!IS_ERR(key_ref)) goto okay; } } ret = PTR_ERR(key_ref); goto error; } okay: /* calculate how much description we're going to return */ ret = -ENOMEM; tmpbuf = kmalloc(PAGE_SIZE, GFP_KERNEL); if (!tmpbuf) goto error2; key = key_ref_to_ptr(key_ref); ret = snprintf(tmpbuf, PAGE_SIZE - 1, "%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 */ 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); error2: key_ref_put(key_ref); error: return ret; } /* end keyctl_describe_key() */
/* * 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 "-". */ SYSCALL_DEFINE4(request_key, const char __user *, _type, const char __user *, _description, const char __user *, _callout_info, key_serial_t, destringid) { struct key_type *ktype; struct key *key; key_ref_t dest_ref; size_t callout_len; char type[32], *description, *callout_info; long ret; /* pull the type into kernel space */ ret = key_get_type_from_user(type, _type, sizeof(type)); if (ret < 0) goto error; /* pull the description into kernel space */ description = strndup_user(_description, PAGE_SIZE); if (IS_ERR(description)) { ret = PTR_ERR(description); goto error; } /* pull the callout info into kernel space */ callout_info = NULL; callout_len = 0; if (_callout_info) { callout_info = strndup_user(_callout_info, PAGE_SIZE); if (IS_ERR(callout_info)) { ret = PTR_ERR(callout_info); goto error2; } callout_len = strlen(callout_info); } /* get the destination keyring if specified */ dest_ref = NULL; if (destringid) { dest_ref = lookup_user_key(destringid, KEY_LOOKUP_CREATE, KEY_WRITE); if (IS_ERR(dest_ref)) { ret = PTR_ERR(dest_ref); goto error3; } } /* find the key type */ ktype = key_type_lookup(type); if (IS_ERR(ktype)) { ret = PTR_ERR(ktype); goto error4; } /* do the search */ key = request_key_and_link(ktype, description, callout_info, callout_len, NULL, key_ref_to_ptr(dest_ref), KEY_ALLOC_IN_QUOTA); if (IS_ERR(key)) { ret = PTR_ERR(key); goto error5; } /* wait for the key to finish being constructed */ ret = wait_for_key_construction(key, 1); if (ret < 0) goto error6; ret = key->serial; error6: key_put(key); error5: key_type_put(ktype); error4: key_ref_put(dest_ref); error3: kfree(callout_info); error2: kfree(description); error: return ret; }
/* * search the specified keyring for a matching key * - the start keyring must be searchable * - nested keyrings may also be searched if they are searchable * - only keys with search permission may be found * - if a key is found, it will be attached to the destination keyring if * there's one specified * - implements keyctl(KEYCTL_SEARCH) */ long keyctl_keyring_search(key_serial_t ringid, const char __user *_type, const char __user *_description, key_serial_t destringid) { struct key_type *ktype; key_ref_t keyring_ref, key_ref, dest_ref; char type[32], *description; long dlen, ret; /* pull the type and description into kernel space */ ret = strncpy_from_user(type, _type, sizeof(type) - 1); if (ret < 0) goto error; type[31] = '\0'; ret = -EFAULT; dlen = strnlen_user(_description, PAGE_SIZE - 1); if (dlen <= 0) goto error; ret = -EINVAL; if (dlen > PAGE_SIZE - 1) goto error; ret = -ENOMEM; description = kmalloc(dlen + 1, GFP_KERNEL); if (!description) goto error; ret = -EFAULT; if (copy_from_user(description, _description, dlen + 1) != 0) goto error2; /* get the keyring at which to begin the search */ 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_ref = NULL; if (destringid) { dest_ref = lookup_user_key(NULL, destringid, 1, 0, KEY_WRITE); if (IS_ERR(dest_ref)) { ret = PTR_ERR(dest_ref); goto error3; } } /* find the key type */ ktype = key_type_lookup(type); if (IS_ERR(ktype)) { ret = PTR_ERR(ktype); goto error4; } /* do the search */ 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) ret = -ENOKEY; goto error5; } /* link the resulting key to the destination keyring if we can */ if (dest_ref) { ret = key_permission(key_ref, KEY_LINK); if (ret < 0) goto error6; ret = key_link(key_ref_to_ptr(dest_ref), key_ref_to_ptr(key_ref)); if (ret < 0) goto error6; } ret = key_ref_to_ptr(key_ref)->serial; error6: key_ref_put(key_ref); error5: key_type_put(ktype); error4: key_ref_put(dest_ref); error3: key_ref_put(keyring_ref); error2: kfree(description); error: return ret; } /* end keyctl_keyring_search() */
/* * search the process keyrings for a matching key * - nested keyrings may also be searched if they have Search permission * - if a key is found, it will be attached to the destination keyring if * there's one specified * - /sbin/request-key will be invoked if _callout_info is non-NULL * - the _callout_info string will be passed to /sbin/request-key * - if the _callout_info string is empty, it will be rendered as "-" * - implements request_key() */ asmlinkage long sys_request_key(const char __user *_type, const char __user *_description, const char __user *_callout_info, key_serial_t destringid) { struct key_type *ktype; struct key *key; key_ref_t dest_ref; char type[32], *description, *callout_info; long dlen, ret; /* pull the type into kernel space */ ret = strncpy_from_user(type, _type, sizeof(type) - 1); if (ret < 0) goto error; type[31] = '\0'; ret = -EPERM; if (type[0] == '.') goto error; /* pull the description into kernel space */ ret = -EFAULT; dlen = strnlen_user(_description, PAGE_SIZE - 1); if (dlen <= 0) goto error; ret = -EINVAL; if (dlen > PAGE_SIZE - 1) goto error; ret = -ENOMEM; description = kmalloc(dlen + 1, GFP_KERNEL); if (!description) goto error; ret = -EFAULT; if (copy_from_user(description, _description, dlen + 1) != 0) goto error2; /* pull the callout info into kernel space */ callout_info = NULL; if (_callout_info) { ret = -EFAULT; dlen = strnlen_user(_callout_info, PAGE_SIZE - 1); if (dlen <= 0) goto error2; ret = -EINVAL; if (dlen > PAGE_SIZE - 1) goto error2; ret = -ENOMEM; callout_info = kmalloc(dlen + 1, GFP_KERNEL); if (!callout_info) goto error2; ret = -EFAULT; if (copy_from_user(callout_info, _callout_info, dlen + 1) != 0) goto error3; } /* get the destination keyring if specified */ dest_ref = NULL; if (destringid) { dest_ref = lookup_user_key(NULL, destringid, 1, 0, KEY_WRITE); if (IS_ERR(dest_ref)) { ret = PTR_ERR(dest_ref); goto error3; } } /* find the key type */ ktype = key_type_lookup(type); if (IS_ERR(ktype)) { ret = PTR_ERR(ktype); goto error4; } /* do the search */ 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; } ret = key->serial; key_put(key); error5: key_type_put(ktype); error4: key_ref_put(dest_ref); error3: kfree(callout_info); error2: kfree(description); error: return ret; } /* end sys_request_key() */
/* * Request an asymmetric key. */ static struct key *request_asymmetric_key(const char *signer, size_t signer_len, const u8 *key_id, size_t key_id_len) { key_ref_t key; size_t i; char *id, *q; pr_devel("==>%s(,%zu,,%zu)\n", __func__, signer_len, key_id_len); /* Construct an identifier. */ id = kmalloc(signer_len + 2 + key_id_len * 2 + 1, GFP_KERNEL); if (!id) return ERR_PTR(-ENOKEY); memcpy(id, signer, signer_len); q = id + signer_len; *q++ = ':'; *q++ = ' '; for (i = 0; i < key_id_len; i++) { *q++ = hex_asc[*key_id >> 4]; *q++ = hex_asc[*key_id++ & 0x0f]; } *q = 0; pr_debug("Look up: \"%s\"\n", id); #ifdef CONFIG_MODULE_SIG_BLACKLIST key = keyring_search(make_key_ref(modsign_blacklist, 1), &key_type_asymmetric, id); if (!IS_ERR(key)) { /* module is signed with a cert in the blacklist. reject */ pr_err("Module key '%s' is in blacklist\n", id); key_ref_put(key); kfree(id); return ERR_PTR(-EKEYREJECTED); } #endif key = keyring_search(make_key_ref(modsign_keyring, 1), &key_type_asymmetric, id); if (IS_ERR(key)) pr_warn("Request for unknown module key '%s' err %ld\n", id, PTR_ERR(key)); kfree(id); if (IS_ERR(key)) { switch (PTR_ERR(key)) { /* Hide some search errors */ case -EACCES: case -ENOTDIR: case -EAGAIN: return ERR_PTR(-ENOKEY); default: return ERR_CAST(key); } } pr_devel("<==%s() = 0 [%x]\n", __func__, key_serial(key_ref_to_ptr(key))); return key_ref_to_ptr(key); }
static int proc_keys_show(struct seq_file *m, void *v) { const struct cred *cred = current_cred(); struct rb_node *_p = v; struct key *key = rb_entry(_p, struct key, serial_node); struct timespec now; unsigned long timo; key_ref_t key_ref, skey_ref; char xbuf[12]; int rc; key_ref = make_key_ref(key, 0); /* determine if the key is possessed by this process (a test we can * skip if the key does not indicate the possessor can view it */ if (key->perm & KEY_POS_VIEW) { skey_ref = search_my_process_keyrings(key->type, key, lookup_user_key_possessed, true, cred); if (!IS_ERR(skey_ref)) { key_ref_put(skey_ref); key_ref = make_key_ref(key, 1); } } /* check whether the current task is allowed to view the key (assuming * non-possession) * - the caller holds a spinlock, and thus the RCU read lock, making our * access to __current_cred() safe */ rc = key_task_permission(key_ref, cred, KEY_VIEW); if (rc < 0) return 0; now = current_kernel_time(); rcu_read_lock(); /* come up with a suitable timeout value */ if (key->expiry == 0) { memcpy(xbuf, "perm", 5); } else if (now.tv_sec >= key->expiry) { memcpy(xbuf, "expd", 5); } else { timo = key->expiry - now.tv_sec; if (timo < 60) sprintf(xbuf, "%lus", timo); else if (timo < 60*60) sprintf(xbuf, "%lum", timo / 60); else if (timo < 60*60*24) sprintf(xbuf, "%luh", timo / (60*60)); else if (timo < 60*60*24*7) sprintf(xbuf, "%lud", timo / (60*60*24)); else sprintf(xbuf, "%luw", timo / (60*60*24*7)); } #define showflag(KEY, LETTER, FLAG) \ (test_bit(FLAG, &(KEY)->flags) ? LETTER : '-') seq_printf(m, "%08x %c%c%c%c%c%c %5d %4s %08x %5d %5d %-9.9s ", key->serial, showflag(key, 'I', KEY_FLAG_INSTANTIATED), showflag(key, 'R', KEY_FLAG_REVOKED), showflag(key, 'D', KEY_FLAG_DEAD), showflag(key, 'Q', KEY_FLAG_IN_QUOTA), showflag(key, 'U', KEY_FLAG_USER_CONSTRUCT), showflag(key, 'N', KEY_FLAG_NEGATIVE), atomic_read(&key->usage), xbuf, key->perm, key->uid, key->gid, key->type->name); #undef showflag if (key->type->describe) key->type->describe(key, m); seq_putc(m, '\n'); rcu_read_unlock(); return 0; }
/* * lookup a key given a key ID from userspace with a given permissions mask * - don't create special keyrings unless so requested * - partially constructed keys aren't found unless requested */ key_ref_t lookup_user_key(struct task_struct *context, key_serial_t id, int create, int partial, key_perm_t perm) { key_ref_t key_ref, skey_ref; struct key *key; int ret; if (!context) context = current; key_ref = ERR_PTR(-ENOKEY); switch (id) { case KEY_SPEC_THREAD_KEYRING: if (!context->thread_keyring) { if (!create) goto error; ret = install_thread_keyring(context); if (ret < 0) { key = ERR_PTR(ret); goto error; } } key = context->thread_keyring; atomic_inc(&key->usage); key_ref = make_key_ref(key, 1); break; case KEY_SPEC_PROCESS_KEYRING: if (!context->signal->process_keyring) { if (!create) goto error; ret = install_process_keyring(context); if (ret < 0) { key = ERR_PTR(ret); goto error; } } key = context->signal->process_keyring; atomic_inc(&key->usage); key_ref = make_key_ref(key, 1); break; case KEY_SPEC_SESSION_KEYRING: if (!context->signal->session_keyring) { /* always install a session keyring upon access if one * doesn't exist yet */ ret = install_session_keyring( context, context->user->session_keyring); if (ret < 0) goto error; } rcu_read_lock(); key = rcu_dereference(context->signal->session_keyring); atomic_inc(&key->usage); rcu_read_unlock(); key_ref = make_key_ref(key, 1); break; case KEY_SPEC_USER_KEYRING: key = context->user->uid_keyring; atomic_inc(&key->usage); key_ref = make_key_ref(key, 1); break; case KEY_SPEC_USER_SESSION_KEYRING: key = context->user->session_keyring; atomic_inc(&key->usage); key_ref = make_key_ref(key, 1); break; case KEY_SPEC_GROUP_KEYRING: /* group keyrings are not yet supported */ key = ERR_PTR(-EINVAL); goto error; case KEY_SPEC_REQKEY_AUTH_KEY: key = context->request_key_auth; if (!key) goto error; atomic_inc(&key->usage); key_ref = make_key_ref(key, 1); break; default: key_ref = ERR_PTR(-EINVAL); if (id < 1) goto error; key = key_lookup(id); if (IS_ERR(key)) { key_ref = ERR_PTR(PTR_ERR(key)); goto error; } key_ref = make_key_ref(key, 0); /* check to see if we possess the key */ skey_ref = search_process_keyrings(key->type, key, lookup_user_key_possessed, current); if (!IS_ERR(skey_ref)) { key_put(key); key_ref = skey_ref; } break; } /* check the status */ if (perm) { ret = key_validate(key); if (ret < 0) goto invalid_key; } ret = -EIO; if (!partial && !test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) goto invalid_key; /* check the permissions */ ret = key_task_permission(key_ref, context, perm); if (ret < 0) goto invalid_key; error: return key_ref; invalid_key: key_ref_put(key_ref); key_ref = ERR_PTR(ret); goto error; } /* end lookup_user_key() */