11da177e4SLinus Torvalds /* process_keys.c: management of a process's keyrings 21da177e4SLinus Torvalds * 38589b4e0SDavid Howells * Copyright (C) 2004-5 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/slab.h> 161da177e4SLinus Torvalds #include <linux/keyctl.h> 171da177e4SLinus Torvalds #include <linux/fs.h> 181da177e4SLinus Torvalds #include <linux/err.h> 19bb003079SIngo Molnar #include <linux/mutex.h> 201da177e4SLinus Torvalds #include <asm/uaccess.h> 211da177e4SLinus Torvalds #include "internal.h" 221da177e4SLinus Torvalds 231da177e4SLinus Torvalds /* session keyring create vs join semaphore */ 24bb003079SIngo Molnar static DEFINE_MUTEX(key_session_mutex); 251da177e4SLinus Torvalds 261da177e4SLinus Torvalds /* the root user's tracking struct */ 271da177e4SLinus Torvalds struct key_user root_key_user = { 281da177e4SLinus Torvalds .usage = ATOMIC_INIT(3), 291da177e4SLinus Torvalds .consq = LIST_HEAD_INIT(root_key_user.consq), 301da177e4SLinus Torvalds .lock = SPIN_LOCK_UNLOCKED, 311da177e4SLinus Torvalds .nkeys = ATOMIC_INIT(2), 321da177e4SLinus Torvalds .nikeys = ATOMIC_INIT(2), 331da177e4SLinus Torvalds .uid = 0, 341da177e4SLinus Torvalds }; 351da177e4SLinus Torvalds 361da177e4SLinus Torvalds /* the root user's UID keyring */ 371da177e4SLinus Torvalds struct key root_user_keyring = { 381da177e4SLinus Torvalds .usage = ATOMIC_INIT(1), 391da177e4SLinus Torvalds .serial = 2, 401da177e4SLinus Torvalds .type = &key_type_keyring, 411da177e4SLinus Torvalds .user = &root_key_user, 421da177e4SLinus Torvalds .sem = __RWSEM_INITIALIZER(root_user_keyring.sem), 4329db9190SDavid Howells .perm = (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_ALL, 4476d8aeabSDavid Howells .flags = 1 << KEY_FLAG_INSTANTIATED, 451da177e4SLinus Torvalds .description = "_uid.0", 461da177e4SLinus Torvalds #ifdef KEY_DEBUGGING 471da177e4SLinus Torvalds .magic = KEY_DEBUG_MAGIC, 481da177e4SLinus Torvalds #endif 491da177e4SLinus Torvalds }; 501da177e4SLinus Torvalds 511da177e4SLinus Torvalds /* the root user's default session keyring */ 521da177e4SLinus Torvalds struct key root_session_keyring = { 531da177e4SLinus Torvalds .usage = ATOMIC_INIT(1), 541da177e4SLinus Torvalds .serial = 1, 551da177e4SLinus Torvalds .type = &key_type_keyring, 561da177e4SLinus Torvalds .user = &root_key_user, 571da177e4SLinus Torvalds .sem = __RWSEM_INITIALIZER(root_session_keyring.sem), 5829db9190SDavid Howells .perm = (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_ALL, 5976d8aeabSDavid Howells .flags = 1 << KEY_FLAG_INSTANTIATED, 601da177e4SLinus Torvalds .description = "_uid_ses.0", 611da177e4SLinus Torvalds #ifdef KEY_DEBUGGING 621da177e4SLinus Torvalds .magic = KEY_DEBUG_MAGIC, 631da177e4SLinus Torvalds #endif 641da177e4SLinus Torvalds }; 651da177e4SLinus Torvalds 661da177e4SLinus Torvalds /*****************************************************************************/ 671da177e4SLinus Torvalds /* 681da177e4SLinus Torvalds * allocate the keyrings to be associated with a UID 691da177e4SLinus Torvalds */ 701da177e4SLinus Torvalds int alloc_uid_keyring(struct user_struct *user) 711da177e4SLinus Torvalds { 721da177e4SLinus Torvalds struct key *uid_keyring, *session_keyring; 731da177e4SLinus Torvalds char buf[20]; 741da177e4SLinus Torvalds int ret; 751da177e4SLinus Torvalds 761da177e4SLinus Torvalds /* concoct a default session keyring */ 771da177e4SLinus Torvalds sprintf(buf, "_uid_ses.%u", user->uid); 781da177e4SLinus Torvalds 791da177e4SLinus Torvalds session_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, 0, NULL); 801da177e4SLinus Torvalds if (IS_ERR(session_keyring)) { 811da177e4SLinus Torvalds ret = PTR_ERR(session_keyring); 821da177e4SLinus Torvalds goto error; 831da177e4SLinus Torvalds } 841da177e4SLinus Torvalds 851da177e4SLinus Torvalds /* and a UID specific keyring, pointed to by the default session 861da177e4SLinus Torvalds * keyring */ 871da177e4SLinus Torvalds sprintf(buf, "_uid.%u", user->uid); 881da177e4SLinus Torvalds 891da177e4SLinus Torvalds uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, 0, 901da177e4SLinus Torvalds session_keyring); 911da177e4SLinus Torvalds if (IS_ERR(uid_keyring)) { 921da177e4SLinus Torvalds key_put(session_keyring); 931da177e4SLinus Torvalds ret = PTR_ERR(uid_keyring); 941da177e4SLinus Torvalds goto error; 951da177e4SLinus Torvalds } 961da177e4SLinus Torvalds 971da177e4SLinus Torvalds /* install the keyrings */ 981da177e4SLinus Torvalds user->uid_keyring = uid_keyring; 991da177e4SLinus Torvalds user->session_keyring = session_keyring; 1001da177e4SLinus Torvalds ret = 0; 1011da177e4SLinus Torvalds 1021da177e4SLinus Torvalds error: 1031da177e4SLinus Torvalds return ret; 1041da177e4SLinus Torvalds 1051da177e4SLinus Torvalds } /* end alloc_uid_keyring() */ 1061da177e4SLinus Torvalds 1071da177e4SLinus Torvalds /*****************************************************************************/ 1081da177e4SLinus Torvalds /* 1091da177e4SLinus Torvalds * deal with the UID changing 1101da177e4SLinus Torvalds */ 1111da177e4SLinus Torvalds void switch_uid_keyring(struct user_struct *new_user) 1121da177e4SLinus Torvalds { 1131da177e4SLinus Torvalds #if 0 /* do nothing for now */ 1141da177e4SLinus Torvalds struct key *old; 1151da177e4SLinus Torvalds 1161da177e4SLinus Torvalds /* switch to the new user's session keyring if we were running under 1171da177e4SLinus Torvalds * root's default session keyring */ 1181da177e4SLinus Torvalds if (new_user->uid != 0 && 1191da177e4SLinus Torvalds current->session_keyring == &root_session_keyring 1201da177e4SLinus Torvalds ) { 1211da177e4SLinus Torvalds atomic_inc(&new_user->session_keyring->usage); 1221da177e4SLinus Torvalds 1231da177e4SLinus Torvalds task_lock(current); 1241da177e4SLinus Torvalds old = current->session_keyring; 1251da177e4SLinus Torvalds current->session_keyring = new_user->session_keyring; 1261da177e4SLinus Torvalds task_unlock(current); 1271da177e4SLinus Torvalds 1281da177e4SLinus Torvalds key_put(old); 1291da177e4SLinus Torvalds } 1301da177e4SLinus Torvalds #endif 1311da177e4SLinus Torvalds 1321da177e4SLinus Torvalds } /* end switch_uid_keyring() */ 1331da177e4SLinus Torvalds 1341da177e4SLinus Torvalds /*****************************************************************************/ 1351da177e4SLinus Torvalds /* 1361da177e4SLinus Torvalds * install a fresh thread keyring, discarding the old one 1371da177e4SLinus Torvalds */ 1381da177e4SLinus Torvalds int install_thread_keyring(struct task_struct *tsk) 1391da177e4SLinus Torvalds { 1401da177e4SLinus Torvalds struct key *keyring, *old; 1411da177e4SLinus Torvalds char buf[20]; 1421da177e4SLinus Torvalds int ret; 1431da177e4SLinus Torvalds 1441da177e4SLinus Torvalds sprintf(buf, "_tid.%u", tsk->pid); 1451da177e4SLinus Torvalds 1461da177e4SLinus Torvalds keyring = keyring_alloc(buf, tsk->uid, tsk->gid, 1, NULL); 1471da177e4SLinus Torvalds if (IS_ERR(keyring)) { 1481da177e4SLinus Torvalds ret = PTR_ERR(keyring); 1491da177e4SLinus Torvalds goto error; 1501da177e4SLinus Torvalds } 1511da177e4SLinus Torvalds 1521da177e4SLinus Torvalds task_lock(tsk); 1531da177e4SLinus Torvalds old = tsk->thread_keyring; 1541da177e4SLinus Torvalds tsk->thread_keyring = keyring; 1551da177e4SLinus Torvalds task_unlock(tsk); 1561da177e4SLinus Torvalds 1571da177e4SLinus Torvalds ret = 0; 1581da177e4SLinus Torvalds 1591da177e4SLinus Torvalds key_put(old); 1601da177e4SLinus Torvalds error: 1611da177e4SLinus Torvalds return ret; 1621da177e4SLinus Torvalds 1631da177e4SLinus Torvalds } /* end install_thread_keyring() */ 1641da177e4SLinus Torvalds 1651da177e4SLinus Torvalds /*****************************************************************************/ 1661da177e4SLinus Torvalds /* 1671da177e4SLinus Torvalds * make sure a process keyring is installed 1681da177e4SLinus Torvalds */ 1693e30148cSDavid Howells int install_process_keyring(struct task_struct *tsk) 1701da177e4SLinus Torvalds { 1711da177e4SLinus Torvalds struct key *keyring; 1721da177e4SLinus Torvalds char buf[20]; 1731da177e4SLinus Torvalds int ret; 1741da177e4SLinus Torvalds 175*1a26feb9SDavid Howells might_sleep(); 176*1a26feb9SDavid Howells 1771da177e4SLinus Torvalds if (!tsk->signal->process_keyring) { 1781da177e4SLinus Torvalds sprintf(buf, "_pid.%u", tsk->tgid); 1791da177e4SLinus Torvalds 1801da177e4SLinus Torvalds keyring = keyring_alloc(buf, tsk->uid, tsk->gid, 1, NULL); 1811da177e4SLinus Torvalds if (IS_ERR(keyring)) { 1821da177e4SLinus Torvalds ret = PTR_ERR(keyring); 1831da177e4SLinus Torvalds goto error; 1841da177e4SLinus Torvalds } 1851da177e4SLinus Torvalds 1868589b4e0SDavid Howells /* attach keyring */ 187*1a26feb9SDavid Howells spin_lock_irq(&tsk->sighand->siglock); 1881da177e4SLinus Torvalds if (!tsk->signal->process_keyring) { 1891da177e4SLinus Torvalds tsk->signal->process_keyring = keyring; 1901da177e4SLinus Torvalds keyring = NULL; 1911da177e4SLinus Torvalds } 192*1a26feb9SDavid Howells spin_unlock_irq(&tsk->sighand->siglock); 1931da177e4SLinus Torvalds 1941da177e4SLinus Torvalds key_put(keyring); 1951da177e4SLinus Torvalds } 1961da177e4SLinus Torvalds 1971da177e4SLinus Torvalds ret = 0; 1981da177e4SLinus Torvalds error: 1991da177e4SLinus Torvalds return ret; 2001da177e4SLinus Torvalds 2011da177e4SLinus Torvalds } /* end install_process_keyring() */ 2021da177e4SLinus Torvalds 2031da177e4SLinus Torvalds /*****************************************************************************/ 2041da177e4SLinus Torvalds /* 2051da177e4SLinus Torvalds * install a session keyring, discarding the old one 2061da177e4SLinus Torvalds * - if a keyring is not supplied, an empty one is invented 2071da177e4SLinus Torvalds */ 2081da177e4SLinus Torvalds static int install_session_keyring(struct task_struct *tsk, 2091da177e4SLinus Torvalds struct key *keyring) 2101da177e4SLinus Torvalds { 2111da177e4SLinus Torvalds struct key *old; 2121da177e4SLinus Torvalds char buf[20]; 213*1a26feb9SDavid Howells 214*1a26feb9SDavid Howells might_sleep(); 2151da177e4SLinus Torvalds 2161da177e4SLinus Torvalds /* create an empty session keyring */ 2171da177e4SLinus Torvalds if (!keyring) { 2181da177e4SLinus Torvalds sprintf(buf, "_ses.%u", tsk->tgid); 2191da177e4SLinus Torvalds 2201da177e4SLinus Torvalds keyring = keyring_alloc(buf, tsk->uid, tsk->gid, 1, NULL); 221*1a26feb9SDavid Howells if (IS_ERR(keyring)) 222*1a26feb9SDavid Howells return PTR_ERR(keyring); 2231da177e4SLinus Torvalds } 2241da177e4SLinus Torvalds else { 2251da177e4SLinus Torvalds atomic_inc(&keyring->usage); 2261da177e4SLinus Torvalds } 2271da177e4SLinus Torvalds 2281da177e4SLinus Torvalds /* install the keyring */ 229*1a26feb9SDavid Howells spin_lock_irq(&tsk->sighand->siglock); 230*1a26feb9SDavid Howells old = tsk->signal->session_keyring; 2318589b4e0SDavid Howells rcu_assign_pointer(tsk->signal->session_keyring, keyring); 232*1a26feb9SDavid Howells spin_unlock_irq(&tsk->sighand->siglock); 2331da177e4SLinus Torvalds 234*1a26feb9SDavid Howells /* we're using RCU on the pointer, but there's no point synchronising 235*1a26feb9SDavid Howells * on it if it didn't previously point to anything */ 236*1a26feb9SDavid Howells if (old) { 237b2b18660SPaul E. McKenney synchronize_rcu(); 2381da177e4SLinus Torvalds key_put(old); 239*1a26feb9SDavid Howells } 240*1a26feb9SDavid Howells 241*1a26feb9SDavid Howells return 0; 2421da177e4SLinus Torvalds 2431da177e4SLinus Torvalds } /* end install_session_keyring() */ 2441da177e4SLinus Torvalds 2451da177e4SLinus Torvalds /*****************************************************************************/ 2461da177e4SLinus Torvalds /* 2471da177e4SLinus Torvalds * copy the keys in a thread group for fork without CLONE_THREAD 2481da177e4SLinus Torvalds */ 2491da177e4SLinus Torvalds int copy_thread_group_keys(struct task_struct *tsk) 2501da177e4SLinus Torvalds { 2511da177e4SLinus Torvalds key_check(current->thread_group->session_keyring); 2521da177e4SLinus Torvalds key_check(current->thread_group->process_keyring); 2531da177e4SLinus Torvalds 2541da177e4SLinus Torvalds /* no process keyring yet */ 2551da177e4SLinus Torvalds tsk->signal->process_keyring = NULL; 2561da177e4SLinus Torvalds 2571da177e4SLinus Torvalds /* same session keyring */ 2588589b4e0SDavid Howells rcu_read_lock(); 2591da177e4SLinus Torvalds tsk->signal->session_keyring = 2608589b4e0SDavid Howells key_get(rcu_dereference(current->signal->session_keyring)); 2618589b4e0SDavid Howells rcu_read_unlock(); 2621da177e4SLinus Torvalds 2631da177e4SLinus Torvalds return 0; 2641da177e4SLinus Torvalds 2651da177e4SLinus Torvalds } /* end copy_thread_group_keys() */ 2661da177e4SLinus Torvalds 2671da177e4SLinus Torvalds /*****************************************************************************/ 2681da177e4SLinus Torvalds /* 2691da177e4SLinus Torvalds * copy the keys for fork 2701da177e4SLinus Torvalds */ 2711da177e4SLinus Torvalds int copy_keys(unsigned long clone_flags, struct task_struct *tsk) 2721da177e4SLinus Torvalds { 2731da177e4SLinus Torvalds key_check(tsk->thread_keyring); 274b5f545c8SDavid Howells key_check(tsk->request_key_auth); 2751da177e4SLinus Torvalds 2761da177e4SLinus Torvalds /* no thread keyring yet */ 2771da177e4SLinus Torvalds tsk->thread_keyring = NULL; 278b5f545c8SDavid Howells 279b5f545c8SDavid Howells /* copy the request_key() authorisation for this thread */ 280b5f545c8SDavid Howells key_get(tsk->request_key_auth); 281b5f545c8SDavid Howells 2821da177e4SLinus Torvalds return 0; 2831da177e4SLinus Torvalds 2841da177e4SLinus Torvalds } /* end copy_keys() */ 2851da177e4SLinus Torvalds 2861da177e4SLinus Torvalds /*****************************************************************************/ 2871da177e4SLinus Torvalds /* 2881da177e4SLinus Torvalds * dispose of thread group keys upon thread group destruction 2891da177e4SLinus Torvalds */ 2901da177e4SLinus Torvalds void exit_thread_group_keys(struct signal_struct *tg) 2911da177e4SLinus Torvalds { 2921da177e4SLinus Torvalds key_put(tg->session_keyring); 2931da177e4SLinus Torvalds key_put(tg->process_keyring); 2941da177e4SLinus Torvalds 2951da177e4SLinus Torvalds } /* end exit_thread_group_keys() */ 2961da177e4SLinus Torvalds 2971da177e4SLinus Torvalds /*****************************************************************************/ 2981da177e4SLinus Torvalds /* 299b5f545c8SDavid Howells * dispose of per-thread keys upon thread exit 3001da177e4SLinus Torvalds */ 3011da177e4SLinus Torvalds void exit_keys(struct task_struct *tsk) 3021da177e4SLinus Torvalds { 3031da177e4SLinus Torvalds key_put(tsk->thread_keyring); 304b5f545c8SDavid Howells key_put(tsk->request_key_auth); 3051da177e4SLinus Torvalds 3061da177e4SLinus Torvalds } /* end exit_keys() */ 3071da177e4SLinus Torvalds 3081da177e4SLinus Torvalds /*****************************************************************************/ 3091da177e4SLinus Torvalds /* 3101da177e4SLinus Torvalds * deal with execve() 3111da177e4SLinus Torvalds */ 3121da177e4SLinus Torvalds int exec_keys(struct task_struct *tsk) 3131da177e4SLinus Torvalds { 3141da177e4SLinus Torvalds struct key *old; 3151da177e4SLinus Torvalds 3161da177e4SLinus Torvalds /* newly exec'd tasks don't get a thread keyring */ 3171da177e4SLinus Torvalds task_lock(tsk); 3181da177e4SLinus Torvalds old = tsk->thread_keyring; 3191da177e4SLinus Torvalds tsk->thread_keyring = NULL; 3201da177e4SLinus Torvalds task_unlock(tsk); 3211da177e4SLinus Torvalds 3221da177e4SLinus Torvalds key_put(old); 3231da177e4SLinus Torvalds 3241da177e4SLinus Torvalds /* discard the process keyring from a newly exec'd task */ 325*1a26feb9SDavid Howells spin_lock_irq(&tsk->sighand->siglock); 3261da177e4SLinus Torvalds old = tsk->signal->process_keyring; 3271da177e4SLinus Torvalds tsk->signal->process_keyring = NULL; 328*1a26feb9SDavid Howells spin_unlock_irq(&tsk->sighand->siglock); 3291da177e4SLinus Torvalds 3301da177e4SLinus Torvalds key_put(old); 3311da177e4SLinus Torvalds 3321da177e4SLinus Torvalds return 0; 3331da177e4SLinus Torvalds 3341da177e4SLinus Torvalds } /* end exec_keys() */ 3351da177e4SLinus Torvalds 3361da177e4SLinus Torvalds /*****************************************************************************/ 3371da177e4SLinus Torvalds /* 3381da177e4SLinus Torvalds * deal with SUID programs 3391da177e4SLinus Torvalds * - we might want to make this invent a new session keyring 3401da177e4SLinus Torvalds */ 3411da177e4SLinus Torvalds int suid_keys(struct task_struct *tsk) 3421da177e4SLinus Torvalds { 3431da177e4SLinus Torvalds return 0; 3441da177e4SLinus Torvalds 3451da177e4SLinus Torvalds } /* end suid_keys() */ 3461da177e4SLinus Torvalds 3471da177e4SLinus Torvalds /*****************************************************************************/ 3481da177e4SLinus Torvalds /* 3491da177e4SLinus Torvalds * the filesystem user ID changed 3501da177e4SLinus Torvalds */ 3511da177e4SLinus Torvalds void key_fsuid_changed(struct task_struct *tsk) 3521da177e4SLinus Torvalds { 3531da177e4SLinus Torvalds /* update the ownership of the thread keyring */ 3541da177e4SLinus Torvalds if (tsk->thread_keyring) { 3551da177e4SLinus Torvalds down_write(&tsk->thread_keyring->sem); 3561da177e4SLinus Torvalds tsk->thread_keyring->uid = tsk->fsuid; 3571da177e4SLinus Torvalds up_write(&tsk->thread_keyring->sem); 3581da177e4SLinus Torvalds } 3591da177e4SLinus Torvalds 3601da177e4SLinus Torvalds } /* end key_fsuid_changed() */ 3611da177e4SLinus Torvalds 3621da177e4SLinus Torvalds /*****************************************************************************/ 3631da177e4SLinus Torvalds /* 3641da177e4SLinus Torvalds * the filesystem group ID changed 3651da177e4SLinus Torvalds */ 3661da177e4SLinus Torvalds void key_fsgid_changed(struct task_struct *tsk) 3671da177e4SLinus Torvalds { 3681da177e4SLinus Torvalds /* update the ownership of the thread keyring */ 3691da177e4SLinus Torvalds if (tsk->thread_keyring) { 3701da177e4SLinus Torvalds down_write(&tsk->thread_keyring->sem); 3711da177e4SLinus Torvalds tsk->thread_keyring->gid = tsk->fsgid; 3721da177e4SLinus Torvalds up_write(&tsk->thread_keyring->sem); 3731da177e4SLinus Torvalds } 3741da177e4SLinus Torvalds 3751da177e4SLinus Torvalds } /* end key_fsgid_changed() */ 3761da177e4SLinus Torvalds 3771da177e4SLinus Torvalds /*****************************************************************************/ 3781da177e4SLinus Torvalds /* 3791da177e4SLinus Torvalds * search the process keyrings for the first matching key 3801da177e4SLinus Torvalds * - we use the supplied match function to see if the description (or other 3811da177e4SLinus Torvalds * feature of interest) matches 3821da177e4SLinus Torvalds * - we return -EAGAIN if we didn't find any matching key 3831da177e4SLinus Torvalds * - we return -ENOKEY if we found only negative matching keys 3841da177e4SLinus Torvalds */ 385664cceb0SDavid Howells key_ref_t search_process_keyrings(struct key_type *type, 3861da177e4SLinus Torvalds const void *description, 3873e30148cSDavid Howells key_match_func_t match, 3883e30148cSDavid Howells struct task_struct *context) 3891da177e4SLinus Torvalds { 3903e30148cSDavid Howells struct request_key_auth *rka; 391b5f545c8SDavid Howells key_ref_t key_ref, ret, err; 3921da177e4SLinus Torvalds 3931da177e4SLinus Torvalds /* we want to return -EAGAIN or -ENOKEY if any of the keyrings were 3941da177e4SLinus Torvalds * searchable, but we failed to find a key or we found a negative key; 3951da177e4SLinus Torvalds * otherwise we want to return a sample error (probably -EACCES) if 3961da177e4SLinus Torvalds * none of the keyrings were searchable 3971da177e4SLinus Torvalds * 3981da177e4SLinus Torvalds * in terms of priority: success > -ENOKEY > -EAGAIN > other error 3991da177e4SLinus Torvalds */ 400664cceb0SDavid Howells key_ref = NULL; 4011da177e4SLinus Torvalds ret = NULL; 4021da177e4SLinus Torvalds err = ERR_PTR(-EAGAIN); 4031da177e4SLinus Torvalds 4041da177e4SLinus Torvalds /* search the thread keyring first */ 4053e30148cSDavid Howells if (context->thread_keyring) { 406664cceb0SDavid Howells key_ref = keyring_search_aux( 407664cceb0SDavid Howells make_key_ref(context->thread_keyring, 1), 4083e30148cSDavid Howells context, type, description, match); 409664cceb0SDavid Howells if (!IS_ERR(key_ref)) 4101da177e4SLinus Torvalds goto found; 4111da177e4SLinus Torvalds 412664cceb0SDavid Howells switch (PTR_ERR(key_ref)) { 4131da177e4SLinus Torvalds case -EAGAIN: /* no key */ 4141da177e4SLinus Torvalds if (ret) 4151da177e4SLinus Torvalds break; 4161da177e4SLinus Torvalds case -ENOKEY: /* negative key */ 417664cceb0SDavid Howells ret = key_ref; 4181da177e4SLinus Torvalds break; 4191da177e4SLinus Torvalds default: 420664cceb0SDavid Howells err = key_ref; 4211da177e4SLinus Torvalds break; 4221da177e4SLinus Torvalds } 4231da177e4SLinus Torvalds } 4241da177e4SLinus Torvalds 4251da177e4SLinus Torvalds /* search the process keyring second */ 4263e30148cSDavid Howells if (context->signal->process_keyring) { 427664cceb0SDavid Howells key_ref = keyring_search_aux( 428664cceb0SDavid Howells make_key_ref(context->signal->process_keyring, 1), 4293e30148cSDavid Howells context, type, description, match); 430664cceb0SDavid Howells if (!IS_ERR(key_ref)) 4311da177e4SLinus Torvalds goto found; 4321da177e4SLinus Torvalds 433664cceb0SDavid Howells switch (PTR_ERR(key_ref)) { 4341da177e4SLinus Torvalds case -EAGAIN: /* no key */ 4351da177e4SLinus Torvalds if (ret) 4361da177e4SLinus Torvalds break; 4371da177e4SLinus Torvalds case -ENOKEY: /* negative key */ 438664cceb0SDavid Howells ret = key_ref; 4391da177e4SLinus Torvalds break; 4401da177e4SLinus Torvalds default: 441664cceb0SDavid Howells err = key_ref; 4421da177e4SLinus Torvalds break; 4431da177e4SLinus Torvalds } 4441da177e4SLinus Torvalds } 4451da177e4SLinus Torvalds 4463e30148cSDavid Howells /* search the session keyring */ 4473e30148cSDavid Howells if (context->signal->session_keyring) { 4488589b4e0SDavid Howells rcu_read_lock(); 449664cceb0SDavid Howells key_ref = keyring_search_aux( 450664cceb0SDavid Howells make_key_ref(rcu_dereference( 451664cceb0SDavid Howells context->signal->session_keyring), 452664cceb0SDavid Howells 1), 4533e30148cSDavid Howells context, type, description, match); 4548589b4e0SDavid Howells rcu_read_unlock(); 4551da177e4SLinus Torvalds 456664cceb0SDavid Howells if (!IS_ERR(key_ref)) 4571da177e4SLinus Torvalds goto found; 4581da177e4SLinus Torvalds 459664cceb0SDavid Howells switch (PTR_ERR(key_ref)) { 4601da177e4SLinus Torvalds case -EAGAIN: /* no key */ 4611da177e4SLinus Torvalds if (ret) 4621da177e4SLinus Torvalds break; 4631da177e4SLinus Torvalds case -ENOKEY: /* negative key */ 464664cceb0SDavid Howells ret = key_ref; 4651da177e4SLinus Torvalds break; 4661da177e4SLinus Torvalds default: 467664cceb0SDavid Howells err = key_ref; 4681da177e4SLinus Torvalds break; 4691da177e4SLinus Torvalds } 4703e30148cSDavid Howells } 4713e30148cSDavid Howells /* or search the user-session keyring */ 4723e30148cSDavid Howells else { 473664cceb0SDavid Howells key_ref = keyring_search_aux( 474664cceb0SDavid Howells make_key_ref(context->user->session_keyring, 1), 4753e30148cSDavid Howells context, type, description, match); 476664cceb0SDavid Howells if (!IS_ERR(key_ref)) 4773e30148cSDavid Howells goto found; 4783e30148cSDavid Howells 479664cceb0SDavid Howells switch (PTR_ERR(key_ref)) { 4803e30148cSDavid Howells case -EAGAIN: /* no key */ 4813e30148cSDavid Howells if (ret) 4823e30148cSDavid Howells break; 4833e30148cSDavid Howells case -ENOKEY: /* negative key */ 484664cceb0SDavid Howells ret = key_ref; 4853e30148cSDavid Howells break; 4863e30148cSDavid Howells default: 487664cceb0SDavid Howells err = key_ref; 4883e30148cSDavid Howells break; 4893e30148cSDavid Howells } 4903e30148cSDavid Howells } 4913e30148cSDavid Howells 492b5f545c8SDavid Howells /* if this process has an instantiation authorisation key, then we also 493b5f545c8SDavid Howells * search the keyrings of the process mentioned there 494b5f545c8SDavid Howells * - we don't permit access to request_key auth keys via this method 495b5f545c8SDavid Howells */ 496b5f545c8SDavid Howells if (context->request_key_auth && 497b5f545c8SDavid Howells context == current && 498b5f545c8SDavid Howells type != &key_type_request_key_auth && 499b5f545c8SDavid Howells key_validate(context->request_key_auth) == 0 500b5f545c8SDavid Howells ) { 501b5f545c8SDavid Howells rka = context->request_key_auth->payload.data; 5023e30148cSDavid Howells 503b5f545c8SDavid Howells key_ref = search_process_keyrings(type, description, match, 504b5f545c8SDavid Howells rka->context); 505b5f545c8SDavid Howells 506b5f545c8SDavid Howells if (!IS_ERR(key_ref)) 507b5f545c8SDavid Howells goto found; 508b5f545c8SDavid Howells 509b5f545c8SDavid Howells switch (PTR_ERR(key_ref)) { 510b5f545c8SDavid Howells case -EAGAIN: /* no key */ 511b5f545c8SDavid Howells if (ret) 512b5f545c8SDavid Howells break; 513b5f545c8SDavid Howells case -ENOKEY: /* negative key */ 514b5f545c8SDavid Howells ret = key_ref; 515b5f545c8SDavid Howells break; 516b5f545c8SDavid Howells default: 517b5f545c8SDavid Howells err = key_ref; 518b5f545c8SDavid Howells break; 519b5f545c8SDavid Howells } 520b5f545c8SDavid Howells } 521b5f545c8SDavid Howells 5221da177e4SLinus Torvalds /* no key - decide on the error we're going to go for */ 523664cceb0SDavid Howells key_ref = ret ? ret : err; 5241da177e4SLinus Torvalds 5251da177e4SLinus Torvalds found: 526664cceb0SDavid Howells return key_ref; 5271da177e4SLinus Torvalds 5281da177e4SLinus Torvalds } /* end search_process_keyrings() */ 5291da177e4SLinus Torvalds 5301da177e4SLinus Torvalds /*****************************************************************************/ 5311da177e4SLinus Torvalds /* 532664cceb0SDavid Howells * see if the key we're looking at is the target key 533664cceb0SDavid Howells */ 534664cceb0SDavid Howells static int lookup_user_key_possessed(const struct key *key, const void *target) 535664cceb0SDavid Howells { 536664cceb0SDavid Howells return key == target; 537664cceb0SDavid Howells 538664cceb0SDavid Howells } /* end lookup_user_key_possessed() */ 539664cceb0SDavid Howells 540664cceb0SDavid Howells /*****************************************************************************/ 541664cceb0SDavid Howells /* 5421da177e4SLinus Torvalds * lookup a key given a key ID from userspace with a given permissions mask 5431da177e4SLinus Torvalds * - don't create special keyrings unless so requested 5441da177e4SLinus Torvalds * - partially constructed keys aren't found unless requested 5451da177e4SLinus Torvalds */ 546664cceb0SDavid Howells key_ref_t lookup_user_key(struct task_struct *context, key_serial_t id, 5473e30148cSDavid Howells int create, int partial, key_perm_t perm) 5481da177e4SLinus Torvalds { 549664cceb0SDavid Howells key_ref_t key_ref, skey_ref; 5501da177e4SLinus Torvalds struct key *key; 5511da177e4SLinus Torvalds int ret; 5521da177e4SLinus Torvalds 5533e30148cSDavid Howells if (!context) 5543e30148cSDavid Howells context = current; 5553e30148cSDavid Howells 556664cceb0SDavid Howells key_ref = ERR_PTR(-ENOKEY); 5571da177e4SLinus Torvalds 5581da177e4SLinus Torvalds switch (id) { 5591da177e4SLinus Torvalds case KEY_SPEC_THREAD_KEYRING: 5603e30148cSDavid Howells if (!context->thread_keyring) { 5611da177e4SLinus Torvalds if (!create) 5621da177e4SLinus Torvalds goto error; 5631da177e4SLinus Torvalds 5643e30148cSDavid Howells ret = install_thread_keyring(context); 5651da177e4SLinus Torvalds if (ret < 0) { 5661da177e4SLinus Torvalds key = ERR_PTR(ret); 5671da177e4SLinus Torvalds goto error; 5681da177e4SLinus Torvalds } 5691da177e4SLinus Torvalds } 5701da177e4SLinus Torvalds 5713e30148cSDavid Howells key = context->thread_keyring; 5721da177e4SLinus Torvalds atomic_inc(&key->usage); 573664cceb0SDavid Howells key_ref = make_key_ref(key, 1); 5741da177e4SLinus Torvalds break; 5751da177e4SLinus Torvalds 5761da177e4SLinus Torvalds case KEY_SPEC_PROCESS_KEYRING: 5773e30148cSDavid Howells if (!context->signal->process_keyring) { 5781da177e4SLinus Torvalds if (!create) 5791da177e4SLinus Torvalds goto error; 5801da177e4SLinus Torvalds 5813e30148cSDavid Howells ret = install_process_keyring(context); 5821da177e4SLinus Torvalds if (ret < 0) { 5831da177e4SLinus Torvalds key = ERR_PTR(ret); 5841da177e4SLinus Torvalds goto error; 5851da177e4SLinus Torvalds } 5861da177e4SLinus Torvalds } 5871da177e4SLinus Torvalds 5883e30148cSDavid Howells key = context->signal->process_keyring; 5891da177e4SLinus Torvalds atomic_inc(&key->usage); 590664cceb0SDavid Howells key_ref = make_key_ref(key, 1); 5911da177e4SLinus Torvalds break; 5921da177e4SLinus Torvalds 5931da177e4SLinus Torvalds case KEY_SPEC_SESSION_KEYRING: 5943e30148cSDavid Howells if (!context->signal->session_keyring) { 5951da177e4SLinus Torvalds /* always install a session keyring upon access if one 5961da177e4SLinus Torvalds * doesn't exist yet */ 5971da177e4SLinus Torvalds ret = install_session_keyring( 5983e30148cSDavid Howells context, context->user->session_keyring); 5991da177e4SLinus Torvalds if (ret < 0) 6001da177e4SLinus Torvalds goto error; 6011da177e4SLinus Torvalds } 6021da177e4SLinus Torvalds 6033e30148cSDavid Howells rcu_read_lock(); 6043e30148cSDavid Howells key = rcu_dereference(context->signal->session_keyring); 6051da177e4SLinus Torvalds atomic_inc(&key->usage); 6063e30148cSDavid Howells rcu_read_unlock(); 607664cceb0SDavid Howells key_ref = make_key_ref(key, 1); 6081da177e4SLinus Torvalds break; 6091da177e4SLinus Torvalds 6101da177e4SLinus Torvalds case KEY_SPEC_USER_KEYRING: 6113e30148cSDavid Howells key = context->user->uid_keyring; 6121da177e4SLinus Torvalds atomic_inc(&key->usage); 613664cceb0SDavid Howells key_ref = make_key_ref(key, 1); 6141da177e4SLinus Torvalds break; 6151da177e4SLinus Torvalds 6161da177e4SLinus Torvalds case KEY_SPEC_USER_SESSION_KEYRING: 6173e30148cSDavid Howells key = context->user->session_keyring; 6181da177e4SLinus Torvalds atomic_inc(&key->usage); 619664cceb0SDavid Howells key_ref = make_key_ref(key, 1); 6201da177e4SLinus Torvalds break; 6211da177e4SLinus Torvalds 6221da177e4SLinus Torvalds case KEY_SPEC_GROUP_KEYRING: 6231da177e4SLinus Torvalds /* group keyrings are not yet supported */ 6241da177e4SLinus Torvalds key = ERR_PTR(-EINVAL); 6251da177e4SLinus Torvalds goto error; 6261da177e4SLinus Torvalds 627b5f545c8SDavid Howells case KEY_SPEC_REQKEY_AUTH_KEY: 628b5f545c8SDavid Howells key = context->request_key_auth; 629b5f545c8SDavid Howells if (!key) 630b5f545c8SDavid Howells goto error; 631b5f545c8SDavid Howells 632b5f545c8SDavid Howells atomic_inc(&key->usage); 633b5f545c8SDavid Howells key_ref = make_key_ref(key, 1); 634b5f545c8SDavid Howells break; 635b5f545c8SDavid Howells 6361da177e4SLinus Torvalds default: 637664cceb0SDavid Howells key_ref = ERR_PTR(-EINVAL); 6381da177e4SLinus Torvalds if (id < 1) 6391da177e4SLinus Torvalds goto error; 6401da177e4SLinus Torvalds 6411da177e4SLinus Torvalds key = key_lookup(id); 642664cceb0SDavid Howells if (IS_ERR(key)) { 643664cceb0SDavid Howells key_ref = ERR_PTR(PTR_ERR(key)); 6441da177e4SLinus Torvalds goto error; 645664cceb0SDavid Howells } 646664cceb0SDavid Howells 647664cceb0SDavid Howells key_ref = make_key_ref(key, 0); 648664cceb0SDavid Howells 649664cceb0SDavid Howells /* check to see if we possess the key */ 650664cceb0SDavid Howells skey_ref = search_process_keyrings(key->type, key, 651664cceb0SDavid Howells lookup_user_key_possessed, 652664cceb0SDavid Howells current); 653664cceb0SDavid Howells 654664cceb0SDavid Howells if (!IS_ERR(skey_ref)) { 655664cceb0SDavid Howells key_put(key); 656664cceb0SDavid Howells key_ref = skey_ref; 657664cceb0SDavid Howells } 658664cceb0SDavid Howells 6591da177e4SLinus Torvalds break; 6601da177e4SLinus Torvalds } 6611da177e4SLinus Torvalds 6623e30148cSDavid Howells /* check the status */ 6631da177e4SLinus Torvalds if (perm) { 6641da177e4SLinus Torvalds ret = key_validate(key); 6651da177e4SLinus Torvalds if (ret < 0) 6661da177e4SLinus Torvalds goto invalid_key; 6671da177e4SLinus Torvalds } 6681da177e4SLinus Torvalds 6691da177e4SLinus Torvalds ret = -EIO; 67076d8aeabSDavid Howells if (!partial && !test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) 6711da177e4SLinus Torvalds goto invalid_key; 6721da177e4SLinus Torvalds 6733e30148cSDavid Howells /* check the permissions */ 67429db9190SDavid Howells ret = key_task_permission(key_ref, context, perm); 67529db9190SDavid Howells if (ret < 0) 6761da177e4SLinus Torvalds goto invalid_key; 6771da177e4SLinus Torvalds 6781da177e4SLinus Torvalds error: 679664cceb0SDavid Howells return key_ref; 6801da177e4SLinus Torvalds 6811da177e4SLinus Torvalds invalid_key: 682664cceb0SDavid Howells key_ref_put(key_ref); 683664cceb0SDavid Howells key_ref = ERR_PTR(ret); 6841da177e4SLinus Torvalds goto error; 6851da177e4SLinus Torvalds 6861da177e4SLinus Torvalds } /* end lookup_user_key() */ 6871da177e4SLinus Torvalds 6881da177e4SLinus Torvalds /*****************************************************************************/ 6891da177e4SLinus Torvalds /* 6901da177e4SLinus Torvalds * join the named keyring as the session keyring if possible, or attempt to 6911da177e4SLinus Torvalds * create a new one of that name if not 6921da177e4SLinus Torvalds * - if the name is NULL, an empty anonymous keyring is installed instead 6931da177e4SLinus Torvalds * - named session keyring joining is done with a semaphore held 6941da177e4SLinus Torvalds */ 6951da177e4SLinus Torvalds long join_session_keyring(const char *name) 6961da177e4SLinus Torvalds { 6971da177e4SLinus Torvalds struct task_struct *tsk = current; 6981da177e4SLinus Torvalds struct key *keyring; 6991da177e4SLinus Torvalds long ret; 7001da177e4SLinus Torvalds 7011da177e4SLinus Torvalds /* if no name is provided, install an anonymous keyring */ 7021da177e4SLinus Torvalds if (!name) { 7031da177e4SLinus Torvalds ret = install_session_keyring(tsk, NULL); 7041da177e4SLinus Torvalds if (ret < 0) 7051da177e4SLinus Torvalds goto error; 7061da177e4SLinus Torvalds 7073e30148cSDavid Howells rcu_read_lock(); 7083e30148cSDavid Howells ret = rcu_dereference(tsk->signal->session_keyring)->serial; 7093e30148cSDavid Howells rcu_read_unlock(); 7101da177e4SLinus Torvalds goto error; 7111da177e4SLinus Torvalds } 7121da177e4SLinus Torvalds 7131da177e4SLinus Torvalds /* allow the user to join or create a named keyring */ 714bb003079SIngo Molnar mutex_lock(&key_session_mutex); 7151da177e4SLinus Torvalds 7161da177e4SLinus Torvalds /* look for an existing keyring of this name */ 7171da177e4SLinus Torvalds keyring = find_keyring_by_name(name, 0); 7181da177e4SLinus Torvalds if (PTR_ERR(keyring) == -ENOKEY) { 7191da177e4SLinus Torvalds /* not found - try and create a new one */ 7201da177e4SLinus Torvalds keyring = keyring_alloc(name, tsk->uid, tsk->gid, 0, NULL); 7211da177e4SLinus Torvalds if (IS_ERR(keyring)) { 7221da177e4SLinus Torvalds ret = PTR_ERR(keyring); 723bcf945d3SDavid Howells goto error2; 7241da177e4SLinus Torvalds } 7251da177e4SLinus Torvalds } 7261da177e4SLinus Torvalds else if (IS_ERR(keyring)) { 7271da177e4SLinus Torvalds ret = PTR_ERR(keyring); 7281da177e4SLinus Torvalds goto error2; 7291da177e4SLinus Torvalds } 7301da177e4SLinus Torvalds 7311da177e4SLinus Torvalds /* we've got a keyring - now to install it */ 7321da177e4SLinus Torvalds ret = install_session_keyring(tsk, keyring); 7331da177e4SLinus Torvalds if (ret < 0) 7341da177e4SLinus Torvalds goto error2; 7351da177e4SLinus Torvalds 7361da177e4SLinus Torvalds ret = keyring->serial; 7371da177e4SLinus Torvalds key_put(keyring); 7381da177e4SLinus Torvalds 7391da177e4SLinus Torvalds error2: 740bb003079SIngo Molnar mutex_unlock(&key_session_mutex); 7411da177e4SLinus Torvalds error: 7421da177e4SLinus Torvalds return ret; 7431da177e4SLinus Torvalds 7441da177e4SLinus Torvalds } /* end join_session_keyring() */ 745