diff options
author | Mark Johnston <markj@FreeBSD.org> | 2021-09-19 17:45:09 +0000 |
---|---|---|
committer | Mark Johnston <markj@FreeBSD.org> | 2021-09-19 17:54:16 +0000 |
commit | fea1a98ead918b39280b586773a923e76194400b (patch) | |
tree | ef81adaf2242fd78acc8cf0ed80f8ae585c88348 | |
parent | 4bda16ff184bfca5ee4bf9709a06323d9cf5945b (diff) | |
download | src-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.c | 14 |
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); |