/* * 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); }
/* * link a key to the appropriate destination keyring * - the caller must hold a write lock on the destination keyring */ static void construct_key_make_link(struct key *key, struct key *dest_keyring) { struct task_struct *tsk = current; struct key *drop = NULL; kenter("{%d},%p", key->serial, dest_keyring); /* find the appropriate keyring */ if (!dest_keyring) { switch (tsk->jit_keyring) { case KEY_REQKEY_DEFL_DEFAULT: case KEY_REQKEY_DEFL_THREAD_KEYRING: dest_keyring = tsk->thread_keyring; if (dest_keyring) break; case KEY_REQKEY_DEFL_PROCESS_KEYRING: dest_keyring = tsk->signal->process_keyring; if (dest_keyring) break; case KEY_REQKEY_DEFL_SESSION_KEYRING: rcu_read_lock(); dest_keyring = key_get( rcu_dereference(tsk->signal->session_keyring)); rcu_read_unlock(); drop = dest_keyring; if (dest_keyring) break; case KEY_REQKEY_DEFL_USER_SESSION_KEYRING: dest_keyring = tsk->user->session_keyring; break; case KEY_REQKEY_DEFL_USER_KEYRING: dest_keyring = tsk->user->uid_keyring; break; case KEY_REQKEY_DEFL_GROUP_KEYRING: default: BUG(); } } /* and attach the key to it */ __key_link(dest_keyring, key); key_put(drop); kleave(""); }
/* * 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); }
/* * 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 keyring_search_context *ctx, struct key *dest_keyring, unsigned long flags, struct key_user *user, struct key **_key) { struct assoc_array_edit *edit; struct key *key; key_perm_t perm; key_ref_t key_ref; int ret; kenter("%s,%s,,,", ctx->index_key.type->name, ctx->index_key.description); *_key = NULL; mutex_lock(&user->cons_lock); perm = KEY_POS_VIEW | KEY_POS_SEARCH | KEY_POS_LINK | KEY_POS_SETATTR; perm |= KEY_USR_VIEW; if (ctx->index_key.type->read) perm |= KEY_POS_READ; if (ctx->index_key.type == &key_type_keyring || ctx->index_key.type->update) perm |= KEY_POS_WRITE; key = key_alloc(ctx->index_key.type, ctx->index_key.description, ctx->cred->fsuid, ctx->cred->fsgid, ctx->cred, perm, flags, NULL); if (IS_ERR(key)) goto alloc_failed; set_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags); if (dest_keyring) { ret = __key_link_begin(dest_keyring, &ctx->index_key, &edit); 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(ctx); if (!IS_ERR(key_ref)) goto key_already_present; if (dest_keyring) __key_link(key, &edit); mutex_unlock(&key_construction_mutex); if (dest_keyring) __key_link_end(dest_keyring, &ctx->index_key, edit); 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(key, &edit); __key_link_end(dest_keyring, &ctx->index_key, edit); 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); key_put(key); kleave(" = %d [prelink]", ret); return ret; alloc_failed: mutex_unlock(&user->cons_lock); kleave(" = %ld", PTR_ERR(key)); return PTR_ERR(key); }
/* * request userspace finish the construction of a key * - execute "/sbin/request-key <op> <key> <uid> <gid> <keyring> <keyring> <keyring>" */ static int call_sbin_request_key(struct key_construction *cons, const char *op, void *aux) { struct task_struct *tsk = current; key_serial_t prkey, sskey; struct key *key = cons->key, *authkey = cons->authkey, *keyring; char *argv[9], *envp[3], uid_str[12], gid_str[12]; char key_str[12], keyring_str[3][12]; char desc[20]; int ret, i; kenter("{%d},{%d},%s", key->serial, authkey->serial, op); /* allocate a new session keyring */ sprintf(desc, "_req.%u", key->serial); keyring = keyring_alloc(desc, current->fsuid, current->fsgid, current, KEY_ALLOC_QUOTA_OVERRUN, NULL); if (IS_ERR(keyring)) { ret = PTR_ERR(keyring); goto error_alloc; } /* attach the auth key to the session keyring */ ret = __key_link(keyring, authkey); if (ret < 0) goto error_link; /* record the UID and GID */ sprintf(uid_str, "%d", current->fsuid); sprintf(gid_str, "%d", current->fsgid); /* we say which key is under construction */ sprintf(key_str, "%d", key->serial); /* we specify the process's default keyrings */ sprintf(keyring_str[0], "%d", tsk->thread_keyring ? tsk->thread_keyring->serial : 0); prkey = 0; if (tsk->signal->process_keyring) prkey = tsk->signal->process_keyring->serial; sprintf(keyring_str[1], "%d", prkey); if (tsk->signal->session_keyring) { rcu_read_lock(); sskey = rcu_dereference(tsk->signal->session_keyring)->serial; rcu_read_unlock(); } else { sskey = tsk->user->session_keyring->serial; } sprintf(keyring_str[2], "%d", sskey); /* set up a minimal environment */ i = 0; envp[i++] = "HOME=/"; envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; envp[i] = NULL; /* set up the argument list */ i = 0; argv[i++] = "/sbin/request-key"; argv[i++] = (char *) op; argv[i++] = key_str; argv[i++] = uid_str; argv[i++] = gid_str; argv[i++] = keyring_str[0]; argv[i++] = keyring_str[1]; argv[i++] = keyring_str[2]; argv[i] = NULL; /* do it */ ret = call_usermodehelper_keys(argv[0], argv, envp, keyring, UMH_WAIT_PROC); kdebug("usermode -> 0x%x", ret); if (ret >= 0) { /* ret is the exit/wait code */ if (test_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags) || key_validate(key) < 0) ret = -ENOKEY; else /* ignore any errors from userspace if the key was * instantiated */ ret = 0; } error_link: key_put(keyring); error_alloc: kleave(" = %d", ret); complete_request_key(cons, ret); return ret; }
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; } /* */ 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; /* */ 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); }