diff options
author | David Howells <dhowells@redhat.com> | 2011-03-07 10:06:20 -0500 |
---|---|---|
committer | James Morris <jmorris@namei.org> | 2011-03-07 19:17:22 -0500 |
commit | ee009e4a0d4555ed522a631bae9896399674f064 (patch) | |
tree | ee309fb4a98d9e7792cec99935c2d33652b3f440 | |
parent | fdd1b94581782a2ddf9124414e5b7a5f48ce2f9c (diff) |
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>
-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 | } |