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> 191da177e4SLinus Torvalds #include <asm/uaccess.h> 201da177e4SLinus Torvalds #include "internal.h" 211da177e4SLinus Torvalds 221da177e4SLinus Torvalds /* session keyring create vs join semaphore */ 231da177e4SLinus Torvalds static DECLARE_MUTEX(key_session_sem); 241da177e4SLinus Torvalds 251da177e4SLinus Torvalds /* the root user's tracking struct */ 261da177e4SLinus Torvalds struct key_user root_key_user = { 271da177e4SLinus Torvalds .usage = ATOMIC_INIT(3), 281da177e4SLinus Torvalds .consq = LIST_HEAD_INIT(root_key_user.consq), 291da177e4SLinus Torvalds .lock = SPIN_LOCK_UNLOCKED, 301da177e4SLinus Torvalds .nkeys = ATOMIC_INIT(2), 311da177e4SLinus Torvalds .nikeys = ATOMIC_INIT(2), 321da177e4SLinus Torvalds .uid = 0, 331da177e4SLinus Torvalds }; 341da177e4SLinus Torvalds 351da177e4SLinus Torvalds /* the root user's UID keyring */ 361da177e4SLinus Torvalds struct key root_user_keyring = { 371da177e4SLinus Torvalds .usage = ATOMIC_INIT(1), 381da177e4SLinus Torvalds .serial = 2, 391da177e4SLinus Torvalds .type = &key_type_keyring, 401da177e4SLinus Torvalds .user = &root_key_user, 411da177e4SLinus Torvalds .sem = __RWSEM_INITIALIZER(root_user_keyring.sem), 421da177e4SLinus Torvalds .perm = KEY_USR_ALL, 4376d8aeabSDavid Howells .flags = 1 << KEY_FLAG_INSTANTIATED, 441da177e4SLinus Torvalds .description = "_uid.0", 451da177e4SLinus Torvalds #ifdef KEY_DEBUGGING 461da177e4SLinus Torvalds .magic = KEY_DEBUG_MAGIC, 471da177e4SLinus Torvalds #endif 481da177e4SLinus Torvalds }; 491da177e4SLinus Torvalds 501da177e4SLinus Torvalds /* the root user's default session keyring */ 511da177e4SLinus Torvalds struct key root_session_keyring = { 521da177e4SLinus Torvalds .usage = ATOMIC_INIT(1), 531da177e4SLinus Torvalds .serial = 1, 541da177e4SLinus Torvalds .type = &key_type_keyring, 551da177e4SLinus Torvalds .user = &root_key_user, 561da177e4SLinus Torvalds .sem = __RWSEM_INITIALIZER(root_session_keyring.sem), 571da177e4SLinus Torvalds .perm = KEY_USR_ALL, 5876d8aeabSDavid Howells .flags = 1 << KEY_FLAG_INSTANTIATED, 591da177e4SLinus Torvalds .description = "_uid_ses.0", 601da177e4SLinus Torvalds #ifdef KEY_DEBUGGING 611da177e4SLinus Torvalds .magic = KEY_DEBUG_MAGIC, 621da177e4SLinus Torvalds #endif 631da177e4SLinus Torvalds }; 641da177e4SLinus Torvalds 651da177e4SLinus Torvalds /*****************************************************************************/ 661da177e4SLinus Torvalds /* 671da177e4SLinus Torvalds * allocate the keyrings to be associated with a UID 681da177e4SLinus Torvalds */ 691da177e4SLinus Torvalds int alloc_uid_keyring(struct user_struct *user) 701da177e4SLinus Torvalds { 711da177e4SLinus Torvalds struct key *uid_keyring, *session_keyring; 721da177e4SLinus Torvalds char buf[20]; 731da177e4SLinus Torvalds int ret; 741da177e4SLinus Torvalds 751da177e4SLinus Torvalds /* concoct a default session keyring */ 761da177e4SLinus Torvalds sprintf(buf, "_uid_ses.%u", user->uid); 771da177e4SLinus Torvalds 781da177e4SLinus Torvalds session_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, 0, NULL); 791da177e4SLinus Torvalds if (IS_ERR(session_keyring)) { 801da177e4SLinus Torvalds ret = PTR_ERR(session_keyring); 811da177e4SLinus Torvalds goto error; 821da177e4SLinus Torvalds } 831da177e4SLinus Torvalds 841da177e4SLinus Torvalds /* and a UID specific keyring, pointed to by the default session 851da177e4SLinus Torvalds * keyring */ 861da177e4SLinus Torvalds sprintf(buf, "_uid.%u", user->uid); 871da177e4SLinus Torvalds 881da177e4SLinus Torvalds uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, 0, 891da177e4SLinus Torvalds session_keyring); 901da177e4SLinus Torvalds if (IS_ERR(uid_keyring)) { 911da177e4SLinus Torvalds key_put(session_keyring); 921da177e4SLinus Torvalds ret = PTR_ERR(uid_keyring); 931da177e4SLinus Torvalds goto error; 941da177e4SLinus Torvalds } 951da177e4SLinus Torvalds 961da177e4SLinus Torvalds /* install the keyrings */ 971da177e4SLinus Torvalds user->uid_keyring = uid_keyring; 981da177e4SLinus Torvalds user->session_keyring = session_keyring; 991da177e4SLinus Torvalds ret = 0; 1001da177e4SLinus Torvalds 1011da177e4SLinus Torvalds error: 1021da177e4SLinus Torvalds return ret; 1031da177e4SLinus Torvalds 1041da177e4SLinus Torvalds } /* end alloc_uid_keyring() */ 1051da177e4SLinus Torvalds 1061da177e4SLinus Torvalds /*****************************************************************************/ 1071da177e4SLinus Torvalds /* 1081da177e4SLinus Torvalds * deal with the UID changing 1091da177e4SLinus Torvalds */ 1101da177e4SLinus Torvalds void switch_uid_keyring(struct user_struct *new_user) 1111da177e4SLinus Torvalds { 1121da177e4SLinus Torvalds #if 0 /* do nothing for now */ 1131da177e4SLinus Torvalds struct key *old; 1141da177e4SLinus Torvalds 1151da177e4SLinus Torvalds /* switch to the new user's session keyring if we were running under 1161da177e4SLinus Torvalds * root's default session keyring */ 1171da177e4SLinus Torvalds if (new_user->uid != 0 && 1181da177e4SLinus Torvalds current->session_keyring == &root_session_keyring 1191da177e4SLinus Torvalds ) { 1201da177e4SLinus Torvalds atomic_inc(&new_user->session_keyring->usage); 1211da177e4SLinus Torvalds 1221da177e4SLinus Torvalds task_lock(current); 1231da177e4SLinus Torvalds old = current->session_keyring; 1241da177e4SLinus Torvalds current->session_keyring = new_user->session_keyring; 1251da177e4SLinus Torvalds task_unlock(current); 1261da177e4SLinus Torvalds 1271da177e4SLinus Torvalds key_put(old); 1281da177e4SLinus Torvalds } 1291da177e4SLinus Torvalds #endif 1301da177e4SLinus Torvalds 1311da177e4SLinus Torvalds } /* end switch_uid_keyring() */ 1321da177e4SLinus Torvalds 1331da177e4SLinus Torvalds /*****************************************************************************/ 1341da177e4SLinus Torvalds /* 1351da177e4SLinus Torvalds * install a fresh thread keyring, discarding the old one 1361da177e4SLinus Torvalds */ 1371da177e4SLinus Torvalds int install_thread_keyring(struct task_struct *tsk) 1381da177e4SLinus Torvalds { 1391da177e4SLinus Torvalds struct key *keyring, *old; 1401da177e4SLinus Torvalds char buf[20]; 1411da177e4SLinus Torvalds int ret; 1421da177e4SLinus Torvalds 1431da177e4SLinus Torvalds sprintf(buf, "_tid.%u", tsk->pid); 1441da177e4SLinus Torvalds 1451da177e4SLinus Torvalds keyring = keyring_alloc(buf, tsk->uid, tsk->gid, 1, NULL); 1461da177e4SLinus Torvalds if (IS_ERR(keyring)) { 1471da177e4SLinus Torvalds ret = PTR_ERR(keyring); 1481da177e4SLinus Torvalds goto error; 1491da177e4SLinus Torvalds } 1501da177e4SLinus Torvalds 1511da177e4SLinus Torvalds task_lock(tsk); 1521da177e4SLinus Torvalds old = tsk->thread_keyring; 1531da177e4SLinus Torvalds tsk->thread_keyring = keyring; 1541da177e4SLinus Torvalds task_unlock(tsk); 1551da177e4SLinus Torvalds 1561da177e4SLinus Torvalds ret = 0; 1571da177e4SLinus Torvalds 1581da177e4SLinus Torvalds key_put(old); 1591da177e4SLinus Torvalds error: 1601da177e4SLinus Torvalds return ret; 1611da177e4SLinus Torvalds 1621da177e4SLinus Torvalds } /* end install_thread_keyring() */ 1631da177e4SLinus Torvalds 1641da177e4SLinus Torvalds /*****************************************************************************/ 1651da177e4SLinus Torvalds /* 1661da177e4SLinus Torvalds * make sure a process keyring is installed 1671da177e4SLinus Torvalds */ 1683e30148cSDavid Howells int install_process_keyring(struct task_struct *tsk) 1691da177e4SLinus Torvalds { 1701da177e4SLinus Torvalds unsigned long flags; 1711da177e4SLinus Torvalds struct key *keyring; 1721da177e4SLinus Torvalds char buf[20]; 1731da177e4SLinus Torvalds int ret; 1741da177e4SLinus Torvalds 1751da177e4SLinus Torvalds if (!tsk->signal->process_keyring) { 1761da177e4SLinus Torvalds sprintf(buf, "_pid.%u", tsk->tgid); 1771da177e4SLinus Torvalds 1781da177e4SLinus Torvalds keyring = keyring_alloc(buf, tsk->uid, tsk->gid, 1, NULL); 1791da177e4SLinus Torvalds if (IS_ERR(keyring)) { 1801da177e4SLinus Torvalds ret = PTR_ERR(keyring); 1811da177e4SLinus Torvalds goto error; 1821da177e4SLinus Torvalds } 1831da177e4SLinus Torvalds 1848589b4e0SDavid Howells /* attach keyring */ 1851da177e4SLinus Torvalds spin_lock_irqsave(&tsk->sighand->siglock, flags); 1861da177e4SLinus Torvalds if (!tsk->signal->process_keyring) { 1871da177e4SLinus Torvalds tsk->signal->process_keyring = keyring; 1881da177e4SLinus Torvalds keyring = NULL; 1891da177e4SLinus Torvalds } 1901da177e4SLinus Torvalds spin_unlock_irqrestore(&tsk->sighand->siglock, flags); 1911da177e4SLinus Torvalds 1921da177e4SLinus Torvalds key_put(keyring); 1931da177e4SLinus Torvalds } 1941da177e4SLinus Torvalds 1951da177e4SLinus Torvalds ret = 0; 1961da177e4SLinus Torvalds error: 1971da177e4SLinus Torvalds return ret; 1981da177e4SLinus Torvalds 1991da177e4SLinus Torvalds } /* end install_process_keyring() */ 2001da177e4SLinus Torvalds 2011da177e4SLinus Torvalds /*****************************************************************************/ 2021da177e4SLinus Torvalds /* 2031da177e4SLinus Torvalds * install a session keyring, discarding the old one 2041da177e4SLinus Torvalds * - if a keyring is not supplied, an empty one is invented 2051da177e4SLinus Torvalds */ 2061da177e4SLinus Torvalds static int install_session_keyring(struct task_struct *tsk, 2071da177e4SLinus Torvalds struct key *keyring) 2081da177e4SLinus Torvalds { 2091da177e4SLinus Torvalds unsigned long flags; 2101da177e4SLinus Torvalds struct key *old; 2111da177e4SLinus Torvalds char buf[20]; 2121da177e4SLinus Torvalds int ret; 2131da177e4SLinus Torvalds 2141da177e4SLinus Torvalds /* create an empty session keyring */ 2151da177e4SLinus Torvalds if (!keyring) { 2161da177e4SLinus Torvalds sprintf(buf, "_ses.%u", tsk->tgid); 2171da177e4SLinus Torvalds 2181da177e4SLinus Torvalds keyring = keyring_alloc(buf, tsk->uid, tsk->gid, 1, NULL); 2191da177e4SLinus Torvalds if (IS_ERR(keyring)) { 2201da177e4SLinus Torvalds ret = PTR_ERR(keyring); 2211da177e4SLinus Torvalds goto error; 2221da177e4SLinus Torvalds } 2231da177e4SLinus Torvalds } 2241da177e4SLinus Torvalds else { 2251da177e4SLinus Torvalds atomic_inc(&keyring->usage); 2261da177e4SLinus Torvalds } 2271da177e4SLinus Torvalds 2281da177e4SLinus Torvalds /* install the keyring */ 2291da177e4SLinus Torvalds spin_lock_irqsave(&tsk->sighand->siglock, flags); 2308589b4e0SDavid Howells old = rcu_dereference(tsk->signal->session_keyring); 2318589b4e0SDavid Howells rcu_assign_pointer(tsk->signal->session_keyring, keyring); 2321da177e4SLinus Torvalds spin_unlock_irqrestore(&tsk->sighand->siglock, flags); 2331da177e4SLinus Torvalds 2341da177e4SLinus Torvalds ret = 0; 2351da177e4SLinus Torvalds 2368589b4e0SDavid Howells /* we're using RCU on the pointer */ 237b2b18660SPaul E. McKenney synchronize_rcu(); 2381da177e4SLinus Torvalds key_put(old); 2391da177e4SLinus Torvalds error: 2401da177e4SLinus Torvalds return ret; 2411da177e4SLinus Torvalds 2421da177e4SLinus Torvalds } /* end install_session_keyring() */ 2431da177e4SLinus Torvalds 2441da177e4SLinus Torvalds /*****************************************************************************/ 2451da177e4SLinus Torvalds /* 2461da177e4SLinus Torvalds * copy the keys in a thread group for fork without CLONE_THREAD 2471da177e4SLinus Torvalds */ 2481da177e4SLinus Torvalds int copy_thread_group_keys(struct task_struct *tsk) 2491da177e4SLinus Torvalds { 2501da177e4SLinus Torvalds key_check(current->thread_group->session_keyring); 2511da177e4SLinus Torvalds key_check(current->thread_group->process_keyring); 2521da177e4SLinus Torvalds 2531da177e4SLinus Torvalds /* no process keyring yet */ 2541da177e4SLinus Torvalds tsk->signal->process_keyring = NULL; 2551da177e4SLinus Torvalds 2561da177e4SLinus Torvalds /* same session keyring */ 2578589b4e0SDavid Howells rcu_read_lock(); 2581da177e4SLinus Torvalds tsk->signal->session_keyring = 2598589b4e0SDavid Howells key_get(rcu_dereference(current->signal->session_keyring)); 2608589b4e0SDavid Howells rcu_read_unlock(); 2611da177e4SLinus Torvalds 2621da177e4SLinus Torvalds return 0; 2631da177e4SLinus Torvalds 2641da177e4SLinus Torvalds } /* end copy_thread_group_keys() */ 2651da177e4SLinus Torvalds 2661da177e4SLinus Torvalds /*****************************************************************************/ 2671da177e4SLinus Torvalds /* 2681da177e4SLinus Torvalds * copy the keys for fork 2691da177e4SLinus Torvalds */ 2701da177e4SLinus Torvalds int copy_keys(unsigned long clone_flags, struct task_struct *tsk) 2711da177e4SLinus Torvalds { 2721da177e4SLinus Torvalds key_check(tsk->thread_keyring); 2731da177e4SLinus Torvalds 2741da177e4SLinus Torvalds /* no thread keyring yet */ 2751da177e4SLinus Torvalds tsk->thread_keyring = NULL; 2761da177e4SLinus Torvalds return 0; 2771da177e4SLinus Torvalds 2781da177e4SLinus Torvalds } /* end copy_keys() */ 2791da177e4SLinus Torvalds 2801da177e4SLinus Torvalds /*****************************************************************************/ 2811da177e4SLinus Torvalds /* 2821da177e4SLinus Torvalds * dispose of thread group keys upon thread group destruction 2831da177e4SLinus Torvalds */ 2841da177e4SLinus Torvalds void exit_thread_group_keys(struct signal_struct *tg) 2851da177e4SLinus Torvalds { 2861da177e4SLinus Torvalds key_put(tg->session_keyring); 2871da177e4SLinus Torvalds key_put(tg->process_keyring); 2881da177e4SLinus Torvalds 2891da177e4SLinus Torvalds } /* end exit_thread_group_keys() */ 2901da177e4SLinus Torvalds 2911da177e4SLinus Torvalds /*****************************************************************************/ 2921da177e4SLinus Torvalds /* 2931da177e4SLinus Torvalds * dispose of keys upon thread exit 2941da177e4SLinus Torvalds */ 2951da177e4SLinus Torvalds void exit_keys(struct task_struct *tsk) 2961da177e4SLinus Torvalds { 2971da177e4SLinus Torvalds key_put(tsk->thread_keyring); 2981da177e4SLinus Torvalds 2991da177e4SLinus Torvalds } /* end exit_keys() */ 3001da177e4SLinus Torvalds 3011da177e4SLinus Torvalds /*****************************************************************************/ 3021da177e4SLinus Torvalds /* 3031da177e4SLinus Torvalds * deal with execve() 3041da177e4SLinus Torvalds */ 3051da177e4SLinus Torvalds int exec_keys(struct task_struct *tsk) 3061da177e4SLinus Torvalds { 3071da177e4SLinus Torvalds unsigned long flags; 3081da177e4SLinus Torvalds struct key *old; 3091da177e4SLinus Torvalds 3101da177e4SLinus Torvalds /* newly exec'd tasks don't get a thread keyring */ 3111da177e4SLinus Torvalds task_lock(tsk); 3121da177e4SLinus Torvalds old = tsk->thread_keyring; 3131da177e4SLinus Torvalds tsk->thread_keyring = NULL; 3141da177e4SLinus Torvalds task_unlock(tsk); 3151da177e4SLinus Torvalds 3161da177e4SLinus Torvalds key_put(old); 3171da177e4SLinus Torvalds 3181da177e4SLinus Torvalds /* discard the process keyring from a newly exec'd task */ 3191da177e4SLinus Torvalds spin_lock_irqsave(&tsk->sighand->siglock, flags); 3201da177e4SLinus Torvalds old = tsk->signal->process_keyring; 3211da177e4SLinus Torvalds tsk->signal->process_keyring = NULL; 3221da177e4SLinus Torvalds spin_unlock_irqrestore(&tsk->sighand->siglock, flags); 3231da177e4SLinus Torvalds 3241da177e4SLinus Torvalds key_put(old); 3251da177e4SLinus Torvalds 3261da177e4SLinus Torvalds return 0; 3271da177e4SLinus Torvalds 3281da177e4SLinus Torvalds } /* end exec_keys() */ 3291da177e4SLinus Torvalds 3301da177e4SLinus Torvalds /*****************************************************************************/ 3311da177e4SLinus Torvalds /* 3321da177e4SLinus Torvalds * deal with SUID programs 3331da177e4SLinus Torvalds * - we might want to make this invent a new session keyring 3341da177e4SLinus Torvalds */ 3351da177e4SLinus Torvalds int suid_keys(struct task_struct *tsk) 3361da177e4SLinus Torvalds { 3371da177e4SLinus Torvalds return 0; 3381da177e4SLinus Torvalds 3391da177e4SLinus Torvalds } /* end suid_keys() */ 3401da177e4SLinus Torvalds 3411da177e4SLinus Torvalds /*****************************************************************************/ 3421da177e4SLinus Torvalds /* 3431da177e4SLinus Torvalds * the filesystem user ID changed 3441da177e4SLinus Torvalds */ 3451da177e4SLinus Torvalds void key_fsuid_changed(struct task_struct *tsk) 3461da177e4SLinus Torvalds { 3471da177e4SLinus Torvalds /* update the ownership of the thread keyring */ 3481da177e4SLinus Torvalds if (tsk->thread_keyring) { 3491da177e4SLinus Torvalds down_write(&tsk->thread_keyring->sem); 3501da177e4SLinus Torvalds tsk->thread_keyring->uid = tsk->fsuid; 3511da177e4SLinus Torvalds up_write(&tsk->thread_keyring->sem); 3521da177e4SLinus Torvalds } 3531da177e4SLinus Torvalds 3541da177e4SLinus Torvalds } /* end key_fsuid_changed() */ 3551da177e4SLinus Torvalds 3561da177e4SLinus Torvalds /*****************************************************************************/ 3571da177e4SLinus Torvalds /* 3581da177e4SLinus Torvalds * the filesystem group ID changed 3591da177e4SLinus Torvalds */ 3601da177e4SLinus Torvalds void key_fsgid_changed(struct task_struct *tsk) 3611da177e4SLinus Torvalds { 3621da177e4SLinus Torvalds /* update the ownership of the thread keyring */ 3631da177e4SLinus Torvalds if (tsk->thread_keyring) { 3641da177e4SLinus Torvalds down_write(&tsk->thread_keyring->sem); 3651da177e4SLinus Torvalds tsk->thread_keyring->gid = tsk->fsgid; 3661da177e4SLinus Torvalds up_write(&tsk->thread_keyring->sem); 3671da177e4SLinus Torvalds } 3681da177e4SLinus Torvalds 3691da177e4SLinus Torvalds } /* end key_fsgid_changed() */ 3701da177e4SLinus Torvalds 3711da177e4SLinus Torvalds /*****************************************************************************/ 3721da177e4SLinus Torvalds /* 3731da177e4SLinus Torvalds * search the process keyrings for the first matching key 3741da177e4SLinus Torvalds * - we use the supplied match function to see if the description (or other 3751da177e4SLinus Torvalds * feature of interest) matches 3761da177e4SLinus Torvalds * - we return -EAGAIN if we didn't find any matching key 3771da177e4SLinus Torvalds * - we return -ENOKEY if we found only negative matching keys 3781da177e4SLinus Torvalds */ 3793e30148cSDavid Howells struct key *search_process_keyrings(struct key_type *type, 3801da177e4SLinus Torvalds const void *description, 3813e30148cSDavid Howells key_match_func_t match, 3823e30148cSDavid Howells struct task_struct *context) 3831da177e4SLinus Torvalds { 3843e30148cSDavid Howells struct request_key_auth *rka; 3853e30148cSDavid Howells struct key *key, *ret, *err, *instkey; 3861da177e4SLinus Torvalds 3871da177e4SLinus Torvalds /* we want to return -EAGAIN or -ENOKEY if any of the keyrings were 3881da177e4SLinus Torvalds * searchable, but we failed to find a key or we found a negative key; 3891da177e4SLinus Torvalds * otherwise we want to return a sample error (probably -EACCES) if 3901da177e4SLinus Torvalds * none of the keyrings were searchable 3911da177e4SLinus Torvalds * 3921da177e4SLinus Torvalds * in terms of priority: success > -ENOKEY > -EAGAIN > other error 3931da177e4SLinus Torvalds */ 3941da177e4SLinus Torvalds key = NULL; 3951da177e4SLinus Torvalds ret = NULL; 3961da177e4SLinus Torvalds err = ERR_PTR(-EAGAIN); 3971da177e4SLinus Torvalds 3981da177e4SLinus Torvalds /* search the thread keyring first */ 3993e30148cSDavid Howells if (context->thread_keyring) { 4003e30148cSDavid Howells key = keyring_search_aux(context->thread_keyring, 4013e30148cSDavid Howells context, type, description, match); 4021da177e4SLinus Torvalds if (!IS_ERR(key)) 4031da177e4SLinus Torvalds goto found; 4041da177e4SLinus Torvalds 4051da177e4SLinus Torvalds switch (PTR_ERR(key)) { 4061da177e4SLinus Torvalds case -EAGAIN: /* no key */ 4071da177e4SLinus Torvalds if (ret) 4081da177e4SLinus Torvalds break; 4091da177e4SLinus Torvalds case -ENOKEY: /* negative key */ 4101da177e4SLinus Torvalds ret = key; 4111da177e4SLinus Torvalds break; 4121da177e4SLinus Torvalds default: 4131da177e4SLinus Torvalds err = key; 4141da177e4SLinus Torvalds break; 4151da177e4SLinus Torvalds } 4161da177e4SLinus Torvalds } 4171da177e4SLinus Torvalds 4181da177e4SLinus Torvalds /* search the process keyring second */ 4193e30148cSDavid Howells if (context->signal->process_keyring) { 4203e30148cSDavid Howells key = keyring_search_aux(context->signal->process_keyring, 4213e30148cSDavid Howells context, type, description, match); 4221da177e4SLinus Torvalds if (!IS_ERR(key)) 4231da177e4SLinus Torvalds goto found; 4241da177e4SLinus Torvalds 4251da177e4SLinus Torvalds switch (PTR_ERR(key)) { 4261da177e4SLinus Torvalds case -EAGAIN: /* no key */ 4271da177e4SLinus Torvalds if (ret) 4281da177e4SLinus Torvalds break; 4291da177e4SLinus Torvalds case -ENOKEY: /* negative key */ 4301da177e4SLinus Torvalds ret = key; 4311da177e4SLinus Torvalds break; 4321da177e4SLinus Torvalds default: 4331da177e4SLinus Torvalds err = key; 4341da177e4SLinus Torvalds break; 4351da177e4SLinus Torvalds } 4361da177e4SLinus Torvalds } 4371da177e4SLinus Torvalds 4383e30148cSDavid Howells /* search the session keyring */ 4393e30148cSDavid Howells if (context->signal->session_keyring) { 4408589b4e0SDavid Howells rcu_read_lock(); 4418589b4e0SDavid Howells key = keyring_search_aux( 4423e30148cSDavid Howells rcu_dereference(context->signal->session_keyring), 4433e30148cSDavid Howells context, type, description, match); 4448589b4e0SDavid Howells rcu_read_unlock(); 4451da177e4SLinus Torvalds 4461da177e4SLinus Torvalds if (!IS_ERR(key)) 4471da177e4SLinus Torvalds goto found; 4481da177e4SLinus Torvalds 4491da177e4SLinus Torvalds switch (PTR_ERR(key)) { 4501da177e4SLinus Torvalds case -EAGAIN: /* no key */ 4511da177e4SLinus Torvalds if (ret) 4521da177e4SLinus Torvalds break; 4531da177e4SLinus Torvalds case -ENOKEY: /* negative key */ 4541da177e4SLinus Torvalds ret = key; 4551da177e4SLinus Torvalds break; 4561da177e4SLinus Torvalds default: 4571da177e4SLinus Torvalds err = key; 4581da177e4SLinus Torvalds break; 4591da177e4SLinus Torvalds } 4601da177e4SLinus Torvalds 4613e30148cSDavid Howells /* if this process has a session keyring and that has an 4623e30148cSDavid Howells * instantiation authorisation key in the bottom level, then we 4633e30148cSDavid Howells * also search the keyrings of the process mentioned there */ 4643e30148cSDavid Howells if (context != current) 4653e30148cSDavid Howells goto no_key; 4663e30148cSDavid Howells 4673e30148cSDavid Howells rcu_read_lock(); 4683e30148cSDavid Howells instkey = __keyring_search_one( 4693e30148cSDavid Howells rcu_dereference(context->signal->session_keyring), 4703e30148cSDavid Howells &key_type_request_key_auth, NULL, 0); 4713e30148cSDavid Howells rcu_read_unlock(); 4723e30148cSDavid Howells 4733e30148cSDavid Howells if (IS_ERR(instkey)) 4743e30148cSDavid Howells goto no_key; 4753e30148cSDavid Howells 4763e30148cSDavid Howells rka = instkey->payload.data; 4773e30148cSDavid Howells 4783e30148cSDavid Howells key = search_process_keyrings(type, description, match, 4793e30148cSDavid Howells rka->context); 4803e30148cSDavid Howells key_put(instkey); 4813e30148cSDavid Howells 4823e30148cSDavid Howells if (!IS_ERR(key)) 4833e30148cSDavid Howells goto found; 4843e30148cSDavid Howells 4853e30148cSDavid Howells switch (PTR_ERR(key)) { 4863e30148cSDavid Howells case -EAGAIN: /* no key */ 4873e30148cSDavid Howells if (ret) 4883e30148cSDavid Howells break; 4893e30148cSDavid Howells case -ENOKEY: /* negative key */ 4903e30148cSDavid Howells ret = key; 4913e30148cSDavid Howells break; 4923e30148cSDavid Howells default: 4933e30148cSDavid Howells err = key; 4943e30148cSDavid Howells break; 4953e30148cSDavid Howells } 4963e30148cSDavid Howells } 4973e30148cSDavid Howells /* or search the user-session keyring */ 4983e30148cSDavid Howells else { 4993e30148cSDavid Howells key = keyring_search_aux(context->user->session_keyring, 5003e30148cSDavid Howells context, type, description, match); 5013e30148cSDavid Howells if (!IS_ERR(key)) 5023e30148cSDavid Howells goto found; 5033e30148cSDavid Howells 5043e30148cSDavid Howells switch (PTR_ERR(key)) { 5053e30148cSDavid Howells case -EAGAIN: /* no key */ 5063e30148cSDavid Howells if (ret) 5073e30148cSDavid Howells break; 5083e30148cSDavid Howells case -ENOKEY: /* negative key */ 5093e30148cSDavid Howells ret = key; 5103e30148cSDavid Howells break; 5113e30148cSDavid Howells default: 5123e30148cSDavid Howells err = key; 5133e30148cSDavid Howells break; 5143e30148cSDavid Howells } 5153e30148cSDavid Howells } 5163e30148cSDavid Howells 5173e30148cSDavid Howells 5183e30148cSDavid Howells no_key: 5191da177e4SLinus Torvalds /* no key - decide on the error we're going to go for */ 5201da177e4SLinus Torvalds key = ret ? ret : err; 5211da177e4SLinus Torvalds 5221da177e4SLinus Torvalds found: 5231da177e4SLinus Torvalds return key; 5241da177e4SLinus Torvalds 5251da177e4SLinus Torvalds } /* end search_process_keyrings() */ 5261da177e4SLinus Torvalds 5271da177e4SLinus Torvalds /*****************************************************************************/ 5281da177e4SLinus Torvalds /* 5291da177e4SLinus Torvalds * lookup a key given a key ID from userspace with a given permissions mask 5301da177e4SLinus Torvalds * - don't create special keyrings unless so requested 5311da177e4SLinus Torvalds * - partially constructed keys aren't found unless requested 5321da177e4SLinus Torvalds */ 5333e30148cSDavid Howells struct key *lookup_user_key(struct task_struct *context, key_serial_t id, 5343e30148cSDavid Howells int create, int partial, key_perm_t perm) 5351da177e4SLinus Torvalds { 5361da177e4SLinus Torvalds struct key *key; 5371da177e4SLinus Torvalds int ret; 5381da177e4SLinus Torvalds 5393e30148cSDavid Howells if (!context) 5403e30148cSDavid Howells context = current; 5413e30148cSDavid Howells 5421da177e4SLinus Torvalds key = ERR_PTR(-ENOKEY); 5431da177e4SLinus Torvalds 5441da177e4SLinus Torvalds switch (id) { 5451da177e4SLinus Torvalds case KEY_SPEC_THREAD_KEYRING: 5463e30148cSDavid Howells if (!context->thread_keyring) { 5471da177e4SLinus Torvalds if (!create) 5481da177e4SLinus Torvalds goto error; 5491da177e4SLinus Torvalds 5503e30148cSDavid Howells ret = install_thread_keyring(context); 5511da177e4SLinus Torvalds if (ret < 0) { 5521da177e4SLinus Torvalds key = ERR_PTR(ret); 5531da177e4SLinus Torvalds goto error; 5541da177e4SLinus Torvalds } 5551da177e4SLinus Torvalds } 5561da177e4SLinus Torvalds 5573e30148cSDavid Howells key = context->thread_keyring; 5581da177e4SLinus Torvalds atomic_inc(&key->usage); 5591da177e4SLinus Torvalds break; 5601da177e4SLinus Torvalds 5611da177e4SLinus Torvalds case KEY_SPEC_PROCESS_KEYRING: 5623e30148cSDavid Howells if (!context->signal->process_keyring) { 5631da177e4SLinus Torvalds if (!create) 5641da177e4SLinus Torvalds goto error; 5651da177e4SLinus Torvalds 5663e30148cSDavid Howells ret = install_process_keyring(context); 5671da177e4SLinus Torvalds if (ret < 0) { 5681da177e4SLinus Torvalds key = ERR_PTR(ret); 5691da177e4SLinus Torvalds goto error; 5701da177e4SLinus Torvalds } 5711da177e4SLinus Torvalds } 5721da177e4SLinus Torvalds 5733e30148cSDavid Howells key = context->signal->process_keyring; 5741da177e4SLinus Torvalds atomic_inc(&key->usage); 5751da177e4SLinus Torvalds break; 5761da177e4SLinus Torvalds 5771da177e4SLinus Torvalds case KEY_SPEC_SESSION_KEYRING: 5783e30148cSDavid Howells if (!context->signal->session_keyring) { 5791da177e4SLinus Torvalds /* always install a session keyring upon access if one 5801da177e4SLinus Torvalds * doesn't exist yet */ 5811da177e4SLinus Torvalds ret = install_session_keyring( 5823e30148cSDavid Howells context, context->user->session_keyring); 5831da177e4SLinus Torvalds if (ret < 0) 5841da177e4SLinus Torvalds goto error; 5851da177e4SLinus Torvalds } 5861da177e4SLinus Torvalds 5873e30148cSDavid Howells rcu_read_lock(); 5883e30148cSDavid Howells key = rcu_dereference(context->signal->session_keyring); 5891da177e4SLinus Torvalds atomic_inc(&key->usage); 5903e30148cSDavid Howells rcu_read_unlock(); 5911da177e4SLinus Torvalds break; 5921da177e4SLinus Torvalds 5931da177e4SLinus Torvalds case KEY_SPEC_USER_KEYRING: 5943e30148cSDavid Howells key = context->user->uid_keyring; 5951da177e4SLinus Torvalds atomic_inc(&key->usage); 5961da177e4SLinus Torvalds break; 5971da177e4SLinus Torvalds 5981da177e4SLinus Torvalds case KEY_SPEC_USER_SESSION_KEYRING: 5993e30148cSDavid Howells key = context->user->session_keyring; 6001da177e4SLinus Torvalds atomic_inc(&key->usage); 6011da177e4SLinus Torvalds break; 6021da177e4SLinus Torvalds 6031da177e4SLinus Torvalds case KEY_SPEC_GROUP_KEYRING: 6041da177e4SLinus Torvalds /* group keyrings are not yet supported */ 6051da177e4SLinus Torvalds key = ERR_PTR(-EINVAL); 6061da177e4SLinus Torvalds goto error; 6071da177e4SLinus Torvalds 6081da177e4SLinus Torvalds default: 6091da177e4SLinus Torvalds key = ERR_PTR(-EINVAL); 6101da177e4SLinus Torvalds if (id < 1) 6111da177e4SLinus Torvalds goto error; 6121da177e4SLinus Torvalds 6131da177e4SLinus Torvalds key = key_lookup(id); 6141da177e4SLinus Torvalds if (IS_ERR(key)) 6151da177e4SLinus Torvalds goto error; 6161da177e4SLinus Torvalds break; 6171da177e4SLinus Torvalds } 6181da177e4SLinus Torvalds 6193e30148cSDavid Howells /* check the status */ 6201da177e4SLinus Torvalds if (perm) { 6211da177e4SLinus Torvalds ret = key_validate(key); 6221da177e4SLinus Torvalds if (ret < 0) 6231da177e4SLinus Torvalds goto invalid_key; 6241da177e4SLinus Torvalds } 6251da177e4SLinus Torvalds 6261da177e4SLinus Torvalds ret = -EIO; 62776d8aeabSDavid Howells if (!partial && !test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) 6281da177e4SLinus Torvalds goto invalid_key; 6291da177e4SLinus Torvalds 6303e30148cSDavid Howells /* check the permissions */ 6311da177e4SLinus Torvalds ret = -EACCES; 6323e30148cSDavid Howells 6333e30148cSDavid Howells if (!key_task_permission(key, context, perm)) 6341da177e4SLinus Torvalds goto invalid_key; 6351da177e4SLinus Torvalds 6361da177e4SLinus Torvalds error: 6371da177e4SLinus Torvalds return key; 6381da177e4SLinus Torvalds 6391da177e4SLinus Torvalds invalid_key: 6401da177e4SLinus Torvalds key_put(key); 6411da177e4SLinus Torvalds key = ERR_PTR(ret); 6421da177e4SLinus Torvalds goto error; 6431da177e4SLinus Torvalds 6441da177e4SLinus Torvalds } /* end lookup_user_key() */ 6451da177e4SLinus Torvalds 6461da177e4SLinus Torvalds /*****************************************************************************/ 6471da177e4SLinus Torvalds /* 6481da177e4SLinus Torvalds * join the named keyring as the session keyring if possible, or attempt to 6491da177e4SLinus Torvalds * create a new one of that name if not 6501da177e4SLinus Torvalds * - if the name is NULL, an empty anonymous keyring is installed instead 6511da177e4SLinus Torvalds * - named session keyring joining is done with a semaphore held 6521da177e4SLinus Torvalds */ 6531da177e4SLinus Torvalds long join_session_keyring(const char *name) 6541da177e4SLinus Torvalds { 6551da177e4SLinus Torvalds struct task_struct *tsk = current; 6561da177e4SLinus Torvalds struct key *keyring; 6571da177e4SLinus Torvalds long ret; 6581da177e4SLinus Torvalds 6591da177e4SLinus Torvalds /* if no name is provided, install an anonymous keyring */ 6601da177e4SLinus Torvalds if (!name) { 6611da177e4SLinus Torvalds ret = install_session_keyring(tsk, NULL); 6621da177e4SLinus Torvalds if (ret < 0) 6631da177e4SLinus Torvalds goto error; 6641da177e4SLinus Torvalds 6653e30148cSDavid Howells rcu_read_lock(); 6663e30148cSDavid Howells ret = rcu_dereference(tsk->signal->session_keyring)->serial; 6673e30148cSDavid Howells rcu_read_unlock(); 6681da177e4SLinus Torvalds goto error; 6691da177e4SLinus Torvalds } 6701da177e4SLinus Torvalds 6711da177e4SLinus Torvalds /* allow the user to join or create a named keyring */ 6721da177e4SLinus Torvalds down(&key_session_sem); 6731da177e4SLinus Torvalds 6741da177e4SLinus Torvalds /* look for an existing keyring of this name */ 6751da177e4SLinus Torvalds keyring = find_keyring_by_name(name, 0); 6761da177e4SLinus Torvalds if (PTR_ERR(keyring) == -ENOKEY) { 6771da177e4SLinus Torvalds /* not found - try and create a new one */ 6781da177e4SLinus Torvalds keyring = keyring_alloc(name, tsk->uid, tsk->gid, 0, NULL); 6791da177e4SLinus Torvalds if (IS_ERR(keyring)) { 6801da177e4SLinus Torvalds ret = PTR_ERR(keyring); 681*bcf945d3SDavid Howells goto error2; 6821da177e4SLinus Torvalds } 6831da177e4SLinus Torvalds } 6841da177e4SLinus Torvalds else if (IS_ERR(keyring)) { 6851da177e4SLinus Torvalds ret = PTR_ERR(keyring); 6861da177e4SLinus Torvalds goto error2; 6871da177e4SLinus Torvalds } 6881da177e4SLinus Torvalds 6891da177e4SLinus Torvalds /* we've got a keyring - now to install it */ 6901da177e4SLinus Torvalds ret = install_session_keyring(tsk, keyring); 6911da177e4SLinus Torvalds if (ret < 0) 6921da177e4SLinus Torvalds goto error2; 6931da177e4SLinus Torvalds 6941da177e4SLinus Torvalds ret = keyring->serial; 6951da177e4SLinus Torvalds key_put(keyring); 6961da177e4SLinus Torvalds 6971da177e4SLinus Torvalds error2: 6981da177e4SLinus Torvalds up(&key_session_sem); 6991da177e4SLinus Torvalds error: 7001da177e4SLinus Torvalds return ret; 7011da177e4SLinus Torvalds 7021da177e4SLinus Torvalds } /* end join_session_keyring() */ 703