Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

KEYS: Add an iovec version of KEYCTL_INSTANTIATE

Add a keyctl op (KEYCTL_INSTANTIATE_IOV) that is like KEYCTL_INSTANTIATE, but
takes an iovec array and concatenates the data in-kernel into one buffer.
Since the KEYCTL_INSTANTIATE copies the data anyway, this isn't too much of a
problem.

Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: James Morris <jmorris@namei.org>

authored by

David Howells and committed by
James Morris
ee009e4a fdd1b945

+167 -11
+11 -4
Documentation/keys.txt
··· 637 637 long keyctl(KEYCTL_INSTANTIATE, key_serial_t key, 638 638 const void *payload, size_t plen, 639 639 key_serial_t keyring); 640 + long keyctl(KEYCTL_INSTANTIATE_IOV, key_serial_t key, 641 + const struct iovec *payload_iov, unsigned ioc, 642 + key_serial_t keyring); 640 643 641 644 If the kernel calls back to userspace to complete the instantiation of a 642 645 key, userspace should use this call to supply data for the key before the ··· 654 651 this case too. 655 652 656 653 The payload and plen arguments describe the payload data as for add_key(). 654 + 655 + The payload_iov and ioc arguments describe the payload data in an iovec 656 + array instead of a single buffer. 657 657 658 658 659 659 (*) Negatively instantiate a partially constructed key. ··· 1250 1244 example, the KDE desktop manager). 1251 1245 1252 1246 The program (or whatever it calls) should finish construction of the key by 1253 - calling KEYCTL_INSTANTIATE, which also permits it to cache the key in one of 1254 - the keyrings (probably the session ring) before returning. Alternatively, the 1255 - key can be marked as negative with KEYCTL_NEGATE or KEYCTL_REJECT; this also 1256 - permits the key to be cached in one of the keyrings. 1247 + calling KEYCTL_INSTANTIATE or KEYCTL_INSTANTIATE_IOV, which also permits it to 1248 + cache the key in one of the keyrings (probably the session ring) before 1249 + returning. Alternatively, the key can be marked as negative with KEYCTL_NEGATE 1250 + or KEYCTL_REJECT; this also permits the key to be cached in one of the 1251 + keyrings. 1257 1252 1258 1253 If it returns with the key remaining in the unconstructed state, the key will 1259 1254 be marked as being negative, it will be added to the session keyring, and an
+5
arch/x86/Kconfig
··· 2138 2138 def_bool y 2139 2139 depends on COMPAT && SYSVIPC 2140 2140 2141 + config KEYS_COMPAT 2142 + bool 2143 + depends on COMPAT && KEYS 2144 + default y 2145 + 2141 2146 endmenu 2142 2147 2143 2148
+1
include/linux/keyctl.h
··· 54 54 #define KEYCTL_GET_SECURITY 17 /* get key security label */ 55 55 #define KEYCTL_SESSION_TO_PARENT 18 /* apply session keyring to parent process */ 56 56 #define KEYCTL_REJECT 19 /* reject a partially constructed key */ 57 + #define KEYCTL_INSTANTIATE_IOV 20 /* instantiate a partially constructed key */ 57 58 58 59 #endif /* _LINUX_KEYCTL_H */
+47
security/keys/compat.c
··· 12 12 #include <linux/syscalls.h> 13 13 #include <linux/keyctl.h> 14 14 #include <linux/compat.h> 15 + #include <linux/slab.h> 15 16 #include "internal.h" 17 + 18 + /* 19 + * Instantiate a key with the specified compatibility multipart payload and 20 + * link the key into the destination keyring if one is given. 21 + * 22 + * The caller must have the appropriate instantiation permit set for this to 23 + * work (see keyctl_assume_authority). No other permissions are required. 24 + * 25 + * If successful, 0 will be returned. 26 + */ 27 + long compat_keyctl_instantiate_key_iov( 28 + key_serial_t id, 29 + const struct compat_iovec __user *_payload_iov, 30 + unsigned ioc, 31 + key_serial_t ringid) 32 + { 33 + struct iovec iovstack[UIO_FASTIOV], *iov = iovstack; 34 + long ret; 35 + 36 + if (_payload_iov == 0 || ioc == 0) 37 + goto no_payload; 38 + 39 + ret = compat_rw_copy_check_uvector(WRITE, _payload_iov, ioc, 40 + ARRAY_SIZE(iovstack), 41 + iovstack, &iov); 42 + if (ret < 0) 43 + return ret; 44 + if (ret == 0) 45 + goto no_payload_free; 46 + 47 + ret = keyctl_instantiate_key_common(id, iov, ioc, ret, ringid); 48 + 49 + if (iov != iovstack) 50 + kfree(iov); 51 + return ret; 52 + 53 + no_payload_free: 54 + if (iov != iovstack) 55 + kfree(iov); 56 + no_payload: 57 + return keyctl_instantiate_key_common(id, NULL, 0, 0, ringid); 58 + } 16 59 17 60 /* 18 61 * The key control system call, 32-bit compatibility version for 64-bit archs ··· 130 87 131 88 case KEYCTL_REJECT: 132 89 return keyctl_reject_key(arg2, arg3, arg4, arg5); 90 + 91 + case KEYCTL_INSTANTIATE_IOV: 92 + return compat_keyctl_instantiate_key_iov( 93 + arg2, compat_ptr(arg3), arg4, arg5); 133 94 134 95 default: 135 96 return -EOPNOTSUPP;
+7
security/keys/internal.h
··· 215 215 size_t buflen); 216 216 extern long keyctl_session_to_parent(void); 217 217 extern long keyctl_reject_key(key_serial_t, unsigned, unsigned, key_serial_t); 218 + extern long keyctl_instantiate_key_iov(key_serial_t, 219 + const struct iovec __user *, 220 + unsigned, key_serial_t); 221 + 222 + extern long keyctl_instantiate_key_common(key_serial_t, 223 + const struct iovec __user *, 224 + unsigned, size_t, key_serial_t); 218 225 219 226 /* 220 227 * Debugging key validation
+96 -7
security/keys/keyctl.c
··· 913 913 } 914 914 915 915 /* 916 + * Copy the iovec data from userspace 917 + */ 918 + static long copy_from_user_iovec(void *buffer, const struct iovec *iov, 919 + unsigned ioc) 920 + { 921 + for (; ioc > 0; ioc--) { 922 + if (copy_from_user(buffer, iov->iov_base, iov->iov_len) != 0) 923 + return -EFAULT; 924 + buffer += iov->iov_len; 925 + iov++; 926 + } 927 + return 0; 928 + } 929 + 930 + /* 916 931 * Instantiate a key with the specified payload and link the key into the 917 932 * destination keyring if one is given. 918 933 * ··· 936 921 * 937 922 * If successful, 0 will be returned. 938 923 */ 939 - long keyctl_instantiate_key(key_serial_t id, 940 - const void __user *_payload, 941 - size_t plen, 942 - key_serial_t ringid) 924 + long keyctl_instantiate_key_common(key_serial_t id, 925 + const struct iovec *payload_iov, 926 + unsigned ioc, 927 + size_t plen, 928 + key_serial_t ringid) 943 929 { 944 930 const struct cred *cred = current_cred(); 945 931 struct request_key_auth *rka; ··· 969 953 /* pull the payload in if one was supplied */ 970 954 payload = NULL; 971 955 972 - if (_payload) { 956 + if (payload_iov) { 973 957 ret = -ENOMEM; 974 958 payload = kmalloc(plen, GFP_KERNEL); 975 959 if (!payload) { ··· 981 965 goto error; 982 966 } 983 967 984 - ret = -EFAULT; 985 - if (copy_from_user(payload, _payload, plen) != 0) 968 + ret = copy_from_user_iovec(payload, payload_iov, ioc); 969 + if (ret < 0) 986 970 goto error2; 987 971 } 988 972 ··· 1010 994 vfree(payload); 1011 995 error: 1012 996 return ret; 997 + } 998 + 999 + /* 1000 + * Instantiate a key with the specified payload and link the key into the 1001 + * destination keyring if one is given. 1002 + * 1003 + * The caller must have the appropriate instantiation permit set for this to 1004 + * work (see keyctl_assume_authority). No other permissions are required. 1005 + * 1006 + * If successful, 0 will be returned. 1007 + */ 1008 + long keyctl_instantiate_key(key_serial_t id, 1009 + const void __user *_payload, 1010 + size_t plen, 1011 + key_serial_t ringid) 1012 + { 1013 + if (_payload && plen) { 1014 + struct iovec iov[1] = { 1015 + [0].iov_base = (void __user *)_payload, 1016 + [0].iov_len = plen 1017 + }; 1018 + 1019 + return keyctl_instantiate_key_common(id, iov, 1, plen, ringid); 1020 + } 1021 + 1022 + return keyctl_instantiate_key_common(id, NULL, 0, 0, ringid); 1023 + } 1024 + 1025 + /* 1026 + * Instantiate a key with the specified multipart payload and link the key into 1027 + * the destination keyring if one is given. 1028 + * 1029 + * The caller must have the appropriate instantiation permit set for this to 1030 + * work (see keyctl_assume_authority). No other permissions are required. 1031 + * 1032 + * If successful, 0 will be returned. 1033 + */ 1034 + long keyctl_instantiate_key_iov(key_serial_t id, 1035 + const struct iovec __user *_payload_iov, 1036 + unsigned ioc, 1037 + key_serial_t ringid) 1038 + { 1039 + struct iovec iovstack[UIO_FASTIOV], *iov = iovstack; 1040 + long ret; 1041 + 1042 + if (_payload_iov == 0 || ioc == 0) 1043 + goto no_payload; 1044 + 1045 + ret = rw_copy_check_uvector(WRITE, _payload_iov, ioc, 1046 + ARRAY_SIZE(iovstack), iovstack, &iov); 1047 + if (ret < 0) 1048 + return ret; 1049 + if (ret == 0) 1050 + goto no_payload_free; 1051 + 1052 + ret = keyctl_instantiate_key_common(id, iov, ioc, ret, ringid); 1053 + 1054 + if (iov != iovstack) 1055 + kfree(iov); 1056 + return ret; 1057 + 1058 + no_payload_free: 1059 + if (iov != iovstack) 1060 + kfree(iov); 1061 + no_payload: 1062 + return keyctl_instantiate_key_common(id, NULL, 0, 0, ringid); 1013 1063 } 1014 1064 1015 1065 /* ··· 1609 1527 (unsigned) arg3, 1610 1528 (unsigned) arg4, 1611 1529 (key_serial_t) arg5); 1530 + 1531 + case KEYCTL_INSTANTIATE_IOV: 1532 + return keyctl_instantiate_key_iov( 1533 + (key_serial_t) arg2, 1534 + (const struct iovec __user *) arg3, 1535 + (unsigned) arg4, 1536 + (key_serial_t) arg5); 1612 1537 1613 1538 default: 1614 1539 return -EOPNOTSUPP;