Update to 2.6.32.41 Mainline
/net/econet/af_econet.c
blob:4be1db5b91cbc0ac883d069effb496a40c45fd26 -> blob:2a3b4e79166d1ad70caf1eb011e8c0396f7e5488
--- net/econet/af_econet.c
+++ net/econet/af_econet.c
@@ -30,7 +30,6 @@
#include <linux/wireless.h>
#include <linux/skbuff.h>
#include <linux/udp.h>
-#include <linux/vmalloc.h>
#include <net/sock.h>
#include <net/inet_common.h>
#include <linux/stat.h>
@@ -276,12 +275,12 @@ static int econet_sendmsg(struct kiocb *
#endif
#ifdef CONFIG_ECONET_AUNUDP
struct msghdr udpmsg;
- struct iovec iov[2];
+ struct iovec iov[msg->msg_iovlen+1];
struct aunhdr ah;
struct sockaddr_in udpdest;
__kernel_size_t size;
+ int i;
mm_segment_t oldfs;
- char *userbuf;
#endif
/*
@@ -319,17 +318,17 @@ static int econet_sendmsg(struct kiocb *
}
}
+ if (len + 15 > dev->mtu) {
+ mutex_unlock(&econet_mutex);
+ return -EMSGSIZE;
+ }
+
if (dev->type == ARPHRD_ECONET) {
/* Real hardware Econet. We're not worthy etc. */
#ifdef CONFIG_ECONET_NATIVE
unsigned short proto = 0;
int res;
- if (len + 15 > dev->mtu) {
- mutex_unlock(&econet_mutex);
- return -EMSGSIZE;
- }
-
dev_hold(dev);
skb = sock_alloc_send_skb(sk, len+LL_ALLOCATED_SPACE(dev),
@@ -405,11 +404,6 @@ static int econet_sendmsg(struct kiocb *
return -ENETDOWN; /* No socket - can't send */
}
- if (len > 32768) {
- err = -E2BIG;
- goto error;
- }
-
/* Make up a UDP datagram and hand it off to some higher intellect. */
memset(&udpdest, 0, sizeof(udpdest));
@@ -441,26 +435,36 @@ static int econet_sendmsg(struct kiocb *
/* tack our header on the front of the iovec */
size = sizeof(struct aunhdr);
+ /*
+ * XXX: that is b0rken. We can't mix userland and kernel pointers
+ * in iovec, since on a lot of platforms copy_from_user() will
+ * *not* work with the kernel and userland ones at the same time,
+ * regardless of what we do with set_fs(). And we are talking about
+ * econet-over-ethernet here, so "it's only ARM anyway" doesn't
+ * apply. Any suggestions on fixing that code? -- AV
+ */
iov[0].iov_base = (void *)&ah;
iov[0].iov_len = size;
-
- userbuf = vmalloc(len);
- if (userbuf == NULL) {
- err = -ENOMEM;
- goto error;
+ for (i = 0; i < msg->msg_iovlen; i++) {
+ void __user *base = msg->msg_iov[i].iov_base;
+ size_t len = msg->msg_iov[i].iov_len;
+ /* Check it now since we switch to KERNEL_DS later. */
+ if (!access_ok(VERIFY_READ, base, len)) {
+ mutex_unlock(&econet_mutex);
+ return -EFAULT;
+ }
+ iov[i+1].iov_base = base;
+ iov[i+1].iov_len = len;
+ size += len;
}
- iov[1].iov_base = userbuf;
- iov[1].iov_len = len;
- err = memcpy_fromiovec(userbuf, msg->msg_iov, len);
- if (err)
- goto error_free_buf;
-
/* Get a skbuff (no data, just holds our cb information) */
if ((skb = sock_alloc_send_skb(sk, 0,
msg->msg_flags & MSG_DONTWAIT,
- &err)) == NULL)
- goto error_free_buf;
+ &err)) == NULL) {
+ mutex_unlock(&econet_mutex);
+ return err;
+ }
eb = (struct ec_cb *)&skb->cb;
@@ -476,7 +480,7 @@ static int econet_sendmsg(struct kiocb *
udpmsg.msg_name = (void *)&udpdest;
udpmsg.msg_namelen = sizeof(udpdest);
udpmsg.msg_iov = &iov[0];
- udpmsg.msg_iovlen = 2;
+ udpmsg.msg_iovlen = msg->msg_iovlen + 1;
udpmsg.msg_control = NULL;
udpmsg.msg_controllen = 0;
udpmsg.msg_flags=0;
@@ -484,13 +488,9 @@ static int econet_sendmsg(struct kiocb *
oldfs = get_fs(); set_fs(KERNEL_DS); /* More privs :-) */
err = sock_sendmsg(udpsock, &udpmsg, size);
set_fs(oldfs);
-
-error_free_buf:
- vfree(userbuf);
#else
err = -EPROTOTYPE;
#endif
- error:
mutex_unlock(&econet_mutex);
return err;