1973c9f4fSDavid Howells /* Userspace key control operations 21da177e4SLinus Torvalds * 33e30148cSDavid 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/syscalls.h> 1759e6b9c1SBryan Schumaker #include <linux/key.h> 181da177e4SLinus Torvalds #include <linux/keyctl.h> 191da177e4SLinus Torvalds #include <linux/fs.h> 20c59ede7bSRandy.Dunlap #include <linux/capability.h> 210cb409d9SDavi Arnaut #include <linux/string.h> 221da177e4SLinus Torvalds #include <linux/err.h> 2338bbca6bSDavid Howells #include <linux/vmalloc.h> 2470a5bb72SDavid Howells #include <linux/security.h> 251da177e4SLinus Torvalds #include <asm/uaccess.h> 261da177e4SLinus Torvalds #include "internal.h" 271da177e4SLinus Torvalds 280cb409d9SDavi Arnaut static int key_get_type_from_user(char *type, 290cb409d9SDavi Arnaut const char __user *_type, 300cb409d9SDavi Arnaut unsigned len) 310cb409d9SDavi Arnaut { 320cb409d9SDavi Arnaut int ret; 330cb409d9SDavi Arnaut 340cb409d9SDavi Arnaut ret = strncpy_from_user(type, _type, len); 350cb409d9SDavi Arnaut if (ret < 0) 364303ef19SDan Carpenter return ret; 370cb409d9SDavi Arnaut if (ret == 0 || ret >= len) 380cb409d9SDavi Arnaut return -EINVAL; 390cb409d9SDavi Arnaut if (type[0] == '.') 400cb409d9SDavi Arnaut return -EPERM; 410cb409d9SDavi Arnaut type[len - 1] = '\0'; 420cb409d9SDavi Arnaut return 0; 430cb409d9SDavi Arnaut } 440cb409d9SDavi Arnaut 451da177e4SLinus Torvalds /* 46973c9f4fSDavid Howells * Extract the description of a new key from userspace and either add it as a 47973c9f4fSDavid Howells * new key to the specified keyring or update a matching key in that keyring. 48973c9f4fSDavid Howells * 49973c9f4fSDavid Howells * The keyring must be writable so that we can attach the key to it. 50973c9f4fSDavid Howells * 51973c9f4fSDavid Howells * If successful, the new key's serial number is returned, otherwise an error 52973c9f4fSDavid Howells * code is returned. 531da177e4SLinus Torvalds */ 541e7bfb21SHeiko Carstens SYSCALL_DEFINE5(add_key, const char __user *, _type, 551e7bfb21SHeiko Carstens const char __user *, _description, 561e7bfb21SHeiko Carstens const void __user *, _payload, 571e7bfb21SHeiko Carstens size_t, plen, 581e7bfb21SHeiko Carstens key_serial_t, ringid) 591da177e4SLinus Torvalds { 60664cceb0SDavid Howells key_ref_t keyring_ref, key_ref; 611da177e4SLinus Torvalds char type[32], *description; 621da177e4SLinus Torvalds void *payload; 630cb409d9SDavi Arnaut long ret; 6438bbca6bSDavid Howells bool vm; 651da177e4SLinus Torvalds 661da177e4SLinus Torvalds ret = -EINVAL; 6738bbca6bSDavid Howells if (plen > 1024 * 1024 - 1) 681da177e4SLinus Torvalds goto error; 691da177e4SLinus Torvalds 701da177e4SLinus Torvalds /* draw all the data into kernel space */ 710cb409d9SDavi Arnaut ret = key_get_type_from_user(type, _type, sizeof(type)); 721da177e4SLinus Torvalds if (ret < 0) 731da177e4SLinus Torvalds goto error; 741da177e4SLinus Torvalds 750cb409d9SDavi Arnaut description = strndup_user(_description, PAGE_SIZE); 760cb409d9SDavi Arnaut if (IS_ERR(description)) { 770cb409d9SDavi Arnaut ret = PTR_ERR(description); 783e30148cSDavid Howells goto error; 790cb409d9SDavi Arnaut } 801da177e4SLinus Torvalds 811da177e4SLinus Torvalds /* pull the payload in if one was supplied */ 821da177e4SLinus Torvalds payload = NULL; 831da177e4SLinus Torvalds 8438bbca6bSDavid Howells vm = false; 851da177e4SLinus Torvalds if (_payload) { 861da177e4SLinus Torvalds ret = -ENOMEM; 874f1c28d2SAndrew Morton payload = kmalloc(plen, GFP_KERNEL | __GFP_NOWARN); 8838bbca6bSDavid Howells if (!payload) { 8938bbca6bSDavid Howells if (plen <= PAGE_SIZE) 9038bbca6bSDavid Howells goto error2; 9138bbca6bSDavid Howells vm = true; 9238bbca6bSDavid Howells payload = vmalloc(plen); 931da177e4SLinus Torvalds if (!payload) 941da177e4SLinus Torvalds goto error2; 9538bbca6bSDavid Howells } 961da177e4SLinus Torvalds 971da177e4SLinus Torvalds ret = -EFAULT; 981da177e4SLinus Torvalds if (copy_from_user(payload, _payload, plen) != 0) 991da177e4SLinus Torvalds goto error3; 1001da177e4SLinus Torvalds } 1011da177e4SLinus Torvalds 1021da177e4SLinus Torvalds /* find the target keyring (which must be writable) */ 1035593122eSDavid Howells keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE); 104664cceb0SDavid Howells if (IS_ERR(keyring_ref)) { 105664cceb0SDavid Howells ret = PTR_ERR(keyring_ref); 1061da177e4SLinus Torvalds goto error3; 1071da177e4SLinus Torvalds } 1081da177e4SLinus Torvalds 1091da177e4SLinus Torvalds /* create or update the requested key and add it to the target 1101da177e4SLinus Torvalds * keyring */ 111664cceb0SDavid Howells key_ref = key_create_or_update(keyring_ref, type, description, 1126b79ccb5SArun Raghavan payload, plen, KEY_PERM_UNDEF, 1136b79ccb5SArun Raghavan KEY_ALLOC_IN_QUOTA); 114664cceb0SDavid Howells if (!IS_ERR(key_ref)) { 115664cceb0SDavid Howells ret = key_ref_to_ptr(key_ref)->serial; 116664cceb0SDavid Howells key_ref_put(key_ref); 1171da177e4SLinus Torvalds } 1181da177e4SLinus Torvalds else { 119664cceb0SDavid Howells ret = PTR_ERR(key_ref); 1201da177e4SLinus Torvalds } 1211da177e4SLinus Torvalds 122664cceb0SDavid Howells key_ref_put(keyring_ref); 1231da177e4SLinus Torvalds error3: 12438bbca6bSDavid Howells if (!vm) 1251da177e4SLinus Torvalds kfree(payload); 12638bbca6bSDavid Howells else 12738bbca6bSDavid Howells vfree(payload); 1281da177e4SLinus Torvalds error2: 1291da177e4SLinus Torvalds kfree(description); 1301da177e4SLinus Torvalds error: 1311da177e4SLinus Torvalds return ret; 132a8b17ed0SDavid Howells } 1331da177e4SLinus Torvalds 1341da177e4SLinus Torvalds /* 135973c9f4fSDavid Howells * Search the process keyrings and keyring trees linked from those for a 136973c9f4fSDavid Howells * matching key. Keyrings must have appropriate Search permission to be 137973c9f4fSDavid Howells * searched. 138973c9f4fSDavid Howells * 139973c9f4fSDavid Howells * If a key is found, it will be attached to the destination keyring if there's 140973c9f4fSDavid Howells * one specified and the serial number of the key will be returned. 141973c9f4fSDavid Howells * 142973c9f4fSDavid Howells * If no key is found, /sbin/request-key will be invoked if _callout_info is 143973c9f4fSDavid Howells * non-NULL in an attempt to create a key. The _callout_info string will be 144973c9f4fSDavid Howells * passed to /sbin/request-key to aid with completing the request. If the 145973c9f4fSDavid Howells * _callout_info string is "" then it will be changed to "-". 1461da177e4SLinus Torvalds */ 1471e7bfb21SHeiko Carstens SYSCALL_DEFINE4(request_key, const char __user *, _type, 1481e7bfb21SHeiko Carstens const char __user *, _description, 1491e7bfb21SHeiko Carstens const char __user *, _callout_info, 1501e7bfb21SHeiko Carstens key_serial_t, destringid) 1511da177e4SLinus Torvalds { 1521da177e4SLinus Torvalds struct key_type *ktype; 153664cceb0SDavid Howells struct key *key; 154664cceb0SDavid Howells key_ref_t dest_ref; 1554a38e122SDavid Howells size_t callout_len; 1561da177e4SLinus Torvalds char type[32], *description, *callout_info; 1570cb409d9SDavi Arnaut long ret; 1581da177e4SLinus Torvalds 1591da177e4SLinus Torvalds /* pull the type into kernel space */ 1600cb409d9SDavi Arnaut ret = key_get_type_from_user(type, _type, sizeof(type)); 1611da177e4SLinus Torvalds if (ret < 0) 1621da177e4SLinus Torvalds goto error; 1631260f801SDavid Howells 1641da177e4SLinus Torvalds /* pull the description into kernel space */ 1650cb409d9SDavi Arnaut description = strndup_user(_description, PAGE_SIZE); 1660cb409d9SDavi Arnaut if (IS_ERR(description)) { 1670cb409d9SDavi Arnaut ret = PTR_ERR(description); 1681da177e4SLinus Torvalds goto error; 1690cb409d9SDavi Arnaut } 1701da177e4SLinus Torvalds 1711da177e4SLinus Torvalds /* pull the callout info into kernel space */ 1721da177e4SLinus Torvalds callout_info = NULL; 1734a38e122SDavid Howells callout_len = 0; 1741da177e4SLinus Torvalds if (_callout_info) { 1750cb409d9SDavi Arnaut callout_info = strndup_user(_callout_info, PAGE_SIZE); 1760cb409d9SDavi Arnaut if (IS_ERR(callout_info)) { 1770cb409d9SDavi Arnaut ret = PTR_ERR(callout_info); 1781da177e4SLinus Torvalds goto error2; 1790cb409d9SDavi Arnaut } 1804a38e122SDavid Howells callout_len = strlen(callout_info); 1811da177e4SLinus Torvalds } 1821da177e4SLinus Torvalds 1831da177e4SLinus Torvalds /* get the destination keyring if specified */ 184664cceb0SDavid Howells dest_ref = NULL; 1851da177e4SLinus Torvalds if (destringid) { 1865593122eSDavid Howells dest_ref = lookup_user_key(destringid, KEY_LOOKUP_CREATE, 1875593122eSDavid Howells KEY_WRITE); 188664cceb0SDavid Howells if (IS_ERR(dest_ref)) { 189664cceb0SDavid Howells ret = PTR_ERR(dest_ref); 1901da177e4SLinus Torvalds goto error3; 1911da177e4SLinus Torvalds } 1921da177e4SLinus Torvalds } 1931da177e4SLinus Torvalds 1941da177e4SLinus Torvalds /* find the key type */ 1951da177e4SLinus Torvalds ktype = key_type_lookup(type); 1961da177e4SLinus Torvalds if (IS_ERR(ktype)) { 1971da177e4SLinus Torvalds ret = PTR_ERR(ktype); 1981da177e4SLinus Torvalds goto error4; 1991da177e4SLinus Torvalds } 2001da177e4SLinus Torvalds 2011da177e4SLinus Torvalds /* do the search */ 2024a38e122SDavid Howells key = request_key_and_link(ktype, description, callout_info, 2034a38e122SDavid Howells callout_len, NULL, key_ref_to_ptr(dest_ref), 2047e047ef5SDavid Howells KEY_ALLOC_IN_QUOTA); 2051da177e4SLinus Torvalds if (IS_ERR(key)) { 2061da177e4SLinus Torvalds ret = PTR_ERR(key); 2071da177e4SLinus Torvalds goto error5; 2081da177e4SLinus Torvalds } 2091da177e4SLinus Torvalds 2104aab1e89SDavid Howells /* wait for the key to finish being constructed */ 2114aab1e89SDavid Howells ret = wait_for_key_construction(key, 1); 2124aab1e89SDavid Howells if (ret < 0) 2134aab1e89SDavid Howells goto error6; 2144aab1e89SDavid Howells 2151da177e4SLinus Torvalds ret = key->serial; 2161da177e4SLinus Torvalds 2174aab1e89SDavid Howells error6: 2181da177e4SLinus Torvalds key_put(key); 2191da177e4SLinus Torvalds error5: 2201da177e4SLinus Torvalds key_type_put(ktype); 2211da177e4SLinus Torvalds error4: 222664cceb0SDavid Howells key_ref_put(dest_ref); 2231da177e4SLinus Torvalds error3: 2241da177e4SLinus Torvalds kfree(callout_info); 2251da177e4SLinus Torvalds error2: 2261da177e4SLinus Torvalds kfree(description); 2271da177e4SLinus Torvalds error: 2281da177e4SLinus Torvalds return ret; 229a8b17ed0SDavid Howells } 2301da177e4SLinus Torvalds 2311da177e4SLinus Torvalds /* 232973c9f4fSDavid Howells * Get the ID of the specified process keyring. 233973c9f4fSDavid Howells * 234973c9f4fSDavid Howells * The requested keyring must have search permission to be found. 235973c9f4fSDavid Howells * 236973c9f4fSDavid Howells * If successful, the ID of the requested keyring will be returned. 2371da177e4SLinus Torvalds */ 2381da177e4SLinus Torvalds long keyctl_get_keyring_ID(key_serial_t id, int create) 2391da177e4SLinus Torvalds { 240664cceb0SDavid Howells key_ref_t key_ref; 2415593122eSDavid Howells unsigned long lflags; 2421da177e4SLinus Torvalds long ret; 2431da177e4SLinus Torvalds 2445593122eSDavid Howells lflags = create ? KEY_LOOKUP_CREATE : 0; 2455593122eSDavid Howells key_ref = lookup_user_key(id, lflags, KEY_SEARCH); 246664cceb0SDavid Howells if (IS_ERR(key_ref)) { 247664cceb0SDavid Howells ret = PTR_ERR(key_ref); 2481da177e4SLinus Torvalds goto error; 2491da177e4SLinus Torvalds } 2501da177e4SLinus Torvalds 251664cceb0SDavid Howells ret = key_ref_to_ptr(key_ref)->serial; 252664cceb0SDavid Howells key_ref_put(key_ref); 2531da177e4SLinus Torvalds error: 2541da177e4SLinus Torvalds return ret; 255973c9f4fSDavid Howells } 2561da177e4SLinus Torvalds 2571da177e4SLinus Torvalds /* 258973c9f4fSDavid Howells * Join a (named) session keyring. 259973c9f4fSDavid Howells * 260973c9f4fSDavid Howells * Create and join an anonymous session keyring or join a named session 261973c9f4fSDavid Howells * keyring, creating it if necessary. A named session keyring must have Search 262973c9f4fSDavid Howells * permission for it to be joined. Session keyrings without this permit will 263973c9f4fSDavid Howells * be skipped over. 264973c9f4fSDavid Howells * 265973c9f4fSDavid Howells * If successful, the ID of the joined session keyring will be returned. 2661da177e4SLinus Torvalds */ 2671da177e4SLinus Torvalds long keyctl_join_session_keyring(const char __user *_name) 2681da177e4SLinus Torvalds { 2691da177e4SLinus Torvalds char *name; 2700cb409d9SDavi Arnaut long ret; 2711da177e4SLinus Torvalds 2721da177e4SLinus Torvalds /* fetch the name from userspace */ 2731da177e4SLinus Torvalds name = NULL; 2741da177e4SLinus Torvalds if (_name) { 2750cb409d9SDavi Arnaut name = strndup_user(_name, PAGE_SIZE); 2760cb409d9SDavi Arnaut if (IS_ERR(name)) { 2770cb409d9SDavi Arnaut ret = PTR_ERR(name); 2781da177e4SLinus Torvalds goto error; 2790cb409d9SDavi Arnaut } 2801da177e4SLinus Torvalds } 2811da177e4SLinus Torvalds 2821da177e4SLinus Torvalds /* join the session */ 2831da177e4SLinus Torvalds ret = join_session_keyring(name); 2840d54ee1cSVegard Nossum kfree(name); 2851da177e4SLinus Torvalds 2861da177e4SLinus Torvalds error: 2871da177e4SLinus Torvalds return ret; 288a8b17ed0SDavid Howells } 2891da177e4SLinus Torvalds 2901da177e4SLinus Torvalds /* 291973c9f4fSDavid Howells * Update a key's data payload from the given data. 292973c9f4fSDavid Howells * 293973c9f4fSDavid Howells * The key must grant the caller Write permission and the key type must support 294973c9f4fSDavid Howells * updating for this to work. A negative key can be positively instantiated 295973c9f4fSDavid Howells * with this call. 296973c9f4fSDavid Howells * 297973c9f4fSDavid Howells * If successful, 0 will be returned. If the key type does not support 298973c9f4fSDavid Howells * updating, then -EOPNOTSUPP will be returned. 2991da177e4SLinus Torvalds */ 3001da177e4SLinus Torvalds long keyctl_update_key(key_serial_t id, 3011da177e4SLinus Torvalds const void __user *_payload, 3021da177e4SLinus Torvalds size_t plen) 3031da177e4SLinus Torvalds { 304664cceb0SDavid Howells key_ref_t key_ref; 3051da177e4SLinus Torvalds void *payload; 3061da177e4SLinus Torvalds long ret; 3071da177e4SLinus Torvalds 3081da177e4SLinus Torvalds ret = -EINVAL; 3091da177e4SLinus Torvalds if (plen > PAGE_SIZE) 3101da177e4SLinus Torvalds goto error; 3111da177e4SLinus Torvalds 3121da177e4SLinus Torvalds /* pull the payload in if one was supplied */ 3131da177e4SLinus Torvalds payload = NULL; 3141da177e4SLinus Torvalds if (_payload) { 3151da177e4SLinus Torvalds ret = -ENOMEM; 3161da177e4SLinus Torvalds payload = kmalloc(plen, GFP_KERNEL); 3171da177e4SLinus Torvalds if (!payload) 3181da177e4SLinus Torvalds goto error; 3191da177e4SLinus Torvalds 3201da177e4SLinus Torvalds ret = -EFAULT; 3211da177e4SLinus Torvalds if (copy_from_user(payload, _payload, plen) != 0) 3221da177e4SLinus Torvalds goto error2; 3231da177e4SLinus Torvalds } 3241da177e4SLinus Torvalds 3251da177e4SLinus Torvalds /* find the target key (which must be writable) */ 3265593122eSDavid Howells key_ref = lookup_user_key(id, 0, KEY_WRITE); 327664cceb0SDavid Howells if (IS_ERR(key_ref)) { 328664cceb0SDavid Howells ret = PTR_ERR(key_ref); 3291da177e4SLinus Torvalds goto error2; 3301da177e4SLinus Torvalds } 3311da177e4SLinus Torvalds 3321da177e4SLinus Torvalds /* update the key */ 333664cceb0SDavid Howells ret = key_update(key_ref, payload, plen); 3341da177e4SLinus Torvalds 335664cceb0SDavid Howells key_ref_put(key_ref); 3361da177e4SLinus Torvalds error2: 3371da177e4SLinus Torvalds kfree(payload); 3381da177e4SLinus Torvalds error: 3391da177e4SLinus Torvalds return ret; 340a8b17ed0SDavid Howells } 3411da177e4SLinus Torvalds 3421da177e4SLinus Torvalds /* 343973c9f4fSDavid Howells * Revoke a key. 344973c9f4fSDavid Howells * 345973c9f4fSDavid Howells * The key must be grant the caller Write or Setattr permission for this to 346973c9f4fSDavid Howells * work. The key type should give up its quota claim when revoked. The key 347973c9f4fSDavid Howells * and any links to the key will be automatically garbage collected after a 348973c9f4fSDavid Howells * certain amount of time (/proc/sys/kernel/keys/gc_delay). 349973c9f4fSDavid Howells * 350973c9f4fSDavid Howells * If successful, 0 is returned. 3511da177e4SLinus Torvalds */ 3521da177e4SLinus Torvalds long keyctl_revoke_key(key_serial_t id) 3531da177e4SLinus Torvalds { 354664cceb0SDavid Howells key_ref_t key_ref; 3551da177e4SLinus Torvalds long ret; 3561da177e4SLinus Torvalds 3575593122eSDavid Howells key_ref = lookup_user_key(id, 0, KEY_WRITE); 358664cceb0SDavid Howells if (IS_ERR(key_ref)) { 359664cceb0SDavid Howells ret = PTR_ERR(key_ref); 3600c2c9a3fSDavid Howells if (ret != -EACCES) 3611da177e4SLinus Torvalds goto error; 3620c2c9a3fSDavid Howells key_ref = lookup_user_key(id, 0, KEY_SETATTR); 3630c2c9a3fSDavid Howells if (IS_ERR(key_ref)) { 3640c2c9a3fSDavid Howells ret = PTR_ERR(key_ref); 3650c2c9a3fSDavid Howells goto error; 3660c2c9a3fSDavid Howells } 3671da177e4SLinus Torvalds } 3681da177e4SLinus Torvalds 369664cceb0SDavid Howells key_revoke(key_ref_to_ptr(key_ref)); 3701da177e4SLinus Torvalds ret = 0; 3711da177e4SLinus Torvalds 372664cceb0SDavid Howells key_ref_put(key_ref); 3731da177e4SLinus Torvalds error: 3741260f801SDavid Howells return ret; 375a8b17ed0SDavid Howells } 3761da177e4SLinus Torvalds 3771da177e4SLinus Torvalds /* 378fd75815fSDavid Howells * Invalidate a key. 379fd75815fSDavid Howells * 380fd75815fSDavid Howells * The key must be grant the caller Invalidate permission for this to work. 381fd75815fSDavid Howells * The key and any links to the key will be automatically garbage collected 382fd75815fSDavid Howells * immediately. 383fd75815fSDavid Howells * 384fd75815fSDavid Howells * If successful, 0 is returned. 385fd75815fSDavid Howells */ 386fd75815fSDavid Howells long keyctl_invalidate_key(key_serial_t id) 387fd75815fSDavid Howells { 388fd75815fSDavid Howells key_ref_t key_ref; 389fd75815fSDavid Howells long ret; 390fd75815fSDavid Howells 391fd75815fSDavid Howells kenter("%d", id); 392fd75815fSDavid Howells 393fd75815fSDavid Howells key_ref = lookup_user_key(id, 0, KEY_SEARCH); 394fd75815fSDavid Howells if (IS_ERR(key_ref)) { 395fd75815fSDavid Howells ret = PTR_ERR(key_ref); 396fd75815fSDavid Howells goto error; 397fd75815fSDavid Howells } 398fd75815fSDavid Howells 399fd75815fSDavid Howells key_invalidate(key_ref_to_ptr(key_ref)); 400fd75815fSDavid Howells ret = 0; 401fd75815fSDavid Howells 402fd75815fSDavid Howells key_ref_put(key_ref); 403fd75815fSDavid Howells error: 404fd75815fSDavid Howells kleave(" = %ld", ret); 405fd75815fSDavid Howells return ret; 406fd75815fSDavid Howells } 407fd75815fSDavid Howells 408fd75815fSDavid Howells /* 409973c9f4fSDavid Howells * Clear the specified keyring, creating an empty process keyring if one of the 410973c9f4fSDavid Howells * special keyring IDs is used. 411973c9f4fSDavid Howells * 412973c9f4fSDavid Howells * The keyring must grant the caller Write permission for this to work. If 413973c9f4fSDavid Howells * successful, 0 will be returned. 4141da177e4SLinus Torvalds */ 4151da177e4SLinus Torvalds long keyctl_keyring_clear(key_serial_t ringid) 4161da177e4SLinus Torvalds { 417664cceb0SDavid Howells key_ref_t keyring_ref; 4181da177e4SLinus Torvalds long ret; 4191da177e4SLinus Torvalds 4205593122eSDavid Howells keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE); 421664cceb0SDavid Howells if (IS_ERR(keyring_ref)) { 422664cceb0SDavid Howells ret = PTR_ERR(keyring_ref); 423700920ebSDavid Howells 424700920ebSDavid Howells /* Root is permitted to invalidate certain special keyrings */ 425700920ebSDavid Howells if (capable(CAP_SYS_ADMIN)) { 426700920ebSDavid Howells keyring_ref = lookup_user_key(ringid, 0, 0); 427700920ebSDavid Howells if (IS_ERR(keyring_ref)) 428700920ebSDavid Howells goto error; 429700920ebSDavid Howells if (test_bit(KEY_FLAG_ROOT_CAN_CLEAR, 430700920ebSDavid Howells &key_ref_to_ptr(keyring_ref)->flags)) 431700920ebSDavid Howells goto clear; 432700920ebSDavid Howells goto error_put; 433700920ebSDavid Howells } 434700920ebSDavid Howells 4351da177e4SLinus Torvalds goto error; 4361da177e4SLinus Torvalds } 4371da177e4SLinus Torvalds 438700920ebSDavid Howells clear: 439664cceb0SDavid Howells ret = keyring_clear(key_ref_to_ptr(keyring_ref)); 440700920ebSDavid Howells error_put: 441664cceb0SDavid Howells key_ref_put(keyring_ref); 4421da177e4SLinus Torvalds error: 4431da177e4SLinus Torvalds return ret; 444a8b17ed0SDavid Howells } 4451da177e4SLinus Torvalds 4461da177e4SLinus Torvalds /* 447973c9f4fSDavid Howells * Create a link from a keyring to a key if there's no matching key in the 448973c9f4fSDavid Howells * keyring, otherwise replace the link to the matching key with a link to the 449973c9f4fSDavid Howells * new key. 450973c9f4fSDavid Howells * 451973c9f4fSDavid Howells * The key must grant the caller Link permission and the the keyring must grant 452973c9f4fSDavid Howells * the caller Write permission. Furthermore, if an additional link is created, 453973c9f4fSDavid Howells * the keyring's quota will be extended. 454973c9f4fSDavid Howells * 455973c9f4fSDavid Howells * If successful, 0 will be returned. 4561da177e4SLinus Torvalds */ 4571da177e4SLinus Torvalds long keyctl_keyring_link(key_serial_t id, key_serial_t ringid) 4581da177e4SLinus Torvalds { 459664cceb0SDavid Howells key_ref_t keyring_ref, key_ref; 4601da177e4SLinus Torvalds long ret; 4611da177e4SLinus Torvalds 4625593122eSDavid Howells keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE); 463664cceb0SDavid Howells if (IS_ERR(keyring_ref)) { 464664cceb0SDavid Howells ret = PTR_ERR(keyring_ref); 4651da177e4SLinus Torvalds goto error; 4661da177e4SLinus Torvalds } 4671da177e4SLinus Torvalds 4685593122eSDavid Howells key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE, KEY_LINK); 469664cceb0SDavid Howells if (IS_ERR(key_ref)) { 470664cceb0SDavid Howells ret = PTR_ERR(key_ref); 4711da177e4SLinus Torvalds goto error2; 4721da177e4SLinus Torvalds } 4731da177e4SLinus Torvalds 474664cceb0SDavid Howells ret = key_link(key_ref_to_ptr(keyring_ref), key_ref_to_ptr(key_ref)); 4751da177e4SLinus Torvalds 476664cceb0SDavid Howells key_ref_put(key_ref); 4771da177e4SLinus Torvalds error2: 478664cceb0SDavid Howells key_ref_put(keyring_ref); 4791da177e4SLinus Torvalds error: 4801da177e4SLinus Torvalds return ret; 481a8b17ed0SDavid Howells } 4821da177e4SLinus Torvalds 4831da177e4SLinus Torvalds /* 484973c9f4fSDavid Howells * Unlink a key from a keyring. 485973c9f4fSDavid Howells * 486973c9f4fSDavid Howells * The keyring must grant the caller Write permission for this to work; the key 487973c9f4fSDavid Howells * itself need not grant the caller anything. If the last link to a key is 488973c9f4fSDavid Howells * removed then that key will be scheduled for destruction. 489973c9f4fSDavid Howells * 490973c9f4fSDavid Howells * If successful, 0 will be returned. 4911da177e4SLinus Torvalds */ 4921da177e4SLinus Torvalds long keyctl_keyring_unlink(key_serial_t id, key_serial_t ringid) 4931da177e4SLinus Torvalds { 494664cceb0SDavid Howells key_ref_t keyring_ref, key_ref; 4951da177e4SLinus Torvalds long ret; 4961da177e4SLinus Torvalds 4975593122eSDavid Howells keyring_ref = lookup_user_key(ringid, 0, KEY_WRITE); 498664cceb0SDavid Howells if (IS_ERR(keyring_ref)) { 499664cceb0SDavid Howells ret = PTR_ERR(keyring_ref); 5001da177e4SLinus Torvalds goto error; 5011da177e4SLinus Torvalds } 5021da177e4SLinus Torvalds 5035593122eSDavid Howells key_ref = lookup_user_key(id, KEY_LOOKUP_FOR_UNLINK, 0); 504664cceb0SDavid Howells if (IS_ERR(key_ref)) { 505664cceb0SDavid Howells ret = PTR_ERR(key_ref); 5061da177e4SLinus Torvalds goto error2; 5071da177e4SLinus Torvalds } 5081da177e4SLinus Torvalds 509664cceb0SDavid Howells ret = key_unlink(key_ref_to_ptr(keyring_ref), key_ref_to_ptr(key_ref)); 5101da177e4SLinus Torvalds 511664cceb0SDavid Howells key_ref_put(key_ref); 5121da177e4SLinus Torvalds error2: 513664cceb0SDavid Howells key_ref_put(keyring_ref); 5141da177e4SLinus Torvalds error: 5151da177e4SLinus Torvalds return ret; 516a8b17ed0SDavid Howells } 5171da177e4SLinus Torvalds 5181da177e4SLinus Torvalds /* 519973c9f4fSDavid Howells * Return a description of a key to userspace. 520973c9f4fSDavid Howells * 521973c9f4fSDavid Howells * The key must grant the caller View permission for this to work. 522973c9f4fSDavid Howells * 523973c9f4fSDavid Howells * If there's a buffer, we place up to buflen bytes of data into it formatted 524973c9f4fSDavid Howells * in the following way: 525973c9f4fSDavid Howells * 5261da177e4SLinus Torvalds * type;uid;gid;perm;description<NUL> 527973c9f4fSDavid Howells * 528973c9f4fSDavid Howells * If successful, we return the amount of description available, irrespective 529973c9f4fSDavid Howells * of how much we may have copied into the buffer. 5301da177e4SLinus Torvalds */ 5311da177e4SLinus Torvalds long keyctl_describe_key(key_serial_t keyid, 5321da177e4SLinus Torvalds char __user *buffer, 5331da177e4SLinus Torvalds size_t buflen) 5341da177e4SLinus Torvalds { 5353e30148cSDavid Howells struct key *key, *instkey; 536664cceb0SDavid Howells key_ref_t key_ref; 5371da177e4SLinus Torvalds char *tmpbuf; 5381da177e4SLinus Torvalds long ret; 5391da177e4SLinus Torvalds 5405593122eSDavid Howells key_ref = lookup_user_key(keyid, KEY_LOOKUP_PARTIAL, KEY_VIEW); 541664cceb0SDavid Howells if (IS_ERR(key_ref)) { 5423e30148cSDavid Howells /* viewing a key under construction is permitted if we have the 5433e30148cSDavid Howells * authorisation token handy */ 544664cceb0SDavid Howells if (PTR_ERR(key_ref) == -EACCES) { 5453e30148cSDavid Howells instkey = key_get_instantiation_authkey(keyid); 5463e30148cSDavid Howells if (!IS_ERR(instkey)) { 5473e30148cSDavid Howells key_put(instkey); 5488bbf4976SDavid Howells key_ref = lookup_user_key(keyid, 5495593122eSDavid Howells KEY_LOOKUP_PARTIAL, 5505593122eSDavid Howells 0); 551664cceb0SDavid Howells if (!IS_ERR(key_ref)) 5523e30148cSDavid Howells goto okay; 5533e30148cSDavid Howells } 5543e30148cSDavid Howells } 5553e30148cSDavid Howells 556664cceb0SDavid Howells ret = PTR_ERR(key_ref); 5571da177e4SLinus Torvalds goto error; 5581da177e4SLinus Torvalds } 5591da177e4SLinus Torvalds 5603e30148cSDavid Howells okay: 5611da177e4SLinus Torvalds /* calculate how much description we're going to return */ 5621da177e4SLinus Torvalds ret = -ENOMEM; 5631da177e4SLinus Torvalds tmpbuf = kmalloc(PAGE_SIZE, GFP_KERNEL); 5641da177e4SLinus Torvalds if (!tmpbuf) 5651da177e4SLinus Torvalds goto error2; 5661da177e4SLinus Torvalds 567664cceb0SDavid Howells key = key_ref_to_ptr(key_ref); 568664cceb0SDavid Howells 5691da177e4SLinus Torvalds ret = snprintf(tmpbuf, PAGE_SIZE - 1, 570664cceb0SDavid Howells "%s;%d;%d;%08x;%s", 57194fd8405SDavid Howells key->type->name, 57294fd8405SDavid Howells key->uid, 57394fd8405SDavid Howells key->gid, 57494fd8405SDavid Howells key->perm, 57594fd8405SDavid Howells key->description ?: ""); 5761da177e4SLinus Torvalds 5771da177e4SLinus Torvalds /* include a NUL char at the end of the data */ 5781da177e4SLinus Torvalds if (ret > PAGE_SIZE - 1) 5791da177e4SLinus Torvalds ret = PAGE_SIZE - 1; 5801da177e4SLinus Torvalds tmpbuf[ret] = 0; 5811da177e4SLinus Torvalds ret++; 5821da177e4SLinus Torvalds 5831da177e4SLinus Torvalds /* consider returning the data */ 5841da177e4SLinus Torvalds if (buffer && buflen > 0) { 5851da177e4SLinus Torvalds if (buflen > ret) 5861da177e4SLinus Torvalds buflen = ret; 5871da177e4SLinus Torvalds 5881da177e4SLinus Torvalds if (copy_to_user(buffer, tmpbuf, buflen) != 0) 5891da177e4SLinus Torvalds ret = -EFAULT; 5901da177e4SLinus Torvalds } 5911da177e4SLinus Torvalds 5921da177e4SLinus Torvalds kfree(tmpbuf); 5931da177e4SLinus Torvalds error2: 594664cceb0SDavid Howells key_ref_put(key_ref); 5951da177e4SLinus Torvalds error: 5961da177e4SLinus Torvalds return ret; 597a8b17ed0SDavid Howells } 5981da177e4SLinus Torvalds 5991da177e4SLinus Torvalds /* 600973c9f4fSDavid Howells * Search the specified keyring and any keyrings it links to for a matching 601973c9f4fSDavid Howells * key. Only keyrings that grant the caller Search permission will be searched 602973c9f4fSDavid Howells * (this includes the starting keyring). Only keys with Search permission can 603973c9f4fSDavid Howells * be found. 604973c9f4fSDavid Howells * 605973c9f4fSDavid Howells * If successful, the found key will be linked to the destination keyring if 606973c9f4fSDavid Howells * supplied and the key has Link permission, and the found key ID will be 607973c9f4fSDavid Howells * returned. 6081da177e4SLinus Torvalds */ 6091da177e4SLinus Torvalds long keyctl_keyring_search(key_serial_t ringid, 6101da177e4SLinus Torvalds const char __user *_type, 6111da177e4SLinus Torvalds const char __user *_description, 6121da177e4SLinus Torvalds key_serial_t destringid) 6131da177e4SLinus Torvalds { 6141da177e4SLinus Torvalds struct key_type *ktype; 615664cceb0SDavid Howells key_ref_t keyring_ref, key_ref, dest_ref; 6161da177e4SLinus Torvalds char type[32], *description; 6170cb409d9SDavi Arnaut long ret; 6181da177e4SLinus Torvalds 6191da177e4SLinus Torvalds /* pull the type and description into kernel space */ 6200cb409d9SDavi Arnaut ret = key_get_type_from_user(type, _type, sizeof(type)); 6211da177e4SLinus Torvalds if (ret < 0) 6221da177e4SLinus Torvalds goto error; 6231da177e4SLinus Torvalds 6240cb409d9SDavi Arnaut description = strndup_user(_description, PAGE_SIZE); 6250cb409d9SDavi Arnaut if (IS_ERR(description)) { 6260cb409d9SDavi Arnaut ret = PTR_ERR(description); 6271da177e4SLinus Torvalds goto error; 6280cb409d9SDavi Arnaut } 6291da177e4SLinus Torvalds 6301da177e4SLinus Torvalds /* get the keyring at which to begin the search */ 6315593122eSDavid Howells keyring_ref = lookup_user_key(ringid, 0, KEY_SEARCH); 632664cceb0SDavid Howells if (IS_ERR(keyring_ref)) { 633664cceb0SDavid Howells ret = PTR_ERR(keyring_ref); 6341da177e4SLinus Torvalds goto error2; 6351da177e4SLinus Torvalds } 6361da177e4SLinus Torvalds 6371da177e4SLinus Torvalds /* get the destination keyring if specified */ 638664cceb0SDavid Howells dest_ref = NULL; 6391da177e4SLinus Torvalds if (destringid) { 6405593122eSDavid Howells dest_ref = lookup_user_key(destringid, KEY_LOOKUP_CREATE, 6415593122eSDavid Howells KEY_WRITE); 642664cceb0SDavid Howells if (IS_ERR(dest_ref)) { 643664cceb0SDavid Howells ret = PTR_ERR(dest_ref); 6441da177e4SLinus Torvalds goto error3; 6451da177e4SLinus Torvalds } 6461da177e4SLinus Torvalds } 6471da177e4SLinus Torvalds 6481da177e4SLinus Torvalds /* find the key type */ 6491da177e4SLinus Torvalds ktype = key_type_lookup(type); 6501da177e4SLinus Torvalds if (IS_ERR(ktype)) { 6511da177e4SLinus Torvalds ret = PTR_ERR(ktype); 6521da177e4SLinus Torvalds goto error4; 6531da177e4SLinus Torvalds } 6541da177e4SLinus Torvalds 6551da177e4SLinus Torvalds /* do the search */ 656664cceb0SDavid Howells key_ref = keyring_search(keyring_ref, ktype, description); 657664cceb0SDavid Howells if (IS_ERR(key_ref)) { 658664cceb0SDavid Howells ret = PTR_ERR(key_ref); 6591da177e4SLinus Torvalds 6601da177e4SLinus Torvalds /* treat lack or presence of a negative key the same */ 6611da177e4SLinus Torvalds if (ret == -EAGAIN) 6621da177e4SLinus Torvalds ret = -ENOKEY; 6631da177e4SLinus Torvalds goto error5; 6641da177e4SLinus Torvalds } 6651da177e4SLinus Torvalds 6661da177e4SLinus Torvalds /* link the resulting key to the destination keyring if we can */ 667664cceb0SDavid Howells if (dest_ref) { 66829db9190SDavid Howells ret = key_permission(key_ref, KEY_LINK); 66929db9190SDavid Howells if (ret < 0) 6701da177e4SLinus Torvalds goto error6; 6711da177e4SLinus Torvalds 672664cceb0SDavid Howells ret = key_link(key_ref_to_ptr(dest_ref), key_ref_to_ptr(key_ref)); 6731da177e4SLinus Torvalds if (ret < 0) 6741da177e4SLinus Torvalds goto error6; 6751da177e4SLinus Torvalds } 6761da177e4SLinus Torvalds 677664cceb0SDavid Howells ret = key_ref_to_ptr(key_ref)->serial; 6781da177e4SLinus Torvalds 6791da177e4SLinus Torvalds error6: 680664cceb0SDavid Howells key_ref_put(key_ref); 6811da177e4SLinus Torvalds error5: 6821da177e4SLinus Torvalds key_type_put(ktype); 6831da177e4SLinus Torvalds error4: 684664cceb0SDavid Howells key_ref_put(dest_ref); 6851da177e4SLinus Torvalds error3: 686664cceb0SDavid Howells key_ref_put(keyring_ref); 6871da177e4SLinus Torvalds error2: 6881da177e4SLinus Torvalds kfree(description); 6891da177e4SLinus Torvalds error: 6901da177e4SLinus Torvalds return ret; 691a8b17ed0SDavid Howells } 6921da177e4SLinus Torvalds 6931da177e4SLinus Torvalds /* 694973c9f4fSDavid Howells * Read a key's payload. 695973c9f4fSDavid Howells * 696973c9f4fSDavid Howells * The key must either grant the caller Read permission, or it must grant the 697973c9f4fSDavid Howells * caller Search permission when searched for from the process keyrings. 698973c9f4fSDavid Howells * 699973c9f4fSDavid Howells * If successful, we place up to buflen bytes of data into the buffer, if one 700973c9f4fSDavid Howells * is provided, and return the amount of data that is available in the key, 701973c9f4fSDavid Howells * irrespective of how much we copied into the buffer. 7021da177e4SLinus Torvalds */ 7031da177e4SLinus Torvalds long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen) 7041da177e4SLinus Torvalds { 705664cceb0SDavid Howells struct key *key; 706664cceb0SDavid Howells key_ref_t key_ref; 7071da177e4SLinus Torvalds long ret; 7081da177e4SLinus Torvalds 7091da177e4SLinus Torvalds /* find the key first */ 7105593122eSDavid Howells key_ref = lookup_user_key(keyid, 0, 0); 711664cceb0SDavid Howells if (IS_ERR(key_ref)) { 712664cceb0SDavid Howells ret = -ENOKEY; 713664cceb0SDavid Howells goto error; 714664cceb0SDavid Howells } 715664cceb0SDavid Howells 716664cceb0SDavid Howells key = key_ref_to_ptr(key_ref); 717664cceb0SDavid Howells 7181da177e4SLinus Torvalds /* see if we can read it directly */ 71929db9190SDavid Howells ret = key_permission(key_ref, KEY_READ); 72029db9190SDavid Howells if (ret == 0) 7211da177e4SLinus Torvalds goto can_read_key; 72229db9190SDavid Howells if (ret != -EACCES) 72329db9190SDavid Howells goto error; 7241da177e4SLinus Torvalds 725664cceb0SDavid Howells /* we can't; see if it's searchable from this process's keyrings 7263e30148cSDavid Howells * - we automatically take account of the fact that it may be 7273e30148cSDavid Howells * dangling off an instantiation key 7283e30148cSDavid Howells */ 729664cceb0SDavid Howells if (!is_key_possessed(key_ref)) { 7301260f801SDavid Howells ret = -EACCES; 7311da177e4SLinus Torvalds goto error2; 7321da177e4SLinus Torvalds } 7331da177e4SLinus Torvalds 7341da177e4SLinus Torvalds /* the key is probably readable - now try to read it */ 7351da177e4SLinus Torvalds can_read_key: 7361da177e4SLinus Torvalds ret = key_validate(key); 7371da177e4SLinus Torvalds if (ret == 0) { 7381da177e4SLinus Torvalds ret = -EOPNOTSUPP; 7391da177e4SLinus Torvalds if (key->type->read) { 7401da177e4SLinus Torvalds /* read the data with the semaphore held (since we 7411da177e4SLinus Torvalds * might sleep) */ 7421da177e4SLinus Torvalds down_read(&key->sem); 7431da177e4SLinus Torvalds ret = key->type->read(key, buffer, buflen); 7441da177e4SLinus Torvalds up_read(&key->sem); 7451da177e4SLinus Torvalds } 7461da177e4SLinus Torvalds } 7471da177e4SLinus Torvalds 7481da177e4SLinus Torvalds error2: 7491da177e4SLinus Torvalds key_put(key); 7501da177e4SLinus Torvalds error: 7511da177e4SLinus Torvalds return ret; 752a8b17ed0SDavid Howells } 7531da177e4SLinus Torvalds 7541da177e4SLinus Torvalds /* 755973c9f4fSDavid Howells * Change the ownership of a key 756973c9f4fSDavid Howells * 757973c9f4fSDavid Howells * The key must grant the caller Setattr permission for this to work, though 758973c9f4fSDavid Howells * the key need not be fully instantiated yet. For the UID to be changed, or 759973c9f4fSDavid Howells * for the GID to be changed to a group the caller is not a member of, the 760973c9f4fSDavid Howells * caller must have sysadmin capability. If either uid or gid is -1 then that 761973c9f4fSDavid Howells * attribute is not changed. 762973c9f4fSDavid Howells * 763973c9f4fSDavid Howells * If the UID is to be changed, the new user must have sufficient quota to 764973c9f4fSDavid Howells * accept the key. The quota deduction will be removed from the old user to 765973c9f4fSDavid Howells * the new user should the attribute be changed. 766973c9f4fSDavid Howells * 767973c9f4fSDavid Howells * If successful, 0 will be returned. 7681da177e4SLinus Torvalds */ 7691da177e4SLinus Torvalds long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid) 7701da177e4SLinus Torvalds { 7715801649dSFredrik Tolf struct key_user *newowner, *zapowner = NULL; 7721da177e4SLinus Torvalds struct key *key; 773664cceb0SDavid Howells key_ref_t key_ref; 7741da177e4SLinus Torvalds long ret; 7751da177e4SLinus Torvalds 7761da177e4SLinus Torvalds ret = 0; 7771da177e4SLinus Torvalds if (uid == (uid_t) -1 && gid == (gid_t) -1) 7781da177e4SLinus Torvalds goto error; 7791da177e4SLinus Torvalds 7805593122eSDavid Howells key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL, 7815593122eSDavid Howells KEY_SETATTR); 782664cceb0SDavid Howells if (IS_ERR(key_ref)) { 783664cceb0SDavid Howells ret = PTR_ERR(key_ref); 7841da177e4SLinus Torvalds goto error; 7851da177e4SLinus Torvalds } 7861da177e4SLinus Torvalds 787664cceb0SDavid Howells key = key_ref_to_ptr(key_ref); 788664cceb0SDavid Howells 7891da177e4SLinus Torvalds /* make the changes with the locks held to prevent chown/chown races */ 7901da177e4SLinus Torvalds ret = -EACCES; 7911da177e4SLinus Torvalds down_write(&key->sem); 7921da177e4SLinus Torvalds 7931da177e4SLinus Torvalds if (!capable(CAP_SYS_ADMIN)) { 7941da177e4SLinus Torvalds /* only the sysadmin can chown a key to some other UID */ 7951da177e4SLinus Torvalds if (uid != (uid_t) -1 && key->uid != uid) 7965801649dSFredrik Tolf goto error_put; 7971da177e4SLinus Torvalds 7981da177e4SLinus Torvalds /* only the sysadmin can set the key's GID to a group other 7991da177e4SLinus Torvalds * than one of those that the current process subscribes to */ 8001da177e4SLinus Torvalds if (gid != (gid_t) -1 && gid != key->gid && !in_group_p(gid)) 8015801649dSFredrik Tolf goto error_put; 8021da177e4SLinus Torvalds } 8031da177e4SLinus Torvalds 8045801649dSFredrik Tolf /* change the UID */ 8051da177e4SLinus Torvalds if (uid != (uid_t) -1 && uid != key->uid) { 8065801649dSFredrik Tolf ret = -ENOMEM; 8071d1e9756SSerge E. Hallyn newowner = key_user_lookup(uid, current_user_ns()); 8085801649dSFredrik Tolf if (!newowner) 8095801649dSFredrik Tolf goto error_put; 8105801649dSFredrik Tolf 8115801649dSFredrik Tolf /* transfer the quota burden to the new user */ 8125801649dSFredrik Tolf if (test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) { 8130b77f5bfSDavid Howells unsigned maxkeys = (uid == 0) ? 8140b77f5bfSDavid Howells key_quota_root_maxkeys : key_quota_maxkeys; 8150b77f5bfSDavid Howells unsigned maxbytes = (uid == 0) ? 8160b77f5bfSDavid Howells key_quota_root_maxbytes : key_quota_maxbytes; 8170b77f5bfSDavid Howells 8185801649dSFredrik Tolf spin_lock(&newowner->lock); 8190b77f5bfSDavid Howells if (newowner->qnkeys + 1 >= maxkeys || 8200b77f5bfSDavid Howells newowner->qnbytes + key->quotalen >= maxbytes || 8210b77f5bfSDavid Howells newowner->qnbytes + key->quotalen < 8220b77f5bfSDavid Howells newowner->qnbytes) 8235801649dSFredrik Tolf goto quota_overrun; 8245801649dSFredrik Tolf 8255801649dSFredrik Tolf newowner->qnkeys++; 8265801649dSFredrik Tolf newowner->qnbytes += key->quotalen; 8275801649dSFredrik Tolf spin_unlock(&newowner->lock); 8285801649dSFredrik Tolf 8295801649dSFredrik Tolf spin_lock(&key->user->lock); 8305801649dSFredrik Tolf key->user->qnkeys--; 8315801649dSFredrik Tolf key->user->qnbytes -= key->quotalen; 8325801649dSFredrik Tolf spin_unlock(&key->user->lock); 8335801649dSFredrik Tolf } 8345801649dSFredrik Tolf 8355801649dSFredrik Tolf atomic_dec(&key->user->nkeys); 8365801649dSFredrik Tolf atomic_inc(&newowner->nkeys); 8375801649dSFredrik Tolf 8385801649dSFredrik Tolf if (test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) { 8395801649dSFredrik Tolf atomic_dec(&key->user->nikeys); 8405801649dSFredrik Tolf atomic_inc(&newowner->nikeys); 8415801649dSFredrik Tolf } 8425801649dSFredrik Tolf 8435801649dSFredrik Tolf zapowner = key->user; 8445801649dSFredrik Tolf key->user = newowner; 8455801649dSFredrik Tolf key->uid = uid; 8461da177e4SLinus Torvalds } 8471da177e4SLinus Torvalds 8481da177e4SLinus Torvalds /* change the GID */ 8491da177e4SLinus Torvalds if (gid != (gid_t) -1) 8501da177e4SLinus Torvalds key->gid = gid; 8511da177e4SLinus Torvalds 8521da177e4SLinus Torvalds ret = 0; 8531da177e4SLinus Torvalds 8545801649dSFredrik Tolf error_put: 8551da177e4SLinus Torvalds up_write(&key->sem); 8561da177e4SLinus Torvalds key_put(key); 8575801649dSFredrik Tolf if (zapowner) 8585801649dSFredrik Tolf key_user_put(zapowner); 8591da177e4SLinus Torvalds error: 8601da177e4SLinus Torvalds return ret; 8611da177e4SLinus Torvalds 8625801649dSFredrik Tolf quota_overrun: 8635801649dSFredrik Tolf spin_unlock(&newowner->lock); 8645801649dSFredrik Tolf zapowner = newowner; 8655801649dSFredrik Tolf ret = -EDQUOT; 8665801649dSFredrik Tolf goto error_put; 867a8b17ed0SDavid Howells } 8685801649dSFredrik Tolf 8691da177e4SLinus Torvalds /* 870973c9f4fSDavid Howells * Change the permission mask on a key. 871973c9f4fSDavid Howells * 872973c9f4fSDavid Howells * The key must grant the caller Setattr permission for this to work, though 873973c9f4fSDavid Howells * the key need not be fully instantiated yet. If the caller does not have 874973c9f4fSDavid Howells * sysadmin capability, it may only change the permission on keys that it owns. 8751da177e4SLinus Torvalds */ 8761da177e4SLinus Torvalds long keyctl_setperm_key(key_serial_t id, key_perm_t perm) 8771da177e4SLinus Torvalds { 8781da177e4SLinus Torvalds struct key *key; 879664cceb0SDavid Howells key_ref_t key_ref; 8801da177e4SLinus Torvalds long ret; 8811da177e4SLinus Torvalds 8821da177e4SLinus Torvalds ret = -EINVAL; 883664cceb0SDavid Howells if (perm & ~(KEY_POS_ALL | KEY_USR_ALL | KEY_GRP_ALL | KEY_OTH_ALL)) 8841da177e4SLinus Torvalds goto error; 8851da177e4SLinus Torvalds 8865593122eSDavid Howells key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL, 8875593122eSDavid Howells KEY_SETATTR); 888664cceb0SDavid Howells if (IS_ERR(key_ref)) { 889664cceb0SDavid Howells ret = PTR_ERR(key_ref); 8901da177e4SLinus Torvalds goto error; 8911da177e4SLinus Torvalds } 8921da177e4SLinus Torvalds 893664cceb0SDavid Howells key = key_ref_to_ptr(key_ref); 894664cceb0SDavid Howells 89576d8aeabSDavid Howells /* make the changes with the locks held to prevent chown/chmod races */ 8961da177e4SLinus Torvalds ret = -EACCES; 8971da177e4SLinus Torvalds down_write(&key->sem); 8981da177e4SLinus Torvalds 89976d8aeabSDavid Howells /* if we're not the sysadmin, we can only change a key that we own */ 90047d804bfSDavid Howells if (capable(CAP_SYS_ADMIN) || key->uid == current_fsuid()) { 9011da177e4SLinus Torvalds key->perm = perm; 9021da177e4SLinus Torvalds ret = 0; 90376d8aeabSDavid Howells } 9041da177e4SLinus Torvalds 9051da177e4SLinus Torvalds up_write(&key->sem); 9061da177e4SLinus Torvalds key_put(key); 9071da177e4SLinus Torvalds error: 9081da177e4SLinus Torvalds return ret; 909a8b17ed0SDavid Howells } 9101da177e4SLinus Torvalds 9118bbf4976SDavid Howells /* 912973c9f4fSDavid Howells * Get the destination keyring for instantiation and check that the caller has 913973c9f4fSDavid Howells * Write permission on it. 9148bbf4976SDavid Howells */ 9158bbf4976SDavid Howells static long get_instantiation_keyring(key_serial_t ringid, 9168bbf4976SDavid Howells struct request_key_auth *rka, 9178bbf4976SDavid Howells struct key **_dest_keyring) 9188bbf4976SDavid Howells { 9198bbf4976SDavid Howells key_ref_t dkref; 9208bbf4976SDavid Howells 9218bbf4976SDavid Howells *_dest_keyring = NULL; 922eca1bf5bSDavid Howells 923eca1bf5bSDavid Howells /* just return a NULL pointer if we weren't asked to make a link */ 924eca1bf5bSDavid Howells if (ringid == 0) 9258bbf4976SDavid Howells return 0; 9268bbf4976SDavid Howells 9278bbf4976SDavid Howells /* if a specific keyring is nominated by ID, then use that */ 9288bbf4976SDavid Howells if (ringid > 0) { 9295593122eSDavid Howells dkref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE); 9308bbf4976SDavid Howells if (IS_ERR(dkref)) 9318bbf4976SDavid Howells return PTR_ERR(dkref); 9328bbf4976SDavid Howells *_dest_keyring = key_ref_to_ptr(dkref); 9338bbf4976SDavid Howells return 0; 9348bbf4976SDavid Howells } 9358bbf4976SDavid Howells 9368bbf4976SDavid Howells if (ringid == KEY_SPEC_REQKEY_AUTH_KEY) 9378bbf4976SDavid Howells return -EINVAL; 9388bbf4976SDavid Howells 9398bbf4976SDavid Howells /* otherwise specify the destination keyring recorded in the 9408bbf4976SDavid Howells * authorisation key (any KEY_SPEC_*_KEYRING) */ 9418bbf4976SDavid Howells if (ringid >= KEY_SPEC_REQUESTOR_KEYRING) { 94221279cfaSDavid Howells *_dest_keyring = key_get(rka->dest_keyring); 9438bbf4976SDavid Howells return 0; 9448bbf4976SDavid Howells } 9458bbf4976SDavid Howells 9468bbf4976SDavid Howells return -ENOKEY; 9478bbf4976SDavid Howells } 9488bbf4976SDavid Howells 949d84f4f99SDavid Howells /* 950973c9f4fSDavid Howells * Change the request_key authorisation key on the current process. 951d84f4f99SDavid Howells */ 952d84f4f99SDavid Howells static int keyctl_change_reqkey_auth(struct key *key) 953d84f4f99SDavid Howells { 954d84f4f99SDavid Howells struct cred *new; 955d84f4f99SDavid Howells 956d84f4f99SDavid Howells new = prepare_creds(); 957d84f4f99SDavid Howells if (!new) 958d84f4f99SDavid Howells return -ENOMEM; 959d84f4f99SDavid Howells 960d84f4f99SDavid Howells key_put(new->request_key_auth); 961d84f4f99SDavid Howells new->request_key_auth = key_get(key); 962d84f4f99SDavid Howells 963d84f4f99SDavid Howells return commit_creds(new); 964d84f4f99SDavid Howells } 965d84f4f99SDavid Howells 9661da177e4SLinus Torvalds /* 967ee009e4aSDavid Howells * Copy the iovec data from userspace 968ee009e4aSDavid Howells */ 969ee009e4aSDavid Howells static long copy_from_user_iovec(void *buffer, const struct iovec *iov, 970ee009e4aSDavid Howells unsigned ioc) 971ee009e4aSDavid Howells { 972ee009e4aSDavid Howells for (; ioc > 0; ioc--) { 973ee009e4aSDavid Howells if (copy_from_user(buffer, iov->iov_base, iov->iov_len) != 0) 974ee009e4aSDavid Howells return -EFAULT; 975ee009e4aSDavid Howells buffer += iov->iov_len; 976ee009e4aSDavid Howells iov++; 977ee009e4aSDavid Howells } 978ee009e4aSDavid Howells return 0; 979ee009e4aSDavid Howells } 980ee009e4aSDavid Howells 981ee009e4aSDavid Howells /* 982973c9f4fSDavid Howells * Instantiate a key with the specified payload and link the key into the 983973c9f4fSDavid Howells * destination keyring if one is given. 984973c9f4fSDavid Howells * 985973c9f4fSDavid Howells * The caller must have the appropriate instantiation permit set for this to 986973c9f4fSDavid Howells * work (see keyctl_assume_authority). No other permissions are required. 987973c9f4fSDavid Howells * 988973c9f4fSDavid Howells * If successful, 0 will be returned. 9891da177e4SLinus Torvalds */ 990ee009e4aSDavid Howells long keyctl_instantiate_key_common(key_serial_t id, 991ee009e4aSDavid Howells const struct iovec *payload_iov, 992ee009e4aSDavid Howells unsigned ioc, 9931da177e4SLinus Torvalds size_t plen, 9941da177e4SLinus Torvalds key_serial_t ringid) 9951da177e4SLinus Torvalds { 996d84f4f99SDavid Howells const struct cred *cred = current_cred(); 9973e30148cSDavid Howells struct request_key_auth *rka; 9988bbf4976SDavid Howells struct key *instkey, *dest_keyring; 9991da177e4SLinus Torvalds void *payload; 10001da177e4SLinus Torvalds long ret; 100138bbca6bSDavid Howells bool vm = false; 10021da177e4SLinus Torvalds 1003d84f4f99SDavid Howells kenter("%d,,%zu,%d", id, plen, ringid); 1004d84f4f99SDavid Howells 10051da177e4SLinus Torvalds ret = -EINVAL; 100638bbca6bSDavid Howells if (plen > 1024 * 1024 - 1) 10071da177e4SLinus Torvalds goto error; 10081da177e4SLinus Torvalds 1009b5f545c8SDavid Howells /* the appropriate instantiation authorisation key must have been 1010b5f545c8SDavid Howells * assumed before calling this */ 1011b5f545c8SDavid Howells ret = -EPERM; 1012d84f4f99SDavid Howells instkey = cred->request_key_auth; 1013b5f545c8SDavid Howells if (!instkey) 1014b5f545c8SDavid Howells goto error; 1015b5f545c8SDavid Howells 1016b5f545c8SDavid Howells rka = instkey->payload.data; 1017b5f545c8SDavid Howells if (rka->target_key->serial != id) 1018b5f545c8SDavid Howells goto error; 1019b5f545c8SDavid Howells 10201da177e4SLinus Torvalds /* pull the payload in if one was supplied */ 10211da177e4SLinus Torvalds payload = NULL; 10221da177e4SLinus Torvalds 1023ee009e4aSDavid Howells if (payload_iov) { 10241da177e4SLinus Torvalds ret = -ENOMEM; 10251da177e4SLinus Torvalds payload = kmalloc(plen, GFP_KERNEL); 102638bbca6bSDavid Howells if (!payload) { 102738bbca6bSDavid Howells if (plen <= PAGE_SIZE) 102838bbca6bSDavid Howells goto error; 102938bbca6bSDavid Howells vm = true; 103038bbca6bSDavid Howells payload = vmalloc(plen); 10311da177e4SLinus Torvalds if (!payload) 10321da177e4SLinus Torvalds goto error; 103338bbca6bSDavid Howells } 10341da177e4SLinus Torvalds 1035ee009e4aSDavid Howells ret = copy_from_user_iovec(payload, payload_iov, ioc); 1036ee009e4aSDavid Howells if (ret < 0) 10371da177e4SLinus Torvalds goto error2; 10381da177e4SLinus Torvalds } 10391da177e4SLinus Torvalds 10403e30148cSDavid Howells /* find the destination keyring amongst those belonging to the 10413e30148cSDavid Howells * requesting task */ 10428bbf4976SDavid Howells ret = get_instantiation_keyring(ringid, rka, &dest_keyring); 10438bbf4976SDavid Howells if (ret < 0) 1044b5f545c8SDavid Howells goto error2; 10451da177e4SLinus Torvalds 10461da177e4SLinus Torvalds /* instantiate the key and link it into a keyring */ 10473e30148cSDavid Howells ret = key_instantiate_and_link(rka->target_key, payload, plen, 10488bbf4976SDavid Howells dest_keyring, instkey); 10491da177e4SLinus Torvalds 10508bbf4976SDavid Howells key_put(dest_keyring); 1051b5f545c8SDavid Howells 1052b5f545c8SDavid Howells /* discard the assumed authority if it's just been disabled by 1053b5f545c8SDavid Howells * instantiation of the key */ 1054d84f4f99SDavid Howells if (ret == 0) 1055d84f4f99SDavid Howells keyctl_change_reqkey_auth(NULL); 1056b5f545c8SDavid Howells 10571da177e4SLinus Torvalds error2: 105838bbca6bSDavid Howells if (!vm) 10591da177e4SLinus Torvalds kfree(payload); 106038bbca6bSDavid Howells else 106138bbca6bSDavid Howells vfree(payload); 10621da177e4SLinus Torvalds error: 10631da177e4SLinus Torvalds return ret; 1064a8b17ed0SDavid Howells } 10651da177e4SLinus Torvalds 10661da177e4SLinus Torvalds /* 1067ee009e4aSDavid Howells * Instantiate a key with the specified payload and link the key into the 1068ee009e4aSDavid Howells * destination keyring if one is given. 1069ee009e4aSDavid Howells * 1070ee009e4aSDavid Howells * The caller must have the appropriate instantiation permit set for this to 1071ee009e4aSDavid Howells * work (see keyctl_assume_authority). No other permissions are required. 1072ee009e4aSDavid Howells * 1073ee009e4aSDavid Howells * If successful, 0 will be returned. 1074ee009e4aSDavid Howells */ 1075ee009e4aSDavid Howells long keyctl_instantiate_key(key_serial_t id, 1076ee009e4aSDavid Howells const void __user *_payload, 1077ee009e4aSDavid Howells size_t plen, 1078ee009e4aSDavid Howells key_serial_t ringid) 1079ee009e4aSDavid Howells { 1080ee009e4aSDavid Howells if (_payload && plen) { 1081ee009e4aSDavid Howells struct iovec iov[1] = { 1082ee009e4aSDavid Howells [0].iov_base = (void __user *)_payload, 1083ee009e4aSDavid Howells [0].iov_len = plen 1084ee009e4aSDavid Howells }; 1085ee009e4aSDavid Howells 1086ee009e4aSDavid Howells return keyctl_instantiate_key_common(id, iov, 1, plen, ringid); 1087ee009e4aSDavid Howells } 1088ee009e4aSDavid Howells 1089ee009e4aSDavid Howells return keyctl_instantiate_key_common(id, NULL, 0, 0, ringid); 1090ee009e4aSDavid Howells } 1091ee009e4aSDavid Howells 1092ee009e4aSDavid Howells /* 1093ee009e4aSDavid Howells * Instantiate a key with the specified multipart payload and link the key into 1094ee009e4aSDavid Howells * the destination keyring if one is given. 1095ee009e4aSDavid Howells * 1096ee009e4aSDavid Howells * The caller must have the appropriate instantiation permit set for this to 1097ee009e4aSDavid Howells * work (see keyctl_assume_authority). No other permissions are required. 1098ee009e4aSDavid Howells * 1099ee009e4aSDavid Howells * If successful, 0 will be returned. 1100ee009e4aSDavid Howells */ 1101ee009e4aSDavid Howells long keyctl_instantiate_key_iov(key_serial_t id, 1102ee009e4aSDavid Howells const struct iovec __user *_payload_iov, 1103ee009e4aSDavid Howells unsigned ioc, 1104ee009e4aSDavid Howells key_serial_t ringid) 1105ee009e4aSDavid Howells { 1106ee009e4aSDavid Howells struct iovec iovstack[UIO_FASTIOV], *iov = iovstack; 1107ee009e4aSDavid Howells long ret; 1108ee009e4aSDavid Howells 1109ee009e4aSDavid Howells if (_payload_iov == 0 || ioc == 0) 1110ee009e4aSDavid Howells goto no_payload; 1111ee009e4aSDavid Howells 1112ee009e4aSDavid Howells ret = rw_copy_check_uvector(WRITE, _payload_iov, ioc, 1113*ac34ebb3SChristopher Yeoh ARRAY_SIZE(iovstack), iovstack, &iov); 1114ee009e4aSDavid Howells if (ret < 0) 1115ee009e4aSDavid Howells return ret; 1116ee009e4aSDavid Howells if (ret == 0) 1117ee009e4aSDavid Howells goto no_payload_free; 1118ee009e4aSDavid Howells 1119ee009e4aSDavid Howells ret = keyctl_instantiate_key_common(id, iov, ioc, ret, ringid); 1120ee009e4aSDavid Howells 1121ee009e4aSDavid Howells if (iov != iovstack) 1122ee009e4aSDavid Howells kfree(iov); 1123ee009e4aSDavid Howells return ret; 1124ee009e4aSDavid Howells 1125ee009e4aSDavid Howells no_payload_free: 1126ee009e4aSDavid Howells if (iov != iovstack) 1127ee009e4aSDavid Howells kfree(iov); 1128ee009e4aSDavid Howells no_payload: 1129ee009e4aSDavid Howells return keyctl_instantiate_key_common(id, NULL, 0, 0, ringid); 1130ee009e4aSDavid Howells } 1131ee009e4aSDavid Howells 1132ee009e4aSDavid Howells /* 1133973c9f4fSDavid Howells * Negatively instantiate the key with the given timeout (in seconds) and link 1134973c9f4fSDavid Howells * the key into the destination keyring if one is given. 1135973c9f4fSDavid Howells * 1136973c9f4fSDavid Howells * The caller must have the appropriate instantiation permit set for this to 1137973c9f4fSDavid Howells * work (see keyctl_assume_authority). No other permissions are required. 1138973c9f4fSDavid Howells * 1139973c9f4fSDavid Howells * The key and any links to the key will be automatically garbage collected 1140973c9f4fSDavid Howells * after the timeout expires. 1141973c9f4fSDavid Howells * 1142973c9f4fSDavid Howells * Negative keys are used to rate limit repeated request_key() calls by causing 1143973c9f4fSDavid Howells * them to return -ENOKEY until the negative key expires. 1144973c9f4fSDavid Howells * 1145973c9f4fSDavid Howells * If successful, 0 will be returned. 11461da177e4SLinus Torvalds */ 11471da177e4SLinus Torvalds long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid) 11481da177e4SLinus Torvalds { 1149fdd1b945SDavid Howells return keyctl_reject_key(id, timeout, ENOKEY, ringid); 1150fdd1b945SDavid Howells } 1151fdd1b945SDavid Howells 1152fdd1b945SDavid Howells /* 1153fdd1b945SDavid Howells * Negatively instantiate the key with the given timeout (in seconds) and error 1154fdd1b945SDavid Howells * code and link the key into the destination keyring if one is given. 1155fdd1b945SDavid Howells * 1156fdd1b945SDavid Howells * The caller must have the appropriate instantiation permit set for this to 1157fdd1b945SDavid Howells * work (see keyctl_assume_authority). No other permissions are required. 1158fdd1b945SDavid Howells * 1159fdd1b945SDavid Howells * The key and any links to the key will be automatically garbage collected 1160fdd1b945SDavid Howells * after the timeout expires. 1161fdd1b945SDavid Howells * 1162fdd1b945SDavid Howells * Negative keys are used to rate limit repeated request_key() calls by causing 1163fdd1b945SDavid Howells * them to return the specified error code until the negative key expires. 1164fdd1b945SDavid Howells * 1165fdd1b945SDavid Howells * If successful, 0 will be returned. 1166fdd1b945SDavid Howells */ 1167fdd1b945SDavid Howells long keyctl_reject_key(key_serial_t id, unsigned timeout, unsigned error, 1168fdd1b945SDavid Howells key_serial_t ringid) 1169fdd1b945SDavid Howells { 1170d84f4f99SDavid Howells const struct cred *cred = current_cred(); 11713e30148cSDavid Howells struct request_key_auth *rka; 11728bbf4976SDavid Howells struct key *instkey, *dest_keyring; 11731da177e4SLinus Torvalds long ret; 11741da177e4SLinus Torvalds 1175fdd1b945SDavid Howells kenter("%d,%u,%u,%d", id, timeout, error, ringid); 1176fdd1b945SDavid Howells 1177fdd1b945SDavid Howells /* must be a valid error code and mustn't be a kernel special */ 1178fdd1b945SDavid Howells if (error <= 0 || 1179fdd1b945SDavid Howells error >= MAX_ERRNO || 1180fdd1b945SDavid Howells error == ERESTARTSYS || 1181fdd1b945SDavid Howells error == ERESTARTNOINTR || 1182fdd1b945SDavid Howells error == ERESTARTNOHAND || 1183fdd1b945SDavid Howells error == ERESTART_RESTARTBLOCK) 1184fdd1b945SDavid Howells return -EINVAL; 1185d84f4f99SDavid Howells 1186b5f545c8SDavid Howells /* the appropriate instantiation authorisation key must have been 1187b5f545c8SDavid Howells * assumed before calling this */ 1188b5f545c8SDavid Howells ret = -EPERM; 1189d84f4f99SDavid Howells instkey = cred->request_key_auth; 1190b5f545c8SDavid Howells if (!instkey) 11911da177e4SLinus Torvalds goto error; 11921da177e4SLinus Torvalds 11933e30148cSDavid Howells rka = instkey->payload.data; 1194b5f545c8SDavid Howells if (rka->target_key->serial != id) 1195b5f545c8SDavid Howells goto error; 11963e30148cSDavid Howells 11971da177e4SLinus Torvalds /* find the destination keyring if present (which must also be 11981da177e4SLinus Torvalds * writable) */ 11998bbf4976SDavid Howells ret = get_instantiation_keyring(ringid, rka, &dest_keyring); 12008bbf4976SDavid Howells if (ret < 0) 1201b5f545c8SDavid Howells goto error; 12021da177e4SLinus Torvalds 12031da177e4SLinus Torvalds /* instantiate the key and link it into a keyring */ 1204fdd1b945SDavid Howells ret = key_reject_and_link(rka->target_key, timeout, error, 12058bbf4976SDavid Howells dest_keyring, instkey); 12061da177e4SLinus Torvalds 12078bbf4976SDavid Howells key_put(dest_keyring); 1208b5f545c8SDavid Howells 1209b5f545c8SDavid Howells /* discard the assumed authority if it's just been disabled by 1210b5f545c8SDavid Howells * instantiation of the key */ 1211d84f4f99SDavid Howells if (ret == 0) 1212d84f4f99SDavid Howells keyctl_change_reqkey_auth(NULL); 1213b5f545c8SDavid Howells 12141da177e4SLinus Torvalds error: 12151da177e4SLinus Torvalds return ret; 1216a8b17ed0SDavid Howells } 12171da177e4SLinus Torvalds 12181da177e4SLinus Torvalds /* 1219973c9f4fSDavid Howells * Read or set the default keyring in which request_key() will cache keys and 1220973c9f4fSDavid Howells * return the old setting. 1221973c9f4fSDavid Howells * 1222973c9f4fSDavid Howells * If a process keyring is specified then this will be created if it doesn't 1223973c9f4fSDavid Howells * yet exist. The old setting will be returned if successful. 12243e30148cSDavid Howells */ 12253e30148cSDavid Howells long keyctl_set_reqkey_keyring(int reqkey_defl) 12263e30148cSDavid Howells { 1227d84f4f99SDavid Howells struct cred *new; 1228d84f4f99SDavid Howells int ret, old_setting; 1229d84f4f99SDavid Howells 1230d84f4f99SDavid Howells old_setting = current_cred_xxx(jit_keyring); 1231d84f4f99SDavid Howells 1232d84f4f99SDavid Howells if (reqkey_defl == KEY_REQKEY_DEFL_NO_CHANGE) 1233d84f4f99SDavid Howells return old_setting; 1234d84f4f99SDavid Howells 1235d84f4f99SDavid Howells new = prepare_creds(); 1236d84f4f99SDavid Howells if (!new) 1237d84f4f99SDavid Howells return -ENOMEM; 12383e30148cSDavid Howells 12393e30148cSDavid Howells switch (reqkey_defl) { 12403e30148cSDavid Howells case KEY_REQKEY_DEFL_THREAD_KEYRING: 1241d84f4f99SDavid Howells ret = install_thread_keyring_to_cred(new); 12423e30148cSDavid Howells if (ret < 0) 1243d84f4f99SDavid Howells goto error; 12443e30148cSDavid Howells goto set; 12453e30148cSDavid Howells 12463e30148cSDavid Howells case KEY_REQKEY_DEFL_PROCESS_KEYRING: 1247d84f4f99SDavid Howells ret = install_process_keyring_to_cred(new); 1248d84f4f99SDavid Howells if (ret < 0) { 1249d84f4f99SDavid Howells if (ret != -EEXIST) 1250d84f4f99SDavid Howells goto error; 1251d84f4f99SDavid Howells ret = 0; 1252d84f4f99SDavid Howells } 1253d84f4f99SDavid Howells goto set; 12543e30148cSDavid Howells 12553e30148cSDavid Howells case KEY_REQKEY_DEFL_DEFAULT: 12563e30148cSDavid Howells case KEY_REQKEY_DEFL_SESSION_KEYRING: 12573e30148cSDavid Howells case KEY_REQKEY_DEFL_USER_KEYRING: 12583e30148cSDavid Howells case KEY_REQKEY_DEFL_USER_SESSION_KEYRING: 1259d84f4f99SDavid Howells case KEY_REQKEY_DEFL_REQUESTOR_KEYRING: 1260d84f4f99SDavid Howells goto set; 12613e30148cSDavid Howells 12623e30148cSDavid Howells case KEY_REQKEY_DEFL_NO_CHANGE: 12633e30148cSDavid Howells case KEY_REQKEY_DEFL_GROUP_KEYRING: 12643e30148cSDavid Howells default: 1265d84f4f99SDavid Howells ret = -EINVAL; 1266d84f4f99SDavid Howells goto error; 12673e30148cSDavid Howells } 12683e30148cSDavid Howells 1269d84f4f99SDavid Howells set: 1270d84f4f99SDavid Howells new->jit_keyring = reqkey_defl; 1271d84f4f99SDavid Howells commit_creds(new); 1272d84f4f99SDavid Howells return old_setting; 1273d84f4f99SDavid Howells error: 1274d84f4f99SDavid Howells abort_creds(new); 12754303ef19SDan Carpenter return ret; 1276a8b17ed0SDavid Howells } 1277d84f4f99SDavid Howells 12783e30148cSDavid Howells /* 1279973c9f4fSDavid Howells * Set or clear the timeout on a key. 1280973c9f4fSDavid Howells * 1281973c9f4fSDavid Howells * Either the key must grant the caller Setattr permission or else the caller 1282973c9f4fSDavid Howells * must hold an instantiation authorisation token for the key. 1283973c9f4fSDavid Howells * 1284973c9f4fSDavid Howells * The timeout is either 0 to clear the timeout, or a number of seconds from 1285973c9f4fSDavid Howells * the current time. The key and any links to the key will be automatically 1286973c9f4fSDavid Howells * garbage collected after the timeout expires. 1287973c9f4fSDavid Howells * 1288973c9f4fSDavid Howells * If successful, 0 is returned. 1289017679c4SDavid Howells */ 1290017679c4SDavid Howells long keyctl_set_timeout(key_serial_t id, unsigned timeout) 1291017679c4SDavid Howells { 12929156235bSDavid Howells struct key *key, *instkey; 1293017679c4SDavid Howells key_ref_t key_ref; 1294017679c4SDavid Howells long ret; 1295017679c4SDavid Howells 12965593122eSDavid Howells key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL, 12975593122eSDavid Howells KEY_SETATTR); 1298017679c4SDavid Howells if (IS_ERR(key_ref)) { 12999156235bSDavid Howells /* setting the timeout on a key under construction is permitted 13009156235bSDavid Howells * if we have the authorisation token handy */ 13019156235bSDavid Howells if (PTR_ERR(key_ref) == -EACCES) { 13029156235bSDavid Howells instkey = key_get_instantiation_authkey(id); 13039156235bSDavid Howells if (!IS_ERR(instkey)) { 13049156235bSDavid Howells key_put(instkey); 13059156235bSDavid Howells key_ref = lookup_user_key(id, 13069156235bSDavid Howells KEY_LOOKUP_PARTIAL, 13079156235bSDavid Howells 0); 13089156235bSDavid Howells if (!IS_ERR(key_ref)) 13099156235bSDavid Howells goto okay; 13109156235bSDavid Howells } 13119156235bSDavid Howells } 13129156235bSDavid Howells 1313017679c4SDavid Howells ret = PTR_ERR(key_ref); 1314017679c4SDavid Howells goto error; 1315017679c4SDavid Howells } 1316017679c4SDavid Howells 13179156235bSDavid Howells okay: 1318017679c4SDavid Howells key = key_ref_to_ptr(key_ref); 131959e6b9c1SBryan Schumaker key_set_timeout(key, timeout); 1320017679c4SDavid Howells key_put(key); 1321017679c4SDavid Howells 1322017679c4SDavid Howells ret = 0; 1323017679c4SDavid Howells error: 1324017679c4SDavid Howells return ret; 1325a8b17ed0SDavid Howells } 1326017679c4SDavid Howells 1327017679c4SDavid Howells /* 1328973c9f4fSDavid Howells * Assume (or clear) the authority to instantiate the specified key. 1329973c9f4fSDavid Howells * 1330973c9f4fSDavid Howells * This sets the authoritative token currently in force for key instantiation. 1331973c9f4fSDavid Howells * This must be done for a key to be instantiated. It has the effect of making 1332973c9f4fSDavid Howells * available all the keys from the caller of the request_key() that created a 1333973c9f4fSDavid Howells * key to request_key() calls made by the caller of this function. 1334973c9f4fSDavid Howells * 1335973c9f4fSDavid Howells * The caller must have the instantiation key in their process keyrings with a 1336973c9f4fSDavid Howells * Search permission grant available to the caller. 1337973c9f4fSDavid Howells * 1338973c9f4fSDavid Howells * If the ID given is 0, then the setting will be cleared and 0 returned. 1339973c9f4fSDavid Howells * 1340973c9f4fSDavid Howells * If the ID given has a matching an authorisation key, then that key will be 1341973c9f4fSDavid Howells * set and its ID will be returned. The authorisation key can be read to get 1342973c9f4fSDavid Howells * the callout information passed to request_key(). 1343b5f545c8SDavid Howells */ 1344b5f545c8SDavid Howells long keyctl_assume_authority(key_serial_t id) 1345b5f545c8SDavid Howells { 1346b5f545c8SDavid Howells struct key *authkey; 1347b5f545c8SDavid Howells long ret; 1348b5f545c8SDavid Howells 1349b5f545c8SDavid Howells /* special key IDs aren't permitted */ 1350b5f545c8SDavid Howells ret = -EINVAL; 1351b5f545c8SDavid Howells if (id < 0) 1352b5f545c8SDavid Howells goto error; 1353b5f545c8SDavid Howells 1354b5f545c8SDavid Howells /* we divest ourselves of authority if given an ID of 0 */ 1355b5f545c8SDavid Howells if (id == 0) { 1356d84f4f99SDavid Howells ret = keyctl_change_reqkey_auth(NULL); 1357b5f545c8SDavid Howells goto error; 1358b5f545c8SDavid Howells } 1359b5f545c8SDavid Howells 1360b5f545c8SDavid Howells /* attempt to assume the authority temporarily granted to us whilst we 1361b5f545c8SDavid Howells * instantiate the specified key 1362b5f545c8SDavid Howells * - the authorisation key must be in the current task's keyrings 1363b5f545c8SDavid Howells * somewhere 1364b5f545c8SDavid Howells */ 1365b5f545c8SDavid Howells authkey = key_get_instantiation_authkey(id); 1366b5f545c8SDavid Howells if (IS_ERR(authkey)) { 1367b5f545c8SDavid Howells ret = PTR_ERR(authkey); 1368b5f545c8SDavid Howells goto error; 1369b5f545c8SDavid Howells } 1370b5f545c8SDavid Howells 1371d84f4f99SDavid Howells ret = keyctl_change_reqkey_auth(authkey); 1372d84f4f99SDavid Howells if (ret < 0) 1373d84f4f99SDavid Howells goto error; 1374d84f4f99SDavid Howells key_put(authkey); 1375b5f545c8SDavid Howells 1376d84f4f99SDavid Howells ret = authkey->serial; 1377b5f545c8SDavid Howells error: 1378b5f545c8SDavid Howells return ret; 1379a8b17ed0SDavid Howells } 1380b5f545c8SDavid Howells 138170a5bb72SDavid Howells /* 1382973c9f4fSDavid Howells * Get a key's the LSM security label. 1383973c9f4fSDavid Howells * 1384973c9f4fSDavid Howells * The key must grant the caller View permission for this to work. 1385973c9f4fSDavid Howells * 1386973c9f4fSDavid Howells * If there's a buffer, then up to buflen bytes of data will be placed into it. 1387973c9f4fSDavid Howells * 1388973c9f4fSDavid Howells * If successful, the amount of information available will be returned, 1389973c9f4fSDavid Howells * irrespective of how much was copied (including the terminal NUL). 139070a5bb72SDavid Howells */ 139170a5bb72SDavid Howells long keyctl_get_security(key_serial_t keyid, 139270a5bb72SDavid Howells char __user *buffer, 139370a5bb72SDavid Howells size_t buflen) 139470a5bb72SDavid Howells { 139570a5bb72SDavid Howells struct key *key, *instkey; 139670a5bb72SDavid Howells key_ref_t key_ref; 139770a5bb72SDavid Howells char *context; 139870a5bb72SDavid Howells long ret; 139970a5bb72SDavid Howells 14005593122eSDavid Howells key_ref = lookup_user_key(keyid, KEY_LOOKUP_PARTIAL, KEY_VIEW); 140170a5bb72SDavid Howells if (IS_ERR(key_ref)) { 140270a5bb72SDavid Howells if (PTR_ERR(key_ref) != -EACCES) 140370a5bb72SDavid Howells return PTR_ERR(key_ref); 140470a5bb72SDavid Howells 140570a5bb72SDavid Howells /* viewing a key under construction is also permitted if we 140670a5bb72SDavid Howells * have the authorisation token handy */ 140770a5bb72SDavid Howells instkey = key_get_instantiation_authkey(keyid); 140870a5bb72SDavid Howells if (IS_ERR(instkey)) 1409fa1cc7b5SRoel Kluin return PTR_ERR(instkey); 141070a5bb72SDavid Howells key_put(instkey); 141170a5bb72SDavid Howells 14125593122eSDavid Howells key_ref = lookup_user_key(keyid, KEY_LOOKUP_PARTIAL, 0); 141370a5bb72SDavid Howells if (IS_ERR(key_ref)) 141470a5bb72SDavid Howells return PTR_ERR(key_ref); 141570a5bb72SDavid Howells } 141670a5bb72SDavid Howells 141770a5bb72SDavid Howells key = key_ref_to_ptr(key_ref); 141870a5bb72SDavid Howells ret = security_key_getsecurity(key, &context); 141970a5bb72SDavid Howells if (ret == 0) { 142070a5bb72SDavid Howells /* if no information was returned, give userspace an empty 142170a5bb72SDavid Howells * string */ 142270a5bb72SDavid Howells ret = 1; 142370a5bb72SDavid Howells if (buffer && buflen > 0 && 142470a5bb72SDavid Howells copy_to_user(buffer, "", 1) != 0) 142570a5bb72SDavid Howells ret = -EFAULT; 142670a5bb72SDavid Howells } else if (ret > 0) { 142770a5bb72SDavid Howells /* return as much data as there's room for */ 142870a5bb72SDavid Howells if (buffer && buflen > 0) { 142970a5bb72SDavid Howells if (buflen > ret) 143070a5bb72SDavid Howells buflen = ret; 143170a5bb72SDavid Howells 143270a5bb72SDavid Howells if (copy_to_user(buffer, context, buflen) != 0) 143370a5bb72SDavid Howells ret = -EFAULT; 143470a5bb72SDavid Howells } 143570a5bb72SDavid Howells 143670a5bb72SDavid Howells kfree(context); 143770a5bb72SDavid Howells } 143870a5bb72SDavid Howells 143970a5bb72SDavid Howells key_ref_put(key_ref); 144070a5bb72SDavid Howells return ret; 144170a5bb72SDavid Howells } 144270a5bb72SDavid Howells 1443ee18d64cSDavid Howells /* 1444973c9f4fSDavid Howells * Attempt to install the calling process's session keyring on the process's 1445973c9f4fSDavid Howells * parent process. 1446973c9f4fSDavid Howells * 1447973c9f4fSDavid Howells * The keyring must exist and must grant the caller LINK permission, and the 1448973c9f4fSDavid Howells * parent process must be single-threaded and must have the same effective 1449973c9f4fSDavid Howells * ownership as this process and mustn't be SUID/SGID. 1450973c9f4fSDavid Howells * 1451973c9f4fSDavid Howells * The keyring will be emplaced on the parent when it next resumes userspace. 1452973c9f4fSDavid Howells * 1453973c9f4fSDavid Howells * If successful, 0 will be returned. 1454ee18d64cSDavid Howells */ 1455ee18d64cSDavid Howells long keyctl_session_to_parent(void) 1456ee18d64cSDavid Howells { 1457a00ae4d2SGeert Uytterhoeven #ifdef TIF_NOTIFY_RESUME 1458ee18d64cSDavid Howells struct task_struct *me, *parent; 1459ee18d64cSDavid Howells const struct cred *mycred, *pcred; 1460ee18d64cSDavid Howells struct cred *cred, *oldcred; 1461ee18d64cSDavid Howells key_ref_t keyring_r; 1462ee18d64cSDavid Howells int ret; 1463ee18d64cSDavid Howells 1464ee18d64cSDavid Howells keyring_r = lookup_user_key(KEY_SPEC_SESSION_KEYRING, 0, KEY_LINK); 1465ee18d64cSDavid Howells if (IS_ERR(keyring_r)) 1466ee18d64cSDavid Howells return PTR_ERR(keyring_r); 1467ee18d64cSDavid Howells 1468ee18d64cSDavid Howells /* our parent is going to need a new cred struct, a new tgcred struct 1469ee18d64cSDavid Howells * and new security data, so we allocate them here to prevent ENOMEM in 1470ee18d64cSDavid Howells * our parent */ 1471ee18d64cSDavid Howells ret = -ENOMEM; 1472ee18d64cSDavid Howells cred = cred_alloc_blank(); 1473ee18d64cSDavid Howells if (!cred) 1474ee18d64cSDavid Howells goto error_keyring; 1475ee18d64cSDavid Howells 1476ee18d64cSDavid Howells cred->tgcred->session_keyring = key_ref_to_ptr(keyring_r); 1477ee18d64cSDavid Howells keyring_r = NULL; 1478ee18d64cSDavid Howells 1479ee18d64cSDavid Howells me = current; 14809d1ac65aSDavid Howells rcu_read_lock(); 1481ee18d64cSDavid Howells write_lock_irq(&tasklist_lock); 1482ee18d64cSDavid Howells 1483ee18d64cSDavid Howells parent = me->real_parent; 1484ee18d64cSDavid Howells ret = -EPERM; 1485ee18d64cSDavid Howells 1486ee18d64cSDavid Howells /* the parent mustn't be init and mustn't be a kernel thread */ 1487ee18d64cSDavid Howells if (parent->pid <= 1 || !parent->mm) 1488ee18d64cSDavid Howells goto not_permitted; 1489ee18d64cSDavid Howells 1490ee18d64cSDavid Howells /* the parent must be single threaded */ 1491dd98acf7SOleg Nesterov if (!thread_group_empty(parent)) 1492ee18d64cSDavid Howells goto not_permitted; 1493ee18d64cSDavid Howells 1494ee18d64cSDavid Howells /* the parent and the child must have different session keyrings or 1495ee18d64cSDavid Howells * there's no point */ 1496ee18d64cSDavid Howells mycred = current_cred(); 1497ee18d64cSDavid Howells pcred = __task_cred(parent); 1498ee18d64cSDavid Howells if (mycred == pcred || 1499ee18d64cSDavid Howells mycred->tgcred->session_keyring == pcred->tgcred->session_keyring) 1500ee18d64cSDavid Howells goto already_same; 1501ee18d64cSDavid Howells 1502ee18d64cSDavid Howells /* the parent must have the same effective ownership and mustn't be 1503ee18d64cSDavid Howells * SUID/SGID */ 1504ee18d64cSDavid Howells if (pcred->uid != mycred->euid || 1505ee18d64cSDavid Howells pcred->euid != mycred->euid || 1506ee18d64cSDavid Howells pcred->suid != mycred->euid || 1507ee18d64cSDavid Howells pcred->gid != mycred->egid || 1508ee18d64cSDavid Howells pcred->egid != mycred->egid || 1509ee18d64cSDavid Howells pcred->sgid != mycred->egid) 1510ee18d64cSDavid Howells goto not_permitted; 1511ee18d64cSDavid Howells 1512ee18d64cSDavid Howells /* the keyrings must have the same UID */ 15133d96406cSDavid Howells if ((pcred->tgcred->session_keyring && 15143d96406cSDavid Howells pcred->tgcred->session_keyring->uid != mycred->euid) || 1515ee18d64cSDavid Howells mycred->tgcred->session_keyring->uid != mycred->euid) 1516ee18d64cSDavid Howells goto not_permitted; 1517ee18d64cSDavid Howells 1518ee18d64cSDavid Howells /* if there's an already pending keyring replacement, then we replace 1519ee18d64cSDavid Howells * that */ 1520ee18d64cSDavid Howells oldcred = parent->replacement_session_keyring; 1521ee18d64cSDavid Howells 1522ee18d64cSDavid Howells /* the replacement session keyring is applied just prior to userspace 1523ee18d64cSDavid Howells * restarting */ 1524ee18d64cSDavid Howells parent->replacement_session_keyring = cred; 1525ee18d64cSDavid Howells cred = NULL; 1526ee18d64cSDavid Howells set_ti_thread_flag(task_thread_info(parent), TIF_NOTIFY_RESUME); 1527ee18d64cSDavid Howells 1528ee18d64cSDavid Howells write_unlock_irq(&tasklist_lock); 15299d1ac65aSDavid Howells rcu_read_unlock(); 1530ee18d64cSDavid Howells if (oldcred) 1531ee18d64cSDavid Howells put_cred(oldcred); 1532ee18d64cSDavid Howells return 0; 1533ee18d64cSDavid Howells 1534ee18d64cSDavid Howells already_same: 1535ee18d64cSDavid Howells ret = 0; 1536ee18d64cSDavid Howells not_permitted: 15375c84342aSMarc Dionne write_unlock_irq(&tasklist_lock); 15389d1ac65aSDavid Howells rcu_read_unlock(); 1539ee18d64cSDavid Howells put_cred(cred); 1540ee18d64cSDavid Howells return ret; 1541ee18d64cSDavid Howells 1542ee18d64cSDavid Howells error_keyring: 1543ee18d64cSDavid Howells key_ref_put(keyring_r); 1544ee18d64cSDavid Howells return ret; 1545a00ae4d2SGeert Uytterhoeven 1546a00ae4d2SGeert Uytterhoeven #else /* !TIF_NOTIFY_RESUME */ 1547a00ae4d2SGeert Uytterhoeven /* 1548a00ae4d2SGeert Uytterhoeven * To be removed when TIF_NOTIFY_RESUME has been implemented on 1549a00ae4d2SGeert Uytterhoeven * m68k/xtensa 1550a00ae4d2SGeert Uytterhoeven */ 1551a00ae4d2SGeert Uytterhoeven #warning TIF_NOTIFY_RESUME not implemented 1552a00ae4d2SGeert Uytterhoeven return -EOPNOTSUPP; 1553a00ae4d2SGeert Uytterhoeven #endif /* !TIF_NOTIFY_RESUME */ 1554ee18d64cSDavid Howells } 1555ee18d64cSDavid Howells 1556b5f545c8SDavid Howells /* 1557973c9f4fSDavid Howells * The key control system call 15581da177e4SLinus Torvalds */ 1559938bb9f5SHeiko Carstens SYSCALL_DEFINE5(keyctl, int, option, unsigned long, arg2, unsigned long, arg3, 1560938bb9f5SHeiko Carstens unsigned long, arg4, unsigned long, arg5) 15611da177e4SLinus Torvalds { 15621da177e4SLinus Torvalds switch (option) { 15631da177e4SLinus Torvalds case KEYCTL_GET_KEYRING_ID: 15641da177e4SLinus Torvalds return keyctl_get_keyring_ID((key_serial_t) arg2, 15651da177e4SLinus Torvalds (int) arg3); 15661da177e4SLinus Torvalds 15671da177e4SLinus Torvalds case KEYCTL_JOIN_SESSION_KEYRING: 15681da177e4SLinus Torvalds return keyctl_join_session_keyring((const char __user *) arg2); 15691da177e4SLinus Torvalds 15701da177e4SLinus Torvalds case KEYCTL_UPDATE: 15711da177e4SLinus Torvalds return keyctl_update_key((key_serial_t) arg2, 15721da177e4SLinus Torvalds (const void __user *) arg3, 15731da177e4SLinus Torvalds (size_t) arg4); 15741da177e4SLinus Torvalds 15751da177e4SLinus Torvalds case KEYCTL_REVOKE: 15761da177e4SLinus Torvalds return keyctl_revoke_key((key_serial_t) arg2); 15771da177e4SLinus Torvalds 15781da177e4SLinus Torvalds case KEYCTL_DESCRIBE: 15791da177e4SLinus Torvalds return keyctl_describe_key((key_serial_t) arg2, 15801da177e4SLinus Torvalds (char __user *) arg3, 15811da177e4SLinus Torvalds (unsigned) arg4); 15821da177e4SLinus Torvalds 15831da177e4SLinus Torvalds case KEYCTL_CLEAR: 15841da177e4SLinus Torvalds return keyctl_keyring_clear((key_serial_t) arg2); 15851da177e4SLinus Torvalds 15861da177e4SLinus Torvalds case KEYCTL_LINK: 15871da177e4SLinus Torvalds return keyctl_keyring_link((key_serial_t) arg2, 15881da177e4SLinus Torvalds (key_serial_t) arg3); 15891da177e4SLinus Torvalds 15901da177e4SLinus Torvalds case KEYCTL_UNLINK: 15911da177e4SLinus Torvalds return keyctl_keyring_unlink((key_serial_t) arg2, 15921da177e4SLinus Torvalds (key_serial_t) arg3); 15931da177e4SLinus Torvalds 15941da177e4SLinus Torvalds case KEYCTL_SEARCH: 15951da177e4SLinus Torvalds return keyctl_keyring_search((key_serial_t) arg2, 15961da177e4SLinus Torvalds (const char __user *) arg3, 15971da177e4SLinus Torvalds (const char __user *) arg4, 15981da177e4SLinus Torvalds (key_serial_t) arg5); 15991da177e4SLinus Torvalds 16001da177e4SLinus Torvalds case KEYCTL_READ: 16011da177e4SLinus Torvalds return keyctl_read_key((key_serial_t) arg2, 16021da177e4SLinus Torvalds (char __user *) arg3, 16031da177e4SLinus Torvalds (size_t) arg4); 16041da177e4SLinus Torvalds 16051da177e4SLinus Torvalds case KEYCTL_CHOWN: 16061da177e4SLinus Torvalds return keyctl_chown_key((key_serial_t) arg2, 16071da177e4SLinus Torvalds (uid_t) arg3, 16081da177e4SLinus Torvalds (gid_t) arg4); 16091da177e4SLinus Torvalds 16101da177e4SLinus Torvalds case KEYCTL_SETPERM: 16111da177e4SLinus Torvalds return keyctl_setperm_key((key_serial_t) arg2, 16121da177e4SLinus Torvalds (key_perm_t) arg3); 16131da177e4SLinus Torvalds 16141da177e4SLinus Torvalds case KEYCTL_INSTANTIATE: 16151da177e4SLinus Torvalds return keyctl_instantiate_key((key_serial_t) arg2, 16161da177e4SLinus Torvalds (const void __user *) arg3, 16171da177e4SLinus Torvalds (size_t) arg4, 16181da177e4SLinus Torvalds (key_serial_t) arg5); 16191da177e4SLinus Torvalds 16201da177e4SLinus Torvalds case KEYCTL_NEGATE: 16211da177e4SLinus Torvalds return keyctl_negate_key((key_serial_t) arg2, 16221da177e4SLinus Torvalds (unsigned) arg3, 16231da177e4SLinus Torvalds (key_serial_t) arg4); 16241da177e4SLinus Torvalds 16253e30148cSDavid Howells case KEYCTL_SET_REQKEY_KEYRING: 16263e30148cSDavid Howells return keyctl_set_reqkey_keyring(arg2); 16273e30148cSDavid Howells 1628017679c4SDavid Howells case KEYCTL_SET_TIMEOUT: 1629017679c4SDavid Howells return keyctl_set_timeout((key_serial_t) arg2, 1630017679c4SDavid Howells (unsigned) arg3); 1631017679c4SDavid Howells 1632b5f545c8SDavid Howells case KEYCTL_ASSUME_AUTHORITY: 1633b5f545c8SDavid Howells return keyctl_assume_authority((key_serial_t) arg2); 1634b5f545c8SDavid Howells 163570a5bb72SDavid Howells case KEYCTL_GET_SECURITY: 163670a5bb72SDavid Howells return keyctl_get_security((key_serial_t) arg2, 163790bd49abSJames Morris (char __user *) arg3, 163870a5bb72SDavid Howells (size_t) arg4); 163970a5bb72SDavid Howells 1640ee18d64cSDavid Howells case KEYCTL_SESSION_TO_PARENT: 1641ee18d64cSDavid Howells return keyctl_session_to_parent(); 1642ee18d64cSDavid Howells 1643fdd1b945SDavid Howells case KEYCTL_REJECT: 1644fdd1b945SDavid Howells return keyctl_reject_key((key_serial_t) arg2, 1645fdd1b945SDavid Howells (unsigned) arg3, 1646fdd1b945SDavid Howells (unsigned) arg4, 1647fdd1b945SDavid Howells (key_serial_t) arg5); 1648fdd1b945SDavid Howells 1649ee009e4aSDavid Howells case KEYCTL_INSTANTIATE_IOV: 1650ee009e4aSDavid Howells return keyctl_instantiate_key_iov( 1651ee009e4aSDavid Howells (key_serial_t) arg2, 1652ee009e4aSDavid Howells (const struct iovec __user *) arg3, 1653ee009e4aSDavid Howells (unsigned) arg4, 1654ee009e4aSDavid Howells (key_serial_t) arg5); 1655ee009e4aSDavid Howells 1656fd75815fSDavid Howells case KEYCTL_INVALIDATE: 1657fd75815fSDavid Howells return keyctl_invalidate_key((key_serial_t) arg2); 1658fd75815fSDavid Howells 16591da177e4SLinus Torvalds default: 16601da177e4SLinus Torvalds return -EOPNOTSUPP; 16611da177e4SLinus Torvalds } 1662a8b17ed0SDavid Howells } 1663