/* * request a key (allow async construction) * - 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 */ struct key *request_key_async(struct key_type *type, const char *description, const char *callout_info) { return request_key_and_link(type, description, callout_info, NULL, NULL, KEY_ALLOC_IN_QUOTA); }
/* * request a key with auxiliary data for the upcaller (allow async construction) * - 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 */ struct key *request_key_async_with_auxdata(struct key_type *type, const char *description, const char *callout_info, void *aux) { return request_key_and_link(type, description, callout_info, aux, NULL, KEY_ALLOC_IN_QUOTA); }
/* * 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 * - waits uninterruptible for creation to complete */ struct key *request_key(struct key_type *type, const char *description, const char *callout_info) { struct key *key; int ret; key = request_key_and_link(type, description, callout_info, NULL, NULL, KEY_ALLOC_IN_QUOTA); if (!IS_ERR(key)) { ret = wait_for_key_construction(key, false); if (ret < 0) { key_put(key); return ERR_PTR(ret); } } return key; }
/** * request_key_with_auxdata - Request a key with auxiliary data for the upcaller * @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. * * As for request_key_and_link() except that it does not add the returned key * to a keyring if found and new keys are always allocated in the user's quota. * * Furthermore, it then works as wait_for_key_construction() to wait for the * completion of keys undergoing construction with a non-interruptible wait. */ struct key *request_key_with_auxdata(struct key_type *type, const char *description, const void *callout_info, size_t callout_len, void *aux) { struct key *key; int ret; key = request_key_and_link(type, description, callout_info, callout_len, aux, NULL, KEY_ALLOC_IN_QUOTA); if (!IS_ERR(key)) { ret = wait_for_key_construction(key, false); if (ret < 0) { key_put(key); return ERR_PTR(ret); } } return 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 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() */