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> 2370a5bb72SDavid Howells #include <linux/security.h> 241da177e4SLinus Torvalds #include <asm/uaccess.h> 251da177e4SLinus Torvalds #include "internal.h" 261da177e4SLinus Torvalds 270cb409d9SDavi Arnaut static int key_get_type_from_user(char *type, 280cb409d9SDavi Arnaut const char __user *_type, 290cb409d9SDavi Arnaut unsigned len) 300cb409d9SDavi Arnaut { 310cb409d9SDavi Arnaut int ret; 320cb409d9SDavi Arnaut 330cb409d9SDavi Arnaut ret = strncpy_from_user(type, _type, len); 340cb409d9SDavi Arnaut 350cb409d9SDavi Arnaut if (ret < 0) 364303ef19SDan Carpenter return ret; 370cb409d9SDavi Arnaut 380cb409d9SDavi Arnaut if (ret == 0 || ret >= len) 390cb409d9SDavi Arnaut return -EINVAL; 400cb409d9SDavi Arnaut 410cb409d9SDavi Arnaut if (type[0] == '.') 420cb409d9SDavi Arnaut return -EPERM; 430cb409d9SDavi Arnaut 440cb409d9SDavi Arnaut type[len - 1] = '\0'; 450cb409d9SDavi Arnaut 460cb409d9SDavi Arnaut return 0; 470cb409d9SDavi Arnaut } 480cb409d9SDavi Arnaut 491da177e4SLinus Torvalds /*****************************************************************************/ 501da177e4SLinus Torvalds /* 511da177e4SLinus Torvalds * extract the description of a new key from userspace and either add it as a 521da177e4SLinus Torvalds * new key to the specified keyring or update a matching key in that keyring 531da177e4SLinus Torvalds * - the keyring must be writable 541da177e4SLinus Torvalds * - returns the new key's serial number 551da177e4SLinus Torvalds * - implements add_key() 561da177e4SLinus Torvalds */ 571e7bfb21SHeiko Carstens SYSCALL_DEFINE5(add_key, const char __user *, _type, 581e7bfb21SHeiko Carstens const char __user *, _description, 591e7bfb21SHeiko Carstens const void __user *, _payload, 601e7bfb21SHeiko Carstens size_t, plen, 611e7bfb21SHeiko Carstens key_serial_t, ringid) 621da177e4SLinus Torvalds { 63664cceb0SDavid Howells key_ref_t keyring_ref, key_ref; 641da177e4SLinus Torvalds char type[32], *description; 651da177e4SLinus Torvalds void *payload; 660cb409d9SDavi Arnaut long ret; 6738bbca6bSDavid Howells bool vm; 681da177e4SLinus Torvalds 691da177e4SLinus Torvalds ret = -EINVAL; 7038bbca6bSDavid Howells if (plen > 1024 * 1024 - 1) 711da177e4SLinus Torvalds goto error; 721da177e4SLinus Torvalds 731da177e4SLinus Torvalds /* draw all the data into kernel space */ 740cb409d9SDavi Arnaut ret = key_get_type_from_user(type, _type, sizeof(type)); 751da177e4SLinus Torvalds if (ret < 0) 761da177e4SLinus Torvalds goto error; 771da177e4SLinus Torvalds 780cb409d9SDavi Arnaut description = strndup_user(_description, PAGE_SIZE); 790cb409d9SDavi Arnaut if (IS_ERR(description)) { 800cb409d9SDavi Arnaut ret = PTR_ERR(description); 813e30148cSDavid Howells goto error; 820cb409d9SDavi Arnaut } 831da177e4SLinus Torvalds 841da177e4SLinus Torvalds /* pull the payload in if one was supplied */ 851da177e4SLinus Torvalds payload = NULL; 861da177e4SLinus Torvalds 8738bbca6bSDavid Howells vm = false; 881da177e4SLinus Torvalds if (_payload) { 891da177e4SLinus Torvalds ret = -ENOMEM; 901da177e4SLinus Torvalds payload = kmalloc(plen, GFP_KERNEL); 9138bbca6bSDavid Howells if (!payload) { 9238bbca6bSDavid Howells if (plen <= PAGE_SIZE) 9338bbca6bSDavid Howells goto error2; 9438bbca6bSDavid Howells vm = true; 9538bbca6bSDavid Howells payload = vmalloc(plen); 961da177e4SLinus Torvalds if (!payload) 971da177e4SLinus Torvalds goto error2; 9838bbca6bSDavid Howells } 991da177e4SLinus Torvalds 1001da177e4SLinus Torvalds ret = -EFAULT; 1011da177e4SLinus Torvalds if (copy_from_user(payload, _payload, plen) != 0) 1021da177e4SLinus Torvalds goto error3; 1031da177e4SLinus Torvalds } 1041da177e4SLinus Torvalds 1051da177e4SLinus Torvalds /* find the target keyring (which must be writable) */ 1065593122eSDavid Howells keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE); 107664cceb0SDavid Howells if (IS_ERR(keyring_ref)) { 108664cceb0SDavid Howells ret = PTR_ERR(keyring_ref); 1091da177e4SLinus Torvalds goto error3; 1101da177e4SLinus Torvalds } 1111da177e4SLinus Torvalds 1121da177e4SLinus Torvalds /* create or update the requested key and add it to the target 1131da177e4SLinus Torvalds * keyring */ 114664cceb0SDavid Howells key_ref = key_create_or_update(keyring_ref, type, description, 1156b79ccb5SArun Raghavan payload, plen, KEY_PERM_UNDEF, 1166b79ccb5SArun Raghavan KEY_ALLOC_IN_QUOTA); 117664cceb0SDavid Howells if (!IS_ERR(key_ref)) { 118664cceb0SDavid Howells ret = key_ref_to_ptr(key_ref)->serial; 119664cceb0SDavid Howells key_ref_put(key_ref); 1201da177e4SLinus Torvalds } 1211da177e4SLinus Torvalds else { 122664cceb0SDavid Howells ret = PTR_ERR(key_ref); 1231da177e4SLinus Torvalds } 1241da177e4SLinus Torvalds 125664cceb0SDavid Howells key_ref_put(keyring_ref); 1261da177e4SLinus Torvalds error3: 12738bbca6bSDavid Howells if (!vm) 1281da177e4SLinus Torvalds kfree(payload); 12938bbca6bSDavid Howells else 13038bbca6bSDavid Howells vfree(payload); 1311da177e4SLinus Torvalds error2: 1321da177e4SLinus Torvalds kfree(description); 1331da177e4SLinus Torvalds error: 1341da177e4SLinus Torvalds return ret; 1351da177e4SLinus Torvalds 1361da177e4SLinus Torvalds } /* end sys_add_key() */ 1371da177e4SLinus Torvalds 1381da177e4SLinus Torvalds /*****************************************************************************/ 1391da177e4SLinus Torvalds /* 1401da177e4SLinus Torvalds * search the process keyrings for a matching key 1411da177e4SLinus Torvalds * - nested keyrings may also be searched if they have Search permission 1421da177e4SLinus Torvalds * - if a key is found, it will be attached to the destination keyring if 1431da177e4SLinus Torvalds * there's one specified 1441da177e4SLinus Torvalds * - /sbin/request-key will be invoked if _callout_info is non-NULL 1451da177e4SLinus Torvalds * - the _callout_info string will be passed to /sbin/request-key 1461da177e4SLinus Torvalds * - if the _callout_info string is empty, it will be rendered as "-" 1471da177e4SLinus Torvalds * - implements request_key() 1481da177e4SLinus Torvalds */ 1491e7bfb21SHeiko Carstens SYSCALL_DEFINE4(request_key, const char __user *, _type, 1501e7bfb21SHeiko Carstens const char __user *, _description, 1511e7bfb21SHeiko Carstens const char __user *, _callout_info, 1521e7bfb21SHeiko Carstens key_serial_t, destringid) 1531da177e4SLinus Torvalds { 1541da177e4SLinus Torvalds struct key_type *ktype; 155664cceb0SDavid Howells struct key *key; 156664cceb0SDavid Howells key_ref_t dest_ref; 1574a38e122SDavid Howells size_t callout_len; 1581da177e4SLinus Torvalds char type[32], *description, *callout_info; 1590cb409d9SDavi Arnaut long ret; 1601da177e4SLinus Torvalds 1611da177e4SLinus Torvalds /* pull the type into kernel space */ 1620cb409d9SDavi Arnaut ret = key_get_type_from_user(type, _type, sizeof(type)); 1631da177e4SLinus Torvalds if (ret < 0) 1641da177e4SLinus Torvalds goto error; 1651260f801SDavid Howells 1661da177e4SLinus Torvalds /* pull the description into kernel space */ 1670cb409d9SDavi Arnaut description = strndup_user(_description, PAGE_SIZE); 1680cb409d9SDavi Arnaut if (IS_ERR(description)) { 1690cb409d9SDavi Arnaut ret = PTR_ERR(description); 1701da177e4SLinus Torvalds goto error; 1710cb409d9SDavi Arnaut } 1721da177e4SLinus Torvalds 1731da177e4SLinus Torvalds /* pull the callout info into kernel space */ 1741da177e4SLinus Torvalds callout_info = NULL; 1754a38e122SDavid Howells callout_len = 0; 1761da177e4SLinus Torvalds if (_callout_info) { 1770cb409d9SDavi Arnaut callout_info = strndup_user(_callout_info, PAGE_SIZE); 1780cb409d9SDavi Arnaut if (IS_ERR(callout_info)) { 1790cb409d9SDavi Arnaut ret = PTR_ERR(callout_info); 1801da177e4SLinus Torvalds goto error2; 1810cb409d9SDavi Arnaut } 1824a38e122SDavid Howells callout_len = strlen(callout_info); 1831da177e4SLinus Torvalds } 1841da177e4SLinus Torvalds 1851da177e4SLinus Torvalds /* get the destination keyring if specified */ 186664cceb0SDavid Howells dest_ref = NULL; 1871da177e4SLinus Torvalds if (destringid) { 1885593122eSDavid Howells dest_ref = lookup_user_key(destringid, KEY_LOOKUP_CREATE, 1895593122eSDavid Howells KEY_WRITE); 190664cceb0SDavid Howells if (IS_ERR(dest_ref)) { 191664cceb0SDavid Howells ret = PTR_ERR(dest_ref); 1921da177e4SLinus Torvalds goto error3; 1931da177e4SLinus Torvalds } 1941da177e4SLinus Torvalds } 1951da177e4SLinus Torvalds 1961da177e4SLinus Torvalds /* find the key type */ 1971da177e4SLinus Torvalds ktype = key_type_lookup(type); 1981da177e4SLinus Torvalds if (IS_ERR(ktype)) { 1991da177e4SLinus Torvalds ret = PTR_ERR(ktype); 2001da177e4SLinus Torvalds goto error4; 2011da177e4SLinus Torvalds } 2021da177e4SLinus Torvalds 2031da177e4SLinus Torvalds /* do the search */ 2044a38e122SDavid Howells key = request_key_and_link(ktype, description, callout_info, 2054a38e122SDavid Howells callout_len, NULL, key_ref_to_ptr(dest_ref), 2067e047ef5SDavid Howells KEY_ALLOC_IN_QUOTA); 2071da177e4SLinus Torvalds if (IS_ERR(key)) { 2081da177e4SLinus Torvalds ret = PTR_ERR(key); 2091da177e4SLinus Torvalds goto error5; 2101da177e4SLinus Torvalds } 2111da177e4SLinus Torvalds 2121da177e4SLinus Torvalds ret = key->serial; 2131da177e4SLinus Torvalds 2141da177e4SLinus Torvalds key_put(key); 2151da177e4SLinus Torvalds error5: 2161da177e4SLinus Torvalds key_type_put(ktype); 2171da177e4SLinus Torvalds error4: 218664cceb0SDavid Howells key_ref_put(dest_ref); 2191da177e4SLinus Torvalds error3: 2201da177e4SLinus Torvalds kfree(callout_info); 2211da177e4SLinus Torvalds error2: 2221da177e4SLinus Torvalds kfree(description); 2231da177e4SLinus Torvalds error: 2241da177e4SLinus Torvalds return ret; 2251da177e4SLinus Torvalds 2261da177e4SLinus Torvalds } /* end sys_request_key() */ 2271da177e4SLinus Torvalds 2281da177e4SLinus Torvalds /*****************************************************************************/ 2291da177e4SLinus Torvalds /* 2301da177e4SLinus Torvalds * get the ID of the specified process keyring 2311da177e4SLinus Torvalds * - the keyring must have search permission to be found 2321da177e4SLinus Torvalds * - implements keyctl(KEYCTL_GET_KEYRING_ID) 2331da177e4SLinus Torvalds */ 2341da177e4SLinus Torvalds long keyctl_get_keyring_ID(key_serial_t id, int create) 2351da177e4SLinus Torvalds { 236664cceb0SDavid Howells key_ref_t key_ref; 2375593122eSDavid Howells unsigned long lflags; 2381da177e4SLinus Torvalds long ret; 2391da177e4SLinus Torvalds 2405593122eSDavid Howells lflags = create ? KEY_LOOKUP_CREATE : 0; 2415593122eSDavid Howells key_ref = lookup_user_key(id, lflags, KEY_SEARCH); 242664cceb0SDavid Howells if (IS_ERR(key_ref)) { 243664cceb0SDavid Howells ret = PTR_ERR(key_ref); 2441da177e4SLinus Torvalds goto error; 2451da177e4SLinus Torvalds } 2461da177e4SLinus Torvalds 247664cceb0SDavid Howells ret = key_ref_to_ptr(key_ref)->serial; 248664cceb0SDavid Howells key_ref_put(key_ref); 2491da177e4SLinus Torvalds error: 2501da177e4SLinus Torvalds return ret; 2511da177e4SLinus Torvalds 2521da177e4SLinus Torvalds } /* end keyctl_get_keyring_ID() */ 2531da177e4SLinus Torvalds 2541da177e4SLinus Torvalds /*****************************************************************************/ 2551da177e4SLinus Torvalds /* 2561da177e4SLinus Torvalds * join the session keyring 2571da177e4SLinus Torvalds * - implements keyctl(KEYCTL_JOIN_SESSION_KEYRING) 2581da177e4SLinus Torvalds */ 2591da177e4SLinus Torvalds long keyctl_join_session_keyring(const char __user *_name) 2601da177e4SLinus Torvalds { 2611da177e4SLinus Torvalds char *name; 2620cb409d9SDavi Arnaut long ret; 2631da177e4SLinus Torvalds 2641da177e4SLinus Torvalds /* fetch the name from userspace */ 2651da177e4SLinus Torvalds name = NULL; 2661da177e4SLinus Torvalds if (_name) { 2670cb409d9SDavi Arnaut name = strndup_user(_name, PAGE_SIZE); 2680cb409d9SDavi Arnaut if (IS_ERR(name)) { 2690cb409d9SDavi Arnaut ret = PTR_ERR(name); 2701da177e4SLinus Torvalds goto error; 2710cb409d9SDavi Arnaut } 2721da177e4SLinus Torvalds } 2731da177e4SLinus Torvalds 2741da177e4SLinus Torvalds /* join the session */ 2751da177e4SLinus Torvalds ret = join_session_keyring(name); 2760d54ee1cSVegard Nossum kfree(name); 2771da177e4SLinus Torvalds 2781da177e4SLinus Torvalds error: 2791da177e4SLinus Torvalds return ret; 2801da177e4SLinus Torvalds 2811da177e4SLinus Torvalds } /* end keyctl_join_session_keyring() */ 2821da177e4SLinus Torvalds 2831da177e4SLinus Torvalds /*****************************************************************************/ 2841da177e4SLinus Torvalds /* 2851da177e4SLinus Torvalds * update a key's data payload 2861da177e4SLinus Torvalds * - the key must be writable 2871da177e4SLinus Torvalds * - implements keyctl(KEYCTL_UPDATE) 2881da177e4SLinus Torvalds */ 2891da177e4SLinus Torvalds long keyctl_update_key(key_serial_t id, 2901da177e4SLinus Torvalds const void __user *_payload, 2911da177e4SLinus Torvalds size_t plen) 2921da177e4SLinus Torvalds { 293664cceb0SDavid Howells key_ref_t key_ref; 2941da177e4SLinus Torvalds void *payload; 2951da177e4SLinus Torvalds long ret; 2961da177e4SLinus Torvalds 2971da177e4SLinus Torvalds ret = -EINVAL; 2981da177e4SLinus Torvalds if (plen > PAGE_SIZE) 2991da177e4SLinus Torvalds goto error; 3001da177e4SLinus Torvalds 3011da177e4SLinus Torvalds /* pull the payload in if one was supplied */ 3021da177e4SLinus Torvalds payload = NULL; 3031da177e4SLinus Torvalds if (_payload) { 3041da177e4SLinus Torvalds ret = -ENOMEM; 3051da177e4SLinus Torvalds payload = kmalloc(plen, GFP_KERNEL); 3061da177e4SLinus Torvalds if (!payload) 3071da177e4SLinus Torvalds goto error; 3081da177e4SLinus Torvalds 3091da177e4SLinus Torvalds ret = -EFAULT; 3101da177e4SLinus Torvalds if (copy_from_user(payload, _payload, plen) != 0) 3111da177e4SLinus Torvalds goto error2; 3121da177e4SLinus Torvalds } 3131da177e4SLinus Torvalds 3141da177e4SLinus Torvalds /* find the target key (which must be writable) */ 3155593122eSDavid Howells key_ref = lookup_user_key(id, 0, KEY_WRITE); 316664cceb0SDavid Howells if (IS_ERR(key_ref)) { 317664cceb0SDavid Howells ret = PTR_ERR(key_ref); 3181da177e4SLinus Torvalds goto error2; 3191da177e4SLinus Torvalds } 3201da177e4SLinus Torvalds 3211da177e4SLinus Torvalds /* update the key */ 322664cceb0SDavid Howells ret = key_update(key_ref, payload, plen); 3231da177e4SLinus Torvalds 324664cceb0SDavid Howells key_ref_put(key_ref); 3251da177e4SLinus Torvalds error2: 3261da177e4SLinus Torvalds kfree(payload); 3271da177e4SLinus Torvalds error: 3281da177e4SLinus Torvalds return ret; 3291da177e4SLinus Torvalds 3301da177e4SLinus Torvalds } /* end keyctl_update_key() */ 3311da177e4SLinus Torvalds 3321da177e4SLinus Torvalds /*****************************************************************************/ 3331da177e4SLinus Torvalds /* 3341da177e4SLinus Torvalds * revoke a key 3351da177e4SLinus Torvalds * - the key must be writable 3361da177e4SLinus Torvalds * - implements keyctl(KEYCTL_REVOKE) 3371da177e4SLinus Torvalds */ 3381da177e4SLinus Torvalds long keyctl_revoke_key(key_serial_t id) 3391da177e4SLinus Torvalds { 340664cceb0SDavid Howells key_ref_t key_ref; 3411da177e4SLinus Torvalds long ret; 3421da177e4SLinus Torvalds 3435593122eSDavid Howells key_ref = lookup_user_key(id, 0, KEY_WRITE); 344664cceb0SDavid Howells if (IS_ERR(key_ref)) { 345664cceb0SDavid Howells ret = PTR_ERR(key_ref); 3460c2c9a3fSDavid Howells if (ret != -EACCES) 3471da177e4SLinus Torvalds goto error; 3480c2c9a3fSDavid Howells key_ref = lookup_user_key(id, 0, KEY_SETATTR); 3490c2c9a3fSDavid Howells if (IS_ERR(key_ref)) { 3500c2c9a3fSDavid Howells ret = PTR_ERR(key_ref); 3510c2c9a3fSDavid Howells goto error; 3520c2c9a3fSDavid Howells } 3531da177e4SLinus Torvalds } 3541da177e4SLinus Torvalds 355664cceb0SDavid Howells key_revoke(key_ref_to_ptr(key_ref)); 3561da177e4SLinus Torvalds ret = 0; 3571da177e4SLinus Torvalds 358664cceb0SDavid Howells key_ref_put(key_ref); 3591da177e4SLinus Torvalds error: 3601260f801SDavid Howells return ret; 3611da177e4SLinus Torvalds 3621da177e4SLinus Torvalds } /* end keyctl_revoke_key() */ 3631da177e4SLinus Torvalds 3641da177e4SLinus Torvalds /*****************************************************************************/ 3651da177e4SLinus Torvalds /* 3661da177e4SLinus Torvalds * clear the specified process keyring 3671da177e4SLinus Torvalds * - the keyring must be writable 3681da177e4SLinus Torvalds * - implements keyctl(KEYCTL_CLEAR) 3691da177e4SLinus Torvalds */ 3701da177e4SLinus Torvalds long keyctl_keyring_clear(key_serial_t ringid) 3711da177e4SLinus Torvalds { 372664cceb0SDavid Howells key_ref_t keyring_ref; 3731da177e4SLinus Torvalds long ret; 3741da177e4SLinus Torvalds 3755593122eSDavid Howells keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE); 376664cceb0SDavid Howells if (IS_ERR(keyring_ref)) { 377664cceb0SDavid Howells ret = PTR_ERR(keyring_ref); 3781da177e4SLinus Torvalds goto error; 3791da177e4SLinus Torvalds } 3801da177e4SLinus Torvalds 381664cceb0SDavid Howells ret = keyring_clear(key_ref_to_ptr(keyring_ref)); 3821da177e4SLinus Torvalds 383664cceb0SDavid Howells key_ref_put(keyring_ref); 3841da177e4SLinus Torvalds error: 3851da177e4SLinus Torvalds return ret; 3861da177e4SLinus Torvalds 3871da177e4SLinus Torvalds } /* end keyctl_keyring_clear() */ 3881da177e4SLinus Torvalds 3891da177e4SLinus Torvalds /*****************************************************************************/ 3901da177e4SLinus Torvalds /* 3911da177e4SLinus Torvalds * link a key into a keyring 3921da177e4SLinus Torvalds * - the keyring must be writable 3931da177e4SLinus Torvalds * - the key must be linkable 3941da177e4SLinus Torvalds * - implements keyctl(KEYCTL_LINK) 3951da177e4SLinus Torvalds */ 3961da177e4SLinus Torvalds long keyctl_keyring_link(key_serial_t id, key_serial_t ringid) 3971da177e4SLinus Torvalds { 398664cceb0SDavid Howells key_ref_t keyring_ref, key_ref; 3991da177e4SLinus Torvalds long ret; 4001da177e4SLinus Torvalds 4015593122eSDavid Howells keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE); 402664cceb0SDavid Howells if (IS_ERR(keyring_ref)) { 403664cceb0SDavid Howells ret = PTR_ERR(keyring_ref); 4041da177e4SLinus Torvalds goto error; 4051da177e4SLinus Torvalds } 4061da177e4SLinus Torvalds 4075593122eSDavid Howells key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE, KEY_LINK); 408664cceb0SDavid Howells if (IS_ERR(key_ref)) { 409664cceb0SDavid Howells ret = PTR_ERR(key_ref); 4101da177e4SLinus Torvalds goto error2; 4111da177e4SLinus Torvalds } 4121da177e4SLinus Torvalds 413664cceb0SDavid Howells ret = key_link(key_ref_to_ptr(keyring_ref), key_ref_to_ptr(key_ref)); 4141da177e4SLinus Torvalds 415664cceb0SDavid Howells key_ref_put(key_ref); 4161da177e4SLinus Torvalds error2: 417664cceb0SDavid Howells key_ref_put(keyring_ref); 4181da177e4SLinus Torvalds error: 4191da177e4SLinus Torvalds return ret; 4201da177e4SLinus Torvalds 4211da177e4SLinus Torvalds } /* end keyctl_keyring_link() */ 4221da177e4SLinus Torvalds 4231da177e4SLinus Torvalds /*****************************************************************************/ 4241da177e4SLinus Torvalds /* 4251da177e4SLinus Torvalds * unlink the first attachment of a key from a keyring 4261da177e4SLinus Torvalds * - the keyring must be writable 4271da177e4SLinus Torvalds * - we don't need any permissions on the key 4281da177e4SLinus Torvalds * - implements keyctl(KEYCTL_UNLINK) 4291da177e4SLinus Torvalds */ 4301da177e4SLinus Torvalds long keyctl_keyring_unlink(key_serial_t id, key_serial_t ringid) 4311da177e4SLinus Torvalds { 432664cceb0SDavid Howells key_ref_t keyring_ref, key_ref; 4331da177e4SLinus Torvalds long ret; 4341da177e4SLinus Torvalds 4355593122eSDavid Howells keyring_ref = lookup_user_key(ringid, 0, KEY_WRITE); 436664cceb0SDavid Howells if (IS_ERR(keyring_ref)) { 437664cceb0SDavid Howells ret = PTR_ERR(keyring_ref); 4381da177e4SLinus Torvalds goto error; 4391da177e4SLinus Torvalds } 4401da177e4SLinus Torvalds 4415593122eSDavid Howells key_ref = lookup_user_key(id, KEY_LOOKUP_FOR_UNLINK, 0); 442664cceb0SDavid Howells if (IS_ERR(key_ref)) { 443664cceb0SDavid Howells ret = PTR_ERR(key_ref); 4441da177e4SLinus Torvalds goto error2; 4451da177e4SLinus Torvalds } 4461da177e4SLinus Torvalds 447664cceb0SDavid Howells ret = key_unlink(key_ref_to_ptr(keyring_ref), key_ref_to_ptr(key_ref)); 4481da177e4SLinus Torvalds 449664cceb0SDavid Howells key_ref_put(key_ref); 4501da177e4SLinus Torvalds error2: 451664cceb0SDavid Howells key_ref_put(keyring_ref); 4521da177e4SLinus Torvalds error: 4531da177e4SLinus Torvalds return ret; 4541da177e4SLinus Torvalds 4551da177e4SLinus Torvalds } /* end keyctl_keyring_unlink() */ 4561da177e4SLinus Torvalds 4571da177e4SLinus Torvalds /*****************************************************************************/ 4581da177e4SLinus Torvalds /* 4591da177e4SLinus Torvalds * describe a user key 4601da177e4SLinus Torvalds * - the key must have view permission 4611da177e4SLinus Torvalds * - if there's a buffer, we place up to buflen bytes of data into it 4621da177e4SLinus Torvalds * - unless there's an error, we return the amount of description available, 4631da177e4SLinus Torvalds * irrespective of how much we may have copied 4641da177e4SLinus Torvalds * - the description is formatted thus: 4651da177e4SLinus Torvalds * type;uid;gid;perm;description<NUL> 4661da177e4SLinus Torvalds * - implements keyctl(KEYCTL_DESCRIBE) 4671da177e4SLinus Torvalds */ 4681da177e4SLinus Torvalds long keyctl_describe_key(key_serial_t keyid, 4691da177e4SLinus Torvalds char __user *buffer, 4701da177e4SLinus Torvalds size_t buflen) 4711da177e4SLinus Torvalds { 4723e30148cSDavid Howells struct key *key, *instkey; 473664cceb0SDavid Howells key_ref_t key_ref; 4741da177e4SLinus Torvalds char *tmpbuf; 4751da177e4SLinus Torvalds long ret; 4761da177e4SLinus Torvalds 4775593122eSDavid Howells key_ref = lookup_user_key(keyid, KEY_LOOKUP_PARTIAL, KEY_VIEW); 478664cceb0SDavid Howells if (IS_ERR(key_ref)) { 4793e30148cSDavid Howells /* viewing a key under construction is permitted if we have the 4803e30148cSDavid Howells * authorisation token handy */ 481664cceb0SDavid Howells if (PTR_ERR(key_ref) == -EACCES) { 4823e30148cSDavid Howells instkey = key_get_instantiation_authkey(keyid); 4833e30148cSDavid Howells if (!IS_ERR(instkey)) { 4843e30148cSDavid Howells key_put(instkey); 4858bbf4976SDavid Howells key_ref = lookup_user_key(keyid, 4865593122eSDavid Howells KEY_LOOKUP_PARTIAL, 4875593122eSDavid Howells 0); 488664cceb0SDavid Howells if (!IS_ERR(key_ref)) 4893e30148cSDavid Howells goto okay; 4903e30148cSDavid Howells } 4913e30148cSDavid Howells } 4923e30148cSDavid Howells 493664cceb0SDavid Howells ret = PTR_ERR(key_ref); 4941da177e4SLinus Torvalds goto error; 4951da177e4SLinus Torvalds } 4961da177e4SLinus Torvalds 4973e30148cSDavid Howells okay: 4981da177e4SLinus Torvalds /* calculate how much description we're going to return */ 4991da177e4SLinus Torvalds ret = -ENOMEM; 5001da177e4SLinus Torvalds tmpbuf = kmalloc(PAGE_SIZE, GFP_KERNEL); 5011da177e4SLinus Torvalds if (!tmpbuf) 5021da177e4SLinus Torvalds goto error2; 5031da177e4SLinus Torvalds 504664cceb0SDavid Howells key = key_ref_to_ptr(key_ref); 505664cceb0SDavid Howells 5061da177e4SLinus Torvalds ret = snprintf(tmpbuf, PAGE_SIZE - 1, 507664cceb0SDavid Howells "%s;%d;%d;%08x;%s", 508*94fd8405SDavid Howells key->type->name, 509*94fd8405SDavid Howells key->uid, 510*94fd8405SDavid Howells key->gid, 511*94fd8405SDavid Howells key->perm, 512*94fd8405SDavid Howells key->description ?: ""); 5131da177e4SLinus Torvalds 5141da177e4SLinus Torvalds /* include a NUL char at the end of the data */ 5151da177e4SLinus Torvalds if (ret > PAGE_SIZE - 1) 5161da177e4SLinus Torvalds ret = PAGE_SIZE - 1; 5171da177e4SLinus Torvalds tmpbuf[ret] = 0; 5181da177e4SLinus Torvalds ret++; 5191da177e4SLinus Torvalds 5201da177e4SLinus Torvalds /* consider returning the data */ 5211da177e4SLinus Torvalds if (buffer && buflen > 0) { 5221da177e4SLinus Torvalds if (buflen > ret) 5231da177e4SLinus Torvalds buflen = ret; 5241da177e4SLinus Torvalds 5251da177e4SLinus Torvalds if (copy_to_user(buffer, tmpbuf, buflen) != 0) 5261da177e4SLinus Torvalds ret = -EFAULT; 5271da177e4SLinus Torvalds } 5281da177e4SLinus Torvalds 5291da177e4SLinus Torvalds kfree(tmpbuf); 5301da177e4SLinus Torvalds error2: 531664cceb0SDavid Howells key_ref_put(key_ref); 5321da177e4SLinus Torvalds error: 5331da177e4SLinus Torvalds return ret; 5341da177e4SLinus Torvalds 5351da177e4SLinus Torvalds } /* end keyctl_describe_key() */ 5361da177e4SLinus Torvalds 5371da177e4SLinus Torvalds /*****************************************************************************/ 5381da177e4SLinus Torvalds /* 5391da177e4SLinus Torvalds * search the specified keyring for a matching key 5401da177e4SLinus Torvalds * - the start keyring must be searchable 5411da177e4SLinus Torvalds * - nested keyrings may also be searched if they are searchable 5421da177e4SLinus Torvalds * - only keys with search permission may be found 5431da177e4SLinus Torvalds * - if a key is found, it will be attached to the destination keyring if 5441da177e4SLinus Torvalds * there's one specified 5451da177e4SLinus Torvalds * - implements keyctl(KEYCTL_SEARCH) 5461da177e4SLinus Torvalds */ 5471da177e4SLinus Torvalds long keyctl_keyring_search(key_serial_t ringid, 5481da177e4SLinus Torvalds const char __user *_type, 5491da177e4SLinus Torvalds const char __user *_description, 5501da177e4SLinus Torvalds key_serial_t destringid) 5511da177e4SLinus Torvalds { 5521da177e4SLinus Torvalds struct key_type *ktype; 553664cceb0SDavid Howells key_ref_t keyring_ref, key_ref, dest_ref; 5541da177e4SLinus Torvalds char type[32], *description; 5550cb409d9SDavi Arnaut long ret; 5561da177e4SLinus Torvalds 5571da177e4SLinus Torvalds /* pull the type and description into kernel space */ 5580cb409d9SDavi Arnaut ret = key_get_type_from_user(type, _type, sizeof(type)); 5591da177e4SLinus Torvalds if (ret < 0) 5601da177e4SLinus Torvalds goto error; 5611da177e4SLinus Torvalds 5620cb409d9SDavi Arnaut description = strndup_user(_description, PAGE_SIZE); 5630cb409d9SDavi Arnaut if (IS_ERR(description)) { 5640cb409d9SDavi Arnaut ret = PTR_ERR(description); 5651da177e4SLinus Torvalds goto error; 5660cb409d9SDavi Arnaut } 5671da177e4SLinus Torvalds 5681da177e4SLinus Torvalds /* get the keyring at which to begin the search */ 5695593122eSDavid Howells keyring_ref = lookup_user_key(ringid, 0, KEY_SEARCH); 570664cceb0SDavid Howells if (IS_ERR(keyring_ref)) { 571664cceb0SDavid Howells ret = PTR_ERR(keyring_ref); 5721da177e4SLinus Torvalds goto error2; 5731da177e4SLinus Torvalds } 5741da177e4SLinus Torvalds 5751da177e4SLinus Torvalds /* get the destination keyring if specified */ 576664cceb0SDavid Howells dest_ref = NULL; 5771da177e4SLinus Torvalds if (destringid) { 5785593122eSDavid Howells dest_ref = lookup_user_key(destringid, KEY_LOOKUP_CREATE, 5795593122eSDavid Howells KEY_WRITE); 580664cceb0SDavid Howells if (IS_ERR(dest_ref)) { 581664cceb0SDavid Howells ret = PTR_ERR(dest_ref); 5821da177e4SLinus Torvalds goto error3; 5831da177e4SLinus Torvalds } 5841da177e4SLinus Torvalds } 5851da177e4SLinus Torvalds 5861da177e4SLinus Torvalds /* find the key type */ 5871da177e4SLinus Torvalds ktype = key_type_lookup(type); 5881da177e4SLinus Torvalds if (IS_ERR(ktype)) { 5891da177e4SLinus Torvalds ret = PTR_ERR(ktype); 5901da177e4SLinus Torvalds goto error4; 5911da177e4SLinus Torvalds } 5921da177e4SLinus Torvalds 5931da177e4SLinus Torvalds /* do the search */ 594664cceb0SDavid Howells key_ref = keyring_search(keyring_ref, ktype, description); 595664cceb0SDavid Howells if (IS_ERR(key_ref)) { 596664cceb0SDavid Howells ret = PTR_ERR(key_ref); 5971da177e4SLinus Torvalds 5981da177e4SLinus Torvalds /* treat lack or presence of a negative key the same */ 5991da177e4SLinus Torvalds if (ret == -EAGAIN) 6001da177e4SLinus Torvalds ret = -ENOKEY; 6011da177e4SLinus Torvalds goto error5; 6021da177e4SLinus Torvalds } 6031da177e4SLinus Torvalds 6041da177e4SLinus Torvalds /* link the resulting key to the destination keyring if we can */ 605664cceb0SDavid Howells if (dest_ref) { 60629db9190SDavid Howells ret = key_permission(key_ref, KEY_LINK); 60729db9190SDavid Howells if (ret < 0) 6081da177e4SLinus Torvalds goto error6; 6091da177e4SLinus Torvalds 610664cceb0SDavid Howells ret = key_link(key_ref_to_ptr(dest_ref), key_ref_to_ptr(key_ref)); 6111da177e4SLinus Torvalds if (ret < 0) 6121da177e4SLinus Torvalds goto error6; 6131da177e4SLinus Torvalds } 6141da177e4SLinus Torvalds 615664cceb0SDavid Howells ret = key_ref_to_ptr(key_ref)->serial; 6161da177e4SLinus Torvalds 6171da177e4SLinus Torvalds error6: 618664cceb0SDavid Howells key_ref_put(key_ref); 6191da177e4SLinus Torvalds error5: 6201da177e4SLinus Torvalds key_type_put(ktype); 6211da177e4SLinus Torvalds error4: 622664cceb0SDavid Howells key_ref_put(dest_ref); 6231da177e4SLinus Torvalds error3: 624664cceb0SDavid Howells key_ref_put(keyring_ref); 6251da177e4SLinus Torvalds error2: 6261da177e4SLinus Torvalds kfree(description); 6271da177e4SLinus Torvalds error: 6281da177e4SLinus Torvalds return ret; 6291da177e4SLinus Torvalds 6301da177e4SLinus Torvalds } /* end keyctl_keyring_search() */ 6311da177e4SLinus Torvalds 6321da177e4SLinus Torvalds /*****************************************************************************/ 6331da177e4SLinus Torvalds /* 6341da177e4SLinus Torvalds * read a user key's payload 6351da177e4SLinus Torvalds * - the keyring must be readable or the key must be searchable from the 6361da177e4SLinus Torvalds * process's keyrings 6371da177e4SLinus Torvalds * - if there's a buffer, we place up to buflen bytes of data into it 6381da177e4SLinus Torvalds * - unless there's an error, we return the amount of data in the key, 6391da177e4SLinus Torvalds * irrespective of how much we may have copied 6401da177e4SLinus Torvalds * - implements keyctl(KEYCTL_READ) 6411da177e4SLinus Torvalds */ 6421da177e4SLinus Torvalds long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen) 6431da177e4SLinus Torvalds { 644664cceb0SDavid Howells struct key *key; 645664cceb0SDavid Howells key_ref_t key_ref; 6461da177e4SLinus Torvalds long ret; 6471da177e4SLinus Torvalds 6481da177e4SLinus Torvalds /* find the key first */ 6495593122eSDavid Howells key_ref = lookup_user_key(keyid, 0, 0); 650664cceb0SDavid Howells if (IS_ERR(key_ref)) { 651664cceb0SDavid Howells ret = -ENOKEY; 652664cceb0SDavid Howells goto error; 653664cceb0SDavid Howells } 654664cceb0SDavid Howells 655664cceb0SDavid Howells key = key_ref_to_ptr(key_ref); 656664cceb0SDavid Howells 6571da177e4SLinus Torvalds /* see if we can read it directly */ 65829db9190SDavid Howells ret = key_permission(key_ref, KEY_READ); 65929db9190SDavid Howells if (ret == 0) 6601da177e4SLinus Torvalds goto can_read_key; 66129db9190SDavid Howells if (ret != -EACCES) 66229db9190SDavid Howells goto error; 6631da177e4SLinus Torvalds 664664cceb0SDavid Howells /* we can't; see if it's searchable from this process's keyrings 6653e30148cSDavid Howells * - we automatically take account of the fact that it may be 6663e30148cSDavid Howells * dangling off an instantiation key 6673e30148cSDavid Howells */ 668664cceb0SDavid Howells if (!is_key_possessed(key_ref)) { 6691260f801SDavid Howells ret = -EACCES; 6701da177e4SLinus Torvalds goto error2; 6711da177e4SLinus Torvalds } 6721da177e4SLinus Torvalds 6731da177e4SLinus Torvalds /* the key is probably readable - now try to read it */ 6741da177e4SLinus Torvalds can_read_key: 6751da177e4SLinus Torvalds ret = key_validate(key); 6761da177e4SLinus Torvalds if (ret == 0) { 6771da177e4SLinus Torvalds ret = -EOPNOTSUPP; 6781da177e4SLinus Torvalds if (key->type->read) { 6791da177e4SLinus Torvalds /* read the data with the semaphore held (since we 6801da177e4SLinus Torvalds * might sleep) */ 6811da177e4SLinus Torvalds down_read(&key->sem); 6821da177e4SLinus Torvalds ret = key->type->read(key, buffer, buflen); 6831da177e4SLinus Torvalds up_read(&key->sem); 6841da177e4SLinus Torvalds } 6851da177e4SLinus Torvalds } 6861da177e4SLinus Torvalds 6871da177e4SLinus Torvalds error2: 6881da177e4SLinus Torvalds key_put(key); 6891da177e4SLinus Torvalds error: 6901da177e4SLinus Torvalds return ret; 6911da177e4SLinus Torvalds 6921da177e4SLinus Torvalds } /* end keyctl_read_key() */ 6931da177e4SLinus Torvalds 6941da177e4SLinus Torvalds /*****************************************************************************/ 6951da177e4SLinus Torvalds /* 6961da177e4SLinus Torvalds * change the ownership of a key 6971da177e4SLinus Torvalds * - the keyring owned by the changer 6981da177e4SLinus Torvalds * - if the uid or gid is -1, then that parameter is not changed 6991da177e4SLinus Torvalds * - implements keyctl(KEYCTL_CHOWN) 7001da177e4SLinus Torvalds */ 7011da177e4SLinus Torvalds long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid) 7021da177e4SLinus Torvalds { 7035801649dSFredrik Tolf struct key_user *newowner, *zapowner = NULL; 7041da177e4SLinus Torvalds struct key *key; 705664cceb0SDavid Howells key_ref_t key_ref; 7061da177e4SLinus Torvalds long ret; 7071da177e4SLinus Torvalds 7081da177e4SLinus Torvalds ret = 0; 7091da177e4SLinus Torvalds if (uid == (uid_t) -1 && gid == (gid_t) -1) 7101da177e4SLinus Torvalds goto error; 7111da177e4SLinus Torvalds 7125593122eSDavid Howells key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL, 7135593122eSDavid Howells KEY_SETATTR); 714664cceb0SDavid Howells if (IS_ERR(key_ref)) { 715664cceb0SDavid Howells ret = PTR_ERR(key_ref); 7161da177e4SLinus Torvalds goto error; 7171da177e4SLinus Torvalds } 7181da177e4SLinus Torvalds 719664cceb0SDavid Howells key = key_ref_to_ptr(key_ref); 720664cceb0SDavid Howells 7211da177e4SLinus Torvalds /* make the changes with the locks held to prevent chown/chown races */ 7221da177e4SLinus Torvalds ret = -EACCES; 7231da177e4SLinus Torvalds down_write(&key->sem); 7241da177e4SLinus Torvalds 7251da177e4SLinus Torvalds if (!capable(CAP_SYS_ADMIN)) { 7261da177e4SLinus Torvalds /* only the sysadmin can chown a key to some other UID */ 7271da177e4SLinus Torvalds if (uid != (uid_t) -1 && key->uid != uid) 7285801649dSFredrik Tolf goto error_put; 7291da177e4SLinus Torvalds 7301da177e4SLinus Torvalds /* only the sysadmin can set the key's GID to a group other 7311da177e4SLinus Torvalds * than one of those that the current process subscribes to */ 7321da177e4SLinus Torvalds if (gid != (gid_t) -1 && gid != key->gid && !in_group_p(gid)) 7335801649dSFredrik Tolf goto error_put; 7341da177e4SLinus Torvalds } 7351da177e4SLinus Torvalds 7365801649dSFredrik Tolf /* change the UID */ 7371da177e4SLinus Torvalds if (uid != (uid_t) -1 && uid != key->uid) { 7385801649dSFredrik Tolf ret = -ENOMEM; 7391d1e9756SSerge E. Hallyn newowner = key_user_lookup(uid, current_user_ns()); 7405801649dSFredrik Tolf if (!newowner) 7415801649dSFredrik Tolf goto error_put; 7425801649dSFredrik Tolf 7435801649dSFredrik Tolf /* transfer the quota burden to the new user */ 7445801649dSFredrik Tolf if (test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) { 7450b77f5bfSDavid Howells unsigned maxkeys = (uid == 0) ? 7460b77f5bfSDavid Howells key_quota_root_maxkeys : key_quota_maxkeys; 7470b77f5bfSDavid Howells unsigned maxbytes = (uid == 0) ? 7480b77f5bfSDavid Howells key_quota_root_maxbytes : key_quota_maxbytes; 7490b77f5bfSDavid Howells 7505801649dSFredrik Tolf spin_lock(&newowner->lock); 7510b77f5bfSDavid Howells if (newowner->qnkeys + 1 >= maxkeys || 7520b77f5bfSDavid Howells newowner->qnbytes + key->quotalen >= maxbytes || 7530b77f5bfSDavid Howells newowner->qnbytes + key->quotalen < 7540b77f5bfSDavid Howells newowner->qnbytes) 7555801649dSFredrik Tolf goto quota_overrun; 7565801649dSFredrik Tolf 7575801649dSFredrik Tolf newowner->qnkeys++; 7585801649dSFredrik Tolf newowner->qnbytes += key->quotalen; 7595801649dSFredrik Tolf spin_unlock(&newowner->lock); 7605801649dSFredrik Tolf 7615801649dSFredrik Tolf spin_lock(&key->user->lock); 7625801649dSFredrik Tolf key->user->qnkeys--; 7635801649dSFredrik Tolf key->user->qnbytes -= key->quotalen; 7645801649dSFredrik Tolf spin_unlock(&key->user->lock); 7655801649dSFredrik Tolf } 7665801649dSFredrik Tolf 7675801649dSFredrik Tolf atomic_dec(&key->user->nkeys); 7685801649dSFredrik Tolf atomic_inc(&newowner->nkeys); 7695801649dSFredrik Tolf 7705801649dSFredrik Tolf if (test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) { 7715801649dSFredrik Tolf atomic_dec(&key->user->nikeys); 7725801649dSFredrik Tolf atomic_inc(&newowner->nikeys); 7735801649dSFredrik Tolf } 7745801649dSFredrik Tolf 7755801649dSFredrik Tolf zapowner = key->user; 7765801649dSFredrik Tolf key->user = newowner; 7775801649dSFredrik Tolf key->uid = uid; 7781da177e4SLinus Torvalds } 7791da177e4SLinus Torvalds 7801da177e4SLinus Torvalds /* change the GID */ 7811da177e4SLinus Torvalds if (gid != (gid_t) -1) 7821da177e4SLinus Torvalds key->gid = gid; 7831da177e4SLinus Torvalds 7841da177e4SLinus Torvalds ret = 0; 7851da177e4SLinus Torvalds 7865801649dSFredrik Tolf error_put: 7871da177e4SLinus Torvalds up_write(&key->sem); 7881da177e4SLinus Torvalds key_put(key); 7895801649dSFredrik Tolf if (zapowner) 7905801649dSFredrik Tolf key_user_put(zapowner); 7911da177e4SLinus Torvalds error: 7921da177e4SLinus Torvalds return ret; 7931da177e4SLinus Torvalds 7945801649dSFredrik Tolf quota_overrun: 7955801649dSFredrik Tolf spin_unlock(&newowner->lock); 7965801649dSFredrik Tolf zapowner = newowner; 7975801649dSFredrik Tolf ret = -EDQUOT; 7985801649dSFredrik Tolf goto error_put; 7995801649dSFredrik Tolf 8001da177e4SLinus Torvalds } /* end keyctl_chown_key() */ 8011da177e4SLinus Torvalds 8021da177e4SLinus Torvalds /*****************************************************************************/ 8031da177e4SLinus Torvalds /* 8041da177e4SLinus Torvalds * change the permission mask on a key 8051da177e4SLinus Torvalds * - the keyring owned by the changer 8061da177e4SLinus Torvalds * - implements keyctl(KEYCTL_SETPERM) 8071da177e4SLinus Torvalds */ 8081da177e4SLinus Torvalds long keyctl_setperm_key(key_serial_t id, key_perm_t perm) 8091da177e4SLinus Torvalds { 8101da177e4SLinus Torvalds struct key *key; 811664cceb0SDavid Howells key_ref_t key_ref; 8121da177e4SLinus Torvalds long ret; 8131da177e4SLinus Torvalds 8141da177e4SLinus Torvalds ret = -EINVAL; 815664cceb0SDavid Howells if (perm & ~(KEY_POS_ALL | KEY_USR_ALL | KEY_GRP_ALL | KEY_OTH_ALL)) 8161da177e4SLinus Torvalds goto error; 8171da177e4SLinus Torvalds 8185593122eSDavid Howells key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL, 8195593122eSDavid Howells KEY_SETATTR); 820664cceb0SDavid Howells if (IS_ERR(key_ref)) { 821664cceb0SDavid Howells ret = PTR_ERR(key_ref); 8221da177e4SLinus Torvalds goto error; 8231da177e4SLinus Torvalds } 8241da177e4SLinus Torvalds 825664cceb0SDavid Howells key = key_ref_to_ptr(key_ref); 826664cceb0SDavid Howells 82776d8aeabSDavid Howells /* make the changes with the locks held to prevent chown/chmod races */ 8281da177e4SLinus Torvalds ret = -EACCES; 8291da177e4SLinus Torvalds down_write(&key->sem); 8301da177e4SLinus Torvalds 83176d8aeabSDavid Howells /* if we're not the sysadmin, we can only change a key that we own */ 83247d804bfSDavid Howells if (capable(CAP_SYS_ADMIN) || key->uid == current_fsuid()) { 8331da177e4SLinus Torvalds key->perm = perm; 8341da177e4SLinus Torvalds ret = 0; 83576d8aeabSDavid Howells } 8361da177e4SLinus Torvalds 8371da177e4SLinus Torvalds up_write(&key->sem); 8381da177e4SLinus Torvalds key_put(key); 8391da177e4SLinus Torvalds error: 8401da177e4SLinus Torvalds return ret; 8411da177e4SLinus Torvalds 8421da177e4SLinus Torvalds } /* end keyctl_setperm_key() */ 8431da177e4SLinus Torvalds 8448bbf4976SDavid Howells /* 8458bbf4976SDavid Howells * get the destination keyring for instantiation 8468bbf4976SDavid Howells */ 8478bbf4976SDavid Howells static long get_instantiation_keyring(key_serial_t ringid, 8488bbf4976SDavid Howells struct request_key_auth *rka, 8498bbf4976SDavid Howells struct key **_dest_keyring) 8508bbf4976SDavid Howells { 8518bbf4976SDavid Howells key_ref_t dkref; 8528bbf4976SDavid Howells 8538bbf4976SDavid Howells *_dest_keyring = NULL; 854eca1bf5bSDavid Howells 855eca1bf5bSDavid Howells /* just return a NULL pointer if we weren't asked to make a link */ 856eca1bf5bSDavid Howells if (ringid == 0) 8578bbf4976SDavid Howells return 0; 8588bbf4976SDavid Howells 8598bbf4976SDavid Howells /* if a specific keyring is nominated by ID, then use that */ 8608bbf4976SDavid Howells if (ringid > 0) { 8615593122eSDavid Howells dkref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE); 8628bbf4976SDavid Howells if (IS_ERR(dkref)) 8638bbf4976SDavid Howells return PTR_ERR(dkref); 8648bbf4976SDavid Howells *_dest_keyring = key_ref_to_ptr(dkref); 8658bbf4976SDavid Howells return 0; 8668bbf4976SDavid Howells } 8678bbf4976SDavid Howells 8688bbf4976SDavid Howells if (ringid == KEY_SPEC_REQKEY_AUTH_KEY) 8698bbf4976SDavid Howells return -EINVAL; 8708bbf4976SDavid Howells 8718bbf4976SDavid Howells /* otherwise specify the destination keyring recorded in the 8728bbf4976SDavid Howells * authorisation key (any KEY_SPEC_*_KEYRING) */ 8738bbf4976SDavid Howells if (ringid >= KEY_SPEC_REQUESTOR_KEYRING) { 87421279cfaSDavid Howells *_dest_keyring = key_get(rka->dest_keyring); 8758bbf4976SDavid Howells return 0; 8768bbf4976SDavid Howells } 8778bbf4976SDavid Howells 8788bbf4976SDavid Howells return -ENOKEY; 8798bbf4976SDavid Howells } 8808bbf4976SDavid Howells 881d84f4f99SDavid Howells /* 882d84f4f99SDavid Howells * change the request_key authorisation key on the current process 883d84f4f99SDavid Howells */ 884d84f4f99SDavid Howells static int keyctl_change_reqkey_auth(struct key *key) 885d84f4f99SDavid Howells { 886d84f4f99SDavid Howells struct cred *new; 887d84f4f99SDavid Howells 888d84f4f99SDavid Howells new = prepare_creds(); 889d84f4f99SDavid Howells if (!new) 890d84f4f99SDavid Howells return -ENOMEM; 891d84f4f99SDavid Howells 892d84f4f99SDavid Howells key_put(new->request_key_auth); 893d84f4f99SDavid Howells new->request_key_auth = key_get(key); 894d84f4f99SDavid Howells 895d84f4f99SDavid Howells return commit_creds(new); 896d84f4f99SDavid Howells } 897d84f4f99SDavid Howells 8981da177e4SLinus Torvalds /*****************************************************************************/ 8991da177e4SLinus Torvalds /* 9001da177e4SLinus Torvalds * instantiate the key with the specified payload, and, if one is given, link 9011da177e4SLinus Torvalds * the key into the keyring 9021da177e4SLinus Torvalds */ 9031da177e4SLinus Torvalds long keyctl_instantiate_key(key_serial_t id, 9041da177e4SLinus Torvalds const void __user *_payload, 9051da177e4SLinus Torvalds size_t plen, 9061da177e4SLinus Torvalds key_serial_t ringid) 9071da177e4SLinus Torvalds { 908d84f4f99SDavid Howells const struct cred *cred = current_cred(); 9093e30148cSDavid Howells struct request_key_auth *rka; 9108bbf4976SDavid Howells struct key *instkey, *dest_keyring; 9111da177e4SLinus Torvalds void *payload; 9121da177e4SLinus Torvalds long ret; 91338bbca6bSDavid Howells bool vm = false; 9141da177e4SLinus Torvalds 915d84f4f99SDavid Howells kenter("%d,,%zu,%d", id, plen, ringid); 916d84f4f99SDavid Howells 9171da177e4SLinus Torvalds ret = -EINVAL; 91838bbca6bSDavid Howells if (plen > 1024 * 1024 - 1) 9191da177e4SLinus Torvalds goto error; 9201da177e4SLinus Torvalds 921b5f545c8SDavid Howells /* the appropriate instantiation authorisation key must have been 922b5f545c8SDavid Howells * assumed before calling this */ 923b5f545c8SDavid Howells ret = -EPERM; 924d84f4f99SDavid Howells instkey = cred->request_key_auth; 925b5f545c8SDavid Howells if (!instkey) 926b5f545c8SDavid Howells goto error; 927b5f545c8SDavid Howells 928b5f545c8SDavid Howells rka = instkey->payload.data; 929b5f545c8SDavid Howells if (rka->target_key->serial != id) 930b5f545c8SDavid Howells goto error; 931b5f545c8SDavid Howells 9321da177e4SLinus Torvalds /* pull the payload in if one was supplied */ 9331da177e4SLinus Torvalds payload = NULL; 9341da177e4SLinus Torvalds 9351da177e4SLinus Torvalds if (_payload) { 9361da177e4SLinus Torvalds ret = -ENOMEM; 9371da177e4SLinus Torvalds payload = kmalloc(plen, GFP_KERNEL); 93838bbca6bSDavid Howells if (!payload) { 93938bbca6bSDavid Howells if (plen <= PAGE_SIZE) 94038bbca6bSDavid Howells goto error; 94138bbca6bSDavid Howells vm = true; 94238bbca6bSDavid Howells payload = vmalloc(plen); 9431da177e4SLinus Torvalds if (!payload) 9441da177e4SLinus Torvalds goto error; 94538bbca6bSDavid Howells } 9461da177e4SLinus Torvalds 9471da177e4SLinus Torvalds ret = -EFAULT; 9481da177e4SLinus Torvalds if (copy_from_user(payload, _payload, plen) != 0) 9491da177e4SLinus Torvalds goto error2; 9501da177e4SLinus Torvalds } 9511da177e4SLinus Torvalds 9523e30148cSDavid Howells /* find the destination keyring amongst those belonging to the 9533e30148cSDavid Howells * requesting task */ 9548bbf4976SDavid Howells ret = get_instantiation_keyring(ringid, rka, &dest_keyring); 9558bbf4976SDavid Howells if (ret < 0) 956b5f545c8SDavid Howells goto error2; 9571da177e4SLinus Torvalds 9581da177e4SLinus Torvalds /* instantiate the key and link it into a keyring */ 9593e30148cSDavid Howells ret = key_instantiate_and_link(rka->target_key, payload, plen, 9608bbf4976SDavid Howells dest_keyring, instkey); 9611da177e4SLinus Torvalds 9628bbf4976SDavid Howells key_put(dest_keyring); 963b5f545c8SDavid Howells 964b5f545c8SDavid Howells /* discard the assumed authority if it's just been disabled by 965b5f545c8SDavid Howells * instantiation of the key */ 966d84f4f99SDavid Howells if (ret == 0) 967d84f4f99SDavid Howells keyctl_change_reqkey_auth(NULL); 968b5f545c8SDavid Howells 9691da177e4SLinus Torvalds error2: 97038bbca6bSDavid Howells if (!vm) 9711da177e4SLinus Torvalds kfree(payload); 97238bbca6bSDavid Howells else 97338bbca6bSDavid Howells vfree(payload); 9741da177e4SLinus Torvalds error: 9751da177e4SLinus Torvalds return ret; 9761da177e4SLinus Torvalds 9771da177e4SLinus Torvalds } /* end keyctl_instantiate_key() */ 9781da177e4SLinus Torvalds 9791da177e4SLinus Torvalds /*****************************************************************************/ 9801da177e4SLinus Torvalds /* 9811da177e4SLinus Torvalds * negatively instantiate the key with the given timeout (in seconds), and, if 9821da177e4SLinus Torvalds * one is given, link the key into the keyring 9831da177e4SLinus Torvalds */ 9841da177e4SLinus Torvalds long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid) 9851da177e4SLinus Torvalds { 986d84f4f99SDavid Howells const struct cred *cred = current_cred(); 9873e30148cSDavid Howells struct request_key_auth *rka; 9888bbf4976SDavid Howells struct key *instkey, *dest_keyring; 9891da177e4SLinus Torvalds long ret; 9901da177e4SLinus Torvalds 991d84f4f99SDavid Howells kenter("%d,%u,%d", id, timeout, ringid); 992d84f4f99SDavid Howells 993b5f545c8SDavid Howells /* the appropriate instantiation authorisation key must have been 994b5f545c8SDavid Howells * assumed before calling this */ 995b5f545c8SDavid Howells ret = -EPERM; 996d84f4f99SDavid Howells instkey = cred->request_key_auth; 997b5f545c8SDavid Howells if (!instkey) 9981da177e4SLinus Torvalds goto error; 9991da177e4SLinus Torvalds 10003e30148cSDavid Howells rka = instkey->payload.data; 1001b5f545c8SDavid Howells if (rka->target_key->serial != id) 1002b5f545c8SDavid Howells goto error; 10033e30148cSDavid Howells 10041da177e4SLinus Torvalds /* find the destination keyring if present (which must also be 10051da177e4SLinus Torvalds * writable) */ 10068bbf4976SDavid Howells ret = get_instantiation_keyring(ringid, rka, &dest_keyring); 10078bbf4976SDavid Howells if (ret < 0) 1008b5f545c8SDavid Howells goto error; 10091da177e4SLinus Torvalds 10101da177e4SLinus Torvalds /* instantiate the key and link it into a keyring */ 1011664cceb0SDavid Howells ret = key_negate_and_link(rka->target_key, timeout, 10128bbf4976SDavid Howells dest_keyring, instkey); 10131da177e4SLinus Torvalds 10148bbf4976SDavid Howells key_put(dest_keyring); 1015b5f545c8SDavid Howells 1016b5f545c8SDavid Howells /* discard the assumed authority if it's just been disabled by 1017b5f545c8SDavid Howells * instantiation of the key */ 1018d84f4f99SDavid Howells if (ret == 0) 1019d84f4f99SDavid Howells keyctl_change_reqkey_auth(NULL); 1020b5f545c8SDavid Howells 10211da177e4SLinus Torvalds error: 10221da177e4SLinus Torvalds return ret; 10231da177e4SLinus Torvalds 10241da177e4SLinus Torvalds } /* end keyctl_negate_key() */ 10251da177e4SLinus Torvalds 10261da177e4SLinus Torvalds /*****************************************************************************/ 10271da177e4SLinus Torvalds /* 10283e30148cSDavid Howells * set the default keyring in which request_key() will cache keys 10293e30148cSDavid Howells * - return the old setting 10303e30148cSDavid Howells */ 10313e30148cSDavid Howells long keyctl_set_reqkey_keyring(int reqkey_defl) 10323e30148cSDavid Howells { 1033d84f4f99SDavid Howells struct cred *new; 1034d84f4f99SDavid Howells int ret, old_setting; 1035d84f4f99SDavid Howells 1036d84f4f99SDavid Howells old_setting = current_cred_xxx(jit_keyring); 1037d84f4f99SDavid Howells 1038d84f4f99SDavid Howells if (reqkey_defl == KEY_REQKEY_DEFL_NO_CHANGE) 1039d84f4f99SDavid Howells return old_setting; 1040d84f4f99SDavid Howells 1041d84f4f99SDavid Howells new = prepare_creds(); 1042d84f4f99SDavid Howells if (!new) 1043d84f4f99SDavid Howells return -ENOMEM; 10443e30148cSDavid Howells 10453e30148cSDavid Howells switch (reqkey_defl) { 10463e30148cSDavid Howells case KEY_REQKEY_DEFL_THREAD_KEYRING: 1047d84f4f99SDavid Howells ret = install_thread_keyring_to_cred(new); 10483e30148cSDavid Howells if (ret < 0) 1049d84f4f99SDavid Howells goto error; 10503e30148cSDavid Howells goto set; 10513e30148cSDavid Howells 10523e30148cSDavid Howells case KEY_REQKEY_DEFL_PROCESS_KEYRING: 1053d84f4f99SDavid Howells ret = install_process_keyring_to_cred(new); 1054d84f4f99SDavid Howells if (ret < 0) { 1055d84f4f99SDavid Howells if (ret != -EEXIST) 1056d84f4f99SDavid Howells goto error; 1057d84f4f99SDavid Howells ret = 0; 1058d84f4f99SDavid Howells } 1059d84f4f99SDavid Howells goto set; 10603e30148cSDavid Howells 10613e30148cSDavid Howells case KEY_REQKEY_DEFL_DEFAULT: 10623e30148cSDavid Howells case KEY_REQKEY_DEFL_SESSION_KEYRING: 10633e30148cSDavid Howells case KEY_REQKEY_DEFL_USER_KEYRING: 10643e30148cSDavid Howells case KEY_REQKEY_DEFL_USER_SESSION_KEYRING: 1065d84f4f99SDavid Howells case KEY_REQKEY_DEFL_REQUESTOR_KEYRING: 1066d84f4f99SDavid Howells goto set; 10673e30148cSDavid Howells 10683e30148cSDavid Howells case KEY_REQKEY_DEFL_NO_CHANGE: 10693e30148cSDavid Howells case KEY_REQKEY_DEFL_GROUP_KEYRING: 10703e30148cSDavid Howells default: 1071d84f4f99SDavid Howells ret = -EINVAL; 1072d84f4f99SDavid Howells goto error; 10733e30148cSDavid Howells } 10743e30148cSDavid Howells 1075d84f4f99SDavid Howells set: 1076d84f4f99SDavid Howells new->jit_keyring = reqkey_defl; 1077d84f4f99SDavid Howells commit_creds(new); 1078d84f4f99SDavid Howells return old_setting; 1079d84f4f99SDavid Howells error: 1080d84f4f99SDavid Howells abort_creds(new); 10814303ef19SDan Carpenter return ret; 1082d84f4f99SDavid Howells 10833e30148cSDavid Howells } /* end keyctl_set_reqkey_keyring() */ 10843e30148cSDavid Howells 10853e30148cSDavid Howells /*****************************************************************************/ 10863e30148cSDavid Howells /* 1087017679c4SDavid Howells * set or clear the timeout for a key 1088017679c4SDavid Howells */ 1089017679c4SDavid Howells long keyctl_set_timeout(key_serial_t id, unsigned timeout) 1090017679c4SDavid Howells { 1091017679c4SDavid Howells struct timespec now; 10929156235bSDavid Howells struct key *key, *instkey; 1093017679c4SDavid Howells key_ref_t key_ref; 1094017679c4SDavid Howells time_t expiry; 1095017679c4SDavid Howells long ret; 1096017679c4SDavid Howells 10975593122eSDavid Howells key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL, 10985593122eSDavid Howells KEY_SETATTR); 1099017679c4SDavid Howells if (IS_ERR(key_ref)) { 11009156235bSDavid Howells /* setting the timeout on a key under construction is permitted 11019156235bSDavid Howells * if we have the authorisation token handy */ 11029156235bSDavid Howells if (PTR_ERR(key_ref) == -EACCES) { 11039156235bSDavid Howells instkey = key_get_instantiation_authkey(id); 11049156235bSDavid Howells if (!IS_ERR(instkey)) { 11059156235bSDavid Howells key_put(instkey); 11069156235bSDavid Howells key_ref = lookup_user_key(id, 11079156235bSDavid Howells KEY_LOOKUP_PARTIAL, 11089156235bSDavid Howells 0); 11099156235bSDavid Howells if (!IS_ERR(key_ref)) 11109156235bSDavid Howells goto okay; 11119156235bSDavid Howells } 11129156235bSDavid Howells } 11139156235bSDavid Howells 1114017679c4SDavid Howells ret = PTR_ERR(key_ref); 1115017679c4SDavid Howells goto error; 1116017679c4SDavid Howells } 1117017679c4SDavid Howells 11189156235bSDavid Howells okay: 1119017679c4SDavid Howells key = key_ref_to_ptr(key_ref); 1120017679c4SDavid Howells 1121017679c4SDavid Howells /* make the changes with the locks held to prevent races */ 1122017679c4SDavid Howells down_write(&key->sem); 1123017679c4SDavid Howells 1124017679c4SDavid Howells expiry = 0; 1125017679c4SDavid Howells if (timeout > 0) { 1126017679c4SDavid Howells now = current_kernel_time(); 1127017679c4SDavid Howells expiry = now.tv_sec + timeout; 1128017679c4SDavid Howells } 1129017679c4SDavid Howells 1130017679c4SDavid Howells key->expiry = expiry; 1131c08ef808SDavid Howells key_schedule_gc(key->expiry + key_gc_delay); 1132017679c4SDavid Howells 1133017679c4SDavid Howells up_write(&key->sem); 1134017679c4SDavid Howells key_put(key); 1135017679c4SDavid Howells 1136017679c4SDavid Howells ret = 0; 1137017679c4SDavid Howells error: 1138017679c4SDavid Howells return ret; 1139017679c4SDavid Howells 1140017679c4SDavid Howells } /* end keyctl_set_timeout() */ 1141017679c4SDavid Howells 1142017679c4SDavid Howells /*****************************************************************************/ 1143017679c4SDavid Howells /* 1144b5f545c8SDavid Howells * assume the authority to instantiate the specified key 1145b5f545c8SDavid Howells */ 1146b5f545c8SDavid Howells long keyctl_assume_authority(key_serial_t id) 1147b5f545c8SDavid Howells { 1148b5f545c8SDavid Howells struct key *authkey; 1149b5f545c8SDavid Howells long ret; 1150b5f545c8SDavid Howells 1151b5f545c8SDavid Howells /* special key IDs aren't permitted */ 1152b5f545c8SDavid Howells ret = -EINVAL; 1153b5f545c8SDavid Howells if (id < 0) 1154b5f545c8SDavid Howells goto error; 1155b5f545c8SDavid Howells 1156b5f545c8SDavid Howells /* we divest ourselves of authority if given an ID of 0 */ 1157b5f545c8SDavid Howells if (id == 0) { 1158d84f4f99SDavid Howells ret = keyctl_change_reqkey_auth(NULL); 1159b5f545c8SDavid Howells goto error; 1160b5f545c8SDavid Howells } 1161b5f545c8SDavid Howells 1162b5f545c8SDavid Howells /* attempt to assume the authority temporarily granted to us whilst we 1163b5f545c8SDavid Howells * instantiate the specified key 1164b5f545c8SDavid Howells * - the authorisation key must be in the current task's keyrings 1165b5f545c8SDavid Howells * somewhere 1166b5f545c8SDavid Howells */ 1167b5f545c8SDavid Howells authkey = key_get_instantiation_authkey(id); 1168b5f545c8SDavid Howells if (IS_ERR(authkey)) { 1169b5f545c8SDavid Howells ret = PTR_ERR(authkey); 1170b5f545c8SDavid Howells goto error; 1171b5f545c8SDavid Howells } 1172b5f545c8SDavid Howells 1173d84f4f99SDavid Howells ret = keyctl_change_reqkey_auth(authkey); 1174d84f4f99SDavid Howells if (ret < 0) 1175d84f4f99SDavid Howells goto error; 1176d84f4f99SDavid Howells key_put(authkey); 1177b5f545c8SDavid Howells 1178d84f4f99SDavid Howells ret = authkey->serial; 1179b5f545c8SDavid Howells error: 1180b5f545c8SDavid Howells return ret; 1181b5f545c8SDavid Howells 1182b5f545c8SDavid Howells } /* end keyctl_assume_authority() */ 1183b5f545c8SDavid Howells 118470a5bb72SDavid Howells /* 118570a5bb72SDavid Howells * get the security label of a key 118670a5bb72SDavid Howells * - the key must grant us view permission 118770a5bb72SDavid Howells * - if there's a buffer, we place up to buflen bytes of data into it 118870a5bb72SDavid Howells * - unless there's an error, we return the amount of information available, 118970a5bb72SDavid Howells * irrespective of how much we may have copied (including the terminal NUL) 119070a5bb72SDavid Howells * - implements keyctl(KEYCTL_GET_SECURITY) 119170a5bb72SDavid Howells */ 119270a5bb72SDavid Howells long keyctl_get_security(key_serial_t keyid, 119370a5bb72SDavid Howells char __user *buffer, 119470a5bb72SDavid Howells size_t buflen) 119570a5bb72SDavid Howells { 119670a5bb72SDavid Howells struct key *key, *instkey; 119770a5bb72SDavid Howells key_ref_t key_ref; 119870a5bb72SDavid Howells char *context; 119970a5bb72SDavid Howells long ret; 120070a5bb72SDavid Howells 12015593122eSDavid Howells key_ref = lookup_user_key(keyid, KEY_LOOKUP_PARTIAL, KEY_VIEW); 120270a5bb72SDavid Howells if (IS_ERR(key_ref)) { 120370a5bb72SDavid Howells if (PTR_ERR(key_ref) != -EACCES) 120470a5bb72SDavid Howells return PTR_ERR(key_ref); 120570a5bb72SDavid Howells 120670a5bb72SDavid Howells /* viewing a key under construction is also permitted if we 120770a5bb72SDavid Howells * have the authorisation token handy */ 120870a5bb72SDavid Howells instkey = key_get_instantiation_authkey(keyid); 120970a5bb72SDavid Howells if (IS_ERR(instkey)) 1210fa1cc7b5SRoel Kluin return PTR_ERR(instkey); 121170a5bb72SDavid Howells key_put(instkey); 121270a5bb72SDavid Howells 12135593122eSDavid Howells key_ref = lookup_user_key(keyid, KEY_LOOKUP_PARTIAL, 0); 121470a5bb72SDavid Howells if (IS_ERR(key_ref)) 121570a5bb72SDavid Howells return PTR_ERR(key_ref); 121670a5bb72SDavid Howells } 121770a5bb72SDavid Howells 121870a5bb72SDavid Howells key = key_ref_to_ptr(key_ref); 121970a5bb72SDavid Howells ret = security_key_getsecurity(key, &context); 122070a5bb72SDavid Howells if (ret == 0) { 122170a5bb72SDavid Howells /* if no information was returned, give userspace an empty 122270a5bb72SDavid Howells * string */ 122370a5bb72SDavid Howells ret = 1; 122470a5bb72SDavid Howells if (buffer && buflen > 0 && 122570a5bb72SDavid Howells copy_to_user(buffer, "", 1) != 0) 122670a5bb72SDavid Howells ret = -EFAULT; 122770a5bb72SDavid Howells } else if (ret > 0) { 122870a5bb72SDavid Howells /* return as much data as there's room for */ 122970a5bb72SDavid Howells if (buffer && buflen > 0) { 123070a5bb72SDavid Howells if (buflen > ret) 123170a5bb72SDavid Howells buflen = ret; 123270a5bb72SDavid Howells 123370a5bb72SDavid Howells if (copy_to_user(buffer, context, buflen) != 0) 123470a5bb72SDavid Howells ret = -EFAULT; 123570a5bb72SDavid Howells } 123670a5bb72SDavid Howells 123770a5bb72SDavid Howells kfree(context); 123870a5bb72SDavid Howells } 123970a5bb72SDavid Howells 124070a5bb72SDavid Howells key_ref_put(key_ref); 124170a5bb72SDavid Howells return ret; 124270a5bb72SDavid Howells } 124370a5bb72SDavid Howells 1244ee18d64cSDavid Howells /* 1245ee18d64cSDavid Howells * attempt to install the calling process's session keyring on the process's 1246ee18d64cSDavid Howells * parent process 1247ee18d64cSDavid Howells * - the keyring must exist and must grant us LINK permission 1248ee18d64cSDavid Howells * - implements keyctl(KEYCTL_SESSION_TO_PARENT) 1249ee18d64cSDavid Howells */ 1250ee18d64cSDavid Howells long keyctl_session_to_parent(void) 1251ee18d64cSDavid Howells { 1252a00ae4d2SGeert Uytterhoeven #ifdef TIF_NOTIFY_RESUME 1253ee18d64cSDavid Howells struct task_struct *me, *parent; 1254ee18d64cSDavid Howells const struct cred *mycred, *pcred; 1255ee18d64cSDavid Howells struct cred *cred, *oldcred; 1256ee18d64cSDavid Howells key_ref_t keyring_r; 1257ee18d64cSDavid Howells int ret; 1258ee18d64cSDavid Howells 1259ee18d64cSDavid Howells keyring_r = lookup_user_key(KEY_SPEC_SESSION_KEYRING, 0, KEY_LINK); 1260ee18d64cSDavid Howells if (IS_ERR(keyring_r)) 1261ee18d64cSDavid Howells return PTR_ERR(keyring_r); 1262ee18d64cSDavid Howells 1263ee18d64cSDavid Howells /* our parent is going to need a new cred struct, a new tgcred struct 1264ee18d64cSDavid Howells * and new security data, so we allocate them here to prevent ENOMEM in 1265ee18d64cSDavid Howells * our parent */ 1266ee18d64cSDavid Howells ret = -ENOMEM; 1267ee18d64cSDavid Howells cred = cred_alloc_blank(); 1268ee18d64cSDavid Howells if (!cred) 1269ee18d64cSDavid Howells goto error_keyring; 1270ee18d64cSDavid Howells 1271ee18d64cSDavid Howells cred->tgcred->session_keyring = key_ref_to_ptr(keyring_r); 1272ee18d64cSDavid Howells keyring_r = NULL; 1273ee18d64cSDavid Howells 1274ee18d64cSDavid Howells me = current; 1275ee18d64cSDavid Howells write_lock_irq(&tasklist_lock); 1276ee18d64cSDavid Howells 1277ee18d64cSDavid Howells parent = me->real_parent; 1278ee18d64cSDavid Howells ret = -EPERM; 1279ee18d64cSDavid Howells 1280ee18d64cSDavid Howells /* the parent mustn't be init and mustn't be a kernel thread */ 1281ee18d64cSDavid Howells if (parent->pid <= 1 || !parent->mm) 1282ee18d64cSDavid Howells goto not_permitted; 1283ee18d64cSDavid Howells 1284ee18d64cSDavid Howells /* the parent must be single threaded */ 1285dd98acf7SOleg Nesterov if (!thread_group_empty(parent)) 1286ee18d64cSDavid Howells goto not_permitted; 1287ee18d64cSDavid Howells 1288ee18d64cSDavid Howells /* the parent and the child must have different session keyrings or 1289ee18d64cSDavid Howells * there's no point */ 1290ee18d64cSDavid Howells mycred = current_cred(); 1291ee18d64cSDavid Howells pcred = __task_cred(parent); 1292ee18d64cSDavid Howells if (mycred == pcred || 1293ee18d64cSDavid Howells mycred->tgcred->session_keyring == pcred->tgcred->session_keyring) 1294ee18d64cSDavid Howells goto already_same; 1295ee18d64cSDavid Howells 1296ee18d64cSDavid Howells /* the parent must have the same effective ownership and mustn't be 1297ee18d64cSDavid Howells * SUID/SGID */ 1298ee18d64cSDavid Howells if (pcred->uid != mycred->euid || 1299ee18d64cSDavid Howells pcred->euid != mycred->euid || 1300ee18d64cSDavid Howells pcred->suid != mycred->euid || 1301ee18d64cSDavid Howells pcred->gid != mycred->egid || 1302ee18d64cSDavid Howells pcred->egid != mycred->egid || 1303ee18d64cSDavid Howells pcred->sgid != mycred->egid) 1304ee18d64cSDavid Howells goto not_permitted; 1305ee18d64cSDavid Howells 1306ee18d64cSDavid Howells /* the keyrings must have the same UID */ 1307ee18d64cSDavid Howells if (pcred->tgcred->session_keyring->uid != mycred->euid || 1308ee18d64cSDavid Howells mycred->tgcred->session_keyring->uid != mycred->euid) 1309ee18d64cSDavid Howells goto not_permitted; 1310ee18d64cSDavid Howells 1311ee18d64cSDavid Howells /* if there's an already pending keyring replacement, then we replace 1312ee18d64cSDavid Howells * that */ 1313ee18d64cSDavid Howells oldcred = parent->replacement_session_keyring; 1314ee18d64cSDavid Howells 1315ee18d64cSDavid Howells /* the replacement session keyring is applied just prior to userspace 1316ee18d64cSDavid Howells * restarting */ 1317ee18d64cSDavid Howells parent->replacement_session_keyring = cred; 1318ee18d64cSDavid Howells cred = NULL; 1319ee18d64cSDavid Howells set_ti_thread_flag(task_thread_info(parent), TIF_NOTIFY_RESUME); 1320ee18d64cSDavid Howells 1321ee18d64cSDavid Howells write_unlock_irq(&tasklist_lock); 1322ee18d64cSDavid Howells if (oldcred) 1323ee18d64cSDavid Howells put_cred(oldcred); 1324ee18d64cSDavid Howells return 0; 1325ee18d64cSDavid Howells 1326ee18d64cSDavid Howells already_same: 1327ee18d64cSDavid Howells ret = 0; 1328ee18d64cSDavid Howells not_permitted: 13295c84342aSMarc Dionne write_unlock_irq(&tasklist_lock); 1330ee18d64cSDavid Howells put_cred(cred); 1331ee18d64cSDavid Howells return ret; 1332ee18d64cSDavid Howells 1333ee18d64cSDavid Howells error_keyring: 1334ee18d64cSDavid Howells key_ref_put(keyring_r); 1335ee18d64cSDavid Howells return ret; 1336a00ae4d2SGeert Uytterhoeven 1337a00ae4d2SGeert Uytterhoeven #else /* !TIF_NOTIFY_RESUME */ 1338a00ae4d2SGeert Uytterhoeven /* 1339a00ae4d2SGeert Uytterhoeven * To be removed when TIF_NOTIFY_RESUME has been implemented on 1340a00ae4d2SGeert Uytterhoeven * m68k/xtensa 1341a00ae4d2SGeert Uytterhoeven */ 1342a00ae4d2SGeert Uytterhoeven #warning TIF_NOTIFY_RESUME not implemented 1343a00ae4d2SGeert Uytterhoeven return -EOPNOTSUPP; 1344a00ae4d2SGeert Uytterhoeven #endif /* !TIF_NOTIFY_RESUME */ 1345ee18d64cSDavid Howells } 1346ee18d64cSDavid Howells 1347b5f545c8SDavid Howells /*****************************************************************************/ 1348b5f545c8SDavid Howells /* 13491da177e4SLinus Torvalds * the key control system call 13501da177e4SLinus Torvalds */ 1351938bb9f5SHeiko Carstens SYSCALL_DEFINE5(keyctl, int, option, unsigned long, arg2, unsigned long, arg3, 1352938bb9f5SHeiko Carstens unsigned long, arg4, unsigned long, arg5) 13531da177e4SLinus Torvalds { 13541da177e4SLinus Torvalds switch (option) { 13551da177e4SLinus Torvalds case KEYCTL_GET_KEYRING_ID: 13561da177e4SLinus Torvalds return keyctl_get_keyring_ID((key_serial_t) arg2, 13571da177e4SLinus Torvalds (int) arg3); 13581da177e4SLinus Torvalds 13591da177e4SLinus Torvalds case KEYCTL_JOIN_SESSION_KEYRING: 13601da177e4SLinus Torvalds return keyctl_join_session_keyring((const char __user *) arg2); 13611da177e4SLinus Torvalds 13621da177e4SLinus Torvalds case KEYCTL_UPDATE: 13631da177e4SLinus Torvalds return keyctl_update_key((key_serial_t) arg2, 13641da177e4SLinus Torvalds (const void __user *) arg3, 13651da177e4SLinus Torvalds (size_t) arg4); 13661da177e4SLinus Torvalds 13671da177e4SLinus Torvalds case KEYCTL_REVOKE: 13681da177e4SLinus Torvalds return keyctl_revoke_key((key_serial_t) arg2); 13691da177e4SLinus Torvalds 13701da177e4SLinus Torvalds case KEYCTL_DESCRIBE: 13711da177e4SLinus Torvalds return keyctl_describe_key((key_serial_t) arg2, 13721da177e4SLinus Torvalds (char __user *) arg3, 13731da177e4SLinus Torvalds (unsigned) arg4); 13741da177e4SLinus Torvalds 13751da177e4SLinus Torvalds case KEYCTL_CLEAR: 13761da177e4SLinus Torvalds return keyctl_keyring_clear((key_serial_t) arg2); 13771da177e4SLinus Torvalds 13781da177e4SLinus Torvalds case KEYCTL_LINK: 13791da177e4SLinus Torvalds return keyctl_keyring_link((key_serial_t) arg2, 13801da177e4SLinus Torvalds (key_serial_t) arg3); 13811da177e4SLinus Torvalds 13821da177e4SLinus Torvalds case KEYCTL_UNLINK: 13831da177e4SLinus Torvalds return keyctl_keyring_unlink((key_serial_t) arg2, 13841da177e4SLinus Torvalds (key_serial_t) arg3); 13851da177e4SLinus Torvalds 13861da177e4SLinus Torvalds case KEYCTL_SEARCH: 13871da177e4SLinus Torvalds return keyctl_keyring_search((key_serial_t) arg2, 13881da177e4SLinus Torvalds (const char __user *) arg3, 13891da177e4SLinus Torvalds (const char __user *) arg4, 13901da177e4SLinus Torvalds (key_serial_t) arg5); 13911da177e4SLinus Torvalds 13921da177e4SLinus Torvalds case KEYCTL_READ: 13931da177e4SLinus Torvalds return keyctl_read_key((key_serial_t) arg2, 13941da177e4SLinus Torvalds (char __user *) arg3, 13951da177e4SLinus Torvalds (size_t) arg4); 13961da177e4SLinus Torvalds 13971da177e4SLinus Torvalds case KEYCTL_CHOWN: 13981da177e4SLinus Torvalds return keyctl_chown_key((key_serial_t) arg2, 13991da177e4SLinus Torvalds (uid_t) arg3, 14001da177e4SLinus Torvalds (gid_t) arg4); 14011da177e4SLinus Torvalds 14021da177e4SLinus Torvalds case KEYCTL_SETPERM: 14031da177e4SLinus Torvalds return keyctl_setperm_key((key_serial_t) arg2, 14041da177e4SLinus Torvalds (key_perm_t) arg3); 14051da177e4SLinus Torvalds 14061da177e4SLinus Torvalds case KEYCTL_INSTANTIATE: 14071da177e4SLinus Torvalds return keyctl_instantiate_key((key_serial_t) arg2, 14081da177e4SLinus Torvalds (const void __user *) arg3, 14091da177e4SLinus Torvalds (size_t) arg4, 14101da177e4SLinus Torvalds (key_serial_t) arg5); 14111da177e4SLinus Torvalds 14121da177e4SLinus Torvalds case KEYCTL_NEGATE: 14131da177e4SLinus Torvalds return keyctl_negate_key((key_serial_t) arg2, 14141da177e4SLinus Torvalds (unsigned) arg3, 14151da177e4SLinus Torvalds (key_serial_t) arg4); 14161da177e4SLinus Torvalds 14173e30148cSDavid Howells case KEYCTL_SET_REQKEY_KEYRING: 14183e30148cSDavid Howells return keyctl_set_reqkey_keyring(arg2); 14193e30148cSDavid Howells 1420017679c4SDavid Howells case KEYCTL_SET_TIMEOUT: 1421017679c4SDavid Howells return keyctl_set_timeout((key_serial_t) arg2, 1422017679c4SDavid Howells (unsigned) arg3); 1423017679c4SDavid Howells 1424b5f545c8SDavid Howells case KEYCTL_ASSUME_AUTHORITY: 1425b5f545c8SDavid Howells return keyctl_assume_authority((key_serial_t) arg2); 1426b5f545c8SDavid Howells 142770a5bb72SDavid Howells case KEYCTL_GET_SECURITY: 142870a5bb72SDavid Howells return keyctl_get_security((key_serial_t) arg2, 142990bd49abSJames Morris (char __user *) arg3, 143070a5bb72SDavid Howells (size_t) arg4); 143170a5bb72SDavid Howells 1432ee18d64cSDavid Howells case KEYCTL_SESSION_TO_PARENT: 1433ee18d64cSDavid Howells return keyctl_session_to_parent(); 1434ee18d64cSDavid Howells 14351da177e4SLinus Torvalds default: 14361da177e4SLinus Torvalds return -EOPNOTSUPP; 14371da177e4SLinus Torvalds } 14381da177e4SLinus Torvalds 14391da177e4SLinus Torvalds } /* end sys_keyctl() */ 1440