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 /security/keys | |
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>
Diffstat (limited to 'security/keys')
-rw-r--r-- | security/keys/compat.c | 47 | ||||
-rw-r--r-- | security/keys/internal.h | 7 | ||||
-rw-r--r-- | security/keys/keyctl.c | 103 |
3 files changed, 150 insertions, 7 deletions
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 | } |