switch keyctl_instantiate_key_common() to iov_iter
authorAl Viro <viro@zeniv.linux.org.uk>
Tue, 17 Mar 2015 13:59:38 +0000 (09:59 -0400)
committerAl Viro <viro@zeniv.linux.org.uk>
Sun, 12 Apr 2015 02:27:12 +0000 (22:27 -0400)
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
security/keys/compat.c
security/keys/internal.h
security/keys/keyctl.c

index 347896548ad3159a152186a4c1a27cdf92f1f4ad..25430a3aa7f7b9d6e6b4d10ae9bc72c8669c00fe 100644 (file)
@@ -31,30 +31,21 @@ static long compat_keyctl_instantiate_key_iov(
        key_serial_t ringid)
 {
        struct iovec iovstack[UIO_FASTIOV], *iov = iovstack;
+       struct iov_iter from;
        long ret;
 
-       if (!_payload_iov || !ioc)
-               goto no_payload;
+       if (!_payload_iov)
+               ioc = 0;
 
-       ret = compat_rw_copy_check_uvector(WRITE, _payload_iov, ioc,
-                                          ARRAY_SIZE(iovstack),
-                                          iovstack, &iov);
+       ret = compat_import_iovec(WRITE, _payload_iov, ioc,
+                                 ARRAY_SIZE(iovstack), &iov,
+                                 &from);
        if (ret < 0)
-               goto err;
-       if (ret == 0)
-               goto no_payload_free;
-
-       ret = keyctl_instantiate_key_common(id, iov, ioc, ret, ringid);
-err:
-       if (iov != iovstack)
-               kfree(iov);
-       return ret;
+               return ret;
 
-no_payload_free:
-       if (iov != iovstack)
-               kfree(iov);
-no_payload:
-       return keyctl_instantiate_key_common(id, NULL, 0, 0, ringid);
+       ret = keyctl_instantiate_key_common(id, &from, ringid);
+       kfree(iov);
+       return ret;
 }
 
 /*
index 200e37867336a3c2903437e97f591fbc302e15b7..5105c2c2da75b0e13dec1196be67c88f4d789e72 100644 (file)
@@ -243,9 +243,10 @@ extern long keyctl_instantiate_key_iov(key_serial_t,
                                       unsigned, key_serial_t);
 extern long keyctl_invalidate_key(key_serial_t);
 
+struct iov_iter;
 extern long keyctl_instantiate_key_common(key_serial_t,
-                                         const struct iovec *,
-                                         unsigned, size_t, key_serial_t);
+                                         struct iov_iter *,
+                                         key_serial_t);
 #ifdef CONFIG_PERSISTENT_KEYRINGS
 extern long keyctl_get_persistent(uid_t, key_serial_t);
 extern unsigned persistent_keyring_expiry;
index 4743d71e4aa6dd12f2456a5f00496c1222775c6a..0b9ec78a7a7ad2b14af1ef0407e051e6dcef29ff 100644 (file)
@@ -997,21 +997,6 @@ static int keyctl_change_reqkey_auth(struct key *key)
        return commit_creds(new);
 }
 
-/*
- * Copy the iovec data from userspace
- */
-static long copy_from_user_iovec(void *buffer, const struct iovec *iov,
-                                unsigned ioc)
-{
-       for (; ioc > 0; ioc--) {
-               if (copy_from_user(buffer, iov->iov_base, iov->iov_len) != 0)
-                       return -EFAULT;
-               buffer += iov->iov_len;
-               iov++;
-       }
-       return 0;
-}
-
 /*
  * Instantiate a key with the specified payload and link the key into the
  * destination keyring if one is given.
@@ -1022,20 +1007,21 @@ static long copy_from_user_iovec(void *buffer, const struct iovec *iov,
  * If successful, 0 will be returned.
  */
 long keyctl_instantiate_key_common(key_serial_t id,
-                                  const struct iovec *payload_iov,
-                                  unsigned ioc,
-                                  size_t plen,
+                                  struct iov_iter *from,
                                   key_serial_t ringid)
 {
        const struct cred *cred = current_cred();
        struct request_key_auth *rka;
        struct key *instkey, *dest_keyring;
+       size_t plen = from ? iov_iter_count(from) : 0;
        void *payload;
        long ret;
-       bool vm = false;
 
        kenter("%d,,%zu,%d", id, plen, ringid);
 
+       if (!plen)
+               from = NULL;
+
        ret = -EINVAL;
        if (plen > 1024 * 1024 - 1)
                goto error;
@@ -1054,20 +1040,19 @@ long keyctl_instantiate_key_common(key_serial_t id,
        /* pull the payload in if one was supplied */
        payload = NULL;
 
-       if (payload_iov) {
+       if (from) {
                ret = -ENOMEM;
                payload = kmalloc(plen, GFP_KERNEL);
                if (!payload) {
                        if (plen <= PAGE_SIZE)
                                goto error;
-                       vm = true;
                        payload = vmalloc(plen);
                        if (!payload)
                                goto error;
                }
 
-               ret = copy_from_user_iovec(payload, payload_iov, ioc);
-               if (ret < 0)
+               ret = -EFAULT;
+               if (copy_from_iter(payload, plen, from) != plen)
                        goto error2;
        }
 
@@ -1089,10 +1074,7 @@ long keyctl_instantiate_key_common(key_serial_t id,
                keyctl_change_reqkey_auth(NULL);
 
 error2:
-       if (!vm)
-               kfree(payload);
-       else
-               vfree(payload);
+       kvfree(payload);
 error:
        return ret;
 }
@@ -1112,15 +1094,19 @@ long keyctl_instantiate_key(key_serial_t id,
                            key_serial_t ringid)
 {
        if (_payload && plen) {
-               struct iovec iov[1] = {
-                       [0].iov_base = (void __user *)_payload,
-                       [0].iov_len  = plen
-               };
+               struct iovec iov;
+               struct iov_iter from;
+               int ret;
 
-               return keyctl_instantiate_key_common(id, iov, 1, plen, ringid);
+               ret = import_single_range(WRITE, (void __user *)_payload, plen,
+                                         &iov, &from);
+               if (unlikely(ret))
+                       return ret;
+
+               return keyctl_instantiate_key_common(id, &from, ringid);
        }
 
-       return keyctl_instantiate_key_common(id, NULL, 0, 0, ringid);
+       return keyctl_instantiate_key_common(id, NULL, ringid);
 }
 
 /*
@@ -1138,29 +1124,19 @@ long keyctl_instantiate_key_iov(key_serial_t id,
                                key_serial_t ringid)
 {
        struct iovec iovstack[UIO_FASTIOV], *iov = iovstack;
+       struct iov_iter from;
        long ret;
 
-       if (!_payload_iov || !ioc)
-               goto no_payload;
+       if (!_payload_iov)
+               ioc = 0;
 
-       ret = rw_copy_check_uvector(WRITE, _payload_iov, ioc,
-                                   ARRAY_SIZE(iovstack), iovstack, &iov);
+       ret = import_iovec(WRITE, _payload_iov, ioc,
+                                   ARRAY_SIZE(iovstack), &iov, &from);
        if (ret < 0)
-               goto err;
-       if (ret == 0)
-               goto no_payload_free;
-
-       ret = keyctl_instantiate_key_common(id, iov, ioc, ret, ringid);
-err:
-       if (iov != iovstack)
-               kfree(iov);
+               return ret;
+       ret = keyctl_instantiate_key_common(id, &from, ringid);
+       kfree(iov);
        return ret;
-
-no_payload_free:
-       if (iov != iovstack)
-               kfree(iov);
-no_payload:
-       return keyctl_instantiate_key_common(id, NULL, 0, 0, ringid);
 }
 
 /*