netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Al Viro <viro@ZenIV.linux.org.uk>
To: davem@davemloft.net
Cc: netdev@vger.kernel.org
Subject: [PATCH 06/17] saner iov_iter initialization primitives
Date: Sat, 11 Apr 2015 22:18:17 +0100	[thread overview]
Message-ID: <1428787108-13650-6-git-send-email-viro@ZenIV.linux.org.uk> (raw)
In-Reply-To: <20150411211742.GJ889@ZenIV.linux.org.uk>

From: Al Viro <viro@zeniv.linux.org.uk>

iovec-backed iov_iter instances are assumed to satisfy several properties:
	* no more than UIO_MAXIOV elements in iovec array
	* total size of all ranges is no more than MAX_RW_COUNT
	* all ranges pass access_ok().

The problem is, invariants of data structures should be established in the
primitives creating those data structures, not in the code using those
primitives.  And iov_iter_init() violates that principle.  For a while we
managed to get away with that, but once the use of iov_iter started to
spread, it didn't take long for shit to hit the fan - missed check in
sys_sendto() had introduced a roothole.

We _do_ have primitives for importing and validating iovecs (both native and
compat ones) and those primitives are almost always followed by shoving the
resulting iovec into iov_iter.  Life would be considerably simpler (and safer)
if we combined those primitives with initializing iov_iter.

That gives us two new primitives - import_iovec() and compat_import_iovec().
Calling conventions:
	iovec = iov_array;
	err = import_iovec(direction, uvec, nr_segs,
			   ARRAY_SIZE(iov_array), &iovec,
			   &iter);
imports user vector into kernel space (into iov_array if it fits, allocated
if it doesn't fit or if iovec was NULL), validates it and sets iter up to
refer to it.  On success 0 is returned and allocated kernel copy (or NULL
if the array had fit into caller-supplied one) is returned via iovec.
On failure all allocations are undone and -E... is returned.  If the total
size of ranges exceeds MAX_RW_COUNT, the excess is silently truncated.

compat_import_iovec() expects uvec to be a pointer to user array of compat_iovec;
otherwise it's identical to import_iovec().

Finally, import_single_range() sets iov_iter backed by single-element iovec
covering a user-supplied range -

	err = import_single_range(direction, address, size, iovec, &iter);

does validation and sets iter up.  Again, size in excess of MAX_RW_COUNT gets
silently truncated.

Next commits will be switching the things up to use of those and reducing
the amount of iov_iter_init() instances.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
 include/linux/uio.h | 14 +++++++++++++
 lib/iov_iter.c      | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 71 insertions(+)

diff --git a/include/linux/uio.h b/include/linux/uio.h
index 7188029..1f4a37f 100644
--- a/include/linux/uio.h
+++ b/include/linux/uio.h
@@ -139,4 +139,18 @@ static inline void iov_iter_reexpand(struct iov_iter *i, size_t count)
 size_t csum_and_copy_to_iter(void *addr, size_t bytes, __wsum *csum, struct iov_iter *i);
 size_t csum_and_copy_from_iter(void *addr, size_t bytes, __wsum *csum, struct iov_iter *i);
 
+int import_iovec(int type, const struct iovec __user * uvector,
+		 unsigned nr_segs, unsigned fast_segs,
+		 struct iovec **iov, struct iov_iter *i);
+
+#ifdef CONFIG_COMPAT
+struct compat_iovec;
+int compat_import_iovec(int type, const struct compat_iovec __user * uvector,
+		 unsigned nr_segs, unsigned fast_segs,
+		 struct iovec **iov, struct iov_iter *i);
+#endif
+
+int import_single_range(int type, void __user *buf, size_t len,
+		 struct iovec *iov, struct iov_iter *i);
+
 #endif
diff --git a/lib/iov_iter.c b/lib/iov_iter.c
index 9d96e283..fc6e33f 100644
--- a/lib/iov_iter.c
+++ b/lib/iov_iter.c
@@ -766,3 +766,60 @@ const void *dup_iter(struct iov_iter *new, struct iov_iter *old, gfp_t flags)
 				   flags);
 }
 EXPORT_SYMBOL(dup_iter);
+
+int 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 0;
+}
+EXPORT_SYMBOL(import_iovec);
+
+#ifdef CONFIG_COMPAT
+#include <linux/compat.h>
+
+int 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 0;
+}
+#endif
+
+int import_single_range(int rw, void __user *buf, size_t len,
+		 struct iovec *iov, struct iov_iter *i)
+{
+	if (len > MAX_RW_COUNT)
+		len = MAX_RW_COUNT;
+	if (unlikely(!access_ok(!rw, buf, len)))
+		return -EFAULT;
+
+	iov->iov_base = buf;
+	iov->iov_len = len;
+	iov_iter_init(i, rw, iov, 1, len);
+	return 0;
+}
-- 
2.1.4

  parent reply	other threads:[~2015-04-11 21:18 UTC|newest]

Thread overview: 36+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-04-11 21:17 [call for review] netdev-related stuff in vfs.git Al Viro
2015-04-11 21:18 ` [PATCH 01/17] fs: remove ki_nbytes Al Viro
2015-04-11 21:18 ` [PATCH 02/17] fuse: handle synchronous iocbs internally Al Viro
2015-04-11 21:18 ` [PATCH 03/17] fs: don't allow to complete sync iocbs through aio_complete Al Viro
2015-04-14 18:00   ` Tadeusz Struk
2015-04-14 18:26     ` Al Viro
2015-04-14 18:37       ` Tadeusz Struk
2015-04-14 19:22         ` Al Viro
2015-04-11 21:18 ` [PATCH 04/17] fs: split generic and aio kiocb Al Viro
2015-04-11 21:18 ` [PATCH 05/17] fs: move struct kiocb to fs.h Al Viro
2015-04-11 21:18 ` Al Viro [this message]
2015-04-11 21:18 ` [PATCH 07/17] RxRPC: Fix the conversion to iov_iter Al Viro
2015-04-11 21:18 ` [PATCH 08/17] RxRPC: Don't call skb_add_data() if there's no data to copy Al Viro
2015-04-11 21:18 ` [PATCH 09/17] RxRPC: Use iov_iter_count() in rxrpc_send_data() instead of the len argument Al Viro
2015-04-11 21:18 ` [PATCH 10/17] AFS: afs_send_empty_reply() doesn't require an iovec array Al Viro
2015-04-11 21:18 ` [PATCH 11/17] RxRPC: Handle VERSION Rx protocol packets Al Viro
2015-04-11 21:18 ` [PATCH 12/17] kafs: Add more "unified AFS" error codes Al Viro
2015-04-11 21:18 ` [PATCH 13/17] net: switch sendto() and recvfrom() to import_single_range() Al Viro
2015-04-11 21:18 ` [PATCH 14/17] net: switch importing msghdr from userland to {compat_,}import_iovec() Al Viro
2015-04-11 21:18 ` [PATCH 15/17] switch kernel_sendmsg() and kernel_recvmsg() to iov_iter_kvec() Al Viro
2015-04-14 16:21   ` David Laight
2015-04-14 16:34     ` Al Viro
2015-04-14 16:36       ` David Laight
2015-04-14 16:59         ` Al Viro
2015-04-15  9:08           ` David Laight
2015-04-15  9:36             ` Daniel Borkmann
2015-04-15  9:53               ` David Laight
2015-04-11 21:18 ` [PATCH 16/17] get rid of the size argument of sock_sendmsg() Al Viro
2015-04-14 16:25   ` David Laight
2015-04-14 16:35     ` Al Viro
2015-04-14 16:44       ` Al Viro
2015-04-14 17:55       ` David Miller
2015-04-15  8:37         ` David Laight
2015-04-15 10:15           ` Eric Dumazet
2015-04-15 16:06           ` David Miller
2015-04-11 21:18 ` [PATCH 17/17] new helper: msg_data_left() Al Viro

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 \
    --in-reply-to=1428787108-13650-6-git-send-email-viro@ZenIV.linux.org.uk \
    --to=viro@zeniv.linux.org.uk \
    --cc=davem@davemloft.net \
    --cc=netdev@vger.kernel.org \
    /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;
as well as URLs for NNTP newsgroup(s).