/* * join the named keyring as the session keyring if possible, or attempt to * create a new one of that name if not * - if the name is NULL, an empty anonymous keyring is installed instead * - named session keyring joining is done with a semaphore held */ long join_session_keyring(const char *name) { struct task_struct *tsk = current; unsigned long flags; struct key *keyring; long ret; /* if no name is provided, install an anonymous keyring */ if (!name) { ret = install_session_keyring(tsk, NULL); if (ret < 0) goto error; spin_lock_irqsave(&tsk->sighand->siglock, flags); ret = tsk->signal->session_keyring->serial; spin_unlock_irqrestore(&tsk->sighand->siglock, flags); goto error; } /* allow the user to join or create a named keyring */ down(&key_session_sem); /* look for an existing keyring of this name */ keyring = find_keyring_by_name(name, 0); if (PTR_ERR(keyring) == -ENOKEY) { /* not found - try and create a new one */ keyring = keyring_alloc(name, tsk->uid, tsk->gid, 0, NULL); if (IS_ERR(keyring)) { ret = PTR_ERR(keyring); goto error; } } else if (IS_ERR(keyring)) { ret = PTR_ERR(keyring); goto error2; } /* we've got a keyring - now to install it */ ret = install_session_keyring(tsk, keyring); if (ret < 0) goto error2; ret = keyring->serial; key_put(keyring); error2: up(&key_session_sem); error: return ret; } /* end join_session_keyring() */
/* * join the named keyring as the session keyring if possible, or attempt to * create a new one of that name if not * - if the name is NULL, an empty anonymous keyring is installed instead * - named session keyring joining is done with a semaphore held */ long join_session_keyring(const char *name) { struct task_struct *tsk = current; struct key *keyring; long ret; /* if no name is provided, install an anonymous keyring */ if (!name) { ret = install_session_keyring(tsk, NULL); if (ret < 0) goto error; rcu_read_lock(); ret = rcu_dereference(tsk->signal->session_keyring)->serial; rcu_read_unlock(); goto error; } /* allow the user to join or create a named keyring */ mutex_lock(&key_session_mutex); /* look for an existing keyring of this name */ keyring = find_keyring_by_name(name, 0); if (PTR_ERR(keyring) == -ENOKEY) { /* not found - try and create a new one */ keyring = keyring_alloc(name, tsk->uid, tsk->gid, tsk, KEY_ALLOC_IN_QUOTA, NULL); if (IS_ERR(keyring)) { ret = PTR_ERR(keyring); goto error2; } } else if (IS_ERR(keyring)) { ret = PTR_ERR(keyring); goto error2; } /* we've got a keyring - now to install it */ ret = install_session_keyring(tsk, keyring); if (ret < 0) goto error2; ret = keyring->serial; key_put(keyring); error2: mutex_unlock(&key_session_mutex); error: return ret; } /* end join_session_keyring() */
/* * 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 */ struct key *lookup_user_key(key_serial_t id, int create, int partial, key_perm_t perm) { struct task_struct *tsk = current; unsigned long flags; struct key *key; int ret; key = ERR_PTR(-ENOKEY); switch (id) { case KEY_SPEC_THREAD_KEYRING: if (!tsk->thread_keyring) { if (!create) goto error; ret = install_thread_keyring(tsk); if (ret < 0) { key = ERR_PTR(ret); goto error; } } key = tsk->thread_keyring; atomic_inc(&key->usage); break; case KEY_SPEC_PROCESS_KEYRING: if (!tsk->signal->process_keyring) { if (!create) goto error; ret = install_process_keyring(tsk); if (ret < 0) { key = ERR_PTR(ret); goto error; } } key = tsk->signal->process_keyring; atomic_inc(&key->usage); break; case KEY_SPEC_SESSION_KEYRING: if (!tsk->signal->session_keyring) { /* always install a session keyring upon access if one * doesn't exist yet */ ret = install_session_keyring( tsk, tsk->user->session_keyring); if (ret < 0) goto error; } spin_lock_irqsave(&tsk->sighand->siglock, flags); key = tsk->signal->session_keyring; atomic_inc(&key->usage); spin_unlock_irqrestore(&tsk->sighand->siglock, flags); break; case KEY_SPEC_USER_KEYRING: key = tsk->user->uid_keyring; atomic_inc(&key->usage); break; case KEY_SPEC_USER_SESSION_KEYRING: key = tsk->user->session_keyring; atomic_inc(&key->usage); break; case KEY_SPEC_GROUP_KEYRING: /* group keyrings are not yet supported */ key = ERR_PTR(-EINVAL); goto error; default: key = ERR_PTR(-EINVAL); if (id < 1) goto error; key = key_lookup(id); if (IS_ERR(key)) goto error; break; } /* check the status and permissions */ if (perm) { ret = key_validate(key); if (ret < 0) goto invalid_key; } ret = -EIO; if (!partial && !(key->flags & KEY_FLAG_INSTANTIATED)) goto invalid_key; ret = -EACCES; if (!key_permission(key, perm)) goto invalid_key; error: return key; invalid_key: key_put(key); key = ERR_PTR(ret); goto error; } /* end lookup_user_key() */
/* * 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() */