From: Christoph Hellwig <[email protected]>
To: Alexander Viro <[email protected]>
Cc: Andrew Morton <[email protected]>,
Jens Axboe <[email protected]>, Arnd Bergmann <[email protected]>,
David Howells <[email protected]>,
David Laight <[email protected]>,
[email protected],
[email protected], [email protected],
[email protected], [email protected],
[email protected], [email protected],
[email protected], [email protected],
[email protected], [email protected],
[email protected], [email protected],
[email protected], [email protected],
[email protected], [email protected]
Subject: [PATCH 05/11] iov_iter: merge the compat case into rw_copy_check_uvector
Date: Mon, 21 Sep 2020 16:34:28 +0200 [thread overview]
Message-ID: <[email protected]> (raw)
In-Reply-To: <[email protected]>
Stop duplicating the iovec verify code, and instead add add a
__import_iovec helper that does the whole verify and import, but takes
a bool compat to decided on the native or compat layout. This also
ends up massively simplifying the calling conventions.
Signed-off-by: Christoph Hellwig <[email protected]>
---
lib/iov_iter.c | 195 ++++++++++++++++++-------------------------------
1 file changed, 70 insertions(+), 125 deletions(-)
diff --git a/lib/iov_iter.c b/lib/iov_iter.c
index a64867501a7483..8bfa47b63d39aa 100644
--- a/lib/iov_iter.c
+++ b/lib/iov_iter.c
@@ -10,6 +10,7 @@
#include <net/checksum.h>
#include <linux/scatterlist.h>
#include <linux/instrumented.h>
+#include <linux/compat.h>
#define PIPE_PARANOIA /* for now */
@@ -1650,43 +1651,76 @@ const void *dup_iter(struct iov_iter *new, struct iov_iter *old, gfp_t flags)
}
EXPORT_SYMBOL(dup_iter);
-static ssize_t rw_copy_check_uvector(int type,
- const struct iovec __user *uvector, unsigned long nr_segs,
- unsigned long fast_segs, struct iovec *fast_pointer,
- struct iovec **ret_pointer)
+static int compat_copy_iovecs_from_user(struct iovec *iov,
+ const struct iovec __user *uvector, unsigned long nr_segs)
+{
+ const struct compat_iovec __user *uiov =
+ (const struct compat_iovec __user *)uvector;
+ unsigned long i;
+ int ret = -EFAULT;
+
+ if (!user_access_begin(uvector, nr_segs * sizeof(*uvector)))
+ return -EFAULT;
+
+ for (i = 0; i < nr_segs; i++) {
+ compat_uptr_t buf;
+ compat_ssize_t len;
+
+ unsafe_get_user(len, &uiov[i].iov_len, out);
+ unsafe_get_user(buf, &uiov[i].iov_base, out);
+
+ /* check for compat_size_t not fitting in compat_ssize_t .. */
+ if (len < 0) {
+ ret = -EINVAL;
+ goto out;
+ }
+ iov[i].iov_base = compat_ptr(buf);
+ iov[i].iov_len = len;
+ }
+ ret = 0;
+out:
+ user_access_end();
+ return ret;
+}
+
+static ssize_t __import_iovec(int type, const struct iovec __user *uvector,
+ unsigned nr_segs, unsigned fast_segs, struct iovec **iovp,
+ struct iov_iter *i, bool compat)
{
+ struct iovec *iov = *iovp;
unsigned long seg;
- ssize_t ret;
- struct iovec *iov = fast_pointer;
+ ssize_t ret = 0;
/*
* SuS says "The readv() function *may* fail if the iovcnt argument
* was less than or equal to 0, or greater than {IOV_MAX}. Linux has
* traditionally returned zero for zero segments, so...
*/
- if (nr_segs == 0) {
- ret = 0;
- goto out;
- }
+ if (nr_segs == 0)
+ goto done;
/*
* First get the "struct iovec" from user memory and
* verify all the pointers
*/
- if (nr_segs > UIO_MAXIOV) {
- ret = -EINVAL;
- goto out;
- }
+ ret = -EINVAL;
+ if (nr_segs > UIO_MAXIOV)
+ goto fail;
if (nr_segs > fast_segs) {
+ ret = -ENOMEM;
iov = kmalloc_array(nr_segs, sizeof(struct iovec), GFP_KERNEL);
- if (iov == NULL) {
- ret = -ENOMEM;
- goto out;
- }
+ if (!iov)
+ goto fail;
}
- if (copy_from_user(iov, uvector, nr_segs*sizeof(*uvector))) {
+
+ if (compat) {
+ ret = compat_copy_iovecs_from_user(iov, uvector, nr_segs);
+ if (ret)
+ goto fail;
+ } else {
ret = -EFAULT;
- goto out;
+ if (copy_from_user(iov, uvector, nr_segs * sizeof(*uvector)))
+ goto fail;
}
/*
@@ -1707,11 +1741,11 @@ static ssize_t rw_copy_check_uvector(int type,
* it's about to overflow ssize_t */
if (len < 0) {
ret = -EINVAL;
- goto out;
+ goto fail;
}
if (type != CHECK_IOVEC_ONLY && !access_ok(buf, len)) {
ret = -EFAULT;
- goto out;
+ goto fail;
}
if (len > MAX_RW_COUNT - ret) {
len = MAX_RW_COUNT - ret;
@@ -1719,8 +1753,17 @@ static ssize_t rw_copy_check_uvector(int type,
}
ret += len;
}
-out:
- *ret_pointer = iov;
+done:
+ iov_iter_init(i, type, iov, nr_segs, ret);
+ if (iov == *iovp)
+ *iovp = NULL;
+ else
+ *iovp = iov;
+ return ret;
+fail:
+ if (iov != *iovp)
+ kfree(iov);
+ *iovp = NULL;
return ret;
}
@@ -1750,116 +1793,18 @@ ssize_t import_iovec(int type, const struct iovec __user * uvector,
unsigned nr_segs, unsigned fast_segs,
struct iovec **iov, struct iov_iter *i)
{
- ssize_t n;
- struct iovec *p;
- n = rw_copy_check_uvector(type, uvector, nr_segs, fast_segs,
- *iov, &p);
- if (n < 0) {
- if (p != *iov)
- kfree(p);
- *iov = NULL;
- return n;
- }
- iov_iter_init(i, type, p, nr_segs, n);
- *iov = p == *iov ? NULL : p;
- return n;
+ return __import_iovec(type, uvector, nr_segs, fast_segs, iov, i, false);
}
EXPORT_SYMBOL(import_iovec);
#ifdef CONFIG_COMPAT
-#include <linux/compat.h>
-
-static ssize_t compat_rw_copy_check_uvector(int type,
- const struct compat_iovec __user *uvector, unsigned long nr_segs,
- unsigned long fast_segs, struct iovec *fast_pointer,
- struct iovec **ret_pointer)
-{
- compat_ssize_t tot_len;
- struct iovec *iov = *ret_pointer = fast_pointer;
- ssize_t ret = 0;
- int seg;
-
- /*
- * SuS says "The readv() function *may* fail if the iovcnt argument
- * was less than or equal to 0, or greater than {IOV_MAX}. Linux has
- * traditionally returned zero for zero segments, so...
- */
- if (nr_segs == 0)
- goto out;
-
- ret = -EINVAL;
- if (nr_segs > UIO_MAXIOV)
- goto out;
- if (nr_segs > fast_segs) {
- ret = -ENOMEM;
- iov = kmalloc_array(nr_segs, sizeof(struct iovec), GFP_KERNEL);
- if (iov == NULL)
- goto out;
- }
- *ret_pointer = iov;
-
- ret = -EFAULT;
- if (!access_ok(uvector, nr_segs*sizeof(*uvector)))
- goto out;
-
- /*
- * Single unix specification:
- * We should -EINVAL if an element length is not >= 0 and fitting an
- * ssize_t.
- *
- * In Linux, the total length is limited to MAX_RW_COUNT, there is
- * no overflow possibility.
- */
- tot_len = 0;
- ret = -EINVAL;
- for (seg = 0; seg < nr_segs; seg++) {
- compat_uptr_t buf;
- compat_ssize_t len;
-
- if (__get_user(len, &uvector->iov_len) ||
- __get_user(buf, &uvector->iov_base)) {
- ret = -EFAULT;
- goto out;
- }
- if (len < 0) /* size_t not fitting in compat_ssize_t .. */
- goto out;
- if (type != CHECK_IOVEC_ONLY &&
- !access_ok(compat_ptr(buf), len)) {
- ret = -EFAULT;
- goto out;
- }
- if (len > MAX_RW_COUNT - tot_len)
- len = MAX_RW_COUNT - tot_len;
- tot_len += len;
- iov->iov_base = compat_ptr(buf);
- iov->iov_len = (compat_size_t) len;
- uvector++;
- iov++;
- }
- ret = tot_len;
-
-out:
- return ret;
-}
-
ssize_t compat_import_iovec(int type,
const struct compat_iovec __user * uvector,
unsigned nr_segs, unsigned fast_segs,
struct iovec **iov, struct iov_iter *i)
{
- ssize_t n;
- struct iovec *p;
- n = compat_rw_copy_check_uvector(type, uvector, nr_segs, fast_segs,
- *iov, &p);
- if (n < 0) {
- if (p != *iov)
- kfree(p);
- *iov = NULL;
- return n;
- }
- iov_iter_init(i, type, p, nr_segs, n);
- *iov = p == *iov ? NULL : p;
- return n;
+ return __import_iovec(type, (const struct iovec __user *)uvector,
+ nr_segs, fast_segs, iov, i, true);
}
EXPORT_SYMBOL(compat_import_iovec);
#endif
--
2.28.0
next prev parent reply other threads:[~2020-09-21 14:35 UTC|newest]
Thread overview: 26+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-09-21 14:34 let import_iovec deal with compat_iovecs as well v2 Christoph Hellwig
2020-09-21 14:34 ` [PATCH 01/11] compat.h: fix a spelling error in <linux/compat.h> Christoph Hellwig
2020-09-21 14:34 ` [PATCH 02/11] mm: call import_iovec() instead of rw_copy_check_uvector() in process_vm_rw() Christoph Hellwig
2020-09-21 14:48 ` Matthew Wilcox
2020-09-21 15:02 ` Al Viro
2020-09-21 15:21 ` David Laight
2020-09-21 15:29 ` Al Viro
2020-09-21 15:44 ` David Laight
2020-09-21 16:27 ` Al Viro
2020-09-21 16:12 ` Christoph Hellwig
2020-09-21 14:34 ` [PATCH 03/11] iov_iter: move rw_copy_check_uvector() into lib/iov_iter.c and mark it static Christoph Hellwig
2020-09-21 14:34 ` [PATCH 04/11] iov_iter: explicitly check for CHECK_IOVEC_ONLY in rw_copy_check_uvector Christoph Hellwig
2020-09-21 15:05 ` David Laight
2020-09-21 15:11 ` Al Viro
2020-09-21 15:26 ` David Laight
2020-09-21 15:07 ` Al Viro
2020-09-21 14:34 ` Christoph Hellwig [this message]
2020-09-21 15:14 ` [PATCH 05/11] iov_iter: merge the compat case into rw_copy_check_uvector Al Viro
2021-01-08 11:49 ` David Laight
2020-09-21 14:34 ` [PATCH 06/11] iov_iter: handle the compat case in import_iovec Christoph Hellwig
2020-09-21 15:20 ` Al Viro
2020-09-21 14:34 ` [PATCH 07/11] fs: remove various compat readv/writev helpers Christoph Hellwig
2020-09-21 14:34 ` [PATCH 08/11] fs: remove the compat readv/writev syscalls Christoph Hellwig
2020-09-21 14:34 ` [PATCH 09/11] fs: remove compat_sys_vmsplice Christoph Hellwig
2020-09-21 14:34 ` [PATCH 10/11] mm: remove compat_process_vm_{readv,writev} Christoph Hellwig
2020-09-21 14:34 ` [PATCH 11/11] security/keys: remove compat_keyctl_instantiate_key_iov Christoph Hellwig
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
[email protected] \
[email protected] \
[email protected] \
[email protected] \
[email protected] \
[email protected] \
[email protected] \
[email protected] \
[email protected] \
[email protected] \
[email protected] \
[email protected] \
[email protected] \
[email protected] \
[email protected] \
[email protected] \
[email protected] \
[email protected] \
[email protected] \
[email protected] \
[email protected] \
[email protected] \
[email protected] \
[email protected] \
[email protected] \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox