process_keys.c revision 67d1214551e800f9fe7dc7c47a346d2df0fafed5
1973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells/* Manage 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 24973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells/* Session keyring create vs join semaphore */ 25bb0030797f55c9996ea1cebd16b65750ceb7e4fdIngo Molnarstatic DEFINE_MUTEX(key_session_mutex); 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells/* User keyring creation semaphore */ 2869664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howellsstatic DEFINE_MUTEX(key_user_keyring_mutex); 2969664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells 30973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells/* 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/* 42973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * Install the user and user session keyrings for the current process's UID. 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 448bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howellsint install_user_keyrings(void) 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 46d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells struct user_struct *user; 47d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells const struct cred *cred; 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct key *uid_keyring, *session_keyring; 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char buf[20]; 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 52d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells cred = current_cred(); 53d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells user = cred->user; 54d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells 5569664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells kenter("%p{%u}", user, user->uid); 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5769664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells if (user->uid_keyring) { 5869664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells kleave(" = 0 [exist]"); 5969664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells return 0; 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6269664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells mutex_lock(&key_user_keyring_mutex); 6369664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells ret = 0; 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6569664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells if (!user->uid_keyring) { 6669664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells /* get the UID-specific keyring 6769664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells * - there may be one in existence already as it may have been 6869664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells * pinned by a session, but the user_struct pointing to it 6969664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells * may have been destroyed by setuid */ 7069664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells sprintf(buf, "_uid.%u", user->uid); 7169664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells 7269664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells uid_keyring = find_keyring_by_name(buf, true); 7369664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells if (IS_ERR(uid_keyring)) { 7469664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, 75d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells cred, KEY_ALLOC_IN_QUOTA, 7669664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells NULL); 7769664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells if (IS_ERR(uid_keyring)) { 7869664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells ret = PTR_ERR(uid_keyring); 7969664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells goto error; 8069664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells } 8169664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells } 8269664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells 8369664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells /* get a default session keyring (which might also exist 8469664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells * already) */ 8569664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells sprintf(buf, "_uid_ses.%u", user->uid); 8669664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells 8769664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells session_keyring = find_keyring_by_name(buf, true); 8869664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells if (IS_ERR(session_keyring)) { 8969664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells session_keyring = 9069664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells keyring_alloc(buf, user->uid, (gid_t) -1, 91d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells cred, KEY_ALLOC_IN_QUOTA, NULL); 9269664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells if (IS_ERR(session_keyring)) { 9369664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells ret = PTR_ERR(session_keyring); 9469664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells goto error_release; 9569664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells } 9669664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells 9769664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells /* we install a link from the user session keyring to 9869664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells * the user keyring */ 9969664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells ret = key_link(session_keyring, uid_keyring); 10069664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells if (ret < 0) 10169664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells goto error_release_both; 10269664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells } 10369664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells 10469664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells /* install the keyrings */ 10569664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells user->uid_keyring = uid_keyring; 10669664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells user->session_keyring = session_keyring; 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10969664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells mutex_unlock(&key_user_keyring_mutex); 11069664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells kleave(" = 0"); 11169664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells return 0; 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11369664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howellserror_release_both: 11469664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells key_put(session_keyring); 11569664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howellserror_release: 11669664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells key_put(uid_keyring); 117664cceb0093b755739e56572b836a99104ee8a75David Howellserror: 11869664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells mutex_unlock(&key_user_keyring_mutex); 11969664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells kleave(" = %d", ret); 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 12169664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells} 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 124973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * Install a fresh thread keyring directly to new credentials. This keyring is 125973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * allowed to overrun the quota. 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/* 141973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * 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/* 164973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * Install a process keyring directly to a credentials struct. 165973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * 166973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * Returns -EEXIST if there was already a process keyring, 0 if one installed, 167973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * and other value on any other error 168d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells */ 169d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howellsint install_process_keyring_to_cred(struct cred *new) 170d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells{ 171d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells struct key *keyring; 172d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells int ret; 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 174d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells if (new->tgcred->process_keyring) 175d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells return -EEXIST; 176d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells 177d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells keyring = keyring_alloc("_pid", new->uid, new->gid, 178d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells new, KEY_ALLOC_QUOTA_OVERRUN, NULL); 179d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells if (IS_ERR(keyring)) 180d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells return PTR_ERR(keyring); 181d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells 182d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells spin_lock_irq(&new->tgcred->lock); 183d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells if (!new->tgcred->process_keyring) { 184d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells new->tgcred->process_keyring = keyring; 185d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells keyring = NULL; 186d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells ret = 0; 187d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells } else { 188d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells ret = -EEXIST; 189d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells } 190d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells spin_unlock_irq(&new->tgcred->lock); 191d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells key_put(keyring); 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 193d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells} 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 196973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * Make sure a process keyring is installed for the current process. The 197973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * existing process keyring is not replaced. 198973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * 199973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * Returns 0 if there is a process keyring by the end of this function, some 200973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * error otherwise. 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 202d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howellsstatic int install_process_keyring(void) 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 204d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells struct cred *new; 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 207d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells new = prepare_creds(); 208d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells if (!new) 209d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells return -ENOMEM; 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 211d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells ret = install_process_keyring_to_cred(new); 212d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells if (ret < 0) { 213d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells abort_creds(new); 21427d6379894be4a81984da4d48002196a83939ca9Andi Kleen return ret != -EEXIST ? ret : 0; 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 217d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells return commit_creds(new); 218d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells} 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 221973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * Install a session keyring directly to a credentials struct. 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 223685bfd2c48bb3284d31e73ff3151c957d76deda9Oleg Nesterovint install_session_keyring_to_cred(struct cred *cred, struct key *keyring) 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2257e047ef5fe2d52e83020e856b1bf2556a6a2ce98David Howells unsigned long flags; 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct key *old; 2271a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells 2281a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells might_sleep(); 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* create an empty session keyring */ 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!keyring) { 2327e047ef5fe2d52e83020e856b1bf2556a6a2ce98David Howells flags = KEY_ALLOC_QUOTA_OVERRUN; 233d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells if (cred->tgcred->session_keyring) 2347e047ef5fe2d52e83020e856b1bf2556a6a2ce98David Howells flags = KEY_ALLOC_IN_QUOTA; 2357e047ef5fe2d52e83020e856b1bf2556a6a2ce98David Howells 236d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells keyring = keyring_alloc("_ses", cred->uid, cred->gid, 237d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells cred, flags, NULL); 2381a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells if (IS_ERR(keyring)) 2391a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells return PTR_ERR(keyring); 240d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells } else { 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atomic_inc(&keyring->usage); 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* install the keyring */ 245d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells spin_lock_irq(&cred->tgcred->lock); 246d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells old = cred->tgcred->session_keyring; 247d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells rcu_assign_pointer(cred->tgcred->session_keyring, keyring); 248d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells spin_unlock_irq(&cred->tgcred->lock); 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2501a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells /* we're using RCU on the pointer, but there's no point synchronising 2511a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells * on it if it didn't previously point to anything */ 2521a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells if (old) { 2531a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells synchronize_rcu(); 2541a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells key_put(old); 2551a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells } 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2571a26feb9622f1b1bc5e4f5f60f65557b73c38cbfDavid Howells return 0; 258d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells} 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 261973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * Install a session keyring, discarding the old one. If a keyring is not 262973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * supplied, an empty one is invented. 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 264d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howellsstatic int install_session_keyring(struct key *keyring) 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 266d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells struct cred *new; 267d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells int ret; 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 269d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells new = prepare_creds(); 270d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells if (!new) 271d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells return -ENOMEM; 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 273995995378f996a8aa1cf4e4ddc0f79fbfd45496fDavid Howells ret = install_session_keyring_to_cred(new, keyring); 274d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells if (ret < 0) { 275d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells abort_creds(new); 276d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells return ret; 277d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells } 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 279d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells return commit_creds(new); 280d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells} 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 283973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * Handle the fsuid changing. 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid key_fsuid_changed(struct task_struct *tsk) 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* update the ownership of the thread keyring */ 288b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells BUG_ON(!tsk->cred); 289b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells if (tsk->cred->thread_keyring) { 290b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells down_write(&tsk->cred->thread_keyring->sem); 291b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells tsk->cred->thread_keyring->uid = tsk->cred->fsuid; 292b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells up_write(&tsk->cred->thread_keyring->sem); 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 294a8b17ed019bd40d3bfa20439d9c36a99f9be9180David Howells} 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 297973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * Handle the fsgid changing. 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid key_fsgid_changed(struct task_struct *tsk) 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* update the ownership of the thread keyring */ 302b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells BUG_ON(!tsk->cred); 303b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells if (tsk->cred->thread_keyring) { 304b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells down_write(&tsk->cred->thread_keyring->sem); 305b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells tsk->cred->thread_keyring->gid = tsk->cred->fsgid; 306b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells up_write(&tsk->cred->thread_keyring->sem); 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 308a8b17ed019bd40d3bfa20439d9c36a99f9be9180David Howells} 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 311973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * Search the process keyrings attached to the supplied cred for the first 312973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * matching key. 313973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * 314973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * The search criteria are the type and the match function. The description is 315973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * given to the match function as a parameter, but doesn't otherwise influence 316973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * the search. Typically the match function will compare the description 317973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * parameter to the key's description. 318973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * 319973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * This can only search keyrings that grant Search permission to the supplied 320973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * credentials. Keyrings linked to searched keyrings will also be searched if 321973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * they grant Search permission too. Keys can only be found if they grant 322973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * Search permission to the credentials. 323973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * 324973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * Returns a pointer to the key with the key usage count incremented if 325973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * successful, -EAGAIN if we didn't find any matching key or -ENOKEY if we only 326973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * matched negative keys. 327973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * 328973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * In the case of a successful return, the possession attribute is set on the 329973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * returned key reference. 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 331927942aabbbe506bf9bc70a16dc5460ecc64c148David Howellskey_ref_t search_my_process_keyrings(struct key_type *type, 332927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells const void *description, 333927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells key_match_func_t match, 33478b7280cce23293f7570ad52c1ffe1485c6d9669David Howells bool no_state_check, 335927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells const struct cred *cred) 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 337b5f545c880a2a47947ba2118b2509644ab7a2969David Howells key_ref_t key_ref, ret, err; 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* we want to return -EAGAIN or -ENOKEY if any of the keyrings were 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * searchable, but we failed to find a key or we found a negative key; 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * otherwise we want to return a sample error (probably -EACCES) if 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * none of the keyrings were searchable 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * in terms of priority: success > -ENOKEY > -EAGAIN > other error 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 346664cceb0093b755739e56572b836a99104ee8a75David Howells key_ref = NULL; 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = NULL; 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = ERR_PTR(-EAGAIN); 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* search the thread keyring first */ 351c69e8d9c01db2adc503464993c358901c9af9de4David Howells if (cred->thread_keyring) { 352664cceb0093b755739e56572b836a99104ee8a75David Howells key_ref = keyring_search_aux( 353c69e8d9c01db2adc503464993c358901c9af9de4David Howells make_key_ref(cred->thread_keyring, 1), 35478b7280cce23293f7570ad52c1ffe1485c6d9669David Howells cred, type, description, match, no_state_check); 355664cceb0093b755739e56572b836a99104ee8a75David Howells if (!IS_ERR(key_ref)) 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto found; 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 358664cceb0093b755739e56572b836a99104ee8a75David Howells switch (PTR_ERR(key_ref)) { 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case -EAGAIN: /* no key */ 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret) 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case -ENOKEY: /* negative key */ 363664cceb0093b755739e56572b836a99104ee8a75David Howells ret = key_ref; 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 366664cceb0093b755739e56572b836a99104ee8a75David Howells err = key_ref; 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* search the process keyring second */ 372bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells if (cred->tgcred->process_keyring) { 373664cceb0093b755739e56572b836a99104ee8a75David Howells key_ref = keyring_search_aux( 374bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells make_key_ref(cred->tgcred->process_keyring, 1), 37578b7280cce23293f7570ad52c1ffe1485c6d9669David Howells cred, type, description, match, no_state_check); 376664cceb0093b755739e56572b836a99104ee8a75David Howells if (!IS_ERR(key_ref)) 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto found; 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 379664cceb0093b755739e56572b836a99104ee8a75David Howells switch (PTR_ERR(key_ref)) { 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case -EAGAIN: /* no key */ 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret) 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case -ENOKEY: /* negative key */ 384664cceb0093b755739e56572b836a99104ee8a75David Howells ret = key_ref; 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 387664cceb0093b755739e56572b836a99104ee8a75David Howells err = key_ref; 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3923e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells /* search the session keyring */ 393bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells if (cred->tgcred->session_keyring) { 3948589b4e00e352f983259140f25a262d973be6bc5David Howells rcu_read_lock(); 395664cceb0093b755739e56572b836a99104ee8a75David Howells key_ref = keyring_search_aux( 396664cceb0093b755739e56572b836a99104ee8a75David Howells make_key_ref(rcu_dereference( 397bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells cred->tgcred->session_keyring), 398664cceb0093b755739e56572b836a99104ee8a75David Howells 1), 39978b7280cce23293f7570ad52c1ffe1485c6d9669David Howells cred, type, description, match, no_state_check); 4008589b4e00e352f983259140f25a262d973be6bc5David Howells rcu_read_unlock(); 4013e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells 402664cceb0093b755739e56572b836a99104ee8a75David Howells if (!IS_ERR(key_ref)) 4033e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells goto found; 4043e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells 405664cceb0093b755739e56572b836a99104ee8a75David Howells switch (PTR_ERR(key_ref)) { 4063e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells case -EAGAIN: /* no key */ 4073e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells if (ret) 4083e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells break; 4093e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells case -ENOKEY: /* negative key */ 410664cceb0093b755739e56572b836a99104ee8a75David Howells ret = key_ref; 4113e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells break; 4123e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells default: 413664cceb0093b755739e56572b836a99104ee8a75David Howells err = key_ref; 4143e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells break; 4153e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells } 416b5f545c880a2a47947ba2118b2509644ab7a2969David Howells } 417b5f545c880a2a47947ba2118b2509644ab7a2969David Howells /* or search the user-session keyring */ 418c69e8d9c01db2adc503464993c358901c9af9de4David Howells else if (cred->user->session_keyring) { 419b5f545c880a2a47947ba2118b2509644ab7a2969David Howells key_ref = keyring_search_aux( 420c69e8d9c01db2adc503464993c358901c9af9de4David Howells make_key_ref(cred->user->session_keyring, 1), 42178b7280cce23293f7570ad52c1ffe1485c6d9669David Howells cred, type, description, match, no_state_check); 422664cceb0093b755739e56572b836a99104ee8a75David Howells if (!IS_ERR(key_ref)) 4233e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells goto found; 4243e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells 425664cceb0093b755739e56572b836a99104ee8a75David Howells switch (PTR_ERR(key_ref)) { 4263e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells case -EAGAIN: /* no key */ 4273e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells if (ret) 4283e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells break; 4293e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells case -ENOKEY: /* negative key */ 430664cceb0093b755739e56572b836a99104ee8a75David Howells ret = key_ref; 4313e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells break; 4323e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells default: 433664cceb0093b755739e56572b836a99104ee8a75David Howells err = key_ref; 4343e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells break; 4353e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells } 4368589b4e00e352f983259140f25a262d973be6bc5David Howells } 437b5f545c880a2a47947ba2118b2509644ab7a2969David Howells 438927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells /* no key - decide on the error we're going to go for */ 439927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells key_ref = ret ? ret : err; 440927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells 441927942aabbbe506bf9bc70a16dc5460ecc64c148David Howellsfound: 442927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells return key_ref; 443927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells} 444927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells 445927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells/* 446973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * Search the process keyrings attached to the supplied cred for the first 447973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * matching key in the manner of search_my_process_keyrings(), but also search 448973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * the keys attached to the assumed authorisation key using its credentials if 449973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * one is available. 450973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * 451973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * Return same as search_my_process_keyrings(). 452927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells */ 453927942aabbbe506bf9bc70a16dc5460ecc64c148David Howellskey_ref_t search_process_keyrings(struct key_type *type, 454927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells const void *description, 455927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells key_match_func_t match, 456927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells const struct cred *cred) 457927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells{ 458927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells struct request_key_auth *rka; 459927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells key_ref_t key_ref, ret = ERR_PTR(-EACCES), err; 460927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells 461927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells might_sleep(); 462927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells 46378b7280cce23293f7570ad52c1ffe1485c6d9669David Howells key_ref = search_my_process_keyrings(type, description, match, 46478b7280cce23293f7570ad52c1ffe1485c6d9669David Howells false, cred); 465927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells if (!IS_ERR(key_ref)) 466927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells goto found; 467927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells err = key_ref; 468927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells 469b5f545c880a2a47947ba2118b2509644ab7a2969David Howells /* if this process has an instantiation authorisation key, then we also 470b5f545c880a2a47947ba2118b2509644ab7a2969David Howells * search the keyrings of the process mentioned there 471b5f545c880a2a47947ba2118b2509644ab7a2969David Howells * - we don't permit access to request_key auth keys via this method 472b5f545c880a2a47947ba2118b2509644ab7a2969David Howells */ 473c69e8d9c01db2adc503464993c358901c9af9de4David Howells if (cred->request_key_auth && 474d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells cred == current_cred() && 47504c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells type != &key_type_request_key_auth 476b5f545c880a2a47947ba2118b2509644ab7a2969David Howells ) { 47704c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells /* defend against the auth key being revoked */ 478c69e8d9c01db2adc503464993c358901c9af9de4David Howells down_read(&cred->request_key_auth->sem); 479b5f545c880a2a47947ba2118b2509644ab7a2969David Howells 480c69e8d9c01db2adc503464993c358901c9af9de4David Howells if (key_validate(cred->request_key_auth) == 0) { 481c69e8d9c01db2adc503464993c358901c9af9de4David Howells rka = cred->request_key_auth->payload.data; 482b5f545c880a2a47947ba2118b2509644ab7a2969David Howells 48304c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells key_ref = search_process_keyrings(type, description, 484d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells match, rka->cred); 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 486c69e8d9c01db2adc503464993c358901c9af9de4David Howells up_read(&cred->request_key_auth->sem); 48704c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells 48804c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells if (!IS_ERR(key_ref)) 48904c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells goto found; 49004c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells 491927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells ret = key_ref; 49204c567d9313e4927b9835361d8ac0318ce65af6bDavid Howells } else { 493c69e8d9c01db2adc503464993c358901c9af9de4David Howells up_read(&cred->request_key_auth->sem); 4943e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells } 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* no key - decide on the error we're going to go for */ 498927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells if (err == ERR_PTR(-ENOKEY) || ret == ERR_PTR(-ENOKEY)) 499927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells key_ref = ERR_PTR(-ENOKEY); 500927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells else if (err == ERR_PTR(-EACCES)) 501927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells key_ref = ret; 502927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells else 503927942aabbbe506bf9bc70a16dc5460ecc64c148David Howells key_ref = err; 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5053e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howellsfound: 506664cceb0093b755739e56572b836a99104ee8a75David Howells return key_ref; 507a8b17ed019bd40d3bfa20439d9c36a99f9be9180David Howells} 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 510973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * See if the key we're looking at is the target key. 511664cceb0093b755739e56572b836a99104ee8a75David Howells */ 512927942aabbbe506bf9bc70a16dc5460ecc64c148David Howellsint lookup_user_key_possessed(const struct key *key, const void *target) 513664cceb0093b755739e56572b836a99104ee8a75David Howells{ 514664cceb0093b755739e56572b836a99104ee8a75David Howells return key == target; 515a8b17ed019bd40d3bfa20439d9c36a99f9be9180David Howells} 516664cceb0093b755739e56572b836a99104ee8a75David Howells 517664cceb0093b755739e56572b836a99104ee8a75David Howells/* 518973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * Look up a key ID given us by userspace with a given permissions mask to get 519973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * the key it refers to. 520973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * 521973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * Flags can be passed to request that special keyrings be created if referred 522973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * to directly, to permit partially constructed keys to be found and to skip 523973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * validity and permission checks on the found key. 524973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * 525973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * Returns a pointer to the key with an incremented usage count if successful; 526973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * -EINVAL if the key ID is invalid; -ENOKEY if the key ID does not correspond 527973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * to a key or the best found key was a negative key; -EKEYREVOKED or 528973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * -EKEYEXPIRED if the best found key was revoked or expired; -EACCES if the 529973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * found key doesn't grant the requested permit or the LSM denied access to it; 530973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * or -ENOMEM if a special keyring couldn't be created. 531973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * 532973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * In the case of a successful return, the possession attribute is set on the 533973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * returned key reference. 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5355593122eec26b061cc0b6fbff32118f1aadf4a27David Howellskey_ref_t lookup_user_key(key_serial_t id, unsigned long lflags, 5368bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells key_perm_t perm) 5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5388bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells struct request_key_auth *rka; 539d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells const struct cred *cred; 5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct key *key; 541b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells key_ref_t key_ref, skey_ref; 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 544bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howellstry_again: 545bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells cred = get_current_cred(); 546664cceb0093b755739e56572b836a99104ee8a75David Howells key_ref = ERR_PTR(-ENOKEY); 5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (id) { 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KEY_SPEC_THREAD_KEYRING: 550b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells if (!cred->thread_keyring) { 5515593122eec26b061cc0b6fbff32118f1aadf4a27David Howells if (!(lflags & KEY_LOOKUP_CREATE)) 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error; 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5548bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells ret = install_thread_keyring(); 5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret < 0) { 5564d09ec0f705cf88a12add029c058b53f288cfaa2Dan Carpenter key_ref = ERR_PTR(ret); 5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error; 5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 559bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells goto reget_creds; 5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 562b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells key = cred->thread_keyring; 5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atomic_inc(&key->usage); 564664cceb0093b755739e56572b836a99104ee8a75David Howells key_ref = make_key_ref(key, 1); 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KEY_SPEC_PROCESS_KEYRING: 568bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells if (!cred->tgcred->process_keyring) { 5695593122eec26b061cc0b6fbff32118f1aadf4a27David Howells if (!(lflags & KEY_LOOKUP_CREATE)) 5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error; 5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5728bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells ret = install_process_keyring(); 5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret < 0) { 5744d09ec0f705cf88a12add029c058b53f288cfaa2Dan Carpenter key_ref = ERR_PTR(ret); 5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error; 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 577bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells goto reget_creds; 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 580bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells key = cred->tgcred->process_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_SESSION_KEYRING: 586bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells if (!cred->tgcred->session_keyring) { 5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* always install a session keyring upon access if one 5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * doesn't exist yet */ 5898bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells ret = install_user_keyrings(); 59069664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells if (ret < 0) 59169664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells goto error; 5923ecf1b4f347210e39b156177e5b8a26ff8d00279David Howells if (lflags & KEY_LOOKUP_CREATE) 5933ecf1b4f347210e39b156177e5b8a26ff8d00279David Howells ret = join_session_keyring(NULL); 5943ecf1b4f347210e39b156177e5b8a26ff8d00279David Howells else 5953ecf1b4f347210e39b156177e5b8a26ff8d00279David Howells ret = install_session_keyring( 5963ecf1b4f347210e39b156177e5b8a26ff8d00279David Howells cred->user->session_keyring); 597d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells 5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret < 0) 5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error; 600bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells goto reget_creds; 6013ecf1b4f347210e39b156177e5b8a26ff8d00279David Howells } else if (cred->tgcred->session_keyring == 6023ecf1b4f347210e39b156177e5b8a26ff8d00279David Howells cred->user->session_keyring && 6033ecf1b4f347210e39b156177e5b8a26ff8d00279David Howells lflags & KEY_LOOKUP_CREATE) { 6043ecf1b4f347210e39b156177e5b8a26ff8d00279David Howells ret = join_session_keyring(NULL); 6053ecf1b4f347210e39b156177e5b8a26ff8d00279David Howells if (ret < 0) 6063ecf1b4f347210e39b156177e5b8a26ff8d00279David Howells goto error; 6073ecf1b4f347210e39b156177e5b8a26ff8d00279David Howells goto reget_creds; 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6103e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells rcu_read_lock(); 611bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells key = rcu_dereference(cred->tgcred->session_keyring); 6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atomic_inc(&key->usage); 6133e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells rcu_read_unlock(); 614664cceb0093b755739e56572b836a99104ee8a75David Howells key_ref = make_key_ref(key, 1); 6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KEY_SPEC_USER_KEYRING: 618b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells if (!cred->user->uid_keyring) { 6198bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells ret = install_user_keyrings(); 62069664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells if (ret < 0) 62169664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells goto error; 62269664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells } 62369664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells 624b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells key = cred->user->uid_keyring; 6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atomic_inc(&key->usage); 626664cceb0093b755739e56572b836a99104ee8a75David Howells key_ref = make_key_ref(key, 1); 6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KEY_SPEC_USER_SESSION_KEYRING: 630b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells if (!cred->user->session_keyring) { 6318bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells ret = install_user_keyrings(); 63269664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells if (ret < 0) 63369664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells goto error; 63469664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells } 63569664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells 636b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells key = cred->user->session_keyring; 6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atomic_inc(&key->usage); 638664cceb0093b755739e56572b836a99104ee8a75David Howells key_ref = make_key_ref(key, 1); 6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KEY_SPEC_GROUP_KEYRING: 6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* group keyrings are not yet supported */ 6434d09ec0f705cf88a12add029c058b53f288cfaa2Dan Carpenter key_ref = ERR_PTR(-EINVAL); 6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error; 6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 646b5f545c880a2a47947ba2118b2509644ab7a2969David Howells case KEY_SPEC_REQKEY_AUTH_KEY: 647b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells key = cred->request_key_auth; 648b5f545c880a2a47947ba2118b2509644ab7a2969David Howells if (!key) 649b5f545c880a2a47947ba2118b2509644ab7a2969David Howells goto error; 650b5f545c880a2a47947ba2118b2509644ab7a2969David Howells 651b5f545c880a2a47947ba2118b2509644ab7a2969David Howells atomic_inc(&key->usage); 652b5f545c880a2a47947ba2118b2509644ab7a2969David Howells key_ref = make_key_ref(key, 1); 653b5f545c880a2a47947ba2118b2509644ab7a2969David Howells break; 654b5f545c880a2a47947ba2118b2509644ab7a2969David Howells 6558bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells case KEY_SPEC_REQUESTOR_KEYRING: 656b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells if (!cred->request_key_auth) 6578bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells goto error; 6588bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells 659b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells down_read(&cred->request_key_auth->sem); 660f67dabbdde1fe112dfff05d02890f1e0d54117a8Dan Carpenter if (test_bit(KEY_FLAG_REVOKED, 661f67dabbdde1fe112dfff05d02890f1e0d54117a8Dan Carpenter &cred->request_key_auth->flags)) { 6628bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells key_ref = ERR_PTR(-EKEYREVOKED); 6638bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells key = NULL; 6648bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells } else { 665b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells rka = cred->request_key_auth->payload.data; 6668bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells key = rka->dest_keyring; 6678bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells atomic_inc(&key->usage); 6688bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells } 669b6dff3ec5e116e3af6f537d4caedcad6b9e5082aDavid Howells up_read(&cred->request_key_auth->sem); 6708bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells if (!key) 6718bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells goto error; 6728bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells key_ref = make_key_ref(key, 1); 6738bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells break; 6748bbf4976b59fc9fc2861e79cab7beb3f6d647640David Howells 6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 676664cceb0093b755739e56572b836a99104ee8a75David Howells key_ref = ERR_PTR(-EINVAL); 6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (id < 1) 6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error; 6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds key = key_lookup(id); 681664cceb0093b755739e56572b836a99104ee8a75David Howells if (IS_ERR(key)) { 682e231c2ee64eb1c5cd3c63c31da9dac7d888dcf7fDavid Howells key_ref = ERR_CAST(key); 6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error; 684664cceb0093b755739e56572b836a99104ee8a75David Howells } 685664cceb0093b755739e56572b836a99104ee8a75David Howells 686664cceb0093b755739e56572b836a99104ee8a75David Howells key_ref = make_key_ref(key, 0); 687664cceb0093b755739e56572b836a99104ee8a75David Howells 688664cceb0093b755739e56572b836a99104ee8a75David Howells /* check to see if we possess the key */ 689664cceb0093b755739e56572b836a99104ee8a75David Howells skey_ref = search_process_keyrings(key->type, key, 690664cceb0093b755739e56572b836a99104ee8a75David Howells lookup_user_key_possessed, 691d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells cred); 692664cceb0093b755739e56572b836a99104ee8a75David Howells 693664cceb0093b755739e56572b836a99104ee8a75David Howells if (!IS_ERR(skey_ref)) { 694664cceb0093b755739e56572b836a99104ee8a75David Howells key_put(key); 695664cceb0093b755739e56572b836a99104ee8a75David Howells key_ref = skey_ref; 696664cceb0093b755739e56572b836a99104ee8a75David Howells } 697664cceb0093b755739e56572b836a99104ee8a75David Howells 6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7015593122eec26b061cc0b6fbff32118f1aadf4a27David Howells /* unlink does not use the nominated key in any way, so can skip all 7025593122eec26b061cc0b6fbff32118f1aadf4a27David Howells * the permission checks as it is only concerned with the keyring */ 7035593122eec26b061cc0b6fbff32118f1aadf4a27David Howells if (lflags & KEY_LOOKUP_FOR_UNLINK) { 7045593122eec26b061cc0b6fbff32118f1aadf4a27David Howells ret = 0; 7055593122eec26b061cc0b6fbff32118f1aadf4a27David Howells goto error; 7065593122eec26b061cc0b6fbff32118f1aadf4a27David Howells } 7075593122eec26b061cc0b6fbff32118f1aadf4a27David Howells 7085593122eec26b061cc0b6fbff32118f1aadf4a27David Howells if (!(lflags & KEY_LOOKUP_PARTIAL)) { 70976181c134f87479fa13bf2548ddf2999055d34d4David Howells ret = wait_for_key_construction(key, true); 71076181c134f87479fa13bf2548ddf2999055d34d4David Howells switch (ret) { 71176181c134f87479fa13bf2548ddf2999055d34d4David Howells case -ERESTARTSYS: 71276181c134f87479fa13bf2548ddf2999055d34d4David Howells goto invalid_key; 71376181c134f87479fa13bf2548ddf2999055d34d4David Howells default: 71476181c134f87479fa13bf2548ddf2999055d34d4David Howells if (perm) 71576181c134f87479fa13bf2548ddf2999055d34d4David Howells goto invalid_key; 71676181c134f87479fa13bf2548ddf2999055d34d4David Howells case 0: 71776181c134f87479fa13bf2548ddf2999055d34d4David Howells break; 71876181c134f87479fa13bf2548ddf2999055d34d4David Howells } 71976181c134f87479fa13bf2548ddf2999055d34d4David Howells } else if (perm) { 7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = key_validate(key); 7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret < 0) 7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto invalid_key; 7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -EIO; 7265593122eec26b061cc0b6fbff32118f1aadf4a27David Howells if (!(lflags & KEY_LOOKUP_PARTIAL) && 7275593122eec26b061cc0b6fbff32118f1aadf4a27David Howells !test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) 7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto invalid_key; 7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7303e30148c3d524a9c1c63ca28261bc24c457eb07aDavid Howells /* check the permissions */ 731d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells ret = key_task_permission(key_ref, cred, perm); 73229db9190634067c5a328ee5fcc2890251b836b4bDavid Howells if (ret < 0) 7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto invalid_key; 7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 73531d5a79d7f3d436da176a78ebc12d53c06da402eDavid Howells key->last_used_at = current_kernel_time().tv_sec; 73631d5a79d7f3d436da176a78ebc12d53c06da402eDavid Howells 737664cceb0093b755739e56572b836a99104ee8a75David Howellserror: 738bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells put_cred(cred); 739664cceb0093b755739e56572b836a99104ee8a75David Howells return key_ref; 7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 741664cceb0093b755739e56572b836a99104ee8a75David Howellsinvalid_key: 742664cceb0093b755739e56572b836a99104ee8a75David Howells key_ref_put(key_ref); 743664cceb0093b755739e56572b836a99104ee8a75David Howells key_ref = ERR_PTR(ret); 7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error; 7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 746bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells /* if we attempted to install a keyring, then it may have caused new 747bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells * creds to be installed */ 748bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howellsreget_creds: 749bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells put_cred(cred); 750bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells goto try_again; 751a8b17ed019bd40d3bfa20439d9c36a99f9be9180David Howells} 752bb952bb98a7e479262c7eb25d5592545a3af147dDavid Howells 7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 754973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * Join the named keyring as the session keyring if possible else attempt to 755973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * create a new one of that name and join that. 756973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * 757973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * If the name is NULL, an empty anonymous keyring will be installed as the 758973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * session keyring. 759973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * 760973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * Named session keyrings are joined with a semaphore held to prevent the 761973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * keyrings from going away whilst the attempt is made to going them and also 762973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * to prevent a race in creating compatible session keyrings. 7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldslong join_session_keyring(const char *name) 7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 766d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells const struct cred *old; 767d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells struct cred *new; 7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct key *keyring; 769d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells long ret, serial; 770d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells 771d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells /* only permit this if there's a single thread in the thread group - 772d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells * this avoids us having to adjust the creds on all threads and risking 773d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells * ENOMEM */ 7745bb459bb45d1ad3c177485dcf0af01580aa31125Oleg Nesterov if (!current_is_single_threaded()) 775d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells return -EMLINK; 776d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells 777d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells new = prepare_creds(); 778d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells if (!new) 779d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells return -ENOMEM; 780d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells old = current_cred(); 7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* if no name is provided, install an anonymous keyring */ 7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!name) { 784d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells ret = install_session_keyring_to_cred(new, NULL); 7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret < 0) 7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error; 7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 788d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells serial = new->tgcred->session_keyring->serial; 789d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells ret = commit_creds(new); 790d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells if (ret == 0) 791d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells ret = serial; 792d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells goto okay; 7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* allow the user to join or create a named keyring */ 796bb0030797f55c9996ea1cebd16b65750ceb7e4fdIngo Molnar mutex_lock(&key_session_mutex); 7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* look for an existing keyring of this name */ 79969664cf16af4f31cd54d77948a4baf9c7e0ca7b9David Howells keyring = find_keyring_by_name(name, false); 8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (PTR_ERR(keyring) == -ENOKEY) { 8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* not found - try and create a new one */ 802d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells keyring = keyring_alloc(name, old->uid, old->gid, old, 8037e047ef5fe2d52e83020e856b1bf2556a6a2ce98David Howells KEY_ALLOC_IN_QUOTA, NULL); 8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (IS_ERR(keyring)) { 8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = PTR_ERR(keyring); 806bcf945d36fa0598f41ac4ad46a9dc43135460263David Howells goto error2; 8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 808d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells } else if (IS_ERR(keyring)) { 8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = PTR_ERR(keyring); 8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error2; 8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* we've got a keyring - now to install it */ 814d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells ret = install_session_keyring_to_cred(new, keyring); 8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret < 0) 8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error2; 8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 818d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells commit_creds(new); 819d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells mutex_unlock(&key_session_mutex); 820d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells 8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = keyring->serial; 8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds key_put(keyring); 823d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howellsokay: 824d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells return ret; 8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 826664cceb0093b755739e56572b836a99104ee8a75David Howellserror2: 827bb0030797f55c9996ea1cebd16b65750ceb7e4fdIngo Molnar mutex_unlock(&key_session_mutex); 828664cceb0093b755739e56572b836a99104ee8a75David Howellserror: 829d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells abort_creds(new); 8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 831d84f4f992cbd76e8f39c488cf0c5d123843923b1David Howells} 832ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells 833ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells/* 834973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * Replace a process's session keyring on behalf of one of its children when 835973c9f4f49ca96a53bcf6384c4c59ccd26c33906David Howells * the target process is about to resume userspace execution. 836ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells */ 83767d1214551e800f9fe7dc7c47a346d2df0fafed5Al Virovoid key_change_session_keyring(struct callback_head *twork) 838ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells{ 839413cd3d9abeaef590e5ce00564f7a443165db238Oleg Nesterov const struct cred *old = current_cred(); 84067d1214551e800f9fe7dc7c47a346d2df0fafed5Al Viro struct cred *new = container_of(twork, struct cred, rcu); 841ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells 842413cd3d9abeaef590e5ce00564f7a443165db238Oleg Nesterov if (unlikely(current->flags & PF_EXITING)) { 843413cd3d9abeaef590e5ce00564f7a443165db238Oleg Nesterov put_cred(new); 844ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells return; 845413cd3d9abeaef590e5ce00564f7a443165db238Oleg Nesterov } 846ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells 847ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells new-> uid = old-> uid; 848ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells new-> euid = old-> euid; 849ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells new-> suid = old-> suid; 850ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells new->fsuid = old->fsuid; 851ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells new-> gid = old-> gid; 852ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells new-> egid = old-> egid; 853ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells new-> sgid = old-> sgid; 854ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells new->fsgid = old->fsgid; 855ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells new->user = get_uid(old->user); 8560093ccb68f3753c0ba4d74c89d7e0f444b8d6123Eric W. Biederman new->user_ns = get_user_ns(new->user_ns); 857ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells new->group_info = get_group_info(old->group_info); 858ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells 859ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells new->securebits = old->securebits; 860ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells new->cap_inheritable = old->cap_inheritable; 861ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells new->cap_permitted = old->cap_permitted; 862ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells new->cap_effective = old->cap_effective; 863ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells new->cap_bset = old->cap_bset; 864ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells 865ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells new->jit_keyring = old->jit_keyring; 866ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells new->thread_keyring = key_get(old->thread_keyring); 867ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells new->tgcred->tgid = old->tgcred->tgid; 868ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells new->tgcred->process_keyring = key_get(old->tgcred->process_keyring); 869ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells 870ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells security_transfer_creds(new, old); 871ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells 872ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells commit_creds(new); 873ee18d64c1f632043a02e6f5ba5e045bb26a5465fDavid Howells} 874