/* * 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; }
/* * 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); 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); }
/* * 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; }
/* * change the permission mask on a key * - the keyring owned by the changer * - implements keyctl(KEYCTL_SETPERM) */ 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_POS_ALL | KEY_USR_ALL | KEY_GRP_ALL | KEY_OTH_ALL)) goto error; 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); /* if we're not the sysadmin, we can only change a key that we own */ if (capable(CAP_SYS_ADMIN) || key->uid == current->fsuid) { key->perm = perm; ret = 0; } up_write(&key->sem); key_put(key); error: return ret; } /* end keyctl_setperm_key() */
/* * Search the current process's keyrings for the authorisation key for * instantiation of a key. */ struct key *key_get_instantiation_authkey(key_serial_t target_id) { char description[16]; struct keyring_search_context ctx = { .index_key.type = &key_type_request_key_auth, .index_key.description = description, .cred = current_cred(), .match_data.cmp = key_default_cmp, .match_data.raw_data = description, .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT, .flags = KEYRING_SEARCH_DO_STATE_CHECK, }; struct key *authkey; key_ref_t authkey_ref; sprintf(description, "%x", target_id); authkey_ref = search_process_keyrings(&ctx); if (IS_ERR(authkey_ref)) { authkey = ERR_CAST(authkey_ref); if (authkey == ERR_PTR(-EAGAIN)) authkey = ERR_PTR(-ENOKEY); goto error; } authkey = key_ref_to_ptr(authkey_ref); if (test_bit(KEY_FLAG_REVOKED, &authkey->flags)) { key_put(authkey); authkey = ERR_PTR(-EKEYREVOKED); } error: return authkey; }
/* * get the authorisation key for instantiation of a specific key if attached to * the current process's keyrings * - this key is inserted into a keyring and that is set as /sbin/request-key's * session keyring * - a target_id of zero specifies any valid token */ struct key *key_get_instantiation_authkey(key_serial_t target_id) { const struct cred *cred = current_cred(); struct key *authkey; key_ref_t authkey_ref; authkey_ref = search_process_keyrings( &key_type_request_key_auth, (void *) (unsigned long) target_id, key_get_instantiation_authkey_match, cred); if (IS_ERR(authkey_ref)) { authkey = ERR_CAST(authkey_ref); goto error; } authkey = key_ref_to_ptr(authkey_ref); if (test_bit(KEY_FLAG_REVOKED, &authkey->flags)) { key_put(authkey); authkey = ERR_PTR(-EKEYREVOKED); } error: return authkey; } /* end key_get_instantiation_authkey() */
/** * x509_request_asymmetric_key - Request a key by X.509 certificate params. * @keyring: The keys to search. * @kid: The key ID. * @partial: Use partial match if true, exact if false. * * Find a key in the given keyring by subject name and key ID. These might, * for instance, be the issuer name and the authority key ID of an X.509 * certificate that needs to be verified. */ struct key *x509_request_asymmetric_key(struct key *keyring, const struct asymmetric_key_id *kid, bool partial) { key_ref_t key; char *id, *p; /* Construct an identifier "id:<keyid>". */ p = id = kmalloc(2 + 1 + kid->len * 2 + 1, GFP_KERNEL); if (!id) return ERR_PTR(-ENOMEM); if (partial) { *p++ = 'i'; *p++ = 'd'; } else { *p++ = 'e'; *p++ = 'x'; } *p++ = ':'; p = bin2hex(p, kid->data, kid->len); *p = 0; pr_debug("Look up: \"%s\"\n", id); key = keyring_search(make_key_ref(keyring, 1), &key_type_asymmetric, id); if (IS_ERR(key)) pr_debug("Request for 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); }
/* * allocate a new key in under-construction state and attempt to link it in to * the requested place * - may return a key that's already under construction instead */ static int construct_alloc_key(struct key_type *type, const char *description, struct key *dest_keyring, unsigned long flags, struct key_user *user, struct key **_key) { const struct cred *cred = current_cred(); struct key *key; key_ref_t key_ref; kenter("%s,%s,,,", type->name, description); mutex_lock(&user->cons_lock); key = key_alloc(type, description, cred->fsuid, cred->fsgid, cred, KEY_POS_ALL, flags); if (IS_ERR(key)) goto alloc_failed; set_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags); down_write(&dest_keyring->sem); /* attach the key to the destination keyring under lock, but we do need * to do another check just in case someone beat us to it whilst we * waited for locks */ mutex_lock(&key_construction_mutex); key_ref = search_process_keyrings(type, description, type->match, cred); if (!IS_ERR(key_ref)) goto key_already_present; __key_link(dest_keyring, key); mutex_unlock(&key_construction_mutex); up_write(&dest_keyring->sem); mutex_unlock(&user->cons_lock); *_key = key; kleave(" = 0 [%d]", key_serial(key)); return 0; key_already_present: mutex_unlock(&key_construction_mutex); if (dest_keyring) up_write(&dest_keyring->sem); mutex_unlock(&user->cons_lock); key_put(key); *_key = key = key_ref_to_ptr(key_ref); kleave(" = -EINPROGRESS [%d]", key_serial(key)); return -EINPROGRESS; alloc_failed: mutex_unlock(&user->cons_lock); *_key = NULL; kleave(" = %ld", PTR_ERR(key)); return PTR_ERR(key); }
/* * Request an asymmetric key. */ static struct key *pkcs7_request_asymmetric_key( struct key *keyring, const char *signer, size_t signer_len, const char *authority, size_t auth_len) { key_ref_t key; char *id; kenter(",%zu,,%zu", signer_len, auth_len); /* Construct an identifier. */ id = kmalloc(signer_len + 2 + auth_len + 1, GFP_KERNEL); if (!id) return ERR_PTR(-ENOMEM); memcpy(id, signer, signer_len); id[signer_len + 0] = ':'; id[signer_len + 1] = ' '; memcpy(id + signer_len + 2, authority, auth_len); id[signer_len + 2 + auth_len] = 0; pr_debug("Look up: \"%s\"\n", id); key = keyring_search(make_key_ref(keyring, 1), &key_type_asymmetric, id); if (IS_ERR(key)) pr_debug("Request for 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); }
/** * x509_request_asymmetric_key - Request a key by X.509 certificate params. * @keyring: The keys to search. * @subject: The name of the subject to whom the key belongs. * @key_id: The subject key ID as a hex string. * * Find a key in the given keyring by subject name and key ID. These might, * for instance, be the issuer name and the authority key ID of an X.509 * certificate that needs to be verified. */ struct key *x509_request_asymmetric_key(struct key *keyring, const char *subject, const char *key_id) { key_ref_t key; size_t subject_len = strlen(subject), key_id_len = strlen(key_id); char *id; /* Construct an identifier "<subjname>:<keyid>". */ id = kmalloc(subject_len + 2 + key_id_len + 1, GFP_KERNEL); if (!id) return ERR_PTR(-ENOMEM); memcpy(id, subject, subject_len); id[subject_len + 0] = ':'; id[subject_len + 1] = ' '; memcpy(id + subject_len + 2, key_id, key_id_len); id[subject_len + 2 + key_id_len] = 0; pr_debug("Look up: \"%s\"\n", id); key = keyring_search(make_key_ref(keyring, 1), &key_type_asymmetric, id); if (IS_ERR(key)) pr_debug("Request for 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); }
/* * change the ownership of a key * - the keyring owned by the changer * - if the uid or gid is -1, then that parameter is not changed * - implements keyctl(KEYCTL_CHOWN) */ 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_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); if (!capable(CAP_SYS_ADMIN)) { /* only the sysadmin can chown a key to some other UID */ if (uid != (uid_t) -1 && key->uid != uid) goto no_access; /* 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)) goto no_access; } /* change the UID (have to update the quotas) */ if (uid != (uid_t) -1 && uid != key->uid) { /* don't support UID changing yet */ ret = -EOPNOTSUPP; goto no_access; } /* change the GID */ if (gid != (gid_t) -1) key->gid = gid; ret = 0; no_access: up_write(&key->sem); key_put(key); error: return ret; } /* end keyctl_chown_key() */
/* * Request an asymmetric key. */ static struct key *request_asymmetric_key(struct key *keyring, uint32_t keyid) { struct key *key; char name[12]; sprintf(name, "id:%08x", keyid); pr_debug("key search: \"%s\"\n", name); key = get_ima_blacklist_keyring(); if (key) { key_ref_t kref; kref = keyring_search(make_key_ref(key, 1), &key_type_asymmetric, name); if (!IS_ERR(kref)) { pr_err("Key '%s' is in ima_blacklist_keyring\n", name); return ERR_PTR(-EKEYREJECTED); } } if (keyring) { /* search in specific keyring */ key_ref_t kref; kref = keyring_search(make_key_ref(keyring, 1), &key_type_asymmetric, name); if (IS_ERR(kref)) key = ERR_CAST(kref); else key = key_ref_to_ptr(kref); } else { key = request_key(&key_type_asymmetric, name, NULL); } if (IS_ERR(key)) { pr_err_ratelimited("Request for unknown key '%s' err %ld\n", name, PTR_ERR(key)); switch (PTR_ERR(key)) { /* Hide some search errors */ case -EACCES: case -ENOTDIR: case -EAGAIN: return ERR_PTR(-ENOKEY); default: return key; } } pr_debug("%s() = 0 [%x]\n", __func__, key_serial(key)); return key; }
/* * read a user key's payload * - the keyring must be readable or the key must be searchable from the * process's keyrings * - 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 data in the key, * irrespective of how much we may have copied * - implements keyctl(KEYCTL_READ) */ long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen) { struct key *key; key_ref_t key_ref; long ret; /* find the key first */ key_ref = lookup_user_key(NULL, keyid, 0, 0, 0); if (IS_ERR(key_ref)) { 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_key: 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); } } error2: key_put(key); error: return ret; } /* end keyctl_read_key() */
/** * request_key_and_link - Request a key and cache it in a keyring. * @type: The type of key we want. * @description: The searchable description of the key. * @callout_info: The data to pass to the instantiation upcall (or NULL). * @callout_len: The length of callout_info. * @aux: Auxiliary data for the upcall. * @dest_keyring: Where to cache the key. * @flags: Flags to key_alloc(). * * A key matching the specified criteria is searched for in the process's * keyrings and returned with its usage count incremented if found. Otherwise, * if callout_info is not NULL, a key will be allocated and some service * (probably in userspace) will be asked to instantiate it. * * If successfully found or created, the key will be linked to the destination * keyring if one is provided. * * Returns a pointer to the key if successful; -EACCES, -ENOKEY, -EKEYREVOKED * or -EKEYEXPIRED if an inaccessible, negative, revoked or expired key was * found; -ENOKEY if no key was found and no @callout_info was given; -EDQUOT * if insufficient key quota was available to create a new key; or -ENOMEM if * insufficient memory was available. * * If the returned key was created, then it may still be under construction, * and wait_for_key_construction() should be used to wait for that to complete. */ struct key *request_key_and_link(struct key_type *type, const char *description, const void *callout_info, size_t callout_len, void *aux, struct key *dest_keyring, unsigned long flags) { const struct cred *cred = current_cred(); struct key *key; key_ref_t key_ref; int ret; kenter("%s,%s,%p,%zu,%p,%p,%lx", type->name, description, callout_info, callout_len, aux, dest_keyring, flags); /* search all the process keyrings for a key */ key_ref = search_process_keyrings(type, description, type->match, cred); if (!IS_ERR(key_ref)) { key = key_ref_to_ptr(key_ref); if (dest_keyring) { construct_get_dest_keyring(&dest_keyring); ret = key_link(dest_keyring, key); key_put(dest_keyring); if (ret < 0) { key_put(key); key = ERR_PTR(ret); goto error; } } } else if (PTR_ERR(key_ref) != -EAGAIN) { key = ERR_CAST(key_ref); } else { /* the search failed, but the keyrings were searchable, so we * should consult userspace if we can */ key = ERR_PTR(-ENOKEY); if (!callout_info) goto error; key = construct_key_and_link(type, description, callout_info, callout_len, aux, dest_keyring, flags); } error: kleave(" = %p", key); return key; }
/** * key_task_permission - Check a key can be used * @key_ref: The key to check. * @cred: The credentials to use. * @perm: The permissions to check for. * * Check to see whether permission is granted to use a key in the desired way, * but permit the security modules to override. * * The caller must hold either a ref on cred or must hold the RCU readlock. * * Returns 0 if successful, -EACCES if access is denied based on the * permissions bits or the LSM check. */ int key_task_permission(const key_ref_t key_ref, const struct cred *cred, unsigned perm) { struct key *key; key_perm_t kperm; int ret; key = key_ref_to_ptr(key_ref); /* use the second 8-bits of permissions for keys the caller owns */ if (uid_eq(key->uid, cred->fsuid)) { kperm = key->perm >> 16; goto use_these_perms; }
/* * check to see whether permission is granted to use a key in the desired way, * but permit the security modules to override */ int key_task_permission(const key_ref_t key_ref, struct task_struct *context, key_perm_t perm) { struct key *key; key_perm_t kperm; int ret; key = key_ref_to_ptr(key_ref); /* use the second 8-bits of permissions for keys the caller owns */ if (key->uid == context->fsuid) { kperm = key->perm >> 16; goto use_these_perms; }
/* * Load the compiled-in keys */ static __init int load_module_signing_keys(void) { key_ref_t key; const u8 *p, *end; size_t plen; pr_notice("Loading module verification certificates\n"); end = modsign_certificate_list_end; p = modsign_certificate_list; 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(modsign_keyring, 1), "asymmetric", NULL, p, plen, (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_VIEW, KEY_ALLOC_NOT_IN_QUOTA); if (IS_ERR(key)) pr_err("MODSIGN: Problem loading in-kernel X.509 certificate (%ld)\n", PTR_ERR(key)); else pr_notice("MODSIGN: Loaded cert '%s'\n", key_ref_to_ptr(key)->description); p += plen; } return 0; dodgy_cert: pr_err("MODSIGN: Problem parsing in-kernel X.509 certificate list\n"); return 0; }
/* * 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() */
static ssize_t dh_data_from_key(key_serial_t keyid, void **data) { struct key *key; key_ref_t key_ref; long status; ssize_t ret; key_ref = lookup_user_key(keyid, 0, KEY_NEED_READ); if (IS_ERR(key_ref)) { ret = -ENOKEY; goto error; } key = key_ref_to_ptr(key_ref); ret = -EOPNOTSUPP; if (key->type == &key_type_user) { down_read(&key->sem); status = key_validate(key); if (status == 0) { const struct user_key_payload *payload; uint8_t *duplicate; payload = user_key_payload_locked(key); duplicate = kmemdup(payload->data, payload->datalen, GFP_KERNEL); if (duplicate) { *data = duplicate; ret = payload->datalen; } else { ret = -ENOMEM; } } up_read(&key->sem); } key_put(key); error: return ret; }
/* * 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() */
/* * request a key * - search the process's keyrings * - check the list of keys being created or updated * - call out to userspace for a key if supplementary info was provided * - cache the key in an appropriate keyring */ struct key *request_key_and_link(struct key_type *type, const char *description, const char *callout_info, void *aux, struct key *dest_keyring, unsigned long flags) { struct key *key; key_ref_t key_ref; kenter("%s,%s,%s,%p,%p,%lx", type->name, description, callout_info, aux, dest_keyring, flags); /* search all the process keyrings for a key */ key_ref = search_process_keyrings(type, description, type->match, current); if (!IS_ERR(key_ref)) { key = key_ref_to_ptr(key_ref); } else if (PTR_ERR(key_ref) != -EAGAIN) { key = ERR_PTR(PTR_ERR(key_ref)); } else { /* the search failed, but the keyrings were searchable, so we * should consult userspace if we can */ key = ERR_PTR(-ENOKEY); if (!callout_info) goto error; key = construct_key_and_link(type, description, callout_info, aux, dest_keyring, flags); } error: kleave(" = %p", key); return 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; }
/* * Allocate a new key in under-construction state and attempt to link it in to * the requested keyring. * * May return a key that's already under construction instead if there was a * race between two thread calling request_key(). */ static int construct_alloc_key(struct key_type *type, const char *description, struct key *dest_keyring, unsigned long flags, struct key_user *user, struct key **_key) { const struct cred *cred = current_cred(); unsigned long prealloc; struct key *key; key_ref_t key_ref; int ret; kenter("%s,%s,,,", type->name, description); *_key = NULL; mutex_lock(&user->cons_lock); key = key_alloc(type, description, cred->fsuid, cred->fsgid, cred, KEY_POS_ALL, flags); if (IS_ERR(key)) goto alloc_failed; set_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags); if (dest_keyring) { ret = __key_link_begin(dest_keyring, type, description, &prealloc); if (ret < 0) goto link_prealloc_failed; } /* attach the key to the destination keyring under lock, but we do need * to do another check just in case someone beat us to it whilst we * waited for locks */ mutex_lock(&key_construction_mutex); key_ref = search_process_keyrings(type, description, type->match, cred); if (!IS_ERR(key_ref)) goto key_already_present; if (dest_keyring) __key_link(dest_keyring, key, &prealloc); mutex_unlock(&key_construction_mutex); if (dest_keyring) __key_link_end(dest_keyring, type, prealloc); mutex_unlock(&user->cons_lock); *_key = key; kleave(" = 0 [%d]", key_serial(key)); return 0; /* the key is now present - we tell the caller that we found it by * returning -EINPROGRESS */ key_already_present: key_put(key); mutex_unlock(&key_construction_mutex); key = key_ref_to_ptr(key_ref); if (dest_keyring) { ret = __key_link_check_live_key(dest_keyring, key); if (ret == 0) __key_link(dest_keyring, key, &prealloc); __key_link_end(dest_keyring, type, prealloc); if (ret < 0) goto link_check_failed; } mutex_unlock(&user->cons_lock); *_key = key; kleave(" = -EINPROGRESS [%d]", key_serial(key)); return -EINPROGRESS; link_check_failed: mutex_unlock(&user->cons_lock); key_put(key); kleave(" = %d [linkcheck]", ret); return ret; link_prealloc_failed: mutex_unlock(&user->cons_lock); kleave(" = %d [prelink]", ret); return ret; alloc_failed: mutex_unlock(&user->cons_lock); kleave(" = %ld", PTR_ERR(key)); return PTR_ERR(key); }
/** * x509_request_asymmetric_key - Request a key by X.509 certificate params. * @keyring: The keys to search. * @id: The issuer & serialNumber to look for or NULL. * @skid: The subjectKeyIdentifier to look for or NULL. * @partial: Use partial match if true, exact if false. * * Find a key in the given keyring by identifier. The preferred identifier is * the issuer + serialNumber and the fallback identifier is the * subjectKeyIdentifier. If both are given, the lookup is by the former, but * the latter must also match. */ struct key *x509_request_asymmetric_key(struct key *keyring, const struct asymmetric_key_id *id, const struct asymmetric_key_id *skid, bool partial) { struct key *key; key_ref_t ref; const char *lookup; char *req, *p; int len; if (id) { lookup = id->data; len = id->len; } else { lookup = skid->data; len = skid->len; } /* Construct an identifier "id:<keyid>". */ p = req = kmalloc(2 + 1 + len * 2 + 1, GFP_KERNEL); if (!req) return ERR_PTR(-ENOMEM); if (partial) { *p++ = 'i'; *p++ = 'd'; } else { *p++ = 'e'; *p++ = 'x'; } *p++ = ':'; p = bin2hex(p, lookup, len); *p = 0; pr_debug("Look up: \"%s\"\n", req); ref = keyring_search(make_key_ref(keyring, 1), &key_type_asymmetric, req); if (IS_ERR(ref)) pr_debug("Request for key '%s' err %ld\n", req, PTR_ERR(ref)); kfree(req); if (IS_ERR(ref)) { switch (PTR_ERR(ref)) { /* Hide some search errors */ case -EACCES: case -ENOTDIR: case -EAGAIN: return ERR_PTR(-ENOKEY); default: return ERR_CAST(ref); } } key = key_ref_to_ptr(ref); if (id && skid) { const struct asymmetric_key_ids *kids = asymmetric_key_ids(key); if (!kids->id[1]) { pr_debug("issuer+serial match, but expected SKID missing\n"); goto reject; } if (!asymmetric_key_id_same(skid, kids->id[1])) { pr_debug("issuer+serial match, but SKID does not\n"); goto reject; } } pr_devel("<==%s() = 0 [%x]\n", __func__, key_serial(key)); return key; reject: key_put(key); return ERR_PTR(-EKEYREJECTED); }
/** * request_key_and_link - Request a key and cache it in a keyring. * @type: The type of key we want. * @description: The searchable description of the key. * @callout_info: The data to pass to the instantiation upcall (or NULL). * @callout_len: The length of callout_info. * @aux: Auxiliary data for the upcall. * @dest_keyring: Where to cache the key. * @flags: Flags to key_alloc(). * * A key matching the specified criteria is searched for in the process's * keyrings and returned with its usage count incremented if found. Otherwise, * if callout_info is not NULL, a key will be allocated and some service * (probably in userspace) will be asked to instantiate it. * * If successfully found or created, the key will be linked to the destination * keyring if one is provided. * * Returns a pointer to the key if successful; -EACCES, -ENOKEY, -EKEYREVOKED * or -EKEYEXPIRED if an inaccessible, negative, revoked or expired key was * found; -ENOKEY if no key was found and no @callout_info was given; -EDQUOT * if insufficient key quota was available to create a new key; or -ENOMEM if * insufficient memory was available. * * If the returned key was created, then it may still be under construction, * and wait_for_key_construction() should be used to wait for that to complete. */ struct key *request_key_and_link(struct key_type *type, const char *description, const void *callout_info, size_t callout_len, void *aux, struct key *dest_keyring, unsigned long flags) { struct keyring_search_context ctx = { .index_key.type = type, .index_key.description = description, .cred = current_cred(), .match_data.cmp = key_default_cmp, .match_data.raw_data = description, .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT, .flags = (KEYRING_SEARCH_DO_STATE_CHECK | KEYRING_SEARCH_SKIP_EXPIRED), }; struct key *key; key_ref_t key_ref; int ret; kenter("%s,%s,%p,%zu,%p,%p,%lx", ctx.index_key.type->name, ctx.index_key.description, callout_info, callout_len, aux, dest_keyring, flags); if (type->match_preparse) { ret = type->match_preparse(&ctx.match_data); if (ret < 0) { key = ERR_PTR(ret); goto error; } } /* search all the process keyrings for a key */ key_ref = search_process_keyrings(&ctx); if (!IS_ERR(key_ref)) { key = key_ref_to_ptr(key_ref); if (dest_keyring) { construct_get_dest_keyring(&dest_keyring); ret = key_link(dest_keyring, key); key_put(dest_keyring); if (ret < 0) { key_put(key); key = ERR_PTR(ret); goto error_free; } } } else if (PTR_ERR(key_ref) != -EAGAIN) { key = ERR_CAST(key_ref); } else { /* the search failed, but the keyrings were searchable, so we * should consult userspace if we can */ key = ERR_PTR(-ENOKEY); if (!callout_info) goto error_free; key = construct_key_and_link(&ctx, callout_info, callout_len, aux, dest_keyring, flags); } error_free: if (type->match_free) type->match_free(&ctx.match_data); error: kleave(" = %p", key); return key; } /** * wait_for_key_construction - Wait for construction of a key to complete * @key: The key being waited for. * @intr: Whether to wait interruptibly. * * Wait for a key to finish being constructed. * * Returns 0 if successful; -ERESTARTSYS if the wait was interrupted; -ENOKEY * if the key was negated; or -EKEYREVOKED or -EKEYEXPIRED if the key was * revoked or expired. */ int wait_for_key_construction(struct key *key, bool intr) { int ret; ret = wait_on_bit(&key->flags, KEY_FLAG_USER_CONSTRUCT, intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE); if (ret) return -ERESTARTSYS; if (test_bit(KEY_FLAG_NEGATIVE, &key->flags)) { smp_rmb(); return key->reject_error; } return key_validate(key); }