summaryrefslogtreecommitdiffstats
path: root/sys/compat
diff options
context:
space:
mode:
authordchagin <dchagin@FreeBSD.org>2016-01-09 16:26:39 +0000
committerdchagin <dchagin@FreeBSD.org>2016-01-09 16:26:39 +0000
commitc0b5073f8da1bd5f4d69c11f33fb728424c7a053 (patch)
tree9e53f2eb7bd6f9995c65e00e0a0fb756d66a5b64 /sys/compat
parenta1e3b366c78d8dbd5b80f830911528438032f941 (diff)
downloadFreeBSD-src-c0b5073f8da1bd5f4d69c11f33fb728424c7a053.zip
FreeBSD-src-c0b5073f8da1bd5f4d69c11f33fb728424c7a053.tar.gz
MFC r283433:
Rewrite linux_recvfrom. To avoid double conversion of sockaddr use kern_recvit() directly. And check fromlen parameter before sockaddr copyin and conversion.
Diffstat (limited to 'sys/compat')
-rw-r--r--sys/compat/linux/linux_socket.c66
1 files changed, 37 insertions, 29 deletions
diff --git a/sys/compat/linux/linux_socket.c b/sys/compat/linux/linux_socket.c
index ad21fe9..99537e5 100644
--- a/sys/compat/linux/linux_socket.c
+++ b/sys/compat/linux/linux_socket.c
@@ -428,7 +428,6 @@ linux_to_bsd_sockaddr(struct sockaddr *arg, int len)
return (error);
}
-
static int
linux_sa_put(struct osockaddr *osa)
{
@@ -1027,41 +1026,50 @@ linux_sendto(struct thread *td, struct linux_sendto_args *args)
int
linux_recvfrom(struct thread *td, struct linux_recvfrom_args *args)
{
- struct recvfrom_args /* {
- int s;
- caddr_t buf;
- size_t len;
- int flags;
- struct sockaddr * __restrict from;
- socklen_t * __restrict fromlenaddr;
- } */ bsd_args;
- size_t len;
+ struct msghdr msg;
+ struct iovec aiov;
int error;
- if ((error = copyin(PTRIN(args->fromlen), &len, sizeof(size_t))))
- return (error);
+ if (PTRIN(args->fromlen) != NULL) {
+ error = copyin(PTRIN(args->fromlen), &msg.msg_namelen,
+ sizeof(msg.msg_namelen));
+ if (error != 0)
+ return (error);
- bsd_args.s = args->s;
- bsd_args.buf = PTRIN(args->buf);
- bsd_args.len = args->len;
- bsd_args.flags = linux_to_bsd_msg_flags(args->flags);
- /* XXX: */
- bsd_args.from = (struct sockaddr * __restrict)PTRIN(args->from);
- bsd_args.fromlenaddr = PTRIN(args->fromlen);/* XXX */
-
- linux_to_bsd_sockaddr((struct sockaddr *)bsd_args.from, len);
- error = sys_recvfrom(td, &bsd_args);
- bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.from);
-
- if (error)
+ error = linux_to_bsd_sockaddr((struct sockaddr *)PTRIN(args->from),
+ msg.msg_namelen);
+ if (error != 0)
+ return (error);
+ } else
+ msg.msg_namelen = 0;
+
+ msg.msg_name = (struct sockaddr * __restrict)PTRIN(args->from);
+ msg.msg_iov = &aiov;
+ msg.msg_iovlen = 1;
+ aiov.iov_base = PTRIN(args->buf);
+ aiov.iov_len = args->len;
+ msg.msg_control = 0;
+ msg.msg_flags = linux_to_bsd_msg_flags(args->flags);
+
+ error = kern_recvit(td, args->s, &msg, UIO_USERSPACE, NULL);
+ if (error != 0)
return (error);
- if (args->from) {
- error = linux_sa_put((struct osockaddr *)
+
+ if (PTRIN(args->from) != NULL) {
+ error = bsd_to_linux_sockaddr((struct sockaddr *)
PTRIN(args->from));
- if (error)
+ if (error != 0)
return (error);
+
+ error = linux_sa_put((struct osockaddr *)
+ PTRIN(args->from));
}
- return (0);
+
+ if (PTRIN(args->fromlen) != NULL)
+ error = copyout(&msg.msg_namelen, PTRIN(args->fromlen),
+ sizeof(msg.msg_namelen));
+
+ return (error);
}
int
OpenPOWER on IntegriCloud