|
@@ -912,6 +912,21 @@ 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.
|
|
@@ -921,10 +936,11 @@ static int keyctl_change_reqkey_auth(struct key *key)
|
|
|
*
|
|
|
* If successful, 0 will be returned.
|
|
|
*/
|
|
|
-long keyctl_instantiate_key(key_serial_t id,
|
|
|
- const void __user *_payload,
|
|
|
- size_t plen,
|
|
|
- key_serial_t ringid)
|
|
|
+long keyctl_instantiate_key_common(key_serial_t id,
|
|
|
+ const struct iovec *payload_iov,
|
|
|
+ unsigned ioc,
|
|
|
+ size_t plen,
|
|
|
+ key_serial_t ringid)
|
|
|
{
|
|
|
const struct cred *cred = current_cred();
|
|
|
struct request_key_auth *rka;
|
|
@@ -953,7 +969,7 @@ long keyctl_instantiate_key(key_serial_t id,
|
|
|
/* pull the payload in if one was supplied */
|
|
|
payload = NULL;
|
|
|
|
|
|
- if (_payload) {
|
|
|
+ if (payload_iov) {
|
|
|
ret = -ENOMEM;
|
|
|
payload = kmalloc(plen, GFP_KERNEL);
|
|
|
if (!payload) {
|
|
@@ -965,8 +981,8 @@ long keyctl_instantiate_key(key_serial_t id,
|
|
|
goto error;
|
|
|
}
|
|
|
|
|
|
- ret = -EFAULT;
|
|
|
- if (copy_from_user(payload, _payload, plen) != 0)
|
|
|
+ ret = copy_from_user_iovec(payload, payload_iov, ioc);
|
|
|
+ if (ret < 0)
|
|
|
goto error2;
|
|
|
}
|
|
|
|
|
@@ -996,6 +1012,72 @@ error:
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Instantiate a key with the specified payload and link the key into the
|
|
|
+ * destination keyring if one is given.
|
|
|
+ *
|
|
|
+ * The caller must have the appropriate instantiation permit set for this to
|
|
|
+ * work (see keyctl_assume_authority). No other permissions are required.
|
|
|
+ *
|
|
|
+ * If successful, 0 will be returned.
|
|
|
+ */
|
|
|
+long keyctl_instantiate_key(key_serial_t id,
|
|
|
+ const void __user *_payload,
|
|
|
+ size_t plen,
|
|
|
+ key_serial_t ringid)
|
|
|
+{
|
|
|
+ if (_payload && plen) {
|
|
|
+ struct iovec iov[1] = {
|
|
|
+ [0].iov_base = (void __user *)_payload,
|
|
|
+ [0].iov_len = plen
|
|
|
+ };
|
|
|
+
|
|
|
+ return keyctl_instantiate_key_common(id, iov, 1, plen, ringid);
|
|
|
+ }
|
|
|
+
|
|
|
+ return keyctl_instantiate_key_common(id, NULL, 0, 0, ringid);
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Instantiate a key with the specified multipart payload and link the key into
|
|
|
+ * the destination keyring if one is given.
|
|
|
+ *
|
|
|
+ * The caller must have the appropriate instantiation permit set for this to
|
|
|
+ * work (see keyctl_assume_authority). No other permissions are required.
|
|
|
+ *
|
|
|
+ * If successful, 0 will be returned.
|
|
|
+ */
|
|
|
+long keyctl_instantiate_key_iov(key_serial_t id,
|
|
|
+ const struct iovec __user *_payload_iov,
|
|
|
+ unsigned ioc,
|
|
|
+ key_serial_t ringid)
|
|
|
+{
|
|
|
+ struct iovec iovstack[UIO_FASTIOV], *iov = iovstack;
|
|
|
+ long ret;
|
|
|
+
|
|
|
+ if (_payload_iov == 0 || ioc == 0)
|
|
|
+ goto no_payload;
|
|
|
+
|
|
|
+ ret = rw_copy_check_uvector(WRITE, _payload_iov, ioc,
|
|
|
+ ARRAY_SIZE(iovstack), iovstack, &iov);
|
|
|
+ if (ret < 0)
|
|
|
+ return ret;
|
|
|
+ if (ret == 0)
|
|
|
+ goto no_payload_free;
|
|
|
+
|
|
|
+ ret = keyctl_instantiate_key_common(id, iov, ioc, ret, ringid);
|
|
|
+
|
|
|
+ if (iov != iovstack)
|
|
|
+ kfree(iov);
|
|
|
+ return ret;
|
|
|
+
|
|
|
+no_payload_free:
|
|
|
+ if (iov != iovstack)
|
|
|
+ kfree(iov);
|
|
|
+no_payload:
|
|
|
+ return keyctl_instantiate_key_common(id, NULL, 0, 0, ringid);
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Negatively instantiate the key with the given timeout (in seconds) and link
|
|
|
* the key into the destination keyring if one is given.
|
|
@@ -1528,6 +1610,13 @@ SYSCALL_DEFINE5(keyctl, int, option, unsigned long, arg2, unsigned long, arg3,
|
|
|
(unsigned) arg4,
|
|
|
(key_serial_t) arg5);
|
|
|
|
|
|
+ case KEYCTL_INSTANTIATE_IOV:
|
|
|
+ return keyctl_instantiate_key_iov(
|
|
|
+ (key_serial_t) arg2,
|
|
|
+ (const struct iovec __user *) arg3,
|
|
|
+ (unsigned) arg4,
|
|
|
+ (key_serial_t) arg5);
|
|
|
+
|
|
|
default:
|
|
|
return -EOPNOTSUPP;
|
|
|
}
|