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