1973c9f4fSDavid Howells /* Manage a process's keyrings 21da177e4SLinus Torvalds * 369664cf1SDavid Howells * Copyright (C) 2004-2005, 2008 Red Hat, Inc. All Rights Reserved. 41da177e4SLinus Torvalds * Written by David Howells (dhowells@redhat.com) 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or 71da177e4SLinus Torvalds * modify it under the terms of the GNU General Public License 81da177e4SLinus Torvalds * as published by the Free Software Foundation; either version 91da177e4SLinus Torvalds * 2 of the License, or (at your option) any later version. 101da177e4SLinus Torvalds */ 111da177e4SLinus Torvalds 121da177e4SLinus Torvalds #include <linux/module.h> 131da177e4SLinus Torvalds #include <linux/init.h> 141da177e4SLinus Torvalds #include <linux/sched.h> 151da177e4SLinus Torvalds #include <linux/keyctl.h> 161da177e4SLinus Torvalds #include <linux/fs.h> 171da177e4SLinus Torvalds #include <linux/err.h> 18bb003079SIngo Molnar #include <linux/mutex.h> 19ee18d64cSDavid Howells #include <linux/security.h> 201d1e9756SSerge E. Hallyn #include <linux/user_namespace.h> 211da177e4SLinus Torvalds #include <asm/uaccess.h> 221da177e4SLinus Torvalds #include "internal.h" 231da177e4SLinus Torvalds 24973c9f4fSDavid Howells /* Session keyring create vs join semaphore */ 25bb003079SIngo Molnar static DEFINE_MUTEX(key_session_mutex); 261da177e4SLinus Torvalds 27973c9f4fSDavid Howells /* User keyring creation semaphore */ 2869664cf1SDavid Howells static DEFINE_MUTEX(key_user_keyring_mutex); 2969664cf1SDavid Howells 30973c9f4fSDavid Howells /* The root user's tracking struct */ 311da177e4SLinus Torvalds struct key_user root_key_user = { 321da177e4SLinus Torvalds .usage = ATOMIC_INIT(3), 3376181c13SDavid Howells .cons_lock = __MUTEX_INITIALIZER(root_key_user.cons_lock), 346cfd76a2SPeter Zijlstra .lock = __SPIN_LOCK_UNLOCKED(root_key_user.lock), 351da177e4SLinus Torvalds .nkeys = ATOMIC_INIT(2), 361da177e4SLinus Torvalds .nikeys = ATOMIC_INIT(2), 379a56c2dbSEric W. Biederman .uid = GLOBAL_ROOT_UID, 381da177e4SLinus Torvalds }; 391da177e4SLinus Torvalds 401da177e4SLinus Torvalds /* 41973c9f4fSDavid Howells * Install the user and user session keyrings for the current process's UID. 421da177e4SLinus Torvalds */ 438bbf4976SDavid Howells int install_user_keyrings(void) 441da177e4SLinus Torvalds { 45d84f4f99SDavid Howells struct user_struct *user; 46d84f4f99SDavid Howells const struct cred *cred; 471da177e4SLinus Torvalds struct key *uid_keyring, *session_keyring; 4896b5c8feSDavid Howells key_perm_t user_keyring_perm; 491da177e4SLinus Torvalds char buf[20]; 501da177e4SLinus Torvalds int ret; 519a56c2dbSEric W. Biederman uid_t uid; 521da177e4SLinus Torvalds 5396b5c8feSDavid Howells user_keyring_perm = (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_ALL; 54d84f4f99SDavid Howells cred = current_cred(); 55d84f4f99SDavid Howells user = cred->user; 569a56c2dbSEric W. Biederman uid = from_kuid(cred->user_ns, user->uid); 57d84f4f99SDavid Howells 589a56c2dbSEric W. Biederman kenter("%p{%u}", user, uid); 591da177e4SLinus Torvalds 600da9dfddSDavid Howells if (user->uid_keyring && user->session_keyring) { 6169664cf1SDavid Howells kleave(" = 0 [exist]"); 6269664cf1SDavid Howells return 0; 631da177e4SLinus Torvalds } 641da177e4SLinus Torvalds 6569664cf1SDavid Howells mutex_lock(&key_user_keyring_mutex); 6669664cf1SDavid Howells ret = 0; 6769664cf1SDavid Howells 6869664cf1SDavid Howells if (!user->uid_keyring) { 6969664cf1SDavid Howells /* get the UID-specific keyring 7069664cf1SDavid Howells * - there may be one in existence already as it may have been 7169664cf1SDavid Howells * pinned by a session, but the user_struct pointing to it 7269664cf1SDavid Howells * may have been destroyed by setuid */ 739a56c2dbSEric W. Biederman sprintf(buf, "_uid.%u", uid); 741da177e4SLinus Torvalds 7569664cf1SDavid Howells uid_keyring = find_keyring_by_name(buf, true); 761da177e4SLinus Torvalds if (IS_ERR(uid_keyring)) { 779a56c2dbSEric W. Biederman uid_keyring = keyring_alloc(buf, user->uid, INVALID_GID, 7896b5c8feSDavid Howells cred, user_keyring_perm, 7996b5c8feSDavid Howells KEY_ALLOC_IN_QUOTA, NULL); 8069664cf1SDavid Howells if (IS_ERR(uid_keyring)) { 811da177e4SLinus Torvalds ret = PTR_ERR(uid_keyring); 821da177e4SLinus Torvalds goto error; 831da177e4SLinus Torvalds } 8469664cf1SDavid Howells } 8569664cf1SDavid Howells 8669664cf1SDavid Howells /* get a default session keyring (which might also exist 8769664cf1SDavid Howells * already) */ 889a56c2dbSEric W. Biederman sprintf(buf, "_uid_ses.%u", uid); 8969664cf1SDavid Howells 9069664cf1SDavid Howells session_keyring = find_keyring_by_name(buf, true); 9169664cf1SDavid Howells if (IS_ERR(session_keyring)) { 9269664cf1SDavid Howells session_keyring = 939a56c2dbSEric W. Biederman keyring_alloc(buf, user->uid, INVALID_GID, 9496b5c8feSDavid Howells cred, user_keyring_perm, 9596b5c8feSDavid Howells KEY_ALLOC_IN_QUOTA, NULL); 9669664cf1SDavid Howells if (IS_ERR(session_keyring)) { 9769664cf1SDavid Howells ret = PTR_ERR(session_keyring); 9869664cf1SDavid Howells goto error_release; 9969664cf1SDavid Howells } 10069664cf1SDavid Howells 10169664cf1SDavid Howells /* we install a link from the user session keyring to 10269664cf1SDavid Howells * the user keyring */ 10369664cf1SDavid Howells ret = key_link(session_keyring, uid_keyring); 10469664cf1SDavid Howells if (ret < 0) 10569664cf1SDavid Howells goto error_release_both; 10669664cf1SDavid Howells } 1071da177e4SLinus Torvalds 1081da177e4SLinus Torvalds /* install the keyrings */ 1091da177e4SLinus Torvalds user->uid_keyring = uid_keyring; 1101da177e4SLinus Torvalds user->session_keyring = session_keyring; 11169664cf1SDavid Howells } 1121da177e4SLinus Torvalds 11369664cf1SDavid Howells mutex_unlock(&key_user_keyring_mutex); 11469664cf1SDavid Howells kleave(" = 0"); 11569664cf1SDavid Howells return 0; 11669664cf1SDavid Howells 11769664cf1SDavid Howells error_release_both: 11869664cf1SDavid Howells key_put(session_keyring); 11969664cf1SDavid Howells error_release: 12069664cf1SDavid Howells key_put(uid_keyring); 1211da177e4SLinus Torvalds error: 12269664cf1SDavid Howells mutex_unlock(&key_user_keyring_mutex); 12369664cf1SDavid Howells kleave(" = %d", ret); 1241da177e4SLinus Torvalds return ret; 12569664cf1SDavid Howells } 1261da177e4SLinus Torvalds 1271da177e4SLinus Torvalds /* 128973c9f4fSDavid Howells * Install a fresh thread keyring directly to new credentials. This keyring is 129973c9f4fSDavid Howells * allowed to overrun the quota. 1301da177e4SLinus Torvalds */ 131d84f4f99SDavid Howells int install_thread_keyring_to_cred(struct cred *new) 1321da177e4SLinus Torvalds { 133d84f4f99SDavid Howells struct key *keyring; 1341da177e4SLinus Torvalds 135d84f4f99SDavid Howells keyring = keyring_alloc("_tid", new->uid, new->gid, new, 13696b5c8feSDavid Howells KEY_POS_ALL | KEY_USR_VIEW, 137d84f4f99SDavid Howells KEY_ALLOC_QUOTA_OVERRUN, NULL); 138d84f4f99SDavid Howells if (IS_ERR(keyring)) 139d84f4f99SDavid Howells return PTR_ERR(keyring); 1401da177e4SLinus Torvalds 141d84f4f99SDavid Howells new->thread_keyring = keyring; 142d84f4f99SDavid Howells return 0; 1431da177e4SLinus Torvalds } 1441da177e4SLinus Torvalds 1451da177e4SLinus Torvalds /* 146973c9f4fSDavid Howells * Install a fresh thread keyring, discarding the old one. 1471da177e4SLinus Torvalds */ 148d84f4f99SDavid Howells static int install_thread_keyring(void) 1491da177e4SLinus Torvalds { 150d84f4f99SDavid Howells struct cred *new; 1511da177e4SLinus Torvalds int ret; 1521da177e4SLinus Torvalds 153d84f4f99SDavid Howells new = prepare_creds(); 154d84f4f99SDavid Howells if (!new) 155d84f4f99SDavid Howells return -ENOMEM; 1561da177e4SLinus Torvalds 157d84f4f99SDavid Howells BUG_ON(new->thread_keyring); 158d84f4f99SDavid Howells 159d84f4f99SDavid Howells ret = install_thread_keyring_to_cred(new); 160d84f4f99SDavid Howells if (ret < 0) { 161d84f4f99SDavid Howells abort_creds(new); 162d84f4f99SDavid Howells return ret; 1631da177e4SLinus Torvalds } 1641da177e4SLinus Torvalds 165d84f4f99SDavid Howells return commit_creds(new); 166d84f4f99SDavid Howells } 1671da177e4SLinus Torvalds 168d84f4f99SDavid Howells /* 169973c9f4fSDavid Howells * Install a process keyring directly to a credentials struct. 170973c9f4fSDavid Howells * 171973c9f4fSDavid Howells * Returns -EEXIST if there was already a process keyring, 0 if one installed, 172973c9f4fSDavid Howells * and other value on any other error 173d84f4f99SDavid Howells */ 174d84f4f99SDavid Howells int install_process_keyring_to_cred(struct cred *new) 175d84f4f99SDavid Howells { 176d84f4f99SDavid Howells struct key *keyring; 177d84f4f99SDavid Howells 1783a50597dSDavid Howells if (new->process_keyring) 179d84f4f99SDavid Howells return -EEXIST; 180d84f4f99SDavid Howells 18196b5c8feSDavid Howells keyring = keyring_alloc("_pid", new->uid, new->gid, new, 18296b5c8feSDavid Howells KEY_POS_ALL | KEY_USR_VIEW, 18396b5c8feSDavid Howells KEY_ALLOC_QUOTA_OVERRUN, NULL); 184d84f4f99SDavid Howells if (IS_ERR(keyring)) 185d84f4f99SDavid Howells return PTR_ERR(keyring); 186d84f4f99SDavid Howells 1873a50597dSDavid Howells new->process_keyring = keyring; 1883a50597dSDavid Howells return 0; 189d84f4f99SDavid Howells } 1901da177e4SLinus Torvalds 1911da177e4SLinus Torvalds /* 192973c9f4fSDavid Howells * Make sure a process keyring is installed for the current process. The 193973c9f4fSDavid Howells * existing process keyring is not replaced. 194973c9f4fSDavid Howells * 195973c9f4fSDavid Howells * Returns 0 if there is a process keyring by the end of this function, some 196973c9f4fSDavid Howells * error otherwise. 1971da177e4SLinus Torvalds */ 198d84f4f99SDavid Howells static int install_process_keyring(void) 1991da177e4SLinus Torvalds { 200d84f4f99SDavid Howells struct cred *new; 2011da177e4SLinus Torvalds int ret; 2021da177e4SLinus Torvalds 203d84f4f99SDavid Howells new = prepare_creds(); 204d84f4f99SDavid Howells if (!new) 205d84f4f99SDavid Howells return -ENOMEM; 2061a26feb9SDavid Howells 207d84f4f99SDavid Howells ret = install_process_keyring_to_cred(new); 208d84f4f99SDavid Howells if (ret < 0) { 209d84f4f99SDavid Howells abort_creds(new); 21027d63798SAndi Kleen return ret != -EEXIST ? ret : 0; 2111da177e4SLinus Torvalds } 2121da177e4SLinus Torvalds 213d84f4f99SDavid Howells return commit_creds(new); 2141da177e4SLinus Torvalds } 2151da177e4SLinus Torvalds 2161da177e4SLinus Torvalds /* 217973c9f4fSDavid Howells * Install a session keyring directly to a credentials struct. 2181da177e4SLinus Torvalds */ 219685bfd2cSOleg Nesterov int install_session_keyring_to_cred(struct cred *cred, struct key *keyring) 2201da177e4SLinus Torvalds { 2217e047ef5SDavid Howells unsigned long flags; 2221da177e4SLinus Torvalds struct key *old; 2231a26feb9SDavid Howells 2241a26feb9SDavid Howells might_sleep(); 2251da177e4SLinus Torvalds 2261da177e4SLinus Torvalds /* create an empty session keyring */ 2271da177e4SLinus Torvalds if (!keyring) { 2287e047ef5SDavid Howells flags = KEY_ALLOC_QUOTA_OVERRUN; 2293a50597dSDavid Howells if (cred->session_keyring) 2307e047ef5SDavid Howells flags = KEY_ALLOC_IN_QUOTA; 2317e047ef5SDavid Howells 23296b5c8feSDavid Howells keyring = keyring_alloc("_ses", cred->uid, cred->gid, cred, 23396b5c8feSDavid Howells KEY_POS_ALL | KEY_USR_VIEW | KEY_USR_READ, 23496b5c8feSDavid Howells flags, NULL); 2351a26feb9SDavid Howells if (IS_ERR(keyring)) 2361a26feb9SDavid Howells return PTR_ERR(keyring); 237d84f4f99SDavid Howells } else { 2381da177e4SLinus Torvalds atomic_inc(&keyring->usage); 2391da177e4SLinus Torvalds } 2401da177e4SLinus Torvalds 2411da177e4SLinus Torvalds /* install the keyring */ 2423a50597dSDavid Howells old = cred->session_keyring; 2433a50597dSDavid Howells rcu_assign_pointer(cred->session_keyring, keyring); 2441da177e4SLinus Torvalds 2453a50597dSDavid Howells if (old) 2461da177e4SLinus Torvalds key_put(old); 2471a26feb9SDavid Howells 2481a26feb9SDavid Howells return 0; 249d84f4f99SDavid Howells } 2501da177e4SLinus Torvalds 2511da177e4SLinus Torvalds /* 252973c9f4fSDavid Howells * Install a session keyring, discarding the old one. If a keyring is not 253973c9f4fSDavid Howells * supplied, an empty one is invented. 2541da177e4SLinus Torvalds */ 255d84f4f99SDavid Howells static int install_session_keyring(struct key *keyring) 2561da177e4SLinus Torvalds { 257d84f4f99SDavid Howells struct cred *new; 258d84f4f99SDavid Howells int ret; 2591da177e4SLinus Torvalds 260d84f4f99SDavid Howells new = prepare_creds(); 261d84f4f99SDavid Howells if (!new) 262d84f4f99SDavid Howells return -ENOMEM; 263b5f545c8SDavid Howells 26499599537SDavid Howells ret = install_session_keyring_to_cred(new, keyring); 265d84f4f99SDavid Howells if (ret < 0) { 266d84f4f99SDavid Howells abort_creds(new); 267d84f4f99SDavid Howells return ret; 268d84f4f99SDavid Howells } 269b5f545c8SDavid Howells 270d84f4f99SDavid Howells return commit_creds(new); 271d84f4f99SDavid Howells } 2721da177e4SLinus Torvalds 2731da177e4SLinus Torvalds /* 274973c9f4fSDavid Howells * Handle the fsuid changing. 2751da177e4SLinus Torvalds */ 2761da177e4SLinus Torvalds void key_fsuid_changed(struct task_struct *tsk) 2771da177e4SLinus Torvalds { 2781da177e4SLinus Torvalds /* update the ownership of the thread keyring */ 279b6dff3ecSDavid Howells BUG_ON(!tsk->cred); 280b6dff3ecSDavid Howells if (tsk->cred->thread_keyring) { 281b6dff3ecSDavid Howells down_write(&tsk->cred->thread_keyring->sem); 282b6dff3ecSDavid Howells tsk->cred->thread_keyring->uid = tsk->cred->fsuid; 283b6dff3ecSDavid Howells up_write(&tsk->cred->thread_keyring->sem); 2841da177e4SLinus Torvalds } 285a8b17ed0SDavid Howells } 2861da177e4SLinus Torvalds 2871da177e4SLinus Torvalds /* 288973c9f4fSDavid Howells * Handle the fsgid changing. 2891da177e4SLinus Torvalds */ 2901da177e4SLinus Torvalds void key_fsgid_changed(struct task_struct *tsk) 2911da177e4SLinus Torvalds { 2921da177e4SLinus Torvalds /* update the ownership of the thread keyring */ 293b6dff3ecSDavid Howells BUG_ON(!tsk->cred); 294b6dff3ecSDavid Howells if (tsk->cred->thread_keyring) { 295b6dff3ecSDavid Howells down_write(&tsk->cred->thread_keyring->sem); 296b6dff3ecSDavid Howells tsk->cred->thread_keyring->gid = tsk->cred->fsgid; 297b6dff3ecSDavid Howells up_write(&tsk->cred->thread_keyring->sem); 2981da177e4SLinus Torvalds } 299a8b17ed0SDavid Howells } 3001da177e4SLinus Torvalds 3011da177e4SLinus Torvalds /* 302973c9f4fSDavid Howells * Search the process keyrings attached to the supplied cred for the first 303973c9f4fSDavid Howells * matching key. 304973c9f4fSDavid Howells * 305973c9f4fSDavid Howells * The search criteria are the type and the match function. The description is 306973c9f4fSDavid Howells * given to the match function as a parameter, but doesn't otherwise influence 307973c9f4fSDavid Howells * the search. Typically the match function will compare the description 308973c9f4fSDavid Howells * parameter to the key's description. 309973c9f4fSDavid Howells * 310973c9f4fSDavid Howells * This can only search keyrings that grant Search permission to the supplied 311973c9f4fSDavid Howells * credentials. Keyrings linked to searched keyrings will also be searched if 312973c9f4fSDavid Howells * they grant Search permission too. Keys can only be found if they grant 313973c9f4fSDavid Howells * Search permission to the credentials. 314973c9f4fSDavid Howells * 315973c9f4fSDavid Howells * Returns a pointer to the key with the key usage count incremented if 316973c9f4fSDavid Howells * successful, -EAGAIN if we didn't find any matching key or -ENOKEY if we only 317973c9f4fSDavid Howells * matched negative keys. 318973c9f4fSDavid Howells * 319973c9f4fSDavid Howells * In the case of a successful return, the possession attribute is set on the 320973c9f4fSDavid Howells * returned key reference. 3211da177e4SLinus Torvalds */ 322*4bdf0bc3SDavid Howells key_ref_t search_my_process_keyrings(struct keyring_search_context *ctx) 3231da177e4SLinus Torvalds { 324b5f545c8SDavid Howells key_ref_t key_ref, ret, err; 3251da177e4SLinus Torvalds 3261da177e4SLinus Torvalds /* we want to return -EAGAIN or -ENOKEY if any of the keyrings were 3271da177e4SLinus Torvalds * searchable, but we failed to find a key or we found a negative key; 3281da177e4SLinus Torvalds * otherwise we want to return a sample error (probably -EACCES) if 3291da177e4SLinus Torvalds * none of the keyrings were searchable 3301da177e4SLinus Torvalds * 3311da177e4SLinus Torvalds * in terms of priority: success > -ENOKEY > -EAGAIN > other error 3321da177e4SLinus Torvalds */ 333664cceb0SDavid Howells key_ref = NULL; 3341da177e4SLinus Torvalds ret = NULL; 3351da177e4SLinus Torvalds err = ERR_PTR(-EAGAIN); 3361da177e4SLinus Torvalds 3371da177e4SLinus Torvalds /* search the thread keyring first */ 338*4bdf0bc3SDavid Howells if (ctx->cred->thread_keyring) { 339664cceb0SDavid Howells key_ref = keyring_search_aux( 340*4bdf0bc3SDavid Howells make_key_ref(ctx->cred->thread_keyring, 1), ctx); 341664cceb0SDavid Howells if (!IS_ERR(key_ref)) 3421da177e4SLinus Torvalds goto found; 3431da177e4SLinus Torvalds 344664cceb0SDavid Howells switch (PTR_ERR(key_ref)) { 3451da177e4SLinus Torvalds case -EAGAIN: /* no key */ 3461da177e4SLinus Torvalds case -ENOKEY: /* negative key */ 347664cceb0SDavid Howells ret = key_ref; 3481da177e4SLinus Torvalds break; 3491da177e4SLinus Torvalds default: 350664cceb0SDavid Howells err = key_ref; 3511da177e4SLinus Torvalds break; 3521da177e4SLinus Torvalds } 3531da177e4SLinus Torvalds } 3541da177e4SLinus Torvalds 3551da177e4SLinus Torvalds /* search the process keyring second */ 356*4bdf0bc3SDavid Howells if (ctx->cred->process_keyring) { 357664cceb0SDavid Howells key_ref = keyring_search_aux( 358*4bdf0bc3SDavid Howells make_key_ref(ctx->cred->process_keyring, 1), ctx); 359664cceb0SDavid Howells if (!IS_ERR(key_ref)) 3601da177e4SLinus Torvalds goto found; 3611da177e4SLinus Torvalds 362664cceb0SDavid Howells switch (PTR_ERR(key_ref)) { 3631da177e4SLinus Torvalds case -EAGAIN: /* no key */ 364fe9453a1SDavid Howells if (ret) 365fe9453a1SDavid Howells break; 3661da177e4SLinus Torvalds case -ENOKEY: /* negative key */ 367664cceb0SDavid Howells ret = key_ref; 3681da177e4SLinus Torvalds break; 3691da177e4SLinus Torvalds default: 370664cceb0SDavid Howells err = key_ref; 3711da177e4SLinus Torvalds break; 3721da177e4SLinus Torvalds } 3731da177e4SLinus Torvalds } 3741da177e4SLinus Torvalds 3753e30148cSDavid Howells /* search the session keyring */ 376*4bdf0bc3SDavid Howells if (ctx->cred->session_keyring) { 3778589b4e0SDavid Howells rcu_read_lock(); 378664cceb0SDavid Howells key_ref = keyring_search_aux( 379*4bdf0bc3SDavid Howells make_key_ref(rcu_dereference(ctx->cred->session_keyring), 1), 380*4bdf0bc3SDavid Howells ctx); 3818589b4e0SDavid Howells rcu_read_unlock(); 3821da177e4SLinus Torvalds 383664cceb0SDavid Howells if (!IS_ERR(key_ref)) 3841da177e4SLinus Torvalds goto found; 3851da177e4SLinus Torvalds 386664cceb0SDavid Howells switch (PTR_ERR(key_ref)) { 3871da177e4SLinus Torvalds case -EAGAIN: /* no key */ 3881da177e4SLinus Torvalds if (ret) 3891da177e4SLinus Torvalds break; 3901da177e4SLinus Torvalds case -ENOKEY: /* negative key */ 391664cceb0SDavid Howells ret = key_ref; 3921da177e4SLinus Torvalds break; 3931da177e4SLinus Torvalds default: 394664cceb0SDavid Howells err = key_ref; 3951da177e4SLinus Torvalds break; 3961da177e4SLinus Torvalds } 3973e30148cSDavid Howells } 3983e30148cSDavid Howells /* or search the user-session keyring */ 399*4bdf0bc3SDavid Howells else if (ctx->cred->user->session_keyring) { 400664cceb0SDavid Howells key_ref = keyring_search_aux( 401*4bdf0bc3SDavid Howells make_key_ref(ctx->cred->user->session_keyring, 1), 402*4bdf0bc3SDavid Howells ctx); 403664cceb0SDavid Howells if (!IS_ERR(key_ref)) 4043e30148cSDavid Howells goto found; 4053e30148cSDavid Howells 406664cceb0SDavid Howells switch (PTR_ERR(key_ref)) { 4073e30148cSDavid Howells case -EAGAIN: /* no key */ 4083e30148cSDavid Howells if (ret) 4093e30148cSDavid Howells break; 4103e30148cSDavid Howells case -ENOKEY: /* negative key */ 411664cceb0SDavid Howells ret = key_ref; 4123e30148cSDavid Howells break; 4133e30148cSDavid Howells default: 414664cceb0SDavid Howells err = key_ref; 4153e30148cSDavid Howells break; 4163e30148cSDavid Howells } 4173e30148cSDavid Howells } 4183e30148cSDavid Howells 419927942aaSDavid Howells /* no key - decide on the error we're going to go for */ 420927942aaSDavid Howells key_ref = ret ? ret : err; 421927942aaSDavid Howells 422927942aaSDavid Howells found: 423927942aaSDavid Howells return key_ref; 424927942aaSDavid Howells } 425927942aaSDavid Howells 426927942aaSDavid Howells /* 427973c9f4fSDavid Howells * Search the process keyrings attached to the supplied cred for the first 428973c9f4fSDavid Howells * matching key in the manner of search_my_process_keyrings(), but also search 429973c9f4fSDavid Howells * the keys attached to the assumed authorisation key using its credentials if 430973c9f4fSDavid Howells * one is available. 431973c9f4fSDavid Howells * 432973c9f4fSDavid Howells * Return same as search_my_process_keyrings(). 433927942aaSDavid Howells */ 434*4bdf0bc3SDavid Howells key_ref_t search_process_keyrings(struct keyring_search_context *ctx) 435927942aaSDavid Howells { 436927942aaSDavid Howells struct request_key_auth *rka; 437927942aaSDavid Howells key_ref_t key_ref, ret = ERR_PTR(-EACCES), err; 438927942aaSDavid Howells 439927942aaSDavid Howells might_sleep(); 440927942aaSDavid Howells 441*4bdf0bc3SDavid Howells key_ref = search_my_process_keyrings(ctx); 442927942aaSDavid Howells if (!IS_ERR(key_ref)) 443927942aaSDavid Howells goto found; 444927942aaSDavid Howells err = key_ref; 445927942aaSDavid Howells 446b5f545c8SDavid Howells /* if this process has an instantiation authorisation key, then we also 447b5f545c8SDavid Howells * search the keyrings of the process mentioned there 448b5f545c8SDavid Howells * - we don't permit access to request_key auth keys via this method 449b5f545c8SDavid Howells */ 450*4bdf0bc3SDavid Howells if (ctx->cred->request_key_auth && 451*4bdf0bc3SDavid Howells ctx->cred == current_cred() && 452*4bdf0bc3SDavid Howells ctx->index_key.type != &key_type_request_key_auth 453b5f545c8SDavid Howells ) { 454*4bdf0bc3SDavid Howells const struct cred *cred = ctx->cred; 455*4bdf0bc3SDavid Howells 45604c567d9SDavid Howells /* defend against the auth key being revoked */ 457c69e8d9cSDavid Howells down_read(&cred->request_key_auth->sem); 45804c567d9SDavid Howells 459*4bdf0bc3SDavid Howells if (key_validate(ctx->cred->request_key_auth) == 0) { 460*4bdf0bc3SDavid Howells rka = ctx->cred->request_key_auth->payload.data; 4613e30148cSDavid Howells 462*4bdf0bc3SDavid Howells ctx->cred = rka->cred; 463*4bdf0bc3SDavid Howells key_ref = search_process_keyrings(ctx); 464*4bdf0bc3SDavid Howells ctx->cred = cred; 46504c567d9SDavid Howells 466c69e8d9cSDavid Howells up_read(&cred->request_key_auth->sem); 467b5f545c8SDavid Howells 468b5f545c8SDavid Howells if (!IS_ERR(key_ref)) 469b5f545c8SDavid Howells goto found; 470b5f545c8SDavid Howells 471b5f545c8SDavid Howells ret = key_ref; 47204c567d9SDavid Howells } else { 473c69e8d9cSDavid Howells up_read(&cred->request_key_auth->sem); 47404c567d9SDavid Howells } 475b5f545c8SDavid Howells } 476b5f545c8SDavid Howells 4771da177e4SLinus Torvalds /* no key - decide on the error we're going to go for */ 478927942aaSDavid Howells if (err == ERR_PTR(-ENOKEY) || ret == ERR_PTR(-ENOKEY)) 479927942aaSDavid Howells key_ref = ERR_PTR(-ENOKEY); 480927942aaSDavid Howells else if (err == ERR_PTR(-EACCES)) 481927942aaSDavid Howells key_ref = ret; 482927942aaSDavid Howells else 483927942aaSDavid Howells key_ref = err; 4841da177e4SLinus Torvalds 4851da177e4SLinus Torvalds found: 486664cceb0SDavid Howells return key_ref; 487a8b17ed0SDavid Howells } 4881da177e4SLinus Torvalds 4891da177e4SLinus Torvalds /* 490973c9f4fSDavid Howells * See if the key we're looking at is the target key. 491664cceb0SDavid Howells */ 492927942aaSDavid Howells int lookup_user_key_possessed(const struct key *key, const void *target) 493664cceb0SDavid Howells { 494664cceb0SDavid Howells return key == target; 495a8b17ed0SDavid Howells } 496664cceb0SDavid Howells 497664cceb0SDavid Howells /* 498973c9f4fSDavid Howells * Look up a key ID given us by userspace with a given permissions mask to get 499973c9f4fSDavid Howells * the key it refers to. 500973c9f4fSDavid Howells * 501973c9f4fSDavid Howells * Flags can be passed to request that special keyrings be created if referred 502973c9f4fSDavid Howells * to directly, to permit partially constructed keys to be found and to skip 503973c9f4fSDavid Howells * validity and permission checks on the found key. 504973c9f4fSDavid Howells * 505973c9f4fSDavid Howells * Returns a pointer to the key with an incremented usage count if successful; 506973c9f4fSDavid Howells * -EINVAL if the key ID is invalid; -ENOKEY if the key ID does not correspond 507973c9f4fSDavid Howells * to a key or the best found key was a negative key; -EKEYREVOKED or 508973c9f4fSDavid Howells * -EKEYEXPIRED if the best found key was revoked or expired; -EACCES if the 509973c9f4fSDavid Howells * found key doesn't grant the requested permit or the LSM denied access to it; 510973c9f4fSDavid Howells * or -ENOMEM if a special keyring couldn't be created. 511973c9f4fSDavid Howells * 512973c9f4fSDavid Howells * In the case of a successful return, the possession attribute is set on the 513973c9f4fSDavid Howells * returned key reference. 5141da177e4SLinus Torvalds */ 5155593122eSDavid Howells key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags, 5168bbf4976SDavid Howells key_perm_t perm) 5171da177e4SLinus Torvalds { 518*4bdf0bc3SDavid Howells struct keyring_search_context ctx = { 519*4bdf0bc3SDavid Howells .match = lookup_user_key_possessed, 520*4bdf0bc3SDavid Howells .flags = (KEYRING_SEARCH_NO_STATE_CHECK | 521*4bdf0bc3SDavid Howells KEYRING_SEARCH_LOOKUP_DIRECT), 522*4bdf0bc3SDavid Howells }; 5238bbf4976SDavid Howells struct request_key_auth *rka; 5241da177e4SLinus Torvalds struct key *key; 525b6dff3ecSDavid Howells key_ref_t key_ref, skey_ref; 5261da177e4SLinus Torvalds int ret; 5271da177e4SLinus Torvalds 528bb952bb9SDavid Howells try_again: 529*4bdf0bc3SDavid Howells ctx.cred = get_current_cred(); 530664cceb0SDavid Howells key_ref = ERR_PTR(-ENOKEY); 5311da177e4SLinus Torvalds 5321da177e4SLinus Torvalds switch (id) { 5331da177e4SLinus Torvalds case KEY_SPEC_THREAD_KEYRING: 534*4bdf0bc3SDavid Howells if (!ctx.cred->thread_keyring) { 5355593122eSDavid Howells if (!(lflags & KEY_LOOKUP_CREATE)) 5361da177e4SLinus Torvalds goto error; 5371da177e4SLinus Torvalds 5388bbf4976SDavid Howells ret = install_thread_keyring(); 5391da177e4SLinus Torvalds if (ret < 0) { 5404d09ec0fSDan Carpenter key_ref = ERR_PTR(ret); 5411da177e4SLinus Torvalds goto error; 5421da177e4SLinus Torvalds } 543bb952bb9SDavid Howells goto reget_creds; 5441da177e4SLinus Torvalds } 5451da177e4SLinus Torvalds 546*4bdf0bc3SDavid Howells key = ctx.cred->thread_keyring; 5471da177e4SLinus Torvalds atomic_inc(&key->usage); 548664cceb0SDavid Howells key_ref = make_key_ref(key, 1); 5491da177e4SLinus Torvalds break; 5501da177e4SLinus Torvalds 5511da177e4SLinus Torvalds case KEY_SPEC_PROCESS_KEYRING: 552*4bdf0bc3SDavid Howells if (!ctx.cred->process_keyring) { 5535593122eSDavid Howells if (!(lflags & KEY_LOOKUP_CREATE)) 5541da177e4SLinus Torvalds goto error; 5551da177e4SLinus Torvalds 5568bbf4976SDavid Howells ret = install_process_keyring(); 5571da177e4SLinus Torvalds if (ret < 0) { 5584d09ec0fSDan Carpenter key_ref = ERR_PTR(ret); 5591da177e4SLinus Torvalds goto error; 5601da177e4SLinus Torvalds } 561bb952bb9SDavid Howells goto reget_creds; 5621da177e4SLinus Torvalds } 5631da177e4SLinus Torvalds 564*4bdf0bc3SDavid Howells key = ctx.cred->process_keyring; 5651da177e4SLinus Torvalds atomic_inc(&key->usage); 566664cceb0SDavid Howells key_ref = make_key_ref(key, 1); 5671da177e4SLinus Torvalds break; 5681da177e4SLinus Torvalds 5691da177e4SLinus Torvalds case KEY_SPEC_SESSION_KEYRING: 570*4bdf0bc3SDavid Howells if (!ctx.cred->session_keyring) { 5711da177e4SLinus Torvalds /* always install a session keyring upon access if one 5721da177e4SLinus Torvalds * doesn't exist yet */ 5738bbf4976SDavid Howells ret = install_user_keyrings(); 57469664cf1SDavid Howells if (ret < 0) 57569664cf1SDavid Howells goto error; 5763ecf1b4fSDavid Howells if (lflags & KEY_LOOKUP_CREATE) 5773ecf1b4fSDavid Howells ret = join_session_keyring(NULL); 5783ecf1b4fSDavid Howells else 579b6dff3ecSDavid Howells ret = install_session_keyring( 580*4bdf0bc3SDavid Howells ctx.cred->user->session_keyring); 581d84f4f99SDavid Howells 5821da177e4SLinus Torvalds if (ret < 0) 5831da177e4SLinus Torvalds goto error; 584bb952bb9SDavid Howells goto reget_creds; 585*4bdf0bc3SDavid Howells } else if (ctx.cred->session_keyring == 586*4bdf0bc3SDavid Howells ctx.cred->user->session_keyring && 5873ecf1b4fSDavid Howells lflags & KEY_LOOKUP_CREATE) { 5883ecf1b4fSDavid Howells ret = join_session_keyring(NULL); 5893ecf1b4fSDavid Howells if (ret < 0) 5903ecf1b4fSDavid Howells goto error; 5913ecf1b4fSDavid Howells goto reget_creds; 5921da177e4SLinus Torvalds } 5931da177e4SLinus Torvalds 5943e30148cSDavid Howells rcu_read_lock(); 595*4bdf0bc3SDavid Howells key = rcu_dereference(ctx.cred->session_keyring); 5961da177e4SLinus Torvalds atomic_inc(&key->usage); 5973e30148cSDavid Howells rcu_read_unlock(); 598664cceb0SDavid Howells key_ref = make_key_ref(key, 1); 5991da177e4SLinus Torvalds break; 6001da177e4SLinus Torvalds 6011da177e4SLinus Torvalds case KEY_SPEC_USER_KEYRING: 602*4bdf0bc3SDavid Howells if (!ctx.cred->user->uid_keyring) { 6038bbf4976SDavid Howells ret = install_user_keyrings(); 60469664cf1SDavid Howells if (ret < 0) 60569664cf1SDavid Howells goto error; 60669664cf1SDavid Howells } 60769664cf1SDavid Howells 608*4bdf0bc3SDavid Howells key = ctx.cred->user->uid_keyring; 6091da177e4SLinus Torvalds atomic_inc(&key->usage); 610664cceb0SDavid Howells key_ref = make_key_ref(key, 1); 6111da177e4SLinus Torvalds break; 6121da177e4SLinus Torvalds 6131da177e4SLinus Torvalds case KEY_SPEC_USER_SESSION_KEYRING: 614*4bdf0bc3SDavid Howells if (!ctx.cred->user->session_keyring) { 6158bbf4976SDavid Howells ret = install_user_keyrings(); 61669664cf1SDavid Howells if (ret < 0) 61769664cf1SDavid Howells goto error; 61869664cf1SDavid Howells } 61969664cf1SDavid Howells 620*4bdf0bc3SDavid Howells key = ctx.cred->user->session_keyring; 6211da177e4SLinus Torvalds atomic_inc(&key->usage); 622664cceb0SDavid Howells key_ref = make_key_ref(key, 1); 6231da177e4SLinus Torvalds break; 6241da177e4SLinus Torvalds 6251da177e4SLinus Torvalds case KEY_SPEC_GROUP_KEYRING: 6261da177e4SLinus Torvalds /* group keyrings are not yet supported */ 6274d09ec0fSDan Carpenter key_ref = ERR_PTR(-EINVAL); 6281da177e4SLinus Torvalds goto error; 6291da177e4SLinus Torvalds 630b5f545c8SDavid Howells case KEY_SPEC_REQKEY_AUTH_KEY: 631*4bdf0bc3SDavid Howells key = ctx.cred->request_key_auth; 632b5f545c8SDavid Howells if (!key) 633b5f545c8SDavid Howells goto error; 634b5f545c8SDavid Howells 635b5f545c8SDavid Howells atomic_inc(&key->usage); 636b5f545c8SDavid Howells key_ref = make_key_ref(key, 1); 637b5f545c8SDavid Howells break; 638b5f545c8SDavid Howells 6398bbf4976SDavid Howells case KEY_SPEC_REQUESTOR_KEYRING: 640*4bdf0bc3SDavid Howells if (!ctx.cred->request_key_auth) 6418bbf4976SDavid Howells goto error; 6428bbf4976SDavid Howells 643*4bdf0bc3SDavid Howells down_read(&ctx.cred->request_key_auth->sem); 644f67dabbdSDan Carpenter if (test_bit(KEY_FLAG_REVOKED, 645*4bdf0bc3SDavid Howells &ctx.cred->request_key_auth->flags)) { 6468bbf4976SDavid Howells key_ref = ERR_PTR(-EKEYREVOKED); 6478bbf4976SDavid Howells key = NULL; 6488bbf4976SDavid Howells } else { 649*4bdf0bc3SDavid Howells rka = ctx.cred->request_key_auth->payload.data; 6508bbf4976SDavid Howells key = rka->dest_keyring; 6518bbf4976SDavid Howells atomic_inc(&key->usage); 6528bbf4976SDavid Howells } 653*4bdf0bc3SDavid Howells up_read(&ctx.cred->request_key_auth->sem); 6548bbf4976SDavid Howells if (!key) 6558bbf4976SDavid Howells goto error; 6568bbf4976SDavid Howells key_ref = make_key_ref(key, 1); 6578bbf4976SDavid Howells break; 6588bbf4976SDavid Howells 6591da177e4SLinus Torvalds default: 660664cceb0SDavid Howells key_ref = ERR_PTR(-EINVAL); 6611da177e4SLinus Torvalds if (id < 1) 6621da177e4SLinus Torvalds goto error; 6631da177e4SLinus Torvalds 6641da177e4SLinus Torvalds key = key_lookup(id); 665664cceb0SDavid Howells if (IS_ERR(key)) { 666e231c2eeSDavid Howells key_ref = ERR_CAST(key); 6671da177e4SLinus Torvalds goto error; 668664cceb0SDavid Howells } 669664cceb0SDavid Howells 670664cceb0SDavid Howells key_ref = make_key_ref(key, 0); 671664cceb0SDavid Howells 672664cceb0SDavid Howells /* check to see if we possess the key */ 673*4bdf0bc3SDavid Howells ctx.index_key.type = key->type; 674*4bdf0bc3SDavid Howells ctx.index_key.description = key->description; 675*4bdf0bc3SDavid Howells ctx.index_key.desc_len = strlen(key->description); 676*4bdf0bc3SDavid Howells ctx.match_data = key; 677*4bdf0bc3SDavid Howells kdebug("check possessed"); 678*4bdf0bc3SDavid Howells skey_ref = search_process_keyrings(&ctx); 679*4bdf0bc3SDavid Howells kdebug("possessed=%p", skey_ref); 680664cceb0SDavid Howells 681664cceb0SDavid Howells if (!IS_ERR(skey_ref)) { 682664cceb0SDavid Howells key_put(key); 683664cceb0SDavid Howells key_ref = skey_ref; 684664cceb0SDavid Howells } 685664cceb0SDavid Howells 6861da177e4SLinus Torvalds break; 6871da177e4SLinus Torvalds } 6881da177e4SLinus Torvalds 6895593122eSDavid Howells /* unlink does not use the nominated key in any way, so can skip all 6905593122eSDavid Howells * the permission checks as it is only concerned with the keyring */ 6915593122eSDavid Howells if (lflags & KEY_LOOKUP_FOR_UNLINK) { 6925593122eSDavid Howells ret = 0; 6935593122eSDavid Howells goto error; 6945593122eSDavid Howells } 6955593122eSDavid Howells 6965593122eSDavid Howells if (!(lflags & KEY_LOOKUP_PARTIAL)) { 69776181c13SDavid Howells ret = wait_for_key_construction(key, true); 69876181c13SDavid Howells switch (ret) { 69976181c13SDavid Howells case -ERESTARTSYS: 70076181c13SDavid Howells goto invalid_key; 70176181c13SDavid Howells default: 70276181c13SDavid Howells if (perm) 70376181c13SDavid Howells goto invalid_key; 70476181c13SDavid Howells case 0: 70576181c13SDavid Howells break; 70676181c13SDavid Howells } 70776181c13SDavid Howells } else if (perm) { 7081da177e4SLinus Torvalds ret = key_validate(key); 7091da177e4SLinus Torvalds if (ret < 0) 7101da177e4SLinus Torvalds goto invalid_key; 7111da177e4SLinus Torvalds } 7121da177e4SLinus Torvalds 7131da177e4SLinus Torvalds ret = -EIO; 7145593122eSDavid Howells if (!(lflags & KEY_LOOKUP_PARTIAL) && 7155593122eSDavid Howells !test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) 7161da177e4SLinus Torvalds goto invalid_key; 7171da177e4SLinus Torvalds 7183e30148cSDavid Howells /* check the permissions */ 719*4bdf0bc3SDavid Howells ret = key_task_permission(key_ref, ctx.cred, perm); 72029db9190SDavid Howells if (ret < 0) 7211da177e4SLinus Torvalds goto invalid_key; 7221da177e4SLinus Torvalds 72331d5a79dSDavid Howells key->last_used_at = current_kernel_time().tv_sec; 72431d5a79dSDavid Howells 7251da177e4SLinus Torvalds error: 726*4bdf0bc3SDavid Howells put_cred(ctx.cred); 727664cceb0SDavid Howells return key_ref; 7281da177e4SLinus Torvalds 7291da177e4SLinus Torvalds invalid_key: 730664cceb0SDavid Howells key_ref_put(key_ref); 731664cceb0SDavid Howells key_ref = ERR_PTR(ret); 7321da177e4SLinus Torvalds goto error; 7331da177e4SLinus Torvalds 734bb952bb9SDavid Howells /* if we attempted to install a keyring, then it may have caused new 735bb952bb9SDavid Howells * creds to be installed */ 736bb952bb9SDavid Howells reget_creds: 737*4bdf0bc3SDavid Howells put_cred(ctx.cred); 738bb952bb9SDavid Howells goto try_again; 739a8b17ed0SDavid Howells } 740bb952bb9SDavid Howells 7411da177e4SLinus Torvalds /* 742973c9f4fSDavid Howells * Join the named keyring as the session keyring if possible else attempt to 743973c9f4fSDavid Howells * create a new one of that name and join that. 744973c9f4fSDavid Howells * 745973c9f4fSDavid Howells * If the name is NULL, an empty anonymous keyring will be installed as the 746973c9f4fSDavid Howells * session keyring. 747973c9f4fSDavid Howells * 748973c9f4fSDavid Howells * Named session keyrings are joined with a semaphore held to prevent the 749973c9f4fSDavid Howells * keyrings from going away whilst the attempt is made to going them and also 750973c9f4fSDavid Howells * to prevent a race in creating compatible session keyrings. 7511da177e4SLinus Torvalds */ 7521da177e4SLinus Torvalds long join_session_keyring(const char *name) 7531da177e4SLinus Torvalds { 754d84f4f99SDavid Howells const struct cred *old; 755d84f4f99SDavid Howells struct cred *new; 7561da177e4SLinus Torvalds struct key *keyring; 757d84f4f99SDavid Howells long ret, serial; 758d84f4f99SDavid Howells 759d84f4f99SDavid Howells new = prepare_creds(); 760d84f4f99SDavid Howells if (!new) 761d84f4f99SDavid Howells return -ENOMEM; 762d84f4f99SDavid Howells old = current_cred(); 7631da177e4SLinus Torvalds 7641da177e4SLinus Torvalds /* if no name is provided, install an anonymous keyring */ 7651da177e4SLinus Torvalds if (!name) { 766d84f4f99SDavid Howells ret = install_session_keyring_to_cred(new, NULL); 7671da177e4SLinus Torvalds if (ret < 0) 7681da177e4SLinus Torvalds goto error; 7691da177e4SLinus Torvalds 7703a50597dSDavid Howells serial = new->session_keyring->serial; 771d84f4f99SDavid Howells ret = commit_creds(new); 772d84f4f99SDavid Howells if (ret == 0) 773d84f4f99SDavid Howells ret = serial; 774d84f4f99SDavid Howells goto okay; 7751da177e4SLinus Torvalds } 7761da177e4SLinus Torvalds 7771da177e4SLinus Torvalds /* allow the user to join or create a named keyring */ 778bb003079SIngo Molnar mutex_lock(&key_session_mutex); 7791da177e4SLinus Torvalds 7801da177e4SLinus Torvalds /* look for an existing keyring of this name */ 78169664cf1SDavid Howells keyring = find_keyring_by_name(name, false); 7821da177e4SLinus Torvalds if (PTR_ERR(keyring) == -ENOKEY) { 7831da177e4SLinus Torvalds /* not found - try and create a new one */ 78496b5c8feSDavid Howells keyring = keyring_alloc( 78596b5c8feSDavid Howells name, old->uid, old->gid, old, 78696b5c8feSDavid Howells KEY_POS_ALL | KEY_USR_VIEW | KEY_USR_READ | KEY_USR_LINK, 7877e047ef5SDavid Howells KEY_ALLOC_IN_QUOTA, NULL); 7881da177e4SLinus Torvalds if (IS_ERR(keyring)) { 7891da177e4SLinus Torvalds ret = PTR_ERR(keyring); 790bcf945d3SDavid Howells goto error2; 7911da177e4SLinus Torvalds } 792d84f4f99SDavid Howells } else if (IS_ERR(keyring)) { 7931da177e4SLinus Torvalds ret = PTR_ERR(keyring); 7941da177e4SLinus Torvalds goto error2; 7953a50597dSDavid Howells } else if (keyring == new->session_keyring) { 7963a50597dSDavid Howells ret = 0; 7973a50597dSDavid Howells goto error2; 7981da177e4SLinus Torvalds } 7991da177e4SLinus Torvalds 8001da177e4SLinus Torvalds /* we've got a keyring - now to install it */ 801d84f4f99SDavid Howells ret = install_session_keyring_to_cred(new, keyring); 8021da177e4SLinus Torvalds if (ret < 0) 8031da177e4SLinus Torvalds goto error2; 8041da177e4SLinus Torvalds 805d84f4f99SDavid Howells commit_creds(new); 806d84f4f99SDavid Howells mutex_unlock(&key_session_mutex); 807d84f4f99SDavid Howells 8081da177e4SLinus Torvalds ret = keyring->serial; 8091da177e4SLinus Torvalds key_put(keyring); 810d84f4f99SDavid Howells okay: 811d84f4f99SDavid Howells return ret; 8121da177e4SLinus Torvalds 8131da177e4SLinus Torvalds error2: 814bb003079SIngo Molnar mutex_unlock(&key_session_mutex); 8151da177e4SLinus Torvalds error: 816d84f4f99SDavid Howells abort_creds(new); 8171da177e4SLinus Torvalds return ret; 818d84f4f99SDavid Howells } 819ee18d64cSDavid Howells 820ee18d64cSDavid Howells /* 821973c9f4fSDavid Howells * Replace a process's session keyring on behalf of one of its children when 822973c9f4fSDavid Howells * the target process is about to resume userspace execution. 823ee18d64cSDavid Howells */ 82467d12145SAl Viro void key_change_session_keyring(struct callback_head *twork) 825ee18d64cSDavid Howells { 826413cd3d9SOleg Nesterov const struct cred *old = current_cred(); 82767d12145SAl Viro struct cred *new = container_of(twork, struct cred, rcu); 828ee18d64cSDavid Howells 829413cd3d9SOleg Nesterov if (unlikely(current->flags & PF_EXITING)) { 830413cd3d9SOleg Nesterov put_cred(new); 831ee18d64cSDavid Howells return; 832413cd3d9SOleg Nesterov } 833ee18d64cSDavid Howells 834ee18d64cSDavid Howells new-> uid = old-> uid; 835ee18d64cSDavid Howells new-> euid = old-> euid; 836ee18d64cSDavid Howells new-> suid = old-> suid; 837ee18d64cSDavid Howells new->fsuid = old->fsuid; 838ee18d64cSDavid Howells new-> gid = old-> gid; 839ee18d64cSDavid Howells new-> egid = old-> egid; 840ee18d64cSDavid Howells new-> sgid = old-> sgid; 841ee18d64cSDavid Howells new->fsgid = old->fsgid; 842ee18d64cSDavid Howells new->user = get_uid(old->user); 843ba0e3427SEric W. Biederman new->user_ns = get_user_ns(old->user_ns); 844ee18d64cSDavid Howells new->group_info = get_group_info(old->group_info); 845ee18d64cSDavid Howells 846ee18d64cSDavid Howells new->securebits = old->securebits; 847ee18d64cSDavid Howells new->cap_inheritable = old->cap_inheritable; 848ee18d64cSDavid Howells new->cap_permitted = old->cap_permitted; 849ee18d64cSDavid Howells new->cap_effective = old->cap_effective; 850ee18d64cSDavid Howells new->cap_bset = old->cap_bset; 851ee18d64cSDavid Howells 852ee18d64cSDavid Howells new->jit_keyring = old->jit_keyring; 853ee18d64cSDavid Howells new->thread_keyring = key_get(old->thread_keyring); 8543a50597dSDavid Howells new->process_keyring = key_get(old->process_keyring); 855ee18d64cSDavid Howells 856ee18d64cSDavid Howells security_transfer_creds(new, old); 857ee18d64cSDavid Howells 858ee18d64cSDavid Howells commit_creds(new); 859ee18d64cSDavid Howells } 860