169664cf1SDavid Howells /* Management of 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/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 2669664cf1SDavid Howells /* user keyring creation semaphore */ 2769664cf1SDavid Howells static DEFINE_MUTEX(key_user_keyring_mutex); 2869664cf1SDavid Howells 291da177e4SLinus Torvalds /* the root user's tracking struct */ 301da177e4SLinus Torvalds struct key_user root_key_user = { 311da177e4SLinus Torvalds .usage = ATOMIC_INIT(3), 3276181c13SDavid Howells .cons_lock = __MUTEX_INITIALIZER(root_key_user.cons_lock), 336cfd76a2SPeter Zijlstra .lock = __SPIN_LOCK_UNLOCKED(root_key_user.lock), 341da177e4SLinus Torvalds .nkeys = ATOMIC_INIT(2), 351da177e4SLinus Torvalds .nikeys = ATOMIC_INIT(2), 361da177e4SLinus Torvalds .uid = 0, 371da177e4SLinus Torvalds }; 381da177e4SLinus Torvalds 391da177e4SLinus Torvalds /*****************************************************************************/ 401da177e4SLinus Torvalds /* 4169664cf1SDavid Howells * install user and user session keyrings for a particular UID 421da177e4SLinus Torvalds */ 43*8bbf4976SDavid Howells int install_user_keyrings(void) 441da177e4SLinus Torvalds { 45*8bbf4976SDavid Howells struct user_struct *user = current->user; 461da177e4SLinus Torvalds struct key *uid_keyring, *session_keyring; 471da177e4SLinus Torvalds char buf[20]; 481da177e4SLinus Torvalds int ret; 491da177e4SLinus Torvalds 5069664cf1SDavid Howells kenter("%p{%u}", user, user->uid); 511da177e4SLinus Torvalds 5269664cf1SDavid Howells if (user->uid_keyring) { 5369664cf1SDavid Howells kleave(" = 0 [exist]"); 5469664cf1SDavid Howells return 0; 551da177e4SLinus Torvalds } 561da177e4SLinus Torvalds 5769664cf1SDavid Howells mutex_lock(&key_user_keyring_mutex); 5869664cf1SDavid Howells ret = 0; 5969664cf1SDavid Howells 6069664cf1SDavid Howells if (!user->uid_keyring) { 6169664cf1SDavid Howells /* get the UID-specific keyring 6269664cf1SDavid Howells * - there may be one in existence already as it may have been 6369664cf1SDavid Howells * pinned by a session, but the user_struct pointing to it 6469664cf1SDavid Howells * may have been destroyed by setuid */ 651da177e4SLinus Torvalds sprintf(buf, "_uid.%u", user->uid); 661da177e4SLinus Torvalds 6769664cf1SDavid Howells uid_keyring = find_keyring_by_name(buf, true); 681da177e4SLinus Torvalds if (IS_ERR(uid_keyring)) { 6969664cf1SDavid Howells uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, 70*8bbf4976SDavid Howells current, KEY_ALLOC_IN_QUOTA, 7169664cf1SDavid Howells NULL); 7269664cf1SDavid Howells if (IS_ERR(uid_keyring)) { 731da177e4SLinus Torvalds ret = PTR_ERR(uid_keyring); 741da177e4SLinus Torvalds goto error; 751da177e4SLinus Torvalds } 7669664cf1SDavid Howells } 7769664cf1SDavid Howells 7869664cf1SDavid Howells /* get a default session keyring (which might also exist 7969664cf1SDavid Howells * already) */ 8069664cf1SDavid Howells sprintf(buf, "_uid_ses.%u", user->uid); 8169664cf1SDavid Howells 8269664cf1SDavid Howells session_keyring = find_keyring_by_name(buf, true); 8369664cf1SDavid Howells if (IS_ERR(session_keyring)) { 8469664cf1SDavid Howells session_keyring = 8569664cf1SDavid Howells keyring_alloc(buf, user->uid, (gid_t) -1, 86*8bbf4976SDavid Howells current, KEY_ALLOC_IN_QUOTA, 87*8bbf4976SDavid Howells NULL); 8869664cf1SDavid Howells if (IS_ERR(session_keyring)) { 8969664cf1SDavid Howells ret = PTR_ERR(session_keyring); 9069664cf1SDavid Howells goto error_release; 9169664cf1SDavid Howells } 9269664cf1SDavid Howells 9369664cf1SDavid Howells /* we install a link from the user session keyring to 9469664cf1SDavid Howells * the user keyring */ 9569664cf1SDavid Howells ret = key_link(session_keyring, uid_keyring); 9669664cf1SDavid Howells if (ret < 0) 9769664cf1SDavid Howells goto error_release_both; 9869664cf1SDavid Howells } 991da177e4SLinus Torvalds 1001da177e4SLinus Torvalds /* install the keyrings */ 1011da177e4SLinus Torvalds user->uid_keyring = uid_keyring; 1021da177e4SLinus Torvalds user->session_keyring = session_keyring; 10369664cf1SDavid Howells } 1041da177e4SLinus Torvalds 10569664cf1SDavid Howells mutex_unlock(&key_user_keyring_mutex); 10669664cf1SDavid Howells kleave(" = 0"); 10769664cf1SDavid Howells return 0; 10869664cf1SDavid Howells 10969664cf1SDavid Howells error_release_both: 11069664cf1SDavid Howells key_put(session_keyring); 11169664cf1SDavid Howells error_release: 11269664cf1SDavid Howells key_put(uid_keyring); 1131da177e4SLinus Torvalds error: 11469664cf1SDavid Howells mutex_unlock(&key_user_keyring_mutex); 11569664cf1SDavid Howells kleave(" = %d", ret); 1161da177e4SLinus Torvalds return ret; 11769664cf1SDavid Howells } 1181da177e4SLinus Torvalds 1191da177e4SLinus Torvalds /*****************************************************************************/ 1201da177e4SLinus Torvalds /* 1211da177e4SLinus Torvalds * deal with the UID changing 1221da177e4SLinus Torvalds */ 1231da177e4SLinus Torvalds void switch_uid_keyring(struct user_struct *new_user) 1241da177e4SLinus Torvalds { 1251da177e4SLinus Torvalds #if 0 /* do nothing for now */ 1261da177e4SLinus Torvalds struct key *old; 1271da177e4SLinus Torvalds 1281da177e4SLinus Torvalds /* switch to the new user's session keyring if we were running under 1291da177e4SLinus Torvalds * root's default session keyring */ 1301da177e4SLinus Torvalds if (new_user->uid != 0 && 1311da177e4SLinus Torvalds current->session_keyring == &root_session_keyring 1321da177e4SLinus Torvalds ) { 1331da177e4SLinus Torvalds atomic_inc(&new_user->session_keyring->usage); 1341da177e4SLinus Torvalds 1351da177e4SLinus Torvalds task_lock(current); 1361da177e4SLinus Torvalds old = current->session_keyring; 1371da177e4SLinus Torvalds current->session_keyring = new_user->session_keyring; 1381da177e4SLinus Torvalds task_unlock(current); 1391da177e4SLinus Torvalds 1401da177e4SLinus Torvalds key_put(old); 1411da177e4SLinus Torvalds } 1421da177e4SLinus Torvalds #endif 1431da177e4SLinus Torvalds 1441da177e4SLinus Torvalds } /* end switch_uid_keyring() */ 1451da177e4SLinus Torvalds 1461da177e4SLinus Torvalds /*****************************************************************************/ 1471da177e4SLinus Torvalds /* 1481da177e4SLinus Torvalds * install a fresh thread keyring, discarding the old one 1491da177e4SLinus Torvalds */ 150*8bbf4976SDavid Howells int install_thread_keyring(void) 1511da177e4SLinus Torvalds { 152*8bbf4976SDavid Howells struct task_struct *tsk = current; 1531da177e4SLinus Torvalds struct key *keyring, *old; 1541da177e4SLinus Torvalds char buf[20]; 1551da177e4SLinus Torvalds int ret; 1561da177e4SLinus Torvalds 1571da177e4SLinus Torvalds sprintf(buf, "_tid.%u", tsk->pid); 1581da177e4SLinus Torvalds 1597e047ef5SDavid Howells keyring = keyring_alloc(buf, tsk->uid, tsk->gid, tsk, 1607e047ef5SDavid Howells KEY_ALLOC_QUOTA_OVERRUN, NULL); 1611da177e4SLinus Torvalds if (IS_ERR(keyring)) { 1621da177e4SLinus Torvalds ret = PTR_ERR(keyring); 1631da177e4SLinus Torvalds goto error; 1641da177e4SLinus Torvalds } 1651da177e4SLinus Torvalds 1661da177e4SLinus Torvalds task_lock(tsk); 1671da177e4SLinus Torvalds old = tsk->thread_keyring; 1681da177e4SLinus Torvalds tsk->thread_keyring = keyring; 1691da177e4SLinus Torvalds task_unlock(tsk); 1701da177e4SLinus Torvalds 1711da177e4SLinus Torvalds ret = 0; 1721da177e4SLinus Torvalds 1731da177e4SLinus Torvalds key_put(old); 1741da177e4SLinus Torvalds error: 1751da177e4SLinus Torvalds return ret; 1761da177e4SLinus Torvalds 1771da177e4SLinus Torvalds } /* end install_thread_keyring() */ 1781da177e4SLinus Torvalds 1791da177e4SLinus Torvalds /*****************************************************************************/ 1801da177e4SLinus Torvalds /* 1811da177e4SLinus Torvalds * make sure a process keyring is installed 1821da177e4SLinus Torvalds */ 183*8bbf4976SDavid Howells int install_process_keyring(void) 1841da177e4SLinus Torvalds { 185*8bbf4976SDavid Howells struct task_struct *tsk = current; 1861da177e4SLinus Torvalds struct key *keyring; 1871da177e4SLinus Torvalds char buf[20]; 1881da177e4SLinus Torvalds int ret; 1891da177e4SLinus Torvalds 1901a26feb9SDavid Howells might_sleep(); 1911a26feb9SDavid Howells 1921da177e4SLinus Torvalds if (!tsk->signal->process_keyring) { 1931da177e4SLinus Torvalds sprintf(buf, "_pid.%u", tsk->tgid); 1941da177e4SLinus Torvalds 1957e047ef5SDavid Howells keyring = keyring_alloc(buf, tsk->uid, tsk->gid, tsk, 1967e047ef5SDavid Howells KEY_ALLOC_QUOTA_OVERRUN, NULL); 1971da177e4SLinus Torvalds if (IS_ERR(keyring)) { 1981da177e4SLinus Torvalds ret = PTR_ERR(keyring); 1991da177e4SLinus Torvalds goto error; 2001da177e4SLinus Torvalds } 2011da177e4SLinus Torvalds 2028589b4e0SDavid Howells /* attach keyring */ 2031a26feb9SDavid Howells spin_lock_irq(&tsk->sighand->siglock); 2041da177e4SLinus Torvalds if (!tsk->signal->process_keyring) { 2051da177e4SLinus Torvalds tsk->signal->process_keyring = keyring; 2061da177e4SLinus Torvalds keyring = NULL; 2071da177e4SLinus Torvalds } 2081a26feb9SDavid Howells spin_unlock_irq(&tsk->sighand->siglock); 2091da177e4SLinus Torvalds 2101da177e4SLinus Torvalds key_put(keyring); 2111da177e4SLinus Torvalds } 2121da177e4SLinus Torvalds 2131da177e4SLinus Torvalds ret = 0; 2141da177e4SLinus Torvalds error: 2151da177e4SLinus Torvalds return ret; 2161da177e4SLinus Torvalds 2171da177e4SLinus Torvalds } /* end install_process_keyring() */ 2181da177e4SLinus Torvalds 2191da177e4SLinus Torvalds /*****************************************************************************/ 2201da177e4SLinus Torvalds /* 2211da177e4SLinus Torvalds * install a session keyring, discarding the old one 2221da177e4SLinus Torvalds * - if a keyring is not supplied, an empty one is invented 2231da177e4SLinus Torvalds */ 224*8bbf4976SDavid Howells static int install_session_keyring(struct key *keyring) 2251da177e4SLinus Torvalds { 226*8bbf4976SDavid Howells struct task_struct *tsk = current; 2277e047ef5SDavid Howells unsigned long flags; 2281da177e4SLinus Torvalds struct key *old; 2291da177e4SLinus Torvalds char buf[20]; 2301a26feb9SDavid Howells 2311a26feb9SDavid Howells might_sleep(); 2321da177e4SLinus Torvalds 2331da177e4SLinus Torvalds /* create an empty session keyring */ 2341da177e4SLinus Torvalds if (!keyring) { 2351da177e4SLinus Torvalds sprintf(buf, "_ses.%u", tsk->tgid); 2361da177e4SLinus Torvalds 2377e047ef5SDavid Howells flags = KEY_ALLOC_QUOTA_OVERRUN; 2387e047ef5SDavid Howells if (tsk->signal->session_keyring) 2397e047ef5SDavid Howells flags = KEY_ALLOC_IN_QUOTA; 2407e047ef5SDavid Howells 2417e047ef5SDavid Howells keyring = keyring_alloc(buf, tsk->uid, tsk->gid, tsk, 2427e047ef5SDavid Howells flags, NULL); 2431a26feb9SDavid Howells if (IS_ERR(keyring)) 2441a26feb9SDavid Howells return PTR_ERR(keyring); 2451da177e4SLinus Torvalds } 2461da177e4SLinus Torvalds else { 2471da177e4SLinus Torvalds atomic_inc(&keyring->usage); 2481da177e4SLinus Torvalds } 2491da177e4SLinus Torvalds 2501da177e4SLinus Torvalds /* install the keyring */ 2511a26feb9SDavid Howells spin_lock_irq(&tsk->sighand->siglock); 2521a26feb9SDavid Howells old = tsk->signal->session_keyring; 2538589b4e0SDavid Howells rcu_assign_pointer(tsk->signal->session_keyring, keyring); 2541a26feb9SDavid Howells spin_unlock_irq(&tsk->sighand->siglock); 2551da177e4SLinus Torvalds 2561a26feb9SDavid Howells /* we're using RCU on the pointer, but there's no point synchronising 2571a26feb9SDavid Howells * on it if it didn't previously point to anything */ 2581a26feb9SDavid Howells if (old) { 259b2b18660SPaul E. McKenney synchronize_rcu(); 2601da177e4SLinus Torvalds key_put(old); 2611a26feb9SDavid Howells } 2621a26feb9SDavid Howells 2631a26feb9SDavid Howells return 0; 2641da177e4SLinus Torvalds 2651da177e4SLinus Torvalds } /* end install_session_keyring() */ 2661da177e4SLinus Torvalds 2671da177e4SLinus Torvalds /*****************************************************************************/ 2681da177e4SLinus Torvalds /* 2691da177e4SLinus Torvalds * copy the keys in a thread group for fork without CLONE_THREAD 2701da177e4SLinus Torvalds */ 2711da177e4SLinus Torvalds int copy_thread_group_keys(struct task_struct *tsk) 2721da177e4SLinus Torvalds { 2731da177e4SLinus Torvalds key_check(current->thread_group->session_keyring); 2741da177e4SLinus Torvalds key_check(current->thread_group->process_keyring); 2751da177e4SLinus Torvalds 2761da177e4SLinus Torvalds /* no process keyring yet */ 2771da177e4SLinus Torvalds tsk->signal->process_keyring = NULL; 2781da177e4SLinus Torvalds 2791da177e4SLinus Torvalds /* same session keyring */ 2808589b4e0SDavid Howells rcu_read_lock(); 2811da177e4SLinus Torvalds tsk->signal->session_keyring = 2828589b4e0SDavid Howells key_get(rcu_dereference(current->signal->session_keyring)); 2838589b4e0SDavid Howells rcu_read_unlock(); 2841da177e4SLinus Torvalds 2851da177e4SLinus Torvalds return 0; 2861da177e4SLinus Torvalds 2871da177e4SLinus Torvalds } /* end copy_thread_group_keys() */ 2881da177e4SLinus Torvalds 2891da177e4SLinus Torvalds /*****************************************************************************/ 2901da177e4SLinus Torvalds /* 2911da177e4SLinus Torvalds * copy the keys for fork 2921da177e4SLinus Torvalds */ 2931da177e4SLinus Torvalds int copy_keys(unsigned long clone_flags, struct task_struct *tsk) 2941da177e4SLinus Torvalds { 2951da177e4SLinus Torvalds key_check(tsk->thread_keyring); 296b5f545c8SDavid Howells key_check(tsk->request_key_auth); 2971da177e4SLinus Torvalds 2981da177e4SLinus Torvalds /* no thread keyring yet */ 2991da177e4SLinus Torvalds tsk->thread_keyring = NULL; 300b5f545c8SDavid Howells 301b5f545c8SDavid Howells /* copy the request_key() authorisation for this thread */ 302b5f545c8SDavid Howells key_get(tsk->request_key_auth); 303b5f545c8SDavid Howells 3041da177e4SLinus Torvalds return 0; 3051da177e4SLinus Torvalds 3061da177e4SLinus Torvalds } /* end copy_keys() */ 3071da177e4SLinus Torvalds 3081da177e4SLinus Torvalds /*****************************************************************************/ 3091da177e4SLinus Torvalds /* 3101da177e4SLinus Torvalds * dispose of thread group keys upon thread group destruction 3111da177e4SLinus Torvalds */ 3121da177e4SLinus Torvalds void exit_thread_group_keys(struct signal_struct *tg) 3131da177e4SLinus Torvalds { 3141da177e4SLinus Torvalds key_put(tg->session_keyring); 3151da177e4SLinus Torvalds key_put(tg->process_keyring); 3161da177e4SLinus Torvalds 3171da177e4SLinus Torvalds } /* end exit_thread_group_keys() */ 3181da177e4SLinus Torvalds 3191da177e4SLinus Torvalds /*****************************************************************************/ 3201da177e4SLinus Torvalds /* 321b5f545c8SDavid Howells * dispose of per-thread keys upon thread exit 3221da177e4SLinus Torvalds */ 3231da177e4SLinus Torvalds void exit_keys(struct task_struct *tsk) 3241da177e4SLinus Torvalds { 3251da177e4SLinus Torvalds key_put(tsk->thread_keyring); 326b5f545c8SDavid Howells key_put(tsk->request_key_auth); 3271da177e4SLinus Torvalds 3281da177e4SLinus Torvalds } /* end exit_keys() */ 3291da177e4SLinus Torvalds 3301da177e4SLinus Torvalds /*****************************************************************************/ 3311da177e4SLinus Torvalds /* 3321da177e4SLinus Torvalds * deal with execve() 3331da177e4SLinus Torvalds */ 3341da177e4SLinus Torvalds int exec_keys(struct task_struct *tsk) 3351da177e4SLinus Torvalds { 3361da177e4SLinus Torvalds struct key *old; 3371da177e4SLinus Torvalds 3381da177e4SLinus Torvalds /* newly exec'd tasks don't get a thread keyring */ 3391da177e4SLinus Torvalds task_lock(tsk); 3401da177e4SLinus Torvalds old = tsk->thread_keyring; 3411da177e4SLinus Torvalds tsk->thread_keyring = NULL; 3421da177e4SLinus Torvalds task_unlock(tsk); 3431da177e4SLinus Torvalds 3441da177e4SLinus Torvalds key_put(old); 3451da177e4SLinus Torvalds 3461da177e4SLinus Torvalds /* discard the process keyring from a newly exec'd task */ 3471a26feb9SDavid Howells spin_lock_irq(&tsk->sighand->siglock); 3481da177e4SLinus Torvalds old = tsk->signal->process_keyring; 3491da177e4SLinus Torvalds tsk->signal->process_keyring = NULL; 3501a26feb9SDavid Howells spin_unlock_irq(&tsk->sighand->siglock); 3511da177e4SLinus Torvalds 3521da177e4SLinus Torvalds key_put(old); 3531da177e4SLinus Torvalds 3541da177e4SLinus Torvalds return 0; 3551da177e4SLinus Torvalds 3561da177e4SLinus Torvalds } /* end exec_keys() */ 3571da177e4SLinus Torvalds 3581da177e4SLinus Torvalds /*****************************************************************************/ 3591da177e4SLinus Torvalds /* 3601da177e4SLinus Torvalds * deal with SUID programs 3611da177e4SLinus Torvalds * - we might want to make this invent a new session keyring 3621da177e4SLinus Torvalds */ 3631da177e4SLinus Torvalds int suid_keys(struct task_struct *tsk) 3641da177e4SLinus Torvalds { 3651da177e4SLinus Torvalds return 0; 3661da177e4SLinus Torvalds 3671da177e4SLinus Torvalds } /* end suid_keys() */ 3681da177e4SLinus Torvalds 3691da177e4SLinus Torvalds /*****************************************************************************/ 3701da177e4SLinus Torvalds /* 3711da177e4SLinus Torvalds * the filesystem user ID changed 3721da177e4SLinus Torvalds */ 3731da177e4SLinus Torvalds void key_fsuid_changed(struct task_struct *tsk) 3741da177e4SLinus Torvalds { 3751da177e4SLinus Torvalds /* update the ownership of the thread keyring */ 3761da177e4SLinus Torvalds if (tsk->thread_keyring) { 3771da177e4SLinus Torvalds down_write(&tsk->thread_keyring->sem); 3781da177e4SLinus Torvalds tsk->thread_keyring->uid = tsk->fsuid; 3791da177e4SLinus Torvalds up_write(&tsk->thread_keyring->sem); 3801da177e4SLinus Torvalds } 3811da177e4SLinus Torvalds 3821da177e4SLinus Torvalds } /* end key_fsuid_changed() */ 3831da177e4SLinus Torvalds 3841da177e4SLinus Torvalds /*****************************************************************************/ 3851da177e4SLinus Torvalds /* 3861da177e4SLinus Torvalds * the filesystem group ID changed 3871da177e4SLinus Torvalds */ 3881da177e4SLinus Torvalds void key_fsgid_changed(struct task_struct *tsk) 3891da177e4SLinus Torvalds { 3901da177e4SLinus Torvalds /* update the ownership of the thread keyring */ 3911da177e4SLinus Torvalds if (tsk->thread_keyring) { 3921da177e4SLinus Torvalds down_write(&tsk->thread_keyring->sem); 3931da177e4SLinus Torvalds tsk->thread_keyring->gid = tsk->fsgid; 3941da177e4SLinus Torvalds up_write(&tsk->thread_keyring->sem); 3951da177e4SLinus Torvalds } 3961da177e4SLinus Torvalds 3971da177e4SLinus Torvalds } /* end key_fsgid_changed() */ 3981da177e4SLinus Torvalds 3991da177e4SLinus Torvalds /*****************************************************************************/ 4001da177e4SLinus Torvalds /* 4011da177e4SLinus Torvalds * search the process keyrings for the first matching key 4021da177e4SLinus Torvalds * - we use the supplied match function to see if the description (or other 4031da177e4SLinus Torvalds * feature of interest) matches 4041da177e4SLinus Torvalds * - we return -EAGAIN if we didn't find any matching key 4051da177e4SLinus Torvalds * - we return -ENOKEY if we found only negative matching keys 4061da177e4SLinus Torvalds */ 407664cceb0SDavid Howells key_ref_t search_process_keyrings(struct key_type *type, 4081da177e4SLinus Torvalds const void *description, 4093e30148cSDavid Howells key_match_func_t match, 4103e30148cSDavid Howells struct task_struct *context) 4111da177e4SLinus Torvalds { 4123e30148cSDavid Howells struct request_key_auth *rka; 413b5f545c8SDavid Howells key_ref_t key_ref, ret, err; 4141da177e4SLinus Torvalds 41504c567d9SDavid Howells might_sleep(); 41604c567d9SDavid Howells 4171da177e4SLinus Torvalds /* we want to return -EAGAIN or -ENOKEY if any of the keyrings were 4181da177e4SLinus Torvalds * searchable, but we failed to find a key or we found a negative key; 4191da177e4SLinus Torvalds * otherwise we want to return a sample error (probably -EACCES) if 4201da177e4SLinus Torvalds * none of the keyrings were searchable 4211da177e4SLinus Torvalds * 4221da177e4SLinus Torvalds * in terms of priority: success > -ENOKEY > -EAGAIN > other error 4231da177e4SLinus Torvalds */ 424664cceb0SDavid Howells key_ref = NULL; 4251da177e4SLinus Torvalds ret = NULL; 4261da177e4SLinus Torvalds err = ERR_PTR(-EAGAIN); 4271da177e4SLinus Torvalds 4281da177e4SLinus Torvalds /* search the thread keyring first */ 4293e30148cSDavid Howells if (context->thread_keyring) { 430664cceb0SDavid Howells key_ref = keyring_search_aux( 431664cceb0SDavid Howells make_key_ref(context->thread_keyring, 1), 4323e30148cSDavid Howells context, type, description, match); 433664cceb0SDavid Howells if (!IS_ERR(key_ref)) 4341da177e4SLinus Torvalds goto found; 4351da177e4SLinus Torvalds 436664cceb0SDavid Howells switch (PTR_ERR(key_ref)) { 4371da177e4SLinus Torvalds case -EAGAIN: /* no key */ 4381da177e4SLinus Torvalds if (ret) 4391da177e4SLinus Torvalds break; 4401da177e4SLinus Torvalds case -ENOKEY: /* negative key */ 441664cceb0SDavid Howells ret = key_ref; 4421da177e4SLinus Torvalds break; 4431da177e4SLinus Torvalds default: 444664cceb0SDavid Howells err = key_ref; 4451da177e4SLinus Torvalds break; 4461da177e4SLinus Torvalds } 4471da177e4SLinus Torvalds } 4481da177e4SLinus Torvalds 4491da177e4SLinus Torvalds /* search the process keyring second */ 4503e30148cSDavid Howells if (context->signal->process_keyring) { 451664cceb0SDavid Howells key_ref = keyring_search_aux( 452664cceb0SDavid Howells make_key_ref(context->signal->process_keyring, 1), 4533e30148cSDavid Howells context, type, description, match); 454664cceb0SDavid Howells if (!IS_ERR(key_ref)) 4551da177e4SLinus Torvalds goto found; 4561da177e4SLinus Torvalds 457664cceb0SDavid Howells switch (PTR_ERR(key_ref)) { 4581da177e4SLinus Torvalds case -EAGAIN: /* no key */ 4591da177e4SLinus Torvalds if (ret) 4601da177e4SLinus Torvalds break; 4611da177e4SLinus Torvalds case -ENOKEY: /* negative key */ 462664cceb0SDavid Howells ret = key_ref; 4631da177e4SLinus Torvalds break; 4641da177e4SLinus Torvalds default: 465664cceb0SDavid Howells err = key_ref; 4661da177e4SLinus Torvalds break; 4671da177e4SLinus Torvalds } 4681da177e4SLinus Torvalds } 4691da177e4SLinus Torvalds 4703e30148cSDavid Howells /* search the session keyring */ 4713e30148cSDavid Howells if (context->signal->session_keyring) { 4728589b4e0SDavid Howells rcu_read_lock(); 473664cceb0SDavid Howells key_ref = keyring_search_aux( 474664cceb0SDavid Howells make_key_ref(rcu_dereference( 475664cceb0SDavid Howells context->signal->session_keyring), 476664cceb0SDavid Howells 1), 4773e30148cSDavid Howells context, type, description, match); 4788589b4e0SDavid Howells rcu_read_unlock(); 4791da177e4SLinus Torvalds 480664cceb0SDavid Howells if (!IS_ERR(key_ref)) 4811da177e4SLinus Torvalds goto found; 4821da177e4SLinus Torvalds 483664cceb0SDavid Howells switch (PTR_ERR(key_ref)) { 4841da177e4SLinus Torvalds case -EAGAIN: /* no key */ 4851da177e4SLinus Torvalds if (ret) 4861da177e4SLinus Torvalds break; 4871da177e4SLinus Torvalds case -ENOKEY: /* negative key */ 488664cceb0SDavid Howells ret = key_ref; 4891da177e4SLinus Torvalds break; 4901da177e4SLinus Torvalds default: 491664cceb0SDavid Howells err = key_ref; 4921da177e4SLinus Torvalds break; 4931da177e4SLinus Torvalds } 4943e30148cSDavid Howells } 4953e30148cSDavid Howells /* or search the user-session keyring */ 49669664cf1SDavid Howells else if (context->user->session_keyring) { 497664cceb0SDavid Howells key_ref = keyring_search_aux( 498664cceb0SDavid Howells make_key_ref(context->user->session_keyring, 1), 4993e30148cSDavid Howells context, type, description, match); 500664cceb0SDavid Howells if (!IS_ERR(key_ref)) 5013e30148cSDavid Howells goto found; 5023e30148cSDavid Howells 503664cceb0SDavid Howells switch (PTR_ERR(key_ref)) { 5043e30148cSDavid Howells case -EAGAIN: /* no key */ 5053e30148cSDavid Howells if (ret) 5063e30148cSDavid Howells break; 5073e30148cSDavid Howells case -ENOKEY: /* negative key */ 508664cceb0SDavid Howells ret = key_ref; 5093e30148cSDavid Howells break; 5103e30148cSDavid Howells default: 511664cceb0SDavid Howells err = key_ref; 5123e30148cSDavid Howells break; 5133e30148cSDavid Howells } 5143e30148cSDavid Howells } 5153e30148cSDavid Howells 516b5f545c8SDavid Howells /* if this process has an instantiation authorisation key, then we also 517b5f545c8SDavid Howells * search the keyrings of the process mentioned there 518b5f545c8SDavid Howells * - we don't permit access to request_key auth keys via this method 519b5f545c8SDavid Howells */ 520b5f545c8SDavid Howells if (context->request_key_auth && 521b5f545c8SDavid Howells context == current && 52204c567d9SDavid Howells type != &key_type_request_key_auth 523b5f545c8SDavid Howells ) { 52404c567d9SDavid Howells /* defend against the auth key being revoked */ 52504c567d9SDavid Howells down_read(&context->request_key_auth->sem); 52604c567d9SDavid Howells 52704c567d9SDavid Howells if (key_validate(context->request_key_auth) == 0) { 528b5f545c8SDavid Howells rka = context->request_key_auth->payload.data; 5293e30148cSDavid Howells 53004c567d9SDavid Howells key_ref = search_process_keyrings(type, description, 53104c567d9SDavid Howells match, rka->context); 53204c567d9SDavid Howells 53304c567d9SDavid Howells up_read(&context->request_key_auth->sem); 534b5f545c8SDavid Howells 535b5f545c8SDavid Howells if (!IS_ERR(key_ref)) 536b5f545c8SDavid Howells goto found; 537b5f545c8SDavid Howells 538b5f545c8SDavid Howells switch (PTR_ERR(key_ref)) { 539b5f545c8SDavid Howells case -EAGAIN: /* no key */ 540b5f545c8SDavid Howells if (ret) 541b5f545c8SDavid Howells break; 542b5f545c8SDavid Howells case -ENOKEY: /* negative key */ 543b5f545c8SDavid Howells ret = key_ref; 544b5f545c8SDavid Howells break; 545b5f545c8SDavid Howells default: 546b5f545c8SDavid Howells err = key_ref; 547b5f545c8SDavid Howells break; 548b5f545c8SDavid Howells } 54904c567d9SDavid Howells } else { 55004c567d9SDavid Howells up_read(&context->request_key_auth->sem); 55104c567d9SDavid Howells } 552b5f545c8SDavid Howells } 553b5f545c8SDavid Howells 5541da177e4SLinus Torvalds /* no key - decide on the error we're going to go for */ 555664cceb0SDavid Howells key_ref = ret ? ret : err; 5561da177e4SLinus Torvalds 5571da177e4SLinus Torvalds found: 558664cceb0SDavid Howells return key_ref; 5591da177e4SLinus Torvalds 5601da177e4SLinus Torvalds } /* end search_process_keyrings() */ 5611da177e4SLinus Torvalds 5621da177e4SLinus Torvalds /*****************************************************************************/ 5631da177e4SLinus Torvalds /* 564664cceb0SDavid Howells * see if the key we're looking at is the target key 565664cceb0SDavid Howells */ 566664cceb0SDavid Howells static int lookup_user_key_possessed(const struct key *key, const void *target) 567664cceb0SDavid Howells { 568664cceb0SDavid Howells return key == target; 569664cceb0SDavid Howells 570664cceb0SDavid Howells } /* end lookup_user_key_possessed() */ 571664cceb0SDavid Howells 572664cceb0SDavid Howells /*****************************************************************************/ 573664cceb0SDavid Howells /* 5741da177e4SLinus Torvalds * lookup a key given a key ID from userspace with a given permissions mask 5751da177e4SLinus Torvalds * - don't create special keyrings unless so requested 5761da177e4SLinus Torvalds * - partially constructed keys aren't found unless requested 5771da177e4SLinus Torvalds */ 578*8bbf4976SDavid Howells key_ref_t lookup_user_key(key_serial_t id, int create, int partial, 579*8bbf4976SDavid Howells key_perm_t perm) 5801da177e4SLinus Torvalds { 581*8bbf4976SDavid Howells struct request_key_auth *rka; 582*8bbf4976SDavid Howells struct task_struct *t = current; 583664cceb0SDavid Howells key_ref_t key_ref, skey_ref; 5841da177e4SLinus Torvalds struct key *key; 5851da177e4SLinus Torvalds int ret; 5861da177e4SLinus Torvalds 587664cceb0SDavid Howells key_ref = ERR_PTR(-ENOKEY); 5881da177e4SLinus Torvalds 5891da177e4SLinus Torvalds switch (id) { 5901da177e4SLinus Torvalds case KEY_SPEC_THREAD_KEYRING: 591*8bbf4976SDavid Howells if (!t->thread_keyring) { 5921da177e4SLinus Torvalds if (!create) 5931da177e4SLinus Torvalds goto error; 5941da177e4SLinus Torvalds 595*8bbf4976SDavid Howells ret = install_thread_keyring(); 5961da177e4SLinus Torvalds if (ret < 0) { 5971da177e4SLinus Torvalds key = ERR_PTR(ret); 5981da177e4SLinus Torvalds goto error; 5991da177e4SLinus Torvalds } 6001da177e4SLinus Torvalds } 6011da177e4SLinus Torvalds 602*8bbf4976SDavid Howells key = t->thread_keyring; 6031da177e4SLinus Torvalds atomic_inc(&key->usage); 604664cceb0SDavid Howells key_ref = make_key_ref(key, 1); 6051da177e4SLinus Torvalds break; 6061da177e4SLinus Torvalds 6071da177e4SLinus Torvalds case KEY_SPEC_PROCESS_KEYRING: 608*8bbf4976SDavid Howells if (!t->signal->process_keyring) { 6091da177e4SLinus Torvalds if (!create) 6101da177e4SLinus Torvalds goto error; 6111da177e4SLinus Torvalds 612*8bbf4976SDavid Howells ret = install_process_keyring(); 6131da177e4SLinus Torvalds if (ret < 0) { 6141da177e4SLinus Torvalds key = ERR_PTR(ret); 6151da177e4SLinus Torvalds goto error; 6161da177e4SLinus Torvalds } 6171da177e4SLinus Torvalds } 6181da177e4SLinus Torvalds 619*8bbf4976SDavid Howells key = t->signal->process_keyring; 6201da177e4SLinus Torvalds atomic_inc(&key->usage); 621664cceb0SDavid Howells key_ref = make_key_ref(key, 1); 6221da177e4SLinus Torvalds break; 6231da177e4SLinus Torvalds 6241da177e4SLinus Torvalds case KEY_SPEC_SESSION_KEYRING: 625*8bbf4976SDavid Howells if (!t->signal->session_keyring) { 6261da177e4SLinus Torvalds /* always install a session keyring upon access if one 6271da177e4SLinus Torvalds * doesn't exist yet */ 628*8bbf4976SDavid Howells ret = install_user_keyrings(); 62969664cf1SDavid Howells if (ret < 0) 63069664cf1SDavid Howells goto error; 631*8bbf4976SDavid Howells ret = install_session_keyring(t->user->session_keyring); 6321da177e4SLinus Torvalds if (ret < 0) 6331da177e4SLinus Torvalds goto error; 6341da177e4SLinus Torvalds } 6351da177e4SLinus Torvalds 6363e30148cSDavid Howells rcu_read_lock(); 637*8bbf4976SDavid Howells key = rcu_dereference(t->signal->session_keyring); 6381da177e4SLinus Torvalds atomic_inc(&key->usage); 6393e30148cSDavid Howells rcu_read_unlock(); 640664cceb0SDavid Howells key_ref = make_key_ref(key, 1); 6411da177e4SLinus Torvalds break; 6421da177e4SLinus Torvalds 6431da177e4SLinus Torvalds case KEY_SPEC_USER_KEYRING: 644*8bbf4976SDavid Howells if (!t->user->uid_keyring) { 645*8bbf4976SDavid Howells ret = install_user_keyrings(); 64669664cf1SDavid Howells if (ret < 0) 64769664cf1SDavid Howells goto error; 64869664cf1SDavid Howells } 64969664cf1SDavid Howells 650*8bbf4976SDavid Howells key = t->user->uid_keyring; 6511da177e4SLinus Torvalds atomic_inc(&key->usage); 652664cceb0SDavid Howells key_ref = make_key_ref(key, 1); 6531da177e4SLinus Torvalds break; 6541da177e4SLinus Torvalds 6551da177e4SLinus Torvalds case KEY_SPEC_USER_SESSION_KEYRING: 656*8bbf4976SDavid Howells if (!t->user->session_keyring) { 657*8bbf4976SDavid Howells ret = install_user_keyrings(); 65869664cf1SDavid Howells if (ret < 0) 65969664cf1SDavid Howells goto error; 66069664cf1SDavid Howells } 66169664cf1SDavid Howells 662*8bbf4976SDavid Howells key = t->user->session_keyring; 6631da177e4SLinus Torvalds atomic_inc(&key->usage); 664664cceb0SDavid Howells key_ref = make_key_ref(key, 1); 6651da177e4SLinus Torvalds break; 6661da177e4SLinus Torvalds 6671da177e4SLinus Torvalds case KEY_SPEC_GROUP_KEYRING: 6681da177e4SLinus Torvalds /* group keyrings are not yet supported */ 6691da177e4SLinus Torvalds key = ERR_PTR(-EINVAL); 6701da177e4SLinus Torvalds goto error; 6711da177e4SLinus Torvalds 672b5f545c8SDavid Howells case KEY_SPEC_REQKEY_AUTH_KEY: 673*8bbf4976SDavid Howells key = t->request_key_auth; 674b5f545c8SDavid Howells if (!key) 675b5f545c8SDavid Howells goto error; 676b5f545c8SDavid Howells 677b5f545c8SDavid Howells atomic_inc(&key->usage); 678b5f545c8SDavid Howells key_ref = make_key_ref(key, 1); 679b5f545c8SDavid Howells break; 680b5f545c8SDavid Howells 681*8bbf4976SDavid Howells case KEY_SPEC_REQUESTOR_KEYRING: 682*8bbf4976SDavid Howells if (!t->request_key_auth) 683*8bbf4976SDavid Howells goto error; 684*8bbf4976SDavid Howells 685*8bbf4976SDavid Howells down_read(&t->request_key_auth->sem); 686*8bbf4976SDavid Howells if (t->request_key_auth->flags & KEY_FLAG_REVOKED) { 687*8bbf4976SDavid Howells key_ref = ERR_PTR(-EKEYREVOKED); 688*8bbf4976SDavid Howells key = NULL; 689*8bbf4976SDavid Howells } else { 690*8bbf4976SDavid Howells rka = t->request_key_auth->payload.data; 691*8bbf4976SDavid Howells key = rka->dest_keyring; 692*8bbf4976SDavid Howells atomic_inc(&key->usage); 693*8bbf4976SDavid Howells } 694*8bbf4976SDavid Howells up_read(&t->request_key_auth->sem); 695*8bbf4976SDavid Howells if (!key) 696*8bbf4976SDavid Howells goto error; 697*8bbf4976SDavid Howells key_ref = make_key_ref(key, 1); 698*8bbf4976SDavid Howells break; 699*8bbf4976SDavid Howells 7001da177e4SLinus Torvalds default: 701664cceb0SDavid Howells key_ref = ERR_PTR(-EINVAL); 7021da177e4SLinus Torvalds if (id < 1) 7031da177e4SLinus Torvalds goto error; 7041da177e4SLinus Torvalds 7051da177e4SLinus Torvalds key = key_lookup(id); 706664cceb0SDavid Howells if (IS_ERR(key)) { 707e231c2eeSDavid Howells key_ref = ERR_CAST(key); 7081da177e4SLinus Torvalds goto error; 709664cceb0SDavid Howells } 710664cceb0SDavid Howells 711664cceb0SDavid Howells key_ref = make_key_ref(key, 0); 712664cceb0SDavid Howells 713664cceb0SDavid Howells /* check to see if we possess the key */ 714664cceb0SDavid Howells skey_ref = search_process_keyrings(key->type, key, 715664cceb0SDavid Howells lookup_user_key_possessed, 716664cceb0SDavid Howells current); 717664cceb0SDavid Howells 718664cceb0SDavid Howells if (!IS_ERR(skey_ref)) { 719664cceb0SDavid Howells key_put(key); 720664cceb0SDavid Howells key_ref = skey_ref; 721664cceb0SDavid Howells } 722664cceb0SDavid Howells 7231da177e4SLinus Torvalds break; 7241da177e4SLinus Torvalds } 7251da177e4SLinus Torvalds 72676181c13SDavid Howells if (!partial) { 72776181c13SDavid Howells ret = wait_for_key_construction(key, true); 72876181c13SDavid Howells switch (ret) { 72976181c13SDavid Howells case -ERESTARTSYS: 73076181c13SDavid Howells goto invalid_key; 73176181c13SDavid Howells default: 73276181c13SDavid Howells if (perm) 73376181c13SDavid Howells goto invalid_key; 73476181c13SDavid Howells case 0: 73576181c13SDavid Howells break; 73676181c13SDavid Howells } 73776181c13SDavid Howells } else if (perm) { 7381da177e4SLinus Torvalds ret = key_validate(key); 7391da177e4SLinus Torvalds if (ret < 0) 7401da177e4SLinus Torvalds goto invalid_key; 7411da177e4SLinus Torvalds } 7421da177e4SLinus Torvalds 7431da177e4SLinus Torvalds ret = -EIO; 74476d8aeabSDavid Howells if (!partial && !test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) 7451da177e4SLinus Torvalds goto invalid_key; 7461da177e4SLinus Torvalds 7473e30148cSDavid Howells /* check the permissions */ 748*8bbf4976SDavid Howells ret = key_task_permission(key_ref, t, perm); 74929db9190SDavid Howells if (ret < 0) 7501da177e4SLinus Torvalds goto invalid_key; 7511da177e4SLinus Torvalds 7521da177e4SLinus Torvalds error: 753664cceb0SDavid Howells return key_ref; 7541da177e4SLinus Torvalds 7551da177e4SLinus Torvalds invalid_key: 756664cceb0SDavid Howells key_ref_put(key_ref); 757664cceb0SDavid Howells key_ref = ERR_PTR(ret); 7581da177e4SLinus Torvalds goto error; 7591da177e4SLinus Torvalds 7601da177e4SLinus Torvalds } /* end lookup_user_key() */ 7611da177e4SLinus Torvalds 7621da177e4SLinus Torvalds /*****************************************************************************/ 7631da177e4SLinus Torvalds /* 7641da177e4SLinus Torvalds * join the named keyring as the session keyring if possible, or attempt to 7651da177e4SLinus Torvalds * create a new one of that name if not 7661da177e4SLinus Torvalds * - if the name is NULL, an empty anonymous keyring is installed instead 7671da177e4SLinus Torvalds * - named session keyring joining is done with a semaphore held 7681da177e4SLinus Torvalds */ 7691da177e4SLinus Torvalds long join_session_keyring(const char *name) 7701da177e4SLinus Torvalds { 7711da177e4SLinus Torvalds struct task_struct *tsk = current; 7721da177e4SLinus Torvalds struct key *keyring; 7731da177e4SLinus Torvalds long ret; 7741da177e4SLinus Torvalds 7751da177e4SLinus Torvalds /* if no name is provided, install an anonymous keyring */ 7761da177e4SLinus Torvalds if (!name) { 777*8bbf4976SDavid Howells ret = install_session_keyring(NULL); 7781da177e4SLinus Torvalds if (ret < 0) 7791da177e4SLinus Torvalds goto error; 7801da177e4SLinus Torvalds 7813e30148cSDavid Howells rcu_read_lock(); 7823e30148cSDavid Howells ret = rcu_dereference(tsk->signal->session_keyring)->serial; 7833e30148cSDavid Howells rcu_read_unlock(); 7841da177e4SLinus Torvalds goto error; 7851da177e4SLinus Torvalds } 7861da177e4SLinus Torvalds 7871da177e4SLinus Torvalds /* allow the user to join or create a named keyring */ 788bb003079SIngo Molnar mutex_lock(&key_session_mutex); 7891da177e4SLinus Torvalds 7901da177e4SLinus Torvalds /* look for an existing keyring of this name */ 79169664cf1SDavid Howells keyring = find_keyring_by_name(name, false); 7921da177e4SLinus Torvalds if (PTR_ERR(keyring) == -ENOKEY) { 7931da177e4SLinus Torvalds /* not found - try and create a new one */ 7947e047ef5SDavid Howells keyring = keyring_alloc(name, tsk->uid, tsk->gid, tsk, 7957e047ef5SDavid Howells KEY_ALLOC_IN_QUOTA, NULL); 7961da177e4SLinus Torvalds if (IS_ERR(keyring)) { 7971da177e4SLinus Torvalds ret = PTR_ERR(keyring); 798bcf945d3SDavid Howells goto error2; 7991da177e4SLinus Torvalds } 8001da177e4SLinus Torvalds } 8011da177e4SLinus Torvalds else if (IS_ERR(keyring)) { 8021da177e4SLinus Torvalds ret = PTR_ERR(keyring); 8031da177e4SLinus Torvalds goto error2; 8041da177e4SLinus Torvalds } 8051da177e4SLinus Torvalds 8061da177e4SLinus Torvalds /* we've got a keyring - now to install it */ 807*8bbf4976SDavid Howells ret = install_session_keyring(keyring); 8081da177e4SLinus Torvalds if (ret < 0) 8091da177e4SLinus Torvalds goto error2; 8101da177e4SLinus Torvalds 8111da177e4SLinus Torvalds ret = keyring->serial; 8121da177e4SLinus Torvalds key_put(keyring); 8131da177e4SLinus Torvalds 8141da177e4SLinus Torvalds error2: 815bb003079SIngo Molnar mutex_unlock(&key_session_mutex); 8161da177e4SLinus Torvalds error: 8171da177e4SLinus Torvalds return ret; 8181da177e4SLinus Torvalds 8191da177e4SLinus Torvalds } /* end join_session_keyring() */ 820