aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Johnston <markj@FreeBSD.org>2021-09-19 17:45:09 +0000
committerMark Johnston <markj@FreeBSD.org>2021-09-19 17:54:16 +0000
commitfea1a98ead918b39280b586773a923e76194400b (patch)
treeef81adaf2242fd78acc8cf0ed80f8ae585c88348
parent4bda16ff184bfca5ee4bf9709a06323d9cf5945b (diff)
downloadsrc-fea1a98ead918b39280b586773a923e76194400b.tar.gz
src-fea1a98ead918b39280b586773a923e76194400b.zip
freebsd32: Fix a double copyin in sendmsg() and recvmsg()
freebsd32_sendmsg() and freebsd32_recvmsg() both copyin the message header twice, once directly and once in freebsd32_copyinmsghdr(). The iovec length from the former is used when copying in msg_iov, but the rest of the kernel uses the iovec length from the latter. When kern_sendit() and kern_recvit() iterate over the iovec to compute the residual for I/O, they can therefore end up walking past the end of the copied in iovec, either resulting in a system call error, userspace memory corruption from uiomove() with invalid iovecs, or a kernel page fault if the copied-in iovec is followed by an unmapped KVA region. Reported by: syzbot+7cc64cd0c49605acd421@syzkaller.appspotmail.com Reviewed by: kib, emaste MFC after: 1 week Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D32010
-rw-r--r--sys/compat/freebsd32/freebsd32_misc.c14
1 files changed, 3 insertions, 11 deletions
diff --git a/sys/compat/freebsd32/freebsd32_misc.c b/sys/compat/freebsd32/freebsd32_misc.c
index be942f9fafd3..08941ebc5be9 100644
--- a/sys/compat/freebsd32/freebsd32_misc.c
+++ b/sys/compat/freebsd32/freebsd32_misc.c
@@ -1414,19 +1414,15 @@ int
freebsd32_recvmsg(struct thread *td, struct freebsd32_recvmsg_args *uap)
{
struct msghdr msg;
- struct msghdr32 m32;
struct iovec *uiov, *iov;
struct mbuf *control = NULL;
struct mbuf **controlp;
-
int error;
- error = copyin(uap->msg, &m32, sizeof(m32));
- if (error)
- return (error);
+
error = freebsd32_copyinmsghdr(uap->msg, &msg);
if (error)
return (error);
- error = freebsd32_copyiniov(PTRIN(m32.msg_iov), m32.msg_iovlen, &iov,
+ error = freebsd32_copyiniov((void *)msg.msg_iov, msg.msg_iovlen, &iov,
EMSGSIZE);
if (error)
return (error);
@@ -1559,19 +1555,15 @@ int
freebsd32_sendmsg(struct thread *td, struct freebsd32_sendmsg_args *uap)
{
struct msghdr msg;
- struct msghdr32 m32;
struct iovec *iov;
struct mbuf *control = NULL;
struct sockaddr *to = NULL;
int error;
- error = copyin(uap->msg, &m32, sizeof(m32));
- if (error)
- return (error);
error = freebsd32_copyinmsghdr(uap->msg, &msg);
if (error)
return (error);
- error = freebsd32_copyiniov(PTRIN(m32.msg_iov), m32.msg_iovlen, &iov,
+ error = freebsd32_copyiniov((void *)msg.msg_iov, msg.msg_iovlen, &iov,
EMSGSIZE);
if (error)
return (error);