process_keys.c revision 685bfd2c48bb3284d31e73ff3151c957d76deda9
169664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells/* Management of a process's keyrings 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 369664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells * Copyright (C) 2004-2005, 2008 Red Hat, Inc. All Rights Reserved. 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Written by David Howells (dhowells@redhat.com) 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * modify it under the terms of the GNU General Public License 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * as published by the Free Software Foundation; either version 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2 of the License, or (at your option) any later version. 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sched.h> 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/keyctl.h> 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/fs.h> 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/err.h> 18bb0030797f55c9996ea1cebd16b65750ceb7e4fdIngo Molnar#include <linux/mutex.h> 19ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells#include <linux/security.h> 201d1e97562e5e2ac60fb7b25437ba619f95f67fabSerge E. Hallyn#include <linux/user_namespace.h> 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h> 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "internal.h" 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* session keyring create vs join semaphore */ 25bb0030797f55c9996ea1cebd16b65750ceb7e4fdIngo Molnarstatic DEFINE_MUTEX(key_session_mutex); 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2769664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells/* user keyring creation semaphore */ 2869664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howellsstatic DEFINE_MUTEX(key_user_keyring_mutex); 2969664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* the root user's tracking struct */ 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct key_user root_key_user = { 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .usage = ATOMIC_INIT(3), 3376181c134f87479fa13bf2548ddf2999055d34d4David Howells .cons_lock = __MUTEX_INITIALIZER(root_key_user.cons_lock), 346cfd76a26d9fe2ba54b9d496a48c1d9285e5c5edPeter Zijlstra .lock = __SPIN_LOCK_UNLOCKED(root_key_user.lock), 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .nkeys = ATOMIC_INIT(2), 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .nikeys = ATOMIC_INIT(2), 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .uid = 0, 381d1e97562e5e2ac60fb7b25437ba619f95f67fabSerge E. Hallyn .user_ns = &init_user_ns, 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*****************************************************************************/ 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4369664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells * install user and user session keyrings for a particular UID 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 458bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howellsint install_user_keyrings(void) 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 47d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells struct user_struct *user; 48d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells const struct cred *cred; 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct key *uid_keyring, *session_keyring; 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char buf[20]; 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 53d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells cred = current_cred(); 54d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells user = cred->user; 55d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells 5669664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells kenter("%p{%u}", user, user->uid); 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5869664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells if (user->uid_keyring) { 5969664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells kleave(" = 0 [exist]"); 6069664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells return 0; 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6369664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells mutex_lock(&key_user_keyring_mutex); 6469664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells ret = 0; 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6669664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells if (!user->uid_keyring) { 6769664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells /* get the UID-specific keyring 6869664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells * - there may be one in existence already as it may have been 6969664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells * pinned by a session, but the user_struct pointing to it 7069664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells * may have been destroyed by setuid */ 7169664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells sprintf(buf, "_uid.%u", user->uid); 7269664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells 7369664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells uid_keyring = find_keyring_by_name(buf, true); 7469664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells if (IS_ERR(uid_keyring)) { 7569664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, 76d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells cred, KEY_ALLOC_IN_QUOTA, 7769664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells NULL); 7869664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells if (IS_ERR(uid_keyring)) { 7969664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells ret = PTR_ERR(uid_keyring); 8069664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells goto error; 8169664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells } 8269664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells } 8369664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells 8469664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells /* get a default session keyring (which might also exist 8569664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells * already) */ 8669664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells sprintf(buf, "_uid_ses.%u", user->uid); 8769664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells 8869664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells session_keyring = find_keyring_by_name(buf, true); 8969664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells if (IS_ERR(session_keyring)) { 9069664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells session_keyring = 9169664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells keyring_alloc(buf, user->uid, (gid_t) -1, 92d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells cred, KEY_ALLOC_IN_QUOTA, NULL); 9369664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells if (IS_ERR(session_keyring)) { 9469664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells ret = PTR_ERR(session_keyring); 9569664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells goto error_release; 9669664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells } 9769664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells 9869664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells /* we install a link from the user session keyring to 9969664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells * the user keyring */ 10069664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells ret = key_link(session_keyring, uid_keyring); 10169664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells if (ret < 0) 10269664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells goto error_release_both; 10369664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells } 10469664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells 10569664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells /* install the keyrings */ 10669664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells user->uid_keyring = uid_keyring; 10769664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells user->session_keyring = session_keyring; 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11069664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells mutex_unlock(&key_user_keyring_mutex); 11169664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells kleave(" = 0"); 11269664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells return 0; 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11469664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howellserror_release_both: 11569664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells key_put(session_keyring); 11669664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howellserror_release: 11769664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells key_put(uid_keyring); 118664cceb0093b755739e56572b836a99104ee8a75David Howellserror: 11969664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells mutex_unlock(&key_user_keyring_mutex); 12069664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells kleave(" = %d", ret); 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 12269664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells} 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 125d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells * install a fresh thread keyring directly to new credentials 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 127d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howellsint install_thread_keyring_to_cred(struct cred *new) 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 129d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells struct key *keyring; 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 131d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells keyring = keyring_alloc("_tid", new->uid, new->gid, new, 132d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells KEY_ALLOC_QUOTA_OVERRUN, NULL); 133d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells if (IS_ERR(keyring)) 134d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells return PTR_ERR(keyring); 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 136d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells new->thread_keyring = keyring; 137d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells return 0; 138d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells} 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * install a fresh thread keyring, discarding the old one 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 143d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howellsstatic int install_thread_keyring(void) 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 145d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells struct cred *new; 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 148d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells new = prepare_creds(); 149d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells if (!new) 150d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells return -ENOMEM; 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 152d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells BUG_ON(new->thread_keyring); 153d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells 154d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells ret = install_thread_keyring_to_cred(new); 155d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells if (ret < 0) { 156d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells abort_creds(new); 157d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells return ret; 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 160d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells return commit_creds(new); 161d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells} 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 163d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells/* 164d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells * install a process keyring directly to a credentials struct 165d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells * - returns -EEXIST if there was already a process keyring, 0 if one installed, 166d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells * and other -ve on any other error 167d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells */ 168d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howellsint install_process_keyring_to_cred(struct cred *new) 169d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells{ 170d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells struct key *keyring; 171d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells int ret; 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 173d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells if (new->tgcred->process_keyring) 174d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells return -EEXIST; 175d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells 176d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells keyring = keyring_alloc("_pid", new->uid, new->gid, 177d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells new, KEY_ALLOC_QUOTA_OVERRUN, NULL); 178d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells if (IS_ERR(keyring)) 179d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells return PTR_ERR(keyring); 180d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells 181d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells spin_lock_irq(&new->tgcred->lock); 182d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells if (!new->tgcred->process_keyring) { 183d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells new->tgcred->process_keyring = keyring; 184d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells keyring = NULL; 185d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells ret = 0; 186d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells } else { 187d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells ret = -EEXIST; 188d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells } 189d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells spin_unlock_irq(&new->tgcred->lock); 190d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells key_put(keyring); 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 192d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells} 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * make sure a process keyring is installed 196d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells * - we 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 198d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howellsstatic int install_process_keyring(void) 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 200d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells struct cred *new; 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 203d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells new = prepare_creds(); 204d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells if (!new) 205d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells return -ENOMEM; 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 207d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells ret = install_process_keyring_to_cred(new); 208d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells if (ret < 0) { 209d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells abort_creds(new); 210d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells return ret != -EEXIST ?: 0; 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 213d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells return commit_creds(new); 214d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells} 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 217d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells * install a session keyring directly to a credentials struct 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 219685bfd2c48bb3284d31e73ff3151c957d76deda9Oleg Nesterovint install_session_keyring_to_cred(struct cred *cred, struct key *keyring) 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2217e047ef5fe2d52e83020e856b1bf2556a6a2ce98David Howells unsigned long flags; 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct key *old; 2231a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells 2241a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells might_sleep(); 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* create an empty session keyring */ 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!keyring) { 2287e047ef5fe2d52e83020e856b1bf2556a6a2ce98David Howells flags = KEY_ALLOC_QUOTA_OVERRUN; 229d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells if (cred->tgcred->session_keyring) 2307e047ef5fe2d52e83020e856b1bf2556a6a2ce98David Howells flags = KEY_ALLOC_IN_QUOTA; 2317e047ef5fe2d52e83020e856b1bf2556a6a2ce98David Howells 232d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells keyring = keyring_alloc("_ses", cred->uid, cred->gid, 233d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells cred, flags, NULL); 2341a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells if (IS_ERR(keyring)) 2351a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells return PTR_ERR(keyring); 236d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells } else { 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atomic_inc(&keyring->usage); 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* install the keyring */ 241d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells spin_lock_irq(&cred->tgcred->lock); 242d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells old = cred->tgcred->session_keyring; 243d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells rcu_assign_pointer(cred->tgcred->session_keyring, keyring); 244d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells spin_unlock_irq(&cred->tgcred->lock); 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2461a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells /* we're using RCU on the pointer, but there's no point synchronising 2471a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells * on it if it didn't previously point to anything */ 2481a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells if (old) { 2491a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells synchronize_rcu(); 2501a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells key_put(old); 2511a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells } 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2531a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells return 0; 254d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells} 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 257d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells * install a session keyring, discarding the old one 258d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells * - if a keyring is not supplied, an empty one is invented 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 260d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howellsstatic int install_session_keyring(struct key *keyring) 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 262d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells struct cred *new; 263d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells int ret; 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 265d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells new = prepare_creds(); 266d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells if (!new) 267d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells return -ENOMEM; 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 269d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells ret = install_session_keyring_to_cred(new, NULL); 270d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells if (ret < 0) { 271d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells abort_creds(new); 272d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells return ret; 273d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells } 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 275d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells return commit_creds(new); 276d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells} 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*****************************************************************************/ 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the filesystem user ID changed 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid key_fsuid_changed(struct task_struct *tsk) 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* update the ownership of the thread keyring */ 285b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells BUG_ON(!tsk->cred); 286b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells if (tsk->cred->thread_keyring) { 287b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells down_write(&tsk->cred->thread_keyring->sem); 288b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells tsk->cred->thread_keyring->uid = tsk->cred->fsuid; 289b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells up_write(&tsk->cred->thread_keyring->sem); 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* end key_fsuid_changed() */ 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*****************************************************************************/ 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the filesystem group ID changed 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid key_fsgid_changed(struct task_struct *tsk) 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* update the ownership of the thread keyring */ 301b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells BUG_ON(!tsk->cred); 302b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells if (tsk->cred->thread_keyring) { 303b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells down_write(&tsk->cred->thread_keyring->sem); 304b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells tsk->cred->thread_keyring->gid = tsk->cred->fsgid; 305b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells up_write(&tsk->cred->thread_keyring->sem); 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* end key_fsgid_changed() */ 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*****************************************************************************/ 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * search the process keyrings for the first matching key 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - we use the supplied match function to see if the description (or other 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * feature of interest) matches 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - we return -EAGAIN if we didn't find any matching key 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - we return -ENOKEY if we found only negative matching keys 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 318664cceb0093b755739e56572b836a99104ee8a75David Howellskey_ref_t search_process_keyrings(struct key_type *type, 319664cceb0093b755739e56572b836a99104ee8a75David Howells const void *description, 320664cceb0093b755739e56572b836a99104ee8a75David Howells key_match_func_t match, 321d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells const struct cred *cred) 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3233e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells struct request_key_auth *rka; 324b5f545c880a2a47947ba2118b2509644ab7a2969David Howells key_ref_t key_ref, ret, err; 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 32604c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells might_sleep(); 32704c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* we want to return -EAGAIN or -ENOKEY if any of the keyrings were 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * searchable, but we failed to find a key or we found a negative key; 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * otherwise we want to return a sample error (probably -EACCES) if 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * none of the keyrings were searchable 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * in terms of priority: success > -ENOKEY > -EAGAIN > other error 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 335664cceb0093b755739e56572b836a99104ee8a75David Howells key_ref = NULL; 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = NULL; 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = ERR_PTR(-EAGAIN); 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* search the thread keyring first */ 340c69e8d9c01db2adc503464993c358901c9af9de4David Howells if (cred->thread_keyring) { 341664cceb0093b755739e56572b836a99104ee8a75David Howells key_ref = keyring_search_aux( 342c69e8d9c01db2adc503464993c358901c9af9de4David Howells make_key_ref(cred->thread_keyring, 1), 343d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells cred, type, description, match); 344664cceb0093b755739e56572b836a99104ee8a75David Howells if (!IS_ERR(key_ref)) 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto found; 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 347664cceb0093b755739e56572b836a99104ee8a75David Howells switch (PTR_ERR(key_ref)) { 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case -EAGAIN: /* no key */ 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret) 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case -ENOKEY: /* negative key */ 352664cceb0093b755739e56572b836a99104ee8a75David Howells ret = key_ref; 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 355664cceb0093b755739e56572b836a99104ee8a75David Howells err = key_ref; 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* search the process keyring second */ 361bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells if (cred->tgcred->process_keyring) { 362664cceb0093b755739e56572b836a99104ee8a75David Howells key_ref = keyring_search_aux( 363bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells make_key_ref(cred->tgcred->process_keyring, 1), 364d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells cred, type, description, match); 365664cceb0093b755739e56572b836a99104ee8a75David Howells if (!IS_ERR(key_ref)) 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto found; 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 368664cceb0093b755739e56572b836a99104ee8a75David Howells switch (PTR_ERR(key_ref)) { 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case -EAGAIN: /* no key */ 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret) 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case -ENOKEY: /* negative key */ 373664cceb0093b755739e56572b836a99104ee8a75David Howells ret = key_ref; 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 376664cceb0093b755739e56572b836a99104ee8a75David Howells err = key_ref; 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3813e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells /* search the session keyring */ 382bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells if (cred->tgcred->session_keyring) { 3838589b4e00e352f983259140f25a262d973be6bc5David Howells rcu_read_lock(); 384664cceb0093b755739e56572b836a99104ee8a75David Howells key_ref = keyring_search_aux( 385664cceb0093b755739e56572b836a99104ee8a75David Howells make_key_ref(rcu_dereference( 386bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells cred->tgcred->session_keyring), 387664cceb0093b755739e56572b836a99104ee8a75David Howells 1), 388d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells cred, type, description, match); 3898589b4e00e352f983259140f25a262d973be6bc5David Howells rcu_read_unlock(); 3903e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells 391664cceb0093b755739e56572b836a99104ee8a75David Howells if (!IS_ERR(key_ref)) 3923e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells goto found; 3933e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells 394664cceb0093b755739e56572b836a99104ee8a75David Howells switch (PTR_ERR(key_ref)) { 3953e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells case -EAGAIN: /* no key */ 3963e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells if (ret) 3973e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells break; 3983e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells case -ENOKEY: /* negative key */ 399664cceb0093b755739e56572b836a99104ee8a75David Howells ret = key_ref; 4003e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells break; 4013e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells default: 402664cceb0093b755739e56572b836a99104ee8a75David Howells err = key_ref; 4033e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells break; 4043e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells } 405b5f545c880a2a47947ba2118b2509644ab7a2969David Howells } 406b5f545c880a2a47947ba2118b2509644ab7a2969David Howells /* or search the user-session keyring */ 407c69e8d9c01db2adc503464993c358901c9af9de4David Howells else if (cred->user->session_keyring) { 408b5f545c880a2a47947ba2118b2509644ab7a2969David Howells key_ref = keyring_search_aux( 409c69e8d9c01db2adc503464993c358901c9af9de4David Howells make_key_ref(cred->user->session_keyring, 1), 410d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells cred, type, description, match); 411664cceb0093b755739e56572b836a99104ee8a75David Howells if (!IS_ERR(key_ref)) 4123e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells goto found; 4133e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells 414664cceb0093b755739e56572b836a99104ee8a75David Howells switch (PTR_ERR(key_ref)) { 4153e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells case -EAGAIN: /* no key */ 4163e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells if (ret) 4173e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells break; 4183e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells case -ENOKEY: /* negative key */ 419664cceb0093b755739e56572b836a99104ee8a75David Howells ret = key_ref; 4203e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells break; 4213e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells default: 422664cceb0093b755739e56572b836a99104ee8a75David Howells err = key_ref; 4233e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells break; 4243e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells } 4258589b4e00e352f983259140f25a262d973be6bc5David Howells } 426b5f545c880a2a47947ba2118b2509644ab7a2969David Howells 427b5f545c880a2a47947ba2118b2509644ab7a2969David Howells /* if this process has an instantiation authorisation key, then we also 428b5f545c880a2a47947ba2118b2509644ab7a2969David Howells * search the keyrings of the process mentioned there 429b5f545c880a2a47947ba2118b2509644ab7a2969David Howells * - we don't permit access to request_key auth keys via this method 430b5f545c880a2a47947ba2118b2509644ab7a2969David Howells */ 431c69e8d9c01db2adc503464993c358901c9af9de4David Howells if (cred->request_key_auth && 432d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells cred == current_cred() && 43304c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells type != &key_type_request_key_auth 434b5f545c880a2a47947ba2118b2509644ab7a2969David Howells ) { 43504c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells /* defend against the auth key being revoked */ 436c69e8d9c01db2adc503464993c358901c9af9de4David Howells down_read(&cred->request_key_auth->sem); 437b5f545c880a2a47947ba2118b2509644ab7a2969David Howells 438c69e8d9c01db2adc503464993c358901c9af9de4David Howells if (key_validate(cred->request_key_auth) == 0) { 439c69e8d9c01db2adc503464993c358901c9af9de4David Howells rka = cred->request_key_auth->payload.data; 440b5f545c880a2a47947ba2118b2509644ab7a2969David Howells 44104c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells key_ref = search_process_keyrings(type, description, 442d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells match, rka->cred); 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 444c69e8d9c01db2adc503464993c358901c9af9de4David Howells up_read(&cred->request_key_auth->sem); 44504c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells 44604c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells if (!IS_ERR(key_ref)) 44704c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells goto found; 44804c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells 44904c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells switch (PTR_ERR(key_ref)) { 45004c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells case -EAGAIN: /* no key */ 45104c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells if (ret) 45204c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells break; 45304c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells case -ENOKEY: /* negative key */ 45404c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells ret = key_ref; 4553e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells break; 45604c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells default: 45704c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells err = key_ref; 45804c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells break; 45904c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells } 46004c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells } else { 461c69e8d9c01db2adc503464993c358901c9af9de4David Howells up_read(&cred->request_key_auth->sem); 4623e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells } 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* no key - decide on the error we're going to go for */ 466664cceb0093b755739e56572b836a99104ee8a75David Howells key_ref = ret ? ret : err; 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4683e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howellsfound: 469664cceb0093b755739e56572b836a99104ee8a75David Howells return key_ref; 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* end search_process_keyrings() */ 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*****************************************************************************/ 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 475664cceb0093b755739e56572b836a99104ee8a75David Howells * see if the key we're looking at is the target key 476664cceb0093b755739e56572b836a99104ee8a75David Howells */ 477664cceb0093b755739e56572b836a99104ee8a75David Howellsstatic int lookup_user_key_possessed(const struct key *key, const void *target) 478664cceb0093b755739e56572b836a99104ee8a75David Howells{ 479664cceb0093b755739e56572b836a99104ee8a75David Howells return key == target; 480664cceb0093b755739e56572b836a99104ee8a75David Howells 481664cceb0093b755739e56572b836a99104ee8a75David Howells} /* end lookup_user_key_possessed() */ 482664cceb0093b755739e56572b836a99104ee8a75David Howells 483664cceb0093b755739e56572b836a99104ee8a75David Howells/*****************************************************************************/ 484664cceb0093b755739e56572b836a99104ee8a75David Howells/* 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * lookup a key given a key ID from userspace with a given permissions mask 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - don't create special keyrings unless so requested 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - partially constructed keys aren't found unless requested 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4895593122eec26b061cc0b6fbff32118f1aadf4a27David Howellskey_ref_t lookup_user_key(key_serial_t id, unsigned long lflags, 4908bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells key_perm_t perm) 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4928bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells struct request_key_auth *rka; 493d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells const struct cred *cred; 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct key *key; 495b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells key_ref_t key_ref, skey_ref; 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 498bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howellstry_again: 499bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells cred = get_current_cred(); 500664cceb0093b755739e56572b836a99104ee8a75David Howells key_ref = ERR_PTR(-ENOKEY); 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (id) { 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KEY_SPEC_THREAD_KEYRING: 504b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells if (!cred->thread_keyring) { 5055593122eec26b061cc0b6fbff32118f1aadf4a27David Howells if (!(lflags & KEY_LOOKUP_CREATE)) 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error; 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5088bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells ret = install_thread_keyring(); 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret < 0) { 5104d09ec0f705cf88a12add029c058b53f288cfaa2Dan Carpenter key_ref = ERR_PTR(ret); 5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error; 5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 513bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells goto reget_creds; 5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 516b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells key = cred->thread_keyring; 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atomic_inc(&key->usage); 518664cceb0093b755739e56572b836a99104ee8a75David Howells key_ref = make_key_ref(key, 1); 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KEY_SPEC_PROCESS_KEYRING: 522bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells if (!cred->tgcred->process_keyring) { 5235593122eec26b061cc0b6fbff32118f1aadf4a27David Howells if (!(lflags & KEY_LOOKUP_CREATE)) 5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error; 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5268bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells ret = install_process_keyring(); 5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret < 0) { 5284d09ec0f705cf88a12add029c058b53f288cfaa2Dan Carpenter key_ref = ERR_PTR(ret); 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error; 5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 531bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells goto reget_creds; 5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 534bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells key = cred->tgcred->process_keyring; 5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atomic_inc(&key->usage); 536664cceb0093b755739e56572b836a99104ee8a75David Howells key_ref = make_key_ref(key, 1); 5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KEY_SPEC_SESSION_KEYRING: 540bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells if (!cred->tgcred->session_keyring) { 5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* always install a session keyring upon access if one 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * doesn't exist yet */ 5438bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells ret = install_user_keyrings(); 54469664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells if (ret < 0) 54569664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells goto error; 546b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells ret = install_session_keyring( 547b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells cred->user->session_keyring); 548d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret < 0) 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error; 551bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells goto reget_creds; 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5543e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells rcu_read_lock(); 555bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells key = rcu_dereference(cred->tgcred->session_keyring); 5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atomic_inc(&key->usage); 5573e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells rcu_read_unlock(); 558664cceb0093b755739e56572b836a99104ee8a75David Howells key_ref = make_key_ref(key, 1); 5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KEY_SPEC_USER_KEYRING: 562b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells if (!cred->user->uid_keyring) { 5638bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells ret = install_user_keyrings(); 56469664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells if (ret < 0) 56569664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells goto error; 56669664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells } 56769664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells 568b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells key = cred->user->uid_keyring; 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atomic_inc(&key->usage); 570664cceb0093b755739e56572b836a99104ee8a75David Howells key_ref = make_key_ref(key, 1); 5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KEY_SPEC_USER_SESSION_KEYRING: 574b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells if (!cred->user->session_keyring) { 5758bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells ret = install_user_keyrings(); 57669664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells if (ret < 0) 57769664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells goto error; 57869664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells } 57969664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells 580b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells key = cred->user->session_keyring; 5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atomic_inc(&key->usage); 582664cceb0093b755739e56572b836a99104ee8a75David Howells key_ref = make_key_ref(key, 1); 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KEY_SPEC_GROUP_KEYRING: 5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* group keyrings are not yet supported */ 5874d09ec0f705cf88a12add029c058b53f288cfaa2Dan Carpenter key_ref = ERR_PTR(-EINVAL); 5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error; 5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 590b5f545c880a2a47947ba2118b2509644ab7a2969David Howells case KEY_SPEC_REQKEY_AUTH_KEY: 591b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells key = cred->request_key_auth; 592b5f545c880a2a47947ba2118b2509644ab7a2969David Howells if (!key) 593b5f545c880a2a47947ba2118b2509644ab7a2969David Howells goto error; 594b5f545c880a2a47947ba2118b2509644ab7a2969David Howells 595b5f545c880a2a47947ba2118b2509644ab7a2969David Howells atomic_inc(&key->usage); 596b5f545c880a2a47947ba2118b2509644ab7a2969David Howells key_ref = make_key_ref(key, 1); 597b5f545c880a2a47947ba2118b2509644ab7a2969David Howells break; 598b5f545c880a2a47947ba2118b2509644ab7a2969David Howells 5998bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells case KEY_SPEC_REQUESTOR_KEYRING: 600b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells if (!cred->request_key_auth) 6018bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells goto error; 6028bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells 603b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells down_read(&cred->request_key_auth->sem); 604b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells if (cred->request_key_auth->flags & KEY_FLAG_REVOKED) { 6058bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells key_ref = ERR_PTR(-EKEYREVOKED); 6068bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells key = NULL; 6078bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells } else { 608b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells rka = cred->request_key_auth->payload.data; 6098bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells key = rka->dest_keyring; 6108bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells atomic_inc(&key->usage); 6118bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells } 612b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells up_read(&cred->request_key_auth->sem); 6138bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells if (!key) 6148bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells goto error; 6158bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells key_ref = make_key_ref(key, 1); 6168bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells break; 6178bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells 6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 619664cceb0093b755739e56572b836a99104ee8a75David Howells key_ref = ERR_PTR(-EINVAL); 6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (id < 1) 6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error; 6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds key = key_lookup(id); 624664cceb0093b755739e56572b836a99104ee8a75David Howells if (IS_ERR(key)) { 625e231c2ee64eb1c5cd3c63c31da9dac7d888dcf7fDavid Howells key_ref = ERR_CAST(key); 6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error; 627664cceb0093b755739e56572b836a99104ee8a75David Howells } 628664cceb0093b755739e56572b836a99104ee8a75David Howells 629664cceb0093b755739e56572b836a99104ee8a75David Howells key_ref = make_key_ref(key, 0); 630664cceb0093b755739e56572b836a99104ee8a75David Howells 631664cceb0093b755739e56572b836a99104ee8a75David Howells /* check to see if we possess the key */ 632664cceb0093b755739e56572b836a99104ee8a75David Howells skey_ref = search_process_keyrings(key->type, key, 633664cceb0093b755739e56572b836a99104ee8a75David Howells lookup_user_key_possessed, 634d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells cred); 635664cceb0093b755739e56572b836a99104ee8a75David Howells 636664cceb0093b755739e56572b836a99104ee8a75David Howells if (!IS_ERR(skey_ref)) { 637664cceb0093b755739e56572b836a99104ee8a75David Howells key_put(key); 638664cceb0093b755739e56572b836a99104ee8a75David Howells key_ref = skey_ref; 639664cceb0093b755739e56572b836a99104ee8a75David Howells } 640664cceb0093b755739e56572b836a99104ee8a75David Howells 6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6445593122eec26b061cc0b6fbff32118f1aadf4a27David Howells /* unlink does not use the nominated key in any way, so can skip all 6455593122eec26b061cc0b6fbff32118f1aadf4a27David Howells * the permission checks as it is only concerned with the keyring */ 6465593122eec26b061cc0b6fbff32118f1aadf4a27David Howells if (lflags & KEY_LOOKUP_FOR_UNLINK) { 6475593122eec26b061cc0b6fbff32118f1aadf4a27David Howells ret = 0; 6485593122eec26b061cc0b6fbff32118f1aadf4a27David Howells goto error; 6495593122eec26b061cc0b6fbff32118f1aadf4a27David Howells } 6505593122eec26b061cc0b6fbff32118f1aadf4a27David Howells 6515593122eec26b061cc0b6fbff32118f1aadf4a27David Howells if (!(lflags & KEY_LOOKUP_PARTIAL)) { 65276181c134f87479fa13bf2548ddf2999055d34d4David Howells ret = wait_for_key_construction(key, true); 65376181c134f87479fa13bf2548ddf2999055d34d4David Howells switch (ret) { 65476181c134f87479fa13bf2548ddf2999055d34d4David Howells case -ERESTARTSYS: 65576181c134f87479fa13bf2548ddf2999055d34d4David Howells goto invalid_key; 65676181c134f87479fa13bf2548ddf2999055d34d4David Howells default: 65776181c134f87479fa13bf2548ddf2999055d34d4David Howells if (perm) 65876181c134f87479fa13bf2548ddf2999055d34d4David Howells goto invalid_key; 65976181c134f87479fa13bf2548ddf2999055d34d4David Howells case 0: 66076181c134f87479fa13bf2548ddf2999055d34d4David Howells break; 66176181c134f87479fa13bf2548ddf2999055d34d4David Howells } 66276181c134f87479fa13bf2548ddf2999055d34d4David Howells } else if (perm) { 6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = key_validate(key); 6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret < 0) 6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto invalid_key; 6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -EIO; 6695593122eec26b061cc0b6fbff32118f1aadf4a27David Howells if (!(lflags & KEY_LOOKUP_PARTIAL) && 6705593122eec26b061cc0b6fbff32118f1aadf4a27David Howells !test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) 6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto invalid_key; 6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6733e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells /* check the permissions */ 674d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells ret = key_task_permission(key_ref, cred, perm); 67529db9190634067c5a328ee5fcc2890251b836b4bDavid Howells if (ret < 0) 6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto invalid_key; 6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 678664cceb0093b755739e56572b836a99104ee8a75David Howellserror: 679bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells put_cred(cred); 680664cceb0093b755739e56572b836a99104ee8a75David Howells return key_ref; 6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 682664cceb0093b755739e56572b836a99104ee8a75David Howellsinvalid_key: 683664cceb0093b755739e56572b836a99104ee8a75David Howells key_ref_put(key_ref); 684664cceb0093b755739e56572b836a99104ee8a75David Howells key_ref = ERR_PTR(ret); 6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error; 6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 687bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells /* if we attempted to install a keyring, then it may have caused new 688bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells * creds to be installed */ 689bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howellsreget_creds: 690bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells put_cred(cred); 691bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells goto try_again; 692bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells 6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* end lookup_user_key() */ 6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*****************************************************************************/ 6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * join the named keyring as the session keyring if possible, or attempt to 6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * create a new one of that name if not 6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - if the name is NULL, an empty anonymous keyring is installed instead 7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - named session keyring joining is done with a semaphore held 7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldslong join_session_keyring(const char *name) 7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 704d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells const struct cred *old; 705d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells struct cred *new; 7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct key *keyring; 707d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells long ret, serial; 708d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells 709d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells /* only permit this if there's a single thread in the thread group - 710d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells * this avoids us having to adjust the creds on all threads and risking 711d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells * ENOMEM */ 7125bb459bb45d1ad3c177485dcf0af01580aa31125Oleg Nesterov if (!current_is_single_threaded()) 713d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells return -EMLINK; 714d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells 715d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells new = prepare_creds(); 716d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells if (!new) 717d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells return -ENOMEM; 718d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells old = current_cred(); 7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* if no name is provided, install an anonymous keyring */ 7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!name) { 722d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells ret = install_session_keyring_to_cred(new, NULL); 7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret < 0) 7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error; 7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 726d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells serial = new->tgcred->session_keyring->serial; 727d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells ret = commit_creds(new); 728d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells if (ret == 0) 729d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells ret = serial; 730d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells goto okay; 7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* allow the user to join or create a named keyring */ 734bb0030797f55c9996ea1cebd16b65750ceb7e4fdIngo Molnar mutex_lock(&key_session_mutex); 7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* look for an existing keyring of this name */ 73769664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells keyring = find_keyring_by_name(name, false); 7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (PTR_ERR(keyring) == -ENOKEY) { 7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* not found - try and create a new one */ 740d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells keyring = keyring_alloc(name, old->uid, old->gid, old, 7417e047ef5fe2d52e83020e856b1bf2556a6a2ce98David Howells KEY_ALLOC_IN_QUOTA, NULL); 7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (IS_ERR(keyring)) { 7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = PTR_ERR(keyring); 744bcf945d36fa0598f41ac4ad46a9dc43135460263David Howells goto error2; 7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 746d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells } else if (IS_ERR(keyring)) { 7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = PTR_ERR(keyring); 7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error2; 7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* we've got a keyring - now to install it */ 752d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells ret = install_session_keyring_to_cred(new, keyring); 7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret < 0) 7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error2; 7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 756d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells commit_creds(new); 757d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells mutex_unlock(&key_session_mutex); 758d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells 7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = keyring->serial; 7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds key_put(keyring); 761d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howellsokay: 762d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells return ret; 7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 764664cceb0093b755739e56572b836a99104ee8a75David Howellserror2: 765bb0030797f55c9996ea1cebd16b65750ceb7e4fdIngo Molnar mutex_unlock(&key_session_mutex); 766664cceb0093b755739e56572b836a99104ee8a75David Howellserror: 767d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells abort_creds(new); 7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 769d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells} 770ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells 771ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells/* 772ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells * Replace a process's session keyring when that process resumes userspace on 773ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells * behalf of one of its children 774ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells */ 775ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howellsvoid key_replace_session_keyring(void) 776ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells{ 777ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells const struct cred *old; 778ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells struct cred *new; 779ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells 780ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells if (!current->replacement_session_keyring) 781ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells return; 782ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells 783ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells write_lock_irq(&tasklist_lock); 784ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells new = current->replacement_session_keyring; 785ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells current->replacement_session_keyring = NULL; 786ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells write_unlock_irq(&tasklist_lock); 787ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells 788ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells if (!new) 789ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells return; 790ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells 791ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells old = current_cred(); 792ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells new-> uid = old-> uid; 793ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells new-> euid = old-> euid; 794ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells new-> suid = old-> suid; 795ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells new->fsuid = old->fsuid; 796ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells new-> gid = old-> gid; 797ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells new-> egid = old-> egid; 798ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells new-> sgid = old-> sgid; 799ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells new->fsgid = old->fsgid; 800ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells new->user = get_uid(old->user); 801ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells new->group_info = get_group_info(old->group_info); 802ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells 803ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells new->securebits = old->securebits; 804ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells new->cap_inheritable = old->cap_inheritable; 805ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells new->cap_permitted = old->cap_permitted; 806ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells new->cap_effective = old->cap_effective; 807ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells new->cap_bset = old->cap_bset; 808ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells 809ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells new->jit_keyring = old->jit_keyring; 810ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells new->thread_keyring = key_get(old->thread_keyring); 811ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells new->tgcred->tgid = old->tgcred->tgid; 812ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells new->tgcred->process_keyring = key_get(old->tgcred->process_keyring); 813ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells 814ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells security_transfer_creds(new, old); 815ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells 816ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells commit_creds(new); 817ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells} 818