diff options
| -rw-r--r-- | Documentation/keys.txt | 15 | ||||
| -rw-r--r-- | arch/x86/Kconfig | 5 | ||||
| -rw-r--r-- | include/linux/keyctl.h | 1 | ||||
| -rw-r--r-- | security/keys/compat.c | 47 | ||||
| -rw-r--r-- | security/keys/internal.h | 7 | ||||
| -rw-r--r-- | security/keys/keyctl.c | 103 |
6 files changed, 167 insertions, 11 deletions
diff --git a/Documentation/keys.txt b/Documentation/keys.txt index a6a97fdfaddd..6523a9e6f293 100644 --- a/Documentation/keys.txt +++ b/Documentation/keys.txt | |||
| @@ -637,6 +637,9 @@ The keyctl syscall functions are: | |||
| 637 | long keyctl(KEYCTL_INSTANTIATE, key_serial_t key, | 637 | long keyctl(KEYCTL_INSTANTIATE, key_serial_t key, |
| 638 | const void *payload, size_t plen, | 638 | const void *payload, size_t plen, |
| 639 | key_serial_t keyring); | 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 | If the kernel calls back to userspace to complete the instantiation of a | 644 | If the kernel calls back to userspace to complete the instantiation of a |
| 642 | key, userspace should use this call to supply data for the key before the | 645 | key, userspace should use this call to supply data for the key before the |
| @@ -652,6 +655,9 @@ The keyctl syscall functions are: | |||
| 652 | 655 | ||
| 653 | The payload and plen arguments describe the payload data as for add_key(). | 656 | The payload and plen arguments describe the payload data as for add_key(). |
| 654 | 657 | ||
| 658 | The payload_iov and ioc arguments describe the payload data in an iovec | ||
| 659 | array instead of a single buffer. | ||
| 660 | |||
| 655 | 661 | ||
| 656 | (*) Negatively instantiate a partially constructed key. | 662 | (*) Negatively instantiate a partially constructed key. |
| 657 | 663 | ||
| @@ -1244,10 +1250,11 @@ hand the request off to (perhaps a path held in placed in another key by, for | |||
| 1244 | example, the KDE desktop manager). | 1250 | example, the KDE desktop manager). |
| 1245 | 1251 | ||
| 1246 | The program (or whatever it calls) should finish construction of the key by | 1252 | The program (or whatever it calls) should finish construction of the key by |
| 1247 | calling KEYCTL_INSTANTIATE, which also permits it to cache the key in one of | 1253 | calling KEYCTL_INSTANTIATE or KEYCTL_INSTANTIATE_IOV, which also permits it to |
| 1248 | the keyrings (probably the session ring) before returning. Alternatively, the | 1254 | cache the key in one of the keyrings (probably the session ring) before |
| 1249 | key can be marked as negative with KEYCTL_NEGATE or KEYCTL_REJECT; this also | 1255 | returning. Alternatively, the key can be marked as negative with KEYCTL_NEGATE |
| 1250 | permits the key to be cached in one of the keyrings. | 1256 | or KEYCTL_REJECT; this also permits the key to be cached in one of the |
| 1257 | keyrings. | ||
| 1251 | 1258 | ||
| 1252 | If it returns with the key remaining in the unconstructed state, the key will | 1259 | If it returns with the key remaining in the unconstructed state, the key will |
| 1253 | be marked as being negative, it will be added to the session keyring, and an | 1260 | be marked as being negative, it will be added to the session keyring, and an |
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index d5ed94d30aad..b46b75bef496 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig | |||
| @@ -2138,6 +2138,11 @@ config SYSVIPC_COMPAT | |||
| 2138 | def_bool y | 2138 | def_bool y |
| 2139 | depends on COMPAT && SYSVIPC | 2139 | depends on COMPAT && SYSVIPC |
| 2140 | 2140 | ||
| 2141 | config KEYS_COMPAT | ||
| 2142 | bool | ||
| 2143 | depends on COMPAT && KEYS | ||
| 2144 | default y | ||
| 2145 | |||
| 2141 | endmenu | 2146 | endmenu |
| 2142 | 2147 | ||
| 2143 | 2148 | ||
diff --git a/include/linux/keyctl.h b/include/linux/keyctl.h index 7022974def0c..9b0b865ce622 100644 --- a/include/linux/keyctl.h +++ b/include/linux/keyctl.h | |||
| @@ -54,5 +54,6 @@ | |||
| 54 | #define KEYCTL_GET_SECURITY 17 /* get key security label */ | 54 | #define KEYCTL_GET_SECURITY 17 /* get key security label */ |
| 55 | #define KEYCTL_SESSION_TO_PARENT 18 /* apply session keyring to parent process */ | 55 | #define KEYCTL_SESSION_TO_PARENT 18 /* apply session keyring to parent process */ |
| 56 | #define KEYCTL_REJECT 19 /* reject a partially constructed key */ | 56 | #define KEYCTL_REJECT 19 /* reject a partially constructed key */ |
| 57 | #define KEYCTL_INSTANTIATE_IOV 20 /* instantiate a partially constructed key */ | ||
| 57 | 58 | ||
| 58 | #endif /* _LINUX_KEYCTL_H */ | 59 | #endif /* _LINUX_KEYCTL_H */ |
diff --git a/security/keys/compat.c b/security/keys/compat.c index 17c99d0149ec..338b510e9027 100644 --- a/security/keys/compat.c +++ b/security/keys/compat.c | |||
| @@ -12,9 +12,52 @@ | |||
| 12 | #include <linux/syscalls.h> | 12 | #include <linux/syscalls.h> |
| 13 | #include <linux/keyctl.h> | 13 | #include <linux/keyctl.h> |
| 14 | #include <linux/compat.h> | 14 | #include <linux/compat.h> |
| 15 | #include <linux/slab.h> | ||
| 15 | #include "internal.h" | 16 | #include "internal.h" |
| 16 | 17 | ||
| 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 | } | ||
| 59 | |||
| 60 | /* | ||
| 18 | * The key control system call, 32-bit compatibility version for 64-bit archs | 61 | * The key control system call, 32-bit compatibility version for 64-bit archs |
| 19 | * | 62 | * |
| 20 | * This should only be called if the 64-bit arch uses weird pointers in 32-bit | 63 | * This should only be called if the 64-bit arch uses weird pointers in 32-bit |
| @@ -88,6 +131,10 @@ asmlinkage long compat_sys_keyctl(u32 option, | |||
| 88 | case KEYCTL_REJECT: | 131 | case KEYCTL_REJECT: |
| 89 | return keyctl_reject_key(arg2, arg3, arg4, arg5); | 132 | return keyctl_reject_key(arg2, arg3, arg4, arg5); |
| 90 | 133 | ||
| 134 | case KEYCTL_INSTANTIATE_IOV: | ||
| 135 | return compat_keyctl_instantiate_key_iov( | ||
| 136 | arg2, compat_ptr(arg3), arg4, arg5); | ||
| 137 | |||
| 91 | default: | 138 | default: |
| 92 | return -EOPNOTSUPP; | 139 | return -EOPNOTSUPP; |
| 93 | } | 140 | } |
diff --git a/security/keys/internal.h b/security/keys/internal.h index 286c0959ee51..07a025f81902 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h | |||
| @@ -215,6 +215,13 @@ extern long keyctl_get_security(key_serial_t keyid, char __user *buffer, | |||
| 215 | size_t buflen); | 215 | size_t buflen); |
| 216 | extern long keyctl_session_to_parent(void); | 216 | extern long keyctl_session_to_parent(void); |
| 217 | extern long keyctl_reject_key(key_serial_t, unsigned, unsigned, key_serial_t); | 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 | * Debugging key validation | 227 | * Debugging key validation |
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index 0d7b1946ff94..427fddcaeb19 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c | |||
| @@ -913,6 +913,21 @@ static int keyctl_change_reqkey_auth(struct key *key) | |||
| 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 | * Instantiate a key with the specified payload and link the key into the | 931 | * Instantiate a key with the specified payload and link the key into the |
| 917 | * destination keyring if one is given. | 932 | * destination keyring if one is given. |
| 918 | * | 933 | * |
| @@ -921,10 +936,11 @@ static int keyctl_change_reqkey_auth(struct key *key) | |||
| 921 | * | 936 | * |
| 922 | * If successful, 0 will be returned. | 937 | * If successful, 0 will be returned. |
| 923 | */ | 938 | */ |
| 924 | long keyctl_instantiate_key(key_serial_t id, | 939 | long keyctl_instantiate_key_common(key_serial_t id, |
| 925 | const void __user *_payload, | 940 | const struct iovec *payload_iov, |
| 926 | size_t plen, | 941 | unsigned ioc, |
| 927 | key_serial_t ringid) | 942 | size_t plen, |
| 943 | key_serial_t ringid) | ||
| 928 | { | 944 | { |
| 929 | const struct cred *cred = current_cred(); | 945 | const struct cred *cred = current_cred(); |
| 930 | struct request_key_auth *rka; | 946 | struct request_key_auth *rka; |
| @@ -953,7 +969,7 @@ long keyctl_instantiate_key(key_serial_t id, | |||
| 953 | /* pull the payload in if one was supplied */ | 969 | /* pull the payload in if one was supplied */ |
| 954 | payload = NULL; | 970 | payload = NULL; |
| 955 | 971 | ||
| 956 | if (_payload) { | 972 | if (payload_iov) { |
| 957 | ret = -ENOMEM; | 973 | ret = -ENOMEM; |
| 958 | payload = kmalloc(plen, GFP_KERNEL); | 974 | payload = kmalloc(plen, GFP_KERNEL); |
| 959 | if (!payload) { | 975 | if (!payload) { |
| @@ -965,8 +981,8 @@ long keyctl_instantiate_key(key_serial_t id, | |||
| 965 | goto error; | 981 | goto error; |
| 966 | } | 982 | } |
| 967 | 983 | ||
| 968 | ret = -EFAULT; | 984 | ret = copy_from_user_iovec(payload, payload_iov, ioc); |
| 969 | if (copy_from_user(payload, _payload, plen) != 0) | 985 | if (ret < 0) |
| 970 | goto error2; | 986 | goto error2; |
| 971 | } | 987 | } |
| 972 | 988 | ||
| @@ -997,6 +1013,72 @@ error: | |||
| 997 | } | 1013 | } |
| 998 | 1014 | ||
| 999 | /* | 1015 | /* |
| 1016 | * Instantiate a key with the specified payload and link the key into the | ||
| 1017 | * destination keyring if one is given. | ||
| 1018 | * | ||
| 1019 | * The caller must have the appropriate instantiation permit set for this to | ||
| 1020 | * work (see keyctl_assume_authority). No other permissions are required. | ||
| 1021 | * | ||
| 1022 | * If successful, 0 will be returned. | ||
| 1023 | */ | ||
| 1024 | long keyctl_instantiate_key(key_serial_t id, | ||
| 1025 | const void __user *_payload, | ||
| 1026 | size_t plen, | ||
| 1027 | key_serial_t ringid) | ||
| 1028 | { | ||
| 1029 | if (_payload && plen) { | ||
| 1030 | struct iovec iov[1] = { | ||
| 1031 | [0].iov_base = (void __user *)_payload, | ||
| 1032 | [0].iov_len = plen | ||
| 1033 | }; | ||
| 1034 | |||
| 1035 | return keyctl_instantiate_key_common(id, iov, 1, plen, ringid); | ||
| 1036 | } | ||
| 1037 | |||
| 1038 | return keyctl_instantiate_key_common(id, NULL, 0, 0, ringid); | ||
| 1039 | } | ||
| 1040 | |||
| 1041 | /* | ||
| 1042 | * Instantiate a key with the specified multipart payload and link the key into | ||
| 1043 | * the destination keyring if one is given. | ||
| 1044 | * | ||
| 1045 | * The caller must have the appropriate instantiation permit set for this to | ||
| 1046 | * work (see keyctl_assume_authority). No other permissions are required. | ||
| 1047 | * | ||
| 1048 | * If successful, 0 will be returned. | ||
| 1049 | */ | ||
| 1050 | long keyctl_instantiate_key_iov(key_serial_t id, | ||
| 1051 | const struct iovec __user *_payload_iov, | ||
| 1052 | unsigned ioc, | ||
| 1053 | key_serial_t ringid) | ||
| 1054 | { | ||
| 1055 | struct iovec iovstack[UIO_FASTIOV], *iov = iovstack; | ||
| 1056 | long ret; | ||
| 1057 | |||
| 1058 | if (_payload_iov == 0 || ioc == 0) | ||
| 1059 | goto no_payload; | ||
| 1060 | |||
| 1061 | ret = rw_copy_check_uvector(WRITE, _payload_iov, ioc, | ||
| 1062 | ARRAY_SIZE(iovstack), iovstack, &iov); | ||
| 1063 | if (ret < 0) | ||
| 1064 | return ret; | ||
| 1065 | if (ret == 0) | ||
| 1066 | goto no_payload_free; | ||
| 1067 | |||
| 1068 | ret = keyctl_instantiate_key_common(id, iov, ioc, ret, ringid); | ||
| 1069 | |||
| 1070 | if (iov != iovstack) | ||
| 1071 | kfree(iov); | ||
| 1072 | return ret; | ||
| 1073 | |||
| 1074 | no_payload_free: | ||
| 1075 | if (iov != iovstack) | ||
| 1076 | kfree(iov); | ||
| 1077 | no_payload: | ||
| 1078 | return keyctl_instantiate_key_common(id, NULL, 0, 0, ringid); | ||
| 1079 | } | ||
| 1080 | |||
| 1081 | /* | ||
| 1000 | * Negatively instantiate the key with the given timeout (in seconds) and link | 1082 | * Negatively instantiate the key with the given timeout (in seconds) and link |
| 1001 | * the key into the destination keyring if one is given. | 1083 | * the key into the destination keyring if one is given. |
| 1002 | * | 1084 | * |
| @@ -1528,6 +1610,13 @@ SYSCALL_DEFINE5(keyctl, int, option, unsigned long, arg2, unsigned long, arg3, | |||
| 1528 | (unsigned) arg4, | 1610 | (unsigned) arg4, |
| 1529 | (key_serial_t) arg5); | 1611 | (key_serial_t) arg5); |
| 1530 | 1612 | ||
| 1613 | case KEYCTL_INSTANTIATE_IOV: | ||
| 1614 | return keyctl_instantiate_key_iov( | ||
| 1615 | (key_serial_t) arg2, | ||
| 1616 | (const struct iovec __user *) arg3, | ||
| 1617 | (unsigned) arg4, | ||
| 1618 | (key_serial_t) arg5); | ||
| 1619 | |||
| 1531 | default: | 1620 | default: |
| 1532 | return -EOPNOTSUPP; | 1621 | return -EOPNOTSUPP; |
| 1533 | } | 1622 | } |
