11da177e4SLinus Torvalds /* keyctl.c: userspace keyctl 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> 171da177e4SLinus Torvalds #include <linux/keyctl.h> 181da177e4SLinus Torvalds #include <linux/fs.h> 19c59ede7bSRandy.Dunlap #include <linux/capability.h> 200cb409d9SDavi Arnaut #include <linux/string.h> 211da177e4SLinus Torvalds #include <linux/err.h> 2238bbca6bSDavid Howells #include <linux/vmalloc.h> 231da177e4SLinus Torvalds #include <asm/uaccess.h> 241da177e4SLinus Torvalds #include "internal.h" 251da177e4SLinus Torvalds 260cb409d9SDavi Arnaut static int key_get_type_from_user(char *type, 270cb409d9SDavi Arnaut const char __user *_type, 280cb409d9SDavi Arnaut unsigned len) 290cb409d9SDavi Arnaut { 300cb409d9SDavi Arnaut int ret; 310cb409d9SDavi Arnaut 320cb409d9SDavi Arnaut ret = strncpy_from_user(type, _type, len); 330cb409d9SDavi Arnaut 340cb409d9SDavi Arnaut if (ret < 0) 350cb409d9SDavi Arnaut return -EFAULT; 360cb409d9SDavi Arnaut 370cb409d9SDavi Arnaut if (ret == 0 || ret >= len) 380cb409d9SDavi Arnaut return -EINVAL; 390cb409d9SDavi Arnaut 400cb409d9SDavi Arnaut if (type[0] == '.') 410cb409d9SDavi Arnaut return -EPERM; 420cb409d9SDavi Arnaut 430cb409d9SDavi Arnaut type[len - 1] = '\0'; 440cb409d9SDavi Arnaut 450cb409d9SDavi Arnaut return 0; 460cb409d9SDavi Arnaut } 470cb409d9SDavi Arnaut 481da177e4SLinus Torvalds /*****************************************************************************/ 491da177e4SLinus Torvalds /* 501da177e4SLinus Torvalds * extract the description of a new key from userspace and either add it as a 511da177e4SLinus Torvalds * new key to the specified keyring or update a matching key in that keyring 521da177e4SLinus Torvalds * - the keyring must be writable 531da177e4SLinus Torvalds * - returns the new key's serial number 541da177e4SLinus Torvalds * - implements add_key() 551da177e4SLinus Torvalds */ 561da177e4SLinus Torvalds asmlinkage long sys_add_key(const char __user *_type, 571da177e4SLinus Torvalds const char __user *_description, 581da177e4SLinus Torvalds const void __user *_payload, 591da177e4SLinus Torvalds size_t plen, 601da177e4SLinus Torvalds key_serial_t ringid) 611da177e4SLinus Torvalds { 62664cceb0SDavid Howells key_ref_t keyring_ref, key_ref; 631da177e4SLinus Torvalds char type[32], *description; 641da177e4SLinus Torvalds void *payload; 650cb409d9SDavi Arnaut long ret; 6638bbca6bSDavid Howells bool vm; 671da177e4SLinus Torvalds 681da177e4SLinus Torvalds ret = -EINVAL; 6938bbca6bSDavid Howells if (plen > 1024 * 1024 - 1) 701da177e4SLinus Torvalds goto error; 711da177e4SLinus Torvalds 721da177e4SLinus Torvalds /* draw all the data into kernel space */ 730cb409d9SDavi Arnaut ret = key_get_type_from_user(type, _type, sizeof(type)); 741da177e4SLinus Torvalds if (ret < 0) 751da177e4SLinus Torvalds goto error; 761da177e4SLinus Torvalds 770cb409d9SDavi Arnaut description = strndup_user(_description, PAGE_SIZE); 780cb409d9SDavi Arnaut if (IS_ERR(description)) { 790cb409d9SDavi Arnaut ret = PTR_ERR(description); 803e30148cSDavid Howells goto error; 810cb409d9SDavi Arnaut } 821da177e4SLinus Torvalds 831da177e4SLinus Torvalds /* pull the payload in if one was supplied */ 841da177e4SLinus Torvalds payload = NULL; 851da177e4SLinus Torvalds 8638bbca6bSDavid Howells vm = false; 871da177e4SLinus Torvalds if (_payload) { 881da177e4SLinus Torvalds ret = -ENOMEM; 891da177e4SLinus Torvalds payload = kmalloc(plen, GFP_KERNEL); 9038bbca6bSDavid Howells if (!payload) { 9138bbca6bSDavid Howells if (plen <= PAGE_SIZE) 9238bbca6bSDavid Howells goto error2; 9338bbca6bSDavid Howells vm = true; 9438bbca6bSDavid Howells payload = vmalloc(plen); 951da177e4SLinus Torvalds if (!payload) 961da177e4SLinus Torvalds goto error2; 9738bbca6bSDavid Howells } 981da177e4SLinus Torvalds 991da177e4SLinus Torvalds ret = -EFAULT; 1001da177e4SLinus Torvalds if (copy_from_user(payload, _payload, plen) != 0) 1011da177e4SLinus Torvalds goto error3; 1021da177e4SLinus Torvalds } 1031da177e4SLinus Torvalds 1041da177e4SLinus Torvalds /* find the target keyring (which must be writable) */ 105664cceb0SDavid Howells keyring_ref = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE); 106664cceb0SDavid Howells if (IS_ERR(keyring_ref)) { 107664cceb0SDavid Howells ret = PTR_ERR(keyring_ref); 1081da177e4SLinus Torvalds goto error3; 1091da177e4SLinus Torvalds } 1101da177e4SLinus Torvalds 1111da177e4SLinus Torvalds /* create or update the requested key and add it to the target 1121da177e4SLinus Torvalds * keyring */ 113664cceb0SDavid Howells key_ref = key_create_or_update(keyring_ref, type, description, 1147e047ef5SDavid Howells payload, plen, KEY_ALLOC_IN_QUOTA); 115664cceb0SDavid Howells if (!IS_ERR(key_ref)) { 116664cceb0SDavid Howells ret = key_ref_to_ptr(key_ref)->serial; 117664cceb0SDavid Howells key_ref_put(key_ref); 1181da177e4SLinus Torvalds } 1191da177e4SLinus Torvalds else { 120664cceb0SDavid Howells ret = PTR_ERR(key_ref); 1211da177e4SLinus Torvalds } 1221da177e4SLinus Torvalds 123664cceb0SDavid Howells key_ref_put(keyring_ref); 1241da177e4SLinus Torvalds error3: 12538bbca6bSDavid Howells if (!vm) 1261da177e4SLinus Torvalds kfree(payload); 12738bbca6bSDavid Howells else 12838bbca6bSDavid Howells vfree(payload); 1291da177e4SLinus Torvalds error2: 1301da177e4SLinus Torvalds kfree(description); 1311da177e4SLinus Torvalds error: 1321da177e4SLinus Torvalds return ret; 1331da177e4SLinus Torvalds 1341da177e4SLinus Torvalds } /* end sys_add_key() */ 1351da177e4SLinus Torvalds 1361da177e4SLinus Torvalds /*****************************************************************************/ 1371da177e4SLinus Torvalds /* 1381da177e4SLinus Torvalds * search the process keyrings for a matching key 1391da177e4SLinus Torvalds * - nested keyrings may also be searched if they have Search permission 1401da177e4SLinus Torvalds * - if a key is found, it will be attached to the destination keyring if 1411da177e4SLinus Torvalds * there's one specified 1421da177e4SLinus Torvalds * - /sbin/request-key will be invoked if _callout_info is non-NULL 1431da177e4SLinus Torvalds * - the _callout_info string will be passed to /sbin/request-key 1441da177e4SLinus Torvalds * - if the _callout_info string is empty, it will be rendered as "-" 1451da177e4SLinus Torvalds * - implements request_key() 1461da177e4SLinus Torvalds */ 1471da177e4SLinus Torvalds asmlinkage long sys_request_key(const char __user *_type, 1481da177e4SLinus Torvalds const char __user *_description, 1491da177e4SLinus Torvalds const char __user *_callout_info, 1501da177e4SLinus Torvalds key_serial_t destringid) 1511da177e4SLinus Torvalds { 1521da177e4SLinus Torvalds struct key_type *ktype; 153664cceb0SDavid Howells struct key *key; 154664cceb0SDavid Howells key_ref_t dest_ref; 155*4a38e122SDavid 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; 173*4a38e122SDavid 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 } 180*4a38e122SDavid 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) { 186664cceb0SDavid Howells dest_ref = lookup_user_key(NULL, destringid, 1, 0, KEY_WRITE); 187664cceb0SDavid Howells if (IS_ERR(dest_ref)) { 188664cceb0SDavid Howells ret = PTR_ERR(dest_ref); 1891da177e4SLinus Torvalds goto error3; 1901da177e4SLinus Torvalds } 1911da177e4SLinus Torvalds } 1921da177e4SLinus Torvalds 1931da177e4SLinus Torvalds /* find the key type */ 1941da177e4SLinus Torvalds ktype = key_type_lookup(type); 1951da177e4SLinus Torvalds if (IS_ERR(ktype)) { 1961da177e4SLinus Torvalds ret = PTR_ERR(ktype); 1971da177e4SLinus Torvalds goto error4; 1981da177e4SLinus Torvalds } 1991da177e4SLinus Torvalds 2001da177e4SLinus Torvalds /* do the search */ 201*4a38e122SDavid Howells key = request_key_and_link(ktype, description, callout_info, 202*4a38e122SDavid Howells callout_len, NULL, key_ref_to_ptr(dest_ref), 2037e047ef5SDavid Howells KEY_ALLOC_IN_QUOTA); 2041da177e4SLinus Torvalds if (IS_ERR(key)) { 2051da177e4SLinus Torvalds ret = PTR_ERR(key); 2061da177e4SLinus Torvalds goto error5; 2071da177e4SLinus Torvalds } 2081da177e4SLinus Torvalds 2091da177e4SLinus Torvalds ret = key->serial; 2101da177e4SLinus Torvalds 2111da177e4SLinus Torvalds key_put(key); 2121da177e4SLinus Torvalds error5: 2131da177e4SLinus Torvalds key_type_put(ktype); 2141da177e4SLinus Torvalds error4: 215664cceb0SDavid Howells key_ref_put(dest_ref); 2161da177e4SLinus Torvalds error3: 2171da177e4SLinus Torvalds kfree(callout_info); 2181da177e4SLinus Torvalds error2: 2191da177e4SLinus Torvalds kfree(description); 2201da177e4SLinus Torvalds error: 2211da177e4SLinus Torvalds return ret; 2221da177e4SLinus Torvalds 2231da177e4SLinus Torvalds } /* end sys_request_key() */ 2241da177e4SLinus Torvalds 2251da177e4SLinus Torvalds /*****************************************************************************/ 2261da177e4SLinus Torvalds /* 2271da177e4SLinus Torvalds * get the ID of the specified process keyring 2281da177e4SLinus Torvalds * - the keyring must have search permission to be found 2291da177e4SLinus Torvalds * - implements keyctl(KEYCTL_GET_KEYRING_ID) 2301da177e4SLinus Torvalds */ 2311da177e4SLinus Torvalds long keyctl_get_keyring_ID(key_serial_t id, int create) 2321da177e4SLinus Torvalds { 233664cceb0SDavid Howells key_ref_t key_ref; 2341da177e4SLinus Torvalds long ret; 2351da177e4SLinus Torvalds 236664cceb0SDavid Howells key_ref = lookup_user_key(NULL, id, create, 0, KEY_SEARCH); 237664cceb0SDavid Howells if (IS_ERR(key_ref)) { 238664cceb0SDavid Howells ret = PTR_ERR(key_ref); 2391da177e4SLinus Torvalds goto error; 2401da177e4SLinus Torvalds } 2411da177e4SLinus Torvalds 242664cceb0SDavid Howells ret = key_ref_to_ptr(key_ref)->serial; 243664cceb0SDavid Howells key_ref_put(key_ref); 2441da177e4SLinus Torvalds error: 2451da177e4SLinus Torvalds return ret; 2461da177e4SLinus Torvalds 2471da177e4SLinus Torvalds } /* end keyctl_get_keyring_ID() */ 2481da177e4SLinus Torvalds 2491da177e4SLinus Torvalds /*****************************************************************************/ 2501da177e4SLinus Torvalds /* 2511da177e4SLinus Torvalds * join the session keyring 2521da177e4SLinus Torvalds * - implements keyctl(KEYCTL_JOIN_SESSION_KEYRING) 2531da177e4SLinus Torvalds */ 2541da177e4SLinus Torvalds long keyctl_join_session_keyring(const char __user *_name) 2551da177e4SLinus Torvalds { 2561da177e4SLinus Torvalds char *name; 2570cb409d9SDavi Arnaut long ret; 2581da177e4SLinus Torvalds 2591da177e4SLinus Torvalds /* fetch the name from userspace */ 2601da177e4SLinus Torvalds name = NULL; 2611da177e4SLinus Torvalds if (_name) { 2620cb409d9SDavi Arnaut name = strndup_user(_name, PAGE_SIZE); 2630cb409d9SDavi Arnaut if (IS_ERR(name)) { 2640cb409d9SDavi Arnaut ret = PTR_ERR(name); 2651da177e4SLinus Torvalds goto error; 2660cb409d9SDavi Arnaut } 2671da177e4SLinus Torvalds } 2681da177e4SLinus Torvalds 2691da177e4SLinus Torvalds /* join the session */ 2701da177e4SLinus Torvalds ret = join_session_keyring(name); 2711da177e4SLinus Torvalds 2721da177e4SLinus Torvalds error: 2731da177e4SLinus Torvalds return ret; 2741da177e4SLinus Torvalds 2751da177e4SLinus Torvalds } /* end keyctl_join_session_keyring() */ 2761da177e4SLinus Torvalds 2771da177e4SLinus Torvalds /*****************************************************************************/ 2781da177e4SLinus Torvalds /* 2791da177e4SLinus Torvalds * update a key's data payload 2801da177e4SLinus Torvalds * - the key must be writable 2811da177e4SLinus Torvalds * - implements keyctl(KEYCTL_UPDATE) 2821da177e4SLinus Torvalds */ 2831da177e4SLinus Torvalds long keyctl_update_key(key_serial_t id, 2841da177e4SLinus Torvalds const void __user *_payload, 2851da177e4SLinus Torvalds size_t plen) 2861da177e4SLinus Torvalds { 287664cceb0SDavid Howells key_ref_t key_ref; 2881da177e4SLinus Torvalds void *payload; 2891da177e4SLinus Torvalds long ret; 2901da177e4SLinus Torvalds 2911da177e4SLinus Torvalds ret = -EINVAL; 2921da177e4SLinus Torvalds if (plen > PAGE_SIZE) 2931da177e4SLinus Torvalds goto error; 2941da177e4SLinus Torvalds 2951da177e4SLinus Torvalds /* pull the payload in if one was supplied */ 2961da177e4SLinus Torvalds payload = NULL; 2971da177e4SLinus Torvalds if (_payload) { 2981da177e4SLinus Torvalds ret = -ENOMEM; 2991da177e4SLinus Torvalds payload = kmalloc(plen, GFP_KERNEL); 3001da177e4SLinus Torvalds if (!payload) 3011da177e4SLinus Torvalds goto error; 3021da177e4SLinus Torvalds 3031da177e4SLinus Torvalds ret = -EFAULT; 3041da177e4SLinus Torvalds if (copy_from_user(payload, _payload, plen) != 0) 3051da177e4SLinus Torvalds goto error2; 3061da177e4SLinus Torvalds } 3071da177e4SLinus Torvalds 3081da177e4SLinus Torvalds /* find the target key (which must be writable) */ 309664cceb0SDavid Howells key_ref = lookup_user_key(NULL, id, 0, 0, KEY_WRITE); 310664cceb0SDavid Howells if (IS_ERR(key_ref)) { 311664cceb0SDavid Howells ret = PTR_ERR(key_ref); 3121da177e4SLinus Torvalds goto error2; 3131da177e4SLinus Torvalds } 3141da177e4SLinus Torvalds 3151da177e4SLinus Torvalds /* update the key */ 316664cceb0SDavid Howells ret = key_update(key_ref, payload, plen); 3171da177e4SLinus Torvalds 318664cceb0SDavid Howells key_ref_put(key_ref); 3191da177e4SLinus Torvalds error2: 3201da177e4SLinus Torvalds kfree(payload); 3211da177e4SLinus Torvalds error: 3221da177e4SLinus Torvalds return ret; 3231da177e4SLinus Torvalds 3241da177e4SLinus Torvalds } /* end keyctl_update_key() */ 3251da177e4SLinus Torvalds 3261da177e4SLinus Torvalds /*****************************************************************************/ 3271da177e4SLinus Torvalds /* 3281da177e4SLinus Torvalds * revoke a key 3291da177e4SLinus Torvalds * - the key must be writable 3301da177e4SLinus Torvalds * - implements keyctl(KEYCTL_REVOKE) 3311da177e4SLinus Torvalds */ 3321da177e4SLinus Torvalds long keyctl_revoke_key(key_serial_t id) 3331da177e4SLinus Torvalds { 334664cceb0SDavid Howells key_ref_t key_ref; 3351da177e4SLinus Torvalds long ret; 3361da177e4SLinus Torvalds 337664cceb0SDavid Howells key_ref = lookup_user_key(NULL, id, 0, 0, KEY_WRITE); 338664cceb0SDavid Howells if (IS_ERR(key_ref)) { 339664cceb0SDavid Howells ret = PTR_ERR(key_ref); 3401da177e4SLinus Torvalds goto error; 3411da177e4SLinus Torvalds } 3421da177e4SLinus Torvalds 343664cceb0SDavid Howells key_revoke(key_ref_to_ptr(key_ref)); 3441da177e4SLinus Torvalds ret = 0; 3451da177e4SLinus Torvalds 346664cceb0SDavid Howells key_ref_put(key_ref); 3471da177e4SLinus Torvalds error: 3481260f801SDavid Howells return ret; 3491da177e4SLinus Torvalds 3501da177e4SLinus Torvalds } /* end keyctl_revoke_key() */ 3511da177e4SLinus Torvalds 3521da177e4SLinus Torvalds /*****************************************************************************/ 3531da177e4SLinus Torvalds /* 3541da177e4SLinus Torvalds * clear the specified process keyring 3551da177e4SLinus Torvalds * - the keyring must be writable 3561da177e4SLinus Torvalds * - implements keyctl(KEYCTL_CLEAR) 3571da177e4SLinus Torvalds */ 3581da177e4SLinus Torvalds long keyctl_keyring_clear(key_serial_t ringid) 3591da177e4SLinus Torvalds { 360664cceb0SDavid Howells key_ref_t keyring_ref; 3611da177e4SLinus Torvalds long ret; 3621da177e4SLinus Torvalds 363664cceb0SDavid Howells keyring_ref = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE); 364664cceb0SDavid Howells if (IS_ERR(keyring_ref)) { 365664cceb0SDavid Howells ret = PTR_ERR(keyring_ref); 3661da177e4SLinus Torvalds goto error; 3671da177e4SLinus Torvalds } 3681da177e4SLinus Torvalds 369664cceb0SDavid Howells ret = keyring_clear(key_ref_to_ptr(keyring_ref)); 3701da177e4SLinus Torvalds 371664cceb0SDavid Howells key_ref_put(keyring_ref); 3721da177e4SLinus Torvalds error: 3731da177e4SLinus Torvalds return ret; 3741da177e4SLinus Torvalds 3751da177e4SLinus Torvalds } /* end keyctl_keyring_clear() */ 3761da177e4SLinus Torvalds 3771da177e4SLinus Torvalds /*****************************************************************************/ 3781da177e4SLinus Torvalds /* 3791da177e4SLinus Torvalds * link a key into a keyring 3801da177e4SLinus Torvalds * - the keyring must be writable 3811da177e4SLinus Torvalds * - the key must be linkable 3821da177e4SLinus Torvalds * - implements keyctl(KEYCTL_LINK) 3831da177e4SLinus Torvalds */ 3841da177e4SLinus Torvalds long keyctl_keyring_link(key_serial_t id, key_serial_t ringid) 3851da177e4SLinus Torvalds { 386664cceb0SDavid Howells key_ref_t keyring_ref, key_ref; 3871da177e4SLinus Torvalds long ret; 3881da177e4SLinus Torvalds 389664cceb0SDavid Howells keyring_ref = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE); 390664cceb0SDavid Howells if (IS_ERR(keyring_ref)) { 391664cceb0SDavid Howells ret = PTR_ERR(keyring_ref); 3921da177e4SLinus Torvalds goto error; 3931da177e4SLinus Torvalds } 3941da177e4SLinus Torvalds 395664cceb0SDavid Howells key_ref = lookup_user_key(NULL, id, 1, 0, KEY_LINK); 396664cceb0SDavid Howells if (IS_ERR(key_ref)) { 397664cceb0SDavid Howells ret = PTR_ERR(key_ref); 3981da177e4SLinus Torvalds goto error2; 3991da177e4SLinus Torvalds } 4001da177e4SLinus Torvalds 401664cceb0SDavid Howells ret = key_link(key_ref_to_ptr(keyring_ref), key_ref_to_ptr(key_ref)); 4021da177e4SLinus Torvalds 403664cceb0SDavid Howells key_ref_put(key_ref); 4041da177e4SLinus Torvalds error2: 405664cceb0SDavid Howells key_ref_put(keyring_ref); 4061da177e4SLinus Torvalds error: 4071da177e4SLinus Torvalds return ret; 4081da177e4SLinus Torvalds 4091da177e4SLinus Torvalds } /* end keyctl_keyring_link() */ 4101da177e4SLinus Torvalds 4111da177e4SLinus Torvalds /*****************************************************************************/ 4121da177e4SLinus Torvalds /* 4131da177e4SLinus Torvalds * unlink the first attachment of a key from a keyring 4141da177e4SLinus Torvalds * - the keyring must be writable 4151da177e4SLinus Torvalds * - we don't need any permissions on the key 4161da177e4SLinus Torvalds * - implements keyctl(KEYCTL_UNLINK) 4171da177e4SLinus Torvalds */ 4181da177e4SLinus Torvalds long keyctl_keyring_unlink(key_serial_t id, key_serial_t ringid) 4191da177e4SLinus Torvalds { 420664cceb0SDavid Howells key_ref_t keyring_ref, key_ref; 4211da177e4SLinus Torvalds long ret; 4221da177e4SLinus Torvalds 423664cceb0SDavid Howells keyring_ref = lookup_user_key(NULL, ringid, 0, 0, KEY_WRITE); 424664cceb0SDavid Howells if (IS_ERR(keyring_ref)) { 425664cceb0SDavid Howells ret = PTR_ERR(keyring_ref); 4261da177e4SLinus Torvalds goto error; 4271da177e4SLinus Torvalds } 4281da177e4SLinus Torvalds 429664cceb0SDavid Howells key_ref = lookup_user_key(NULL, id, 0, 0, 0); 430664cceb0SDavid Howells if (IS_ERR(key_ref)) { 431664cceb0SDavid Howells ret = PTR_ERR(key_ref); 4321da177e4SLinus Torvalds goto error2; 4331da177e4SLinus Torvalds } 4341da177e4SLinus Torvalds 435664cceb0SDavid Howells ret = key_unlink(key_ref_to_ptr(keyring_ref), key_ref_to_ptr(key_ref)); 4361da177e4SLinus Torvalds 437664cceb0SDavid Howells key_ref_put(key_ref); 4381da177e4SLinus Torvalds error2: 439664cceb0SDavid Howells key_ref_put(keyring_ref); 4401da177e4SLinus Torvalds error: 4411da177e4SLinus Torvalds return ret; 4421da177e4SLinus Torvalds 4431da177e4SLinus Torvalds } /* end keyctl_keyring_unlink() */ 4441da177e4SLinus Torvalds 4451da177e4SLinus Torvalds /*****************************************************************************/ 4461da177e4SLinus Torvalds /* 4471da177e4SLinus Torvalds * describe a user key 4481da177e4SLinus Torvalds * - the key must have view permission 4491da177e4SLinus Torvalds * - if there's a buffer, we place up to buflen bytes of data into it 4501da177e4SLinus Torvalds * - unless there's an error, we return the amount of description available, 4511da177e4SLinus Torvalds * irrespective of how much we may have copied 4521da177e4SLinus Torvalds * - the description is formatted thus: 4531da177e4SLinus Torvalds * type;uid;gid;perm;description<NUL> 4541da177e4SLinus Torvalds * - implements keyctl(KEYCTL_DESCRIBE) 4551da177e4SLinus Torvalds */ 4561da177e4SLinus Torvalds long keyctl_describe_key(key_serial_t keyid, 4571da177e4SLinus Torvalds char __user *buffer, 4581da177e4SLinus Torvalds size_t buflen) 4591da177e4SLinus Torvalds { 4603e30148cSDavid Howells struct key *key, *instkey; 461664cceb0SDavid Howells key_ref_t key_ref; 4621da177e4SLinus Torvalds char *tmpbuf; 4631da177e4SLinus Torvalds long ret; 4641da177e4SLinus Torvalds 465664cceb0SDavid Howells key_ref = lookup_user_key(NULL, keyid, 0, 1, KEY_VIEW); 466664cceb0SDavid Howells if (IS_ERR(key_ref)) { 4673e30148cSDavid Howells /* viewing a key under construction is permitted if we have the 4683e30148cSDavid Howells * authorisation token handy */ 469664cceb0SDavid Howells if (PTR_ERR(key_ref) == -EACCES) { 4703e30148cSDavid Howells instkey = key_get_instantiation_authkey(keyid); 4713e30148cSDavid Howells if (!IS_ERR(instkey)) { 4723e30148cSDavid Howells key_put(instkey); 473664cceb0SDavid Howells key_ref = lookup_user_key(NULL, keyid, 474664cceb0SDavid Howells 0, 1, 0); 475664cceb0SDavid Howells if (!IS_ERR(key_ref)) 4763e30148cSDavid Howells goto okay; 4773e30148cSDavid Howells } 4783e30148cSDavid Howells } 4793e30148cSDavid Howells 480664cceb0SDavid Howells ret = PTR_ERR(key_ref); 4811da177e4SLinus Torvalds goto error; 4821da177e4SLinus Torvalds } 4831da177e4SLinus Torvalds 4843e30148cSDavid Howells okay: 4851da177e4SLinus Torvalds /* calculate how much description we're going to return */ 4861da177e4SLinus Torvalds ret = -ENOMEM; 4871da177e4SLinus Torvalds tmpbuf = kmalloc(PAGE_SIZE, GFP_KERNEL); 4881da177e4SLinus Torvalds if (!tmpbuf) 4891da177e4SLinus Torvalds goto error2; 4901da177e4SLinus Torvalds 491664cceb0SDavid Howells key = key_ref_to_ptr(key_ref); 492664cceb0SDavid Howells 4931da177e4SLinus Torvalds ret = snprintf(tmpbuf, PAGE_SIZE - 1, 494664cceb0SDavid Howells "%s;%d;%d;%08x;%s", 495664cceb0SDavid Howells key_ref_to_ptr(key_ref)->type->name, 496664cceb0SDavid Howells key_ref_to_ptr(key_ref)->uid, 497664cceb0SDavid Howells key_ref_to_ptr(key_ref)->gid, 498664cceb0SDavid Howells key_ref_to_ptr(key_ref)->perm, 499664cceb0SDavid Howells key_ref_to_ptr(key_ref)->description ? 500664cceb0SDavid Howells key_ref_to_ptr(key_ref)->description : "" 5011da177e4SLinus Torvalds ); 5021da177e4SLinus Torvalds 5031da177e4SLinus Torvalds /* include a NUL char at the end of the data */ 5041da177e4SLinus Torvalds if (ret > PAGE_SIZE - 1) 5051da177e4SLinus Torvalds ret = PAGE_SIZE - 1; 5061da177e4SLinus Torvalds tmpbuf[ret] = 0; 5071da177e4SLinus Torvalds ret++; 5081da177e4SLinus Torvalds 5091da177e4SLinus Torvalds /* consider returning the data */ 5101da177e4SLinus Torvalds if (buffer && buflen > 0) { 5111da177e4SLinus Torvalds if (buflen > ret) 5121da177e4SLinus Torvalds buflen = ret; 5131da177e4SLinus Torvalds 5141da177e4SLinus Torvalds if (copy_to_user(buffer, tmpbuf, buflen) != 0) 5151da177e4SLinus Torvalds ret = -EFAULT; 5161da177e4SLinus Torvalds } 5171da177e4SLinus Torvalds 5181da177e4SLinus Torvalds kfree(tmpbuf); 5191da177e4SLinus Torvalds error2: 520664cceb0SDavid Howells key_ref_put(key_ref); 5211da177e4SLinus Torvalds error: 5221da177e4SLinus Torvalds return ret; 5231da177e4SLinus Torvalds 5241da177e4SLinus Torvalds } /* end keyctl_describe_key() */ 5251da177e4SLinus Torvalds 5261da177e4SLinus Torvalds /*****************************************************************************/ 5271da177e4SLinus Torvalds /* 5281da177e4SLinus Torvalds * search the specified keyring for a matching key 5291da177e4SLinus Torvalds * - the start keyring must be searchable 5301da177e4SLinus Torvalds * - nested keyrings may also be searched if they are searchable 5311da177e4SLinus Torvalds * - only keys with search permission may be found 5321da177e4SLinus Torvalds * - if a key is found, it will be attached to the destination keyring if 5331da177e4SLinus Torvalds * there's one specified 5341da177e4SLinus Torvalds * - implements keyctl(KEYCTL_SEARCH) 5351da177e4SLinus Torvalds */ 5361da177e4SLinus Torvalds long keyctl_keyring_search(key_serial_t ringid, 5371da177e4SLinus Torvalds const char __user *_type, 5381da177e4SLinus Torvalds const char __user *_description, 5391da177e4SLinus Torvalds key_serial_t destringid) 5401da177e4SLinus Torvalds { 5411da177e4SLinus Torvalds struct key_type *ktype; 542664cceb0SDavid Howells key_ref_t keyring_ref, key_ref, dest_ref; 5431da177e4SLinus Torvalds char type[32], *description; 5440cb409d9SDavi Arnaut long ret; 5451da177e4SLinus Torvalds 5461da177e4SLinus Torvalds /* pull the type and description into kernel space */ 5470cb409d9SDavi Arnaut ret = key_get_type_from_user(type, _type, sizeof(type)); 5481da177e4SLinus Torvalds if (ret < 0) 5491da177e4SLinus Torvalds goto error; 5501da177e4SLinus Torvalds 5510cb409d9SDavi Arnaut description = strndup_user(_description, PAGE_SIZE); 5520cb409d9SDavi Arnaut if (IS_ERR(description)) { 5530cb409d9SDavi Arnaut ret = PTR_ERR(description); 5541da177e4SLinus Torvalds goto error; 5550cb409d9SDavi Arnaut } 5561da177e4SLinus Torvalds 5571da177e4SLinus Torvalds /* get the keyring at which to begin the search */ 558664cceb0SDavid Howells keyring_ref = lookup_user_key(NULL, ringid, 0, 0, KEY_SEARCH); 559664cceb0SDavid Howells if (IS_ERR(keyring_ref)) { 560664cceb0SDavid Howells ret = PTR_ERR(keyring_ref); 5611da177e4SLinus Torvalds goto error2; 5621da177e4SLinus Torvalds } 5631da177e4SLinus Torvalds 5641da177e4SLinus Torvalds /* get the destination keyring if specified */ 565664cceb0SDavid Howells dest_ref = NULL; 5661da177e4SLinus Torvalds if (destringid) { 567664cceb0SDavid Howells dest_ref = lookup_user_key(NULL, destringid, 1, 0, KEY_WRITE); 568664cceb0SDavid Howells if (IS_ERR(dest_ref)) { 569664cceb0SDavid Howells ret = PTR_ERR(dest_ref); 5701da177e4SLinus Torvalds goto error3; 5711da177e4SLinus Torvalds } 5721da177e4SLinus Torvalds } 5731da177e4SLinus Torvalds 5741da177e4SLinus Torvalds /* find the key type */ 5751da177e4SLinus Torvalds ktype = key_type_lookup(type); 5761da177e4SLinus Torvalds if (IS_ERR(ktype)) { 5771da177e4SLinus Torvalds ret = PTR_ERR(ktype); 5781da177e4SLinus Torvalds goto error4; 5791da177e4SLinus Torvalds } 5801da177e4SLinus Torvalds 5811da177e4SLinus Torvalds /* do the search */ 582664cceb0SDavid Howells key_ref = keyring_search(keyring_ref, ktype, description); 583664cceb0SDavid Howells if (IS_ERR(key_ref)) { 584664cceb0SDavid Howells ret = PTR_ERR(key_ref); 5851da177e4SLinus Torvalds 5861da177e4SLinus Torvalds /* treat lack or presence of a negative key the same */ 5871da177e4SLinus Torvalds if (ret == -EAGAIN) 5881da177e4SLinus Torvalds ret = -ENOKEY; 5891da177e4SLinus Torvalds goto error5; 5901da177e4SLinus Torvalds } 5911da177e4SLinus Torvalds 5921da177e4SLinus Torvalds /* link the resulting key to the destination keyring if we can */ 593664cceb0SDavid Howells if (dest_ref) { 59429db9190SDavid Howells ret = key_permission(key_ref, KEY_LINK); 59529db9190SDavid Howells if (ret < 0) 5961da177e4SLinus Torvalds goto error6; 5971da177e4SLinus Torvalds 598664cceb0SDavid Howells ret = key_link(key_ref_to_ptr(dest_ref), key_ref_to_ptr(key_ref)); 5991da177e4SLinus Torvalds if (ret < 0) 6001da177e4SLinus Torvalds goto error6; 6011da177e4SLinus Torvalds } 6021da177e4SLinus Torvalds 603664cceb0SDavid Howells ret = key_ref_to_ptr(key_ref)->serial; 6041da177e4SLinus Torvalds 6051da177e4SLinus Torvalds error6: 606664cceb0SDavid Howells key_ref_put(key_ref); 6071da177e4SLinus Torvalds error5: 6081da177e4SLinus Torvalds key_type_put(ktype); 6091da177e4SLinus Torvalds error4: 610664cceb0SDavid Howells key_ref_put(dest_ref); 6111da177e4SLinus Torvalds error3: 612664cceb0SDavid Howells key_ref_put(keyring_ref); 6131da177e4SLinus Torvalds error2: 6141da177e4SLinus Torvalds kfree(description); 6151da177e4SLinus Torvalds error: 6161da177e4SLinus Torvalds return ret; 6171da177e4SLinus Torvalds 6181da177e4SLinus Torvalds } /* end keyctl_keyring_search() */ 6191da177e4SLinus Torvalds 6201da177e4SLinus Torvalds /*****************************************************************************/ 6211da177e4SLinus Torvalds /* 6221da177e4SLinus Torvalds * read a user key's payload 6231da177e4SLinus Torvalds * - the keyring must be readable or the key must be searchable from the 6241da177e4SLinus Torvalds * process's keyrings 6251da177e4SLinus Torvalds * - if there's a buffer, we place up to buflen bytes of data into it 6261da177e4SLinus Torvalds * - unless there's an error, we return the amount of data in the key, 6271da177e4SLinus Torvalds * irrespective of how much we may have copied 6281da177e4SLinus Torvalds * - implements keyctl(KEYCTL_READ) 6291da177e4SLinus Torvalds */ 6301da177e4SLinus Torvalds long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen) 6311da177e4SLinus Torvalds { 632664cceb0SDavid Howells struct key *key; 633664cceb0SDavid Howells key_ref_t key_ref; 6341da177e4SLinus Torvalds long ret; 6351da177e4SLinus Torvalds 6361da177e4SLinus Torvalds /* find the key first */ 637664cceb0SDavid Howells key_ref = lookup_user_key(NULL, keyid, 0, 0, 0); 638664cceb0SDavid Howells if (IS_ERR(key_ref)) { 639664cceb0SDavid Howells ret = -ENOKEY; 640664cceb0SDavid Howells goto error; 641664cceb0SDavid Howells } 642664cceb0SDavid Howells 643664cceb0SDavid Howells key = key_ref_to_ptr(key_ref); 644664cceb0SDavid Howells 6451da177e4SLinus Torvalds /* see if we can read it directly */ 64629db9190SDavid Howells ret = key_permission(key_ref, KEY_READ); 64729db9190SDavid Howells if (ret == 0) 6481da177e4SLinus Torvalds goto can_read_key; 64929db9190SDavid Howells if (ret != -EACCES) 65029db9190SDavid Howells goto error; 6511da177e4SLinus Torvalds 652664cceb0SDavid Howells /* we can't; see if it's searchable from this process's keyrings 6533e30148cSDavid Howells * - we automatically take account of the fact that it may be 6543e30148cSDavid Howells * dangling off an instantiation key 6553e30148cSDavid Howells */ 656664cceb0SDavid Howells if (!is_key_possessed(key_ref)) { 6571260f801SDavid Howells ret = -EACCES; 6581da177e4SLinus Torvalds goto error2; 6591da177e4SLinus Torvalds } 6601da177e4SLinus Torvalds 6611da177e4SLinus Torvalds /* the key is probably readable - now try to read it */ 6621da177e4SLinus Torvalds can_read_key: 6631da177e4SLinus Torvalds ret = key_validate(key); 6641da177e4SLinus Torvalds if (ret == 0) { 6651da177e4SLinus Torvalds ret = -EOPNOTSUPP; 6661da177e4SLinus Torvalds if (key->type->read) { 6671da177e4SLinus Torvalds /* read the data with the semaphore held (since we 6681da177e4SLinus Torvalds * might sleep) */ 6691da177e4SLinus Torvalds down_read(&key->sem); 6701da177e4SLinus Torvalds ret = key->type->read(key, buffer, buflen); 6711da177e4SLinus Torvalds up_read(&key->sem); 6721da177e4SLinus Torvalds } 6731da177e4SLinus Torvalds } 6741da177e4SLinus Torvalds 6751da177e4SLinus Torvalds error2: 6761da177e4SLinus Torvalds key_put(key); 6771da177e4SLinus Torvalds error: 6781da177e4SLinus Torvalds return ret; 6791da177e4SLinus Torvalds 6801da177e4SLinus Torvalds } /* end keyctl_read_key() */ 6811da177e4SLinus Torvalds 6821da177e4SLinus Torvalds /*****************************************************************************/ 6831da177e4SLinus Torvalds /* 6841da177e4SLinus Torvalds * change the ownership of a key 6851da177e4SLinus Torvalds * - the keyring owned by the changer 6861da177e4SLinus Torvalds * - if the uid or gid is -1, then that parameter is not changed 6871da177e4SLinus Torvalds * - implements keyctl(KEYCTL_CHOWN) 6881da177e4SLinus Torvalds */ 6891da177e4SLinus Torvalds long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid) 6901da177e4SLinus Torvalds { 6915801649dSFredrik Tolf struct key_user *newowner, *zapowner = NULL; 6921da177e4SLinus Torvalds struct key *key; 693664cceb0SDavid Howells key_ref_t key_ref; 6941da177e4SLinus Torvalds long ret; 6951da177e4SLinus Torvalds 6961da177e4SLinus Torvalds ret = 0; 6971da177e4SLinus Torvalds if (uid == (uid_t) -1 && gid == (gid_t) -1) 6981da177e4SLinus Torvalds goto error; 6991da177e4SLinus Torvalds 70029db9190SDavid Howells key_ref = lookup_user_key(NULL, id, 1, 1, KEY_SETATTR); 701664cceb0SDavid Howells if (IS_ERR(key_ref)) { 702664cceb0SDavid Howells ret = PTR_ERR(key_ref); 7031da177e4SLinus Torvalds goto error; 7041da177e4SLinus Torvalds } 7051da177e4SLinus Torvalds 706664cceb0SDavid Howells key = key_ref_to_ptr(key_ref); 707664cceb0SDavid Howells 7081da177e4SLinus Torvalds /* make the changes with the locks held to prevent chown/chown races */ 7091da177e4SLinus Torvalds ret = -EACCES; 7101da177e4SLinus Torvalds down_write(&key->sem); 7111da177e4SLinus Torvalds 7121da177e4SLinus Torvalds if (!capable(CAP_SYS_ADMIN)) { 7131da177e4SLinus Torvalds /* only the sysadmin can chown a key to some other UID */ 7141da177e4SLinus Torvalds if (uid != (uid_t) -1 && key->uid != uid) 7155801649dSFredrik Tolf goto error_put; 7161da177e4SLinus Torvalds 7171da177e4SLinus Torvalds /* only the sysadmin can set the key's GID to a group other 7181da177e4SLinus Torvalds * than one of those that the current process subscribes to */ 7191da177e4SLinus Torvalds if (gid != (gid_t) -1 && gid != key->gid && !in_group_p(gid)) 7205801649dSFredrik Tolf goto error_put; 7211da177e4SLinus Torvalds } 7221da177e4SLinus Torvalds 7235801649dSFredrik Tolf /* change the UID */ 7241da177e4SLinus Torvalds if (uid != (uid_t) -1 && uid != key->uid) { 7255801649dSFredrik Tolf ret = -ENOMEM; 7265801649dSFredrik Tolf newowner = key_user_lookup(uid); 7275801649dSFredrik Tolf if (!newowner) 7285801649dSFredrik Tolf goto error_put; 7295801649dSFredrik Tolf 7305801649dSFredrik Tolf /* transfer the quota burden to the new user */ 7315801649dSFredrik Tolf if (test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) { 7325801649dSFredrik Tolf spin_lock(&newowner->lock); 7335801649dSFredrik Tolf if (newowner->qnkeys + 1 >= KEYQUOTA_MAX_KEYS || 7345801649dSFredrik Tolf newowner->qnbytes + key->quotalen >= 7355801649dSFredrik Tolf KEYQUOTA_MAX_BYTES) 7365801649dSFredrik Tolf goto quota_overrun; 7375801649dSFredrik Tolf 7385801649dSFredrik Tolf newowner->qnkeys++; 7395801649dSFredrik Tolf newowner->qnbytes += key->quotalen; 7405801649dSFredrik Tolf spin_unlock(&newowner->lock); 7415801649dSFredrik Tolf 7425801649dSFredrik Tolf spin_lock(&key->user->lock); 7435801649dSFredrik Tolf key->user->qnkeys--; 7445801649dSFredrik Tolf key->user->qnbytes -= key->quotalen; 7455801649dSFredrik Tolf spin_unlock(&key->user->lock); 7465801649dSFredrik Tolf } 7475801649dSFredrik Tolf 7485801649dSFredrik Tolf atomic_dec(&key->user->nkeys); 7495801649dSFredrik Tolf atomic_inc(&newowner->nkeys); 7505801649dSFredrik Tolf 7515801649dSFredrik Tolf if (test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) { 7525801649dSFredrik Tolf atomic_dec(&key->user->nikeys); 7535801649dSFredrik Tolf atomic_inc(&newowner->nikeys); 7545801649dSFredrik Tolf } 7555801649dSFredrik Tolf 7565801649dSFredrik Tolf zapowner = key->user; 7575801649dSFredrik Tolf key->user = newowner; 7585801649dSFredrik Tolf key->uid = uid; 7591da177e4SLinus Torvalds } 7601da177e4SLinus Torvalds 7611da177e4SLinus Torvalds /* change the GID */ 7621da177e4SLinus Torvalds if (gid != (gid_t) -1) 7631da177e4SLinus Torvalds key->gid = gid; 7641da177e4SLinus Torvalds 7651da177e4SLinus Torvalds ret = 0; 7661da177e4SLinus Torvalds 7675801649dSFredrik Tolf error_put: 7681da177e4SLinus Torvalds up_write(&key->sem); 7691da177e4SLinus Torvalds key_put(key); 7705801649dSFredrik Tolf if (zapowner) 7715801649dSFredrik Tolf key_user_put(zapowner); 7721da177e4SLinus Torvalds error: 7731da177e4SLinus Torvalds return ret; 7741da177e4SLinus Torvalds 7755801649dSFredrik Tolf quota_overrun: 7765801649dSFredrik Tolf spin_unlock(&newowner->lock); 7775801649dSFredrik Tolf zapowner = newowner; 7785801649dSFredrik Tolf ret = -EDQUOT; 7795801649dSFredrik Tolf goto error_put; 7805801649dSFredrik Tolf 7811da177e4SLinus Torvalds } /* end keyctl_chown_key() */ 7821da177e4SLinus Torvalds 7831da177e4SLinus Torvalds /*****************************************************************************/ 7841da177e4SLinus Torvalds /* 7851da177e4SLinus Torvalds * change the permission mask on a key 7861da177e4SLinus Torvalds * - the keyring owned by the changer 7871da177e4SLinus Torvalds * - implements keyctl(KEYCTL_SETPERM) 7881da177e4SLinus Torvalds */ 7891da177e4SLinus Torvalds long keyctl_setperm_key(key_serial_t id, key_perm_t perm) 7901da177e4SLinus Torvalds { 7911da177e4SLinus Torvalds struct key *key; 792664cceb0SDavid Howells key_ref_t key_ref; 7931da177e4SLinus Torvalds long ret; 7941da177e4SLinus Torvalds 7951da177e4SLinus Torvalds ret = -EINVAL; 796664cceb0SDavid Howells if (perm & ~(KEY_POS_ALL | KEY_USR_ALL | KEY_GRP_ALL | KEY_OTH_ALL)) 7971da177e4SLinus Torvalds goto error; 7981da177e4SLinus Torvalds 79929db9190SDavid Howells key_ref = lookup_user_key(NULL, id, 1, 1, KEY_SETATTR); 800664cceb0SDavid Howells if (IS_ERR(key_ref)) { 801664cceb0SDavid Howells ret = PTR_ERR(key_ref); 8021da177e4SLinus Torvalds goto error; 8031da177e4SLinus Torvalds } 8041da177e4SLinus Torvalds 805664cceb0SDavid Howells key = key_ref_to_ptr(key_ref); 806664cceb0SDavid Howells 80776d8aeabSDavid Howells /* make the changes with the locks held to prevent chown/chmod races */ 8081da177e4SLinus Torvalds ret = -EACCES; 8091da177e4SLinus Torvalds down_write(&key->sem); 8101da177e4SLinus Torvalds 81176d8aeabSDavid Howells /* if we're not the sysadmin, we can only change a key that we own */ 81276d8aeabSDavid Howells if (capable(CAP_SYS_ADMIN) || key->uid == current->fsuid) { 8131da177e4SLinus Torvalds key->perm = perm; 8141da177e4SLinus Torvalds ret = 0; 81576d8aeabSDavid Howells } 8161da177e4SLinus Torvalds 8171da177e4SLinus Torvalds up_write(&key->sem); 8181da177e4SLinus Torvalds key_put(key); 8191da177e4SLinus Torvalds error: 8201da177e4SLinus Torvalds return ret; 8211da177e4SLinus Torvalds 8221da177e4SLinus Torvalds } /* end keyctl_setperm_key() */ 8231da177e4SLinus Torvalds 8241da177e4SLinus Torvalds /*****************************************************************************/ 8251da177e4SLinus Torvalds /* 8261da177e4SLinus Torvalds * instantiate the key with the specified payload, and, if one is given, link 8271da177e4SLinus Torvalds * the key into the keyring 8281da177e4SLinus Torvalds */ 8291da177e4SLinus Torvalds long keyctl_instantiate_key(key_serial_t id, 8301da177e4SLinus Torvalds const void __user *_payload, 8311da177e4SLinus Torvalds size_t plen, 8321da177e4SLinus Torvalds key_serial_t ringid) 8331da177e4SLinus Torvalds { 8343e30148cSDavid Howells struct request_key_auth *rka; 835664cceb0SDavid Howells struct key *instkey; 836664cceb0SDavid Howells key_ref_t keyring_ref; 8371da177e4SLinus Torvalds void *payload; 8381da177e4SLinus Torvalds long ret; 83938bbca6bSDavid Howells bool vm = false; 8401da177e4SLinus Torvalds 8411da177e4SLinus Torvalds ret = -EINVAL; 84238bbca6bSDavid Howells if (plen > 1024 * 1024 - 1) 8431da177e4SLinus Torvalds goto error; 8441da177e4SLinus Torvalds 845b5f545c8SDavid Howells /* the appropriate instantiation authorisation key must have been 846b5f545c8SDavid Howells * assumed before calling this */ 847b5f545c8SDavid Howells ret = -EPERM; 848b5f545c8SDavid Howells instkey = current->request_key_auth; 849b5f545c8SDavid Howells if (!instkey) 850b5f545c8SDavid Howells goto error; 851b5f545c8SDavid Howells 852b5f545c8SDavid Howells rka = instkey->payload.data; 853b5f545c8SDavid Howells if (rka->target_key->serial != id) 854b5f545c8SDavid Howells goto error; 855b5f545c8SDavid Howells 8561da177e4SLinus Torvalds /* pull the payload in if one was supplied */ 8571da177e4SLinus Torvalds payload = NULL; 8581da177e4SLinus Torvalds 8591da177e4SLinus Torvalds if (_payload) { 8601da177e4SLinus Torvalds ret = -ENOMEM; 8611da177e4SLinus Torvalds payload = kmalloc(plen, GFP_KERNEL); 86238bbca6bSDavid Howells if (!payload) { 86338bbca6bSDavid Howells if (plen <= PAGE_SIZE) 86438bbca6bSDavid Howells goto error; 86538bbca6bSDavid Howells vm = true; 86638bbca6bSDavid Howells payload = vmalloc(plen); 8671da177e4SLinus Torvalds if (!payload) 8681da177e4SLinus Torvalds goto error; 86938bbca6bSDavid Howells } 8701da177e4SLinus Torvalds 8711da177e4SLinus Torvalds ret = -EFAULT; 8721da177e4SLinus Torvalds if (copy_from_user(payload, _payload, plen) != 0) 8731da177e4SLinus Torvalds goto error2; 8741da177e4SLinus Torvalds } 8751da177e4SLinus Torvalds 8763e30148cSDavid Howells /* find the destination keyring amongst those belonging to the 8773e30148cSDavid Howells * requesting task */ 878664cceb0SDavid Howells keyring_ref = NULL; 8791da177e4SLinus Torvalds if (ringid) { 880664cceb0SDavid Howells keyring_ref = lookup_user_key(rka->context, ringid, 1, 0, 8813e30148cSDavid Howells KEY_WRITE); 882664cceb0SDavid Howells if (IS_ERR(keyring_ref)) { 883664cceb0SDavid Howells ret = PTR_ERR(keyring_ref); 884b5f545c8SDavid Howells goto error2; 8851da177e4SLinus Torvalds } 8861da177e4SLinus Torvalds } 8871da177e4SLinus Torvalds 8881da177e4SLinus Torvalds /* instantiate the key and link it into a keyring */ 8893e30148cSDavid Howells ret = key_instantiate_and_link(rka->target_key, payload, plen, 890664cceb0SDavid Howells key_ref_to_ptr(keyring_ref), instkey); 8911da177e4SLinus Torvalds 892664cceb0SDavid Howells key_ref_put(keyring_ref); 893b5f545c8SDavid Howells 894b5f545c8SDavid Howells /* discard the assumed authority if it's just been disabled by 895b5f545c8SDavid Howells * instantiation of the key */ 896b5f545c8SDavid Howells if (ret == 0) { 897b5f545c8SDavid Howells key_put(current->request_key_auth); 898b5f545c8SDavid Howells current->request_key_auth = NULL; 899b5f545c8SDavid Howells } 900b5f545c8SDavid Howells 9011da177e4SLinus Torvalds error2: 90238bbca6bSDavid Howells if (!vm) 9031da177e4SLinus Torvalds kfree(payload); 90438bbca6bSDavid Howells else 90538bbca6bSDavid Howells vfree(payload); 9061da177e4SLinus Torvalds error: 9071da177e4SLinus Torvalds return ret; 9081da177e4SLinus Torvalds 9091da177e4SLinus Torvalds } /* end keyctl_instantiate_key() */ 9101da177e4SLinus Torvalds 9111da177e4SLinus Torvalds /*****************************************************************************/ 9121da177e4SLinus Torvalds /* 9131da177e4SLinus Torvalds * negatively instantiate the key with the given timeout (in seconds), and, if 9141da177e4SLinus Torvalds * one is given, link the key into the keyring 9151da177e4SLinus Torvalds */ 9161da177e4SLinus Torvalds long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid) 9171da177e4SLinus Torvalds { 9183e30148cSDavid Howells struct request_key_auth *rka; 919664cceb0SDavid Howells struct key *instkey; 920664cceb0SDavid Howells key_ref_t keyring_ref; 9211da177e4SLinus Torvalds long ret; 9221da177e4SLinus Torvalds 923b5f545c8SDavid Howells /* the appropriate instantiation authorisation key must have been 924b5f545c8SDavid Howells * assumed before calling this */ 925b5f545c8SDavid Howells ret = -EPERM; 926b5f545c8SDavid Howells instkey = current->request_key_auth; 927b5f545c8SDavid Howells if (!instkey) 9281da177e4SLinus Torvalds goto error; 9291da177e4SLinus Torvalds 9303e30148cSDavid Howells rka = instkey->payload.data; 931b5f545c8SDavid Howells if (rka->target_key->serial != id) 932b5f545c8SDavid Howells goto error; 9333e30148cSDavid Howells 9341da177e4SLinus Torvalds /* find the destination keyring if present (which must also be 9351da177e4SLinus Torvalds * writable) */ 936664cceb0SDavid Howells keyring_ref = NULL; 9371da177e4SLinus Torvalds if (ringid) { 938664cceb0SDavid Howells keyring_ref = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE); 939664cceb0SDavid Howells if (IS_ERR(keyring_ref)) { 940664cceb0SDavid Howells ret = PTR_ERR(keyring_ref); 941b5f545c8SDavid Howells goto error; 9421da177e4SLinus Torvalds } 9431da177e4SLinus Torvalds } 9441da177e4SLinus Torvalds 9451da177e4SLinus Torvalds /* instantiate the key and link it into a keyring */ 946664cceb0SDavid Howells ret = key_negate_and_link(rka->target_key, timeout, 947664cceb0SDavid Howells key_ref_to_ptr(keyring_ref), instkey); 9481da177e4SLinus Torvalds 949664cceb0SDavid Howells key_ref_put(keyring_ref); 950b5f545c8SDavid Howells 951b5f545c8SDavid Howells /* discard the assumed authority if it's just been disabled by 952b5f545c8SDavid Howells * instantiation of the key */ 953b5f545c8SDavid Howells if (ret == 0) { 954b5f545c8SDavid Howells key_put(current->request_key_auth); 955b5f545c8SDavid Howells current->request_key_auth = NULL; 956b5f545c8SDavid Howells } 957b5f545c8SDavid Howells 9581da177e4SLinus Torvalds error: 9591da177e4SLinus Torvalds return ret; 9601da177e4SLinus Torvalds 9611da177e4SLinus Torvalds } /* end keyctl_negate_key() */ 9621da177e4SLinus Torvalds 9631da177e4SLinus Torvalds /*****************************************************************************/ 9641da177e4SLinus Torvalds /* 9653e30148cSDavid Howells * set the default keyring in which request_key() will cache keys 9663e30148cSDavid Howells * - return the old setting 9673e30148cSDavid Howells */ 9683e30148cSDavid Howells long keyctl_set_reqkey_keyring(int reqkey_defl) 9693e30148cSDavid Howells { 9703e30148cSDavid Howells int ret; 9713e30148cSDavid Howells 9723e30148cSDavid Howells switch (reqkey_defl) { 9733e30148cSDavid Howells case KEY_REQKEY_DEFL_THREAD_KEYRING: 9743e30148cSDavid Howells ret = install_thread_keyring(current); 9753e30148cSDavid Howells if (ret < 0) 9763e30148cSDavid Howells return ret; 9773e30148cSDavid Howells goto set; 9783e30148cSDavid Howells 9793e30148cSDavid Howells case KEY_REQKEY_DEFL_PROCESS_KEYRING: 9803e30148cSDavid Howells ret = install_process_keyring(current); 9813e30148cSDavid Howells if (ret < 0) 9823e30148cSDavid Howells return ret; 9833e30148cSDavid Howells 9843e30148cSDavid Howells case KEY_REQKEY_DEFL_DEFAULT: 9853e30148cSDavid Howells case KEY_REQKEY_DEFL_SESSION_KEYRING: 9863e30148cSDavid Howells case KEY_REQKEY_DEFL_USER_KEYRING: 9873e30148cSDavid Howells case KEY_REQKEY_DEFL_USER_SESSION_KEYRING: 9883e30148cSDavid Howells set: 9893e30148cSDavid Howells current->jit_keyring = reqkey_defl; 9903e30148cSDavid Howells 9913e30148cSDavid Howells case KEY_REQKEY_DEFL_NO_CHANGE: 9923e30148cSDavid Howells return current->jit_keyring; 9933e30148cSDavid Howells 9943e30148cSDavid Howells case KEY_REQKEY_DEFL_GROUP_KEYRING: 9953e30148cSDavid Howells default: 9963e30148cSDavid Howells return -EINVAL; 9973e30148cSDavid Howells } 9983e30148cSDavid Howells 9993e30148cSDavid Howells } /* end keyctl_set_reqkey_keyring() */ 10003e30148cSDavid Howells 10013e30148cSDavid Howells /*****************************************************************************/ 10023e30148cSDavid Howells /* 1003017679c4SDavid Howells * set or clear the timeout for a key 1004017679c4SDavid Howells */ 1005017679c4SDavid Howells long keyctl_set_timeout(key_serial_t id, unsigned timeout) 1006017679c4SDavid Howells { 1007017679c4SDavid Howells struct timespec now; 1008017679c4SDavid Howells struct key *key; 1009017679c4SDavid Howells key_ref_t key_ref; 1010017679c4SDavid Howells time_t expiry; 1011017679c4SDavid Howells long ret; 1012017679c4SDavid Howells 1013017679c4SDavid Howells key_ref = lookup_user_key(NULL, id, 1, 1, KEY_SETATTR); 1014017679c4SDavid Howells if (IS_ERR(key_ref)) { 1015017679c4SDavid Howells ret = PTR_ERR(key_ref); 1016017679c4SDavid Howells goto error; 1017017679c4SDavid Howells } 1018017679c4SDavid Howells 1019017679c4SDavid Howells key = key_ref_to_ptr(key_ref); 1020017679c4SDavid Howells 1021017679c4SDavid Howells /* make the changes with the locks held to prevent races */ 1022017679c4SDavid Howells down_write(&key->sem); 1023017679c4SDavid Howells 1024017679c4SDavid Howells expiry = 0; 1025017679c4SDavid Howells if (timeout > 0) { 1026017679c4SDavid Howells now = current_kernel_time(); 1027017679c4SDavid Howells expiry = now.tv_sec + timeout; 1028017679c4SDavid Howells } 1029017679c4SDavid Howells 1030017679c4SDavid Howells key->expiry = expiry; 1031017679c4SDavid Howells 1032017679c4SDavid Howells up_write(&key->sem); 1033017679c4SDavid Howells key_put(key); 1034017679c4SDavid Howells 1035017679c4SDavid Howells ret = 0; 1036017679c4SDavid Howells error: 1037017679c4SDavid Howells return ret; 1038017679c4SDavid Howells 1039017679c4SDavid Howells } /* end keyctl_set_timeout() */ 1040017679c4SDavid Howells 1041017679c4SDavid Howells /*****************************************************************************/ 1042017679c4SDavid Howells /* 1043b5f545c8SDavid Howells * assume the authority to instantiate the specified key 1044b5f545c8SDavid Howells */ 1045b5f545c8SDavid Howells long keyctl_assume_authority(key_serial_t id) 1046b5f545c8SDavid Howells { 1047b5f545c8SDavid Howells struct key *authkey; 1048b5f545c8SDavid Howells long ret; 1049b5f545c8SDavid Howells 1050b5f545c8SDavid Howells /* special key IDs aren't permitted */ 1051b5f545c8SDavid Howells ret = -EINVAL; 1052b5f545c8SDavid Howells if (id < 0) 1053b5f545c8SDavid Howells goto error; 1054b5f545c8SDavid Howells 1055b5f545c8SDavid Howells /* we divest ourselves of authority if given an ID of 0 */ 1056b5f545c8SDavid Howells if (id == 0) { 1057b5f545c8SDavid Howells key_put(current->request_key_auth); 1058b5f545c8SDavid Howells current->request_key_auth = NULL; 1059b5f545c8SDavid Howells ret = 0; 1060b5f545c8SDavid Howells goto error; 1061b5f545c8SDavid Howells } 1062b5f545c8SDavid Howells 1063b5f545c8SDavid Howells /* attempt to assume the authority temporarily granted to us whilst we 1064b5f545c8SDavid Howells * instantiate the specified key 1065b5f545c8SDavid Howells * - the authorisation key must be in the current task's keyrings 1066b5f545c8SDavid Howells * somewhere 1067b5f545c8SDavid Howells */ 1068b5f545c8SDavid Howells authkey = key_get_instantiation_authkey(id); 1069b5f545c8SDavid Howells if (IS_ERR(authkey)) { 1070b5f545c8SDavid Howells ret = PTR_ERR(authkey); 1071b5f545c8SDavid Howells goto error; 1072b5f545c8SDavid Howells } 1073b5f545c8SDavid Howells 1074b5f545c8SDavid Howells key_put(current->request_key_auth); 1075b5f545c8SDavid Howells current->request_key_auth = authkey; 1076b5f545c8SDavid Howells ret = authkey->serial; 1077b5f545c8SDavid Howells 1078b5f545c8SDavid Howells error: 1079b5f545c8SDavid Howells return ret; 1080b5f545c8SDavid Howells 1081b5f545c8SDavid Howells } /* end keyctl_assume_authority() */ 1082b5f545c8SDavid Howells 1083b5f545c8SDavid Howells /*****************************************************************************/ 1084b5f545c8SDavid Howells /* 10851da177e4SLinus Torvalds * the key control system call 10861da177e4SLinus Torvalds */ 10871da177e4SLinus Torvalds asmlinkage long sys_keyctl(int option, unsigned long arg2, unsigned long arg3, 10881da177e4SLinus Torvalds unsigned long arg4, unsigned long arg5) 10891da177e4SLinus Torvalds { 10901da177e4SLinus Torvalds switch (option) { 10911da177e4SLinus Torvalds case KEYCTL_GET_KEYRING_ID: 10921da177e4SLinus Torvalds return keyctl_get_keyring_ID((key_serial_t) arg2, 10931da177e4SLinus Torvalds (int) arg3); 10941da177e4SLinus Torvalds 10951da177e4SLinus Torvalds case KEYCTL_JOIN_SESSION_KEYRING: 10961da177e4SLinus Torvalds return keyctl_join_session_keyring((const char __user *) arg2); 10971da177e4SLinus Torvalds 10981da177e4SLinus Torvalds case KEYCTL_UPDATE: 10991da177e4SLinus Torvalds return keyctl_update_key((key_serial_t) arg2, 11001da177e4SLinus Torvalds (const void __user *) arg3, 11011da177e4SLinus Torvalds (size_t) arg4); 11021da177e4SLinus Torvalds 11031da177e4SLinus Torvalds case KEYCTL_REVOKE: 11041da177e4SLinus Torvalds return keyctl_revoke_key((key_serial_t) arg2); 11051da177e4SLinus Torvalds 11061da177e4SLinus Torvalds case KEYCTL_DESCRIBE: 11071da177e4SLinus Torvalds return keyctl_describe_key((key_serial_t) arg2, 11081da177e4SLinus Torvalds (char __user *) arg3, 11091da177e4SLinus Torvalds (unsigned) arg4); 11101da177e4SLinus Torvalds 11111da177e4SLinus Torvalds case KEYCTL_CLEAR: 11121da177e4SLinus Torvalds return keyctl_keyring_clear((key_serial_t) arg2); 11131da177e4SLinus Torvalds 11141da177e4SLinus Torvalds case KEYCTL_LINK: 11151da177e4SLinus Torvalds return keyctl_keyring_link((key_serial_t) arg2, 11161da177e4SLinus Torvalds (key_serial_t) arg3); 11171da177e4SLinus Torvalds 11181da177e4SLinus Torvalds case KEYCTL_UNLINK: 11191da177e4SLinus Torvalds return keyctl_keyring_unlink((key_serial_t) arg2, 11201da177e4SLinus Torvalds (key_serial_t) arg3); 11211da177e4SLinus Torvalds 11221da177e4SLinus Torvalds case KEYCTL_SEARCH: 11231da177e4SLinus Torvalds return keyctl_keyring_search((key_serial_t) arg2, 11241da177e4SLinus Torvalds (const char __user *) arg3, 11251da177e4SLinus Torvalds (const char __user *) arg4, 11261da177e4SLinus Torvalds (key_serial_t) arg5); 11271da177e4SLinus Torvalds 11281da177e4SLinus Torvalds case KEYCTL_READ: 11291da177e4SLinus Torvalds return keyctl_read_key((key_serial_t) arg2, 11301da177e4SLinus Torvalds (char __user *) arg3, 11311da177e4SLinus Torvalds (size_t) arg4); 11321da177e4SLinus Torvalds 11331da177e4SLinus Torvalds case KEYCTL_CHOWN: 11341da177e4SLinus Torvalds return keyctl_chown_key((key_serial_t) arg2, 11351da177e4SLinus Torvalds (uid_t) arg3, 11361da177e4SLinus Torvalds (gid_t) arg4); 11371da177e4SLinus Torvalds 11381da177e4SLinus Torvalds case KEYCTL_SETPERM: 11391da177e4SLinus Torvalds return keyctl_setperm_key((key_serial_t) arg2, 11401da177e4SLinus Torvalds (key_perm_t) arg3); 11411da177e4SLinus Torvalds 11421da177e4SLinus Torvalds case KEYCTL_INSTANTIATE: 11431da177e4SLinus Torvalds return keyctl_instantiate_key((key_serial_t) arg2, 11441da177e4SLinus Torvalds (const void __user *) arg3, 11451da177e4SLinus Torvalds (size_t) arg4, 11461da177e4SLinus Torvalds (key_serial_t) arg5); 11471da177e4SLinus Torvalds 11481da177e4SLinus Torvalds case KEYCTL_NEGATE: 11491da177e4SLinus Torvalds return keyctl_negate_key((key_serial_t) arg2, 11501da177e4SLinus Torvalds (unsigned) arg3, 11511da177e4SLinus Torvalds (key_serial_t) arg4); 11521da177e4SLinus Torvalds 11533e30148cSDavid Howells case KEYCTL_SET_REQKEY_KEYRING: 11543e30148cSDavid Howells return keyctl_set_reqkey_keyring(arg2); 11553e30148cSDavid Howells 1156017679c4SDavid Howells case KEYCTL_SET_TIMEOUT: 1157017679c4SDavid Howells return keyctl_set_timeout((key_serial_t) arg2, 1158017679c4SDavid Howells (unsigned) arg3); 1159017679c4SDavid Howells 1160b5f545c8SDavid Howells case KEYCTL_ASSUME_AUTHORITY: 1161b5f545c8SDavid Howells return keyctl_assume_authority((key_serial_t) arg2); 1162b5f545c8SDavid Howells 11631da177e4SLinus Torvalds default: 11641da177e4SLinus Torvalds return -EOPNOTSUPP; 11651da177e4SLinus Torvalds } 11661da177e4SLinus Torvalds 11671da177e4SLinus Torvalds } /* end sys_keyctl() */ 1168