aboutsummaryrefslogtreecommitdiffstats
path: root/security
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2011-03-07 10:06:20 -0500
committerJames Morris <jmorris@namei.org>2011-03-07 19:17:22 -0500
commitee009e4a0d4555ed522a631bae9896399674f064 (patch)
treeee309fb4a98d9e7792cec99935c2d33652b3f440 /security
parentfdd1b94581782a2ddf9124414e5b7a5f48ce2f9c (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')
-rw-r--r--security/keys/compat.c47
-rw-r--r--security/keys/internal.h7
-rw-r--r--security/keys/keyctl.c103
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 */
27long 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
53no_payload_free:
54 if (iov != iovstack)
55 kfree(iov);
56no_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);
216extern long keyctl_session_to_parent(void); 216extern long keyctl_session_to_parent(void);
217extern long keyctl_reject_key(key_serial_t, unsigned, unsigned, key_serial_t); 217extern long keyctl_reject_key(key_serial_t, unsigned, unsigned, key_serial_t);
218extern long keyctl_instantiate_key_iov(key_serial_t,
219 const struct iovec __user *,
220 unsigned, key_serial_t);
221
222extern 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 */
918static 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 */
924long keyctl_instantiate_key(key_serial_t id, 939long 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 */
1024long 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 */
1050long 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
1074no_payload_free:
1075 if (iov != iovstack)
1076 kfree(iov);
1077no_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 }