Restore the length check of a sockaddr passed from userland at udp6_output

A sockaddr with invalid length could be passed to the network stack resulting in
a kernel panic like this:

	panic: sockaddr_copy: source too long, 28 < 128 bytes
	fatal breakpoint trap in supervisor mode
	trap type 1 code 0 rip 0xffffffff80216c35 cs 0x8 rflags 0x246 cr2 0x7f7ff7ef3000 ilevel 0x4 rsp 0xffff80003308b690
	curlwp 0xfffffe803e11ca40 pid 48.1 lowest kstack 0xffff8000330852c0
	Stopped in pid 48.1 (a.out) at  netbsd:breakpoint+0x5:  leave
	db{1}> bt
	breakpoint() at netbsd:breakpoint+0x5
	vpanic() at netbsd:vpanic+0x140
	panic() at netbsd:panic+0x3c
	sockaddr_copy() at netbsd:sockaddr_copy+0x95
	rtcache_setdst() at netbsd:rtcache_setdst+0x73
	rtcache_lookup2() at netbsd:rtcache_lookup2+0x56
	in6_selectroute() at netbsd:in6_selectroute+0x184
	in6_selectsrc() at netbsd:in6_selectsrc+0x119
	udp6_output() at netbsd:udp6_output+0x25e
	udp6_send_wrapper() at netbsd:udp6_send_wrapper+0x8a
	sosend() at netbsd:sosend+0x7bf
	do_sys_sendmsg_so() at netbsd:do_sys_sendmsg_so+0x28e
	do_sys_sendmsg() at netbsd:do_sys_sendmsg+0x89
	sys_sendto() at netbsd:sys_sendto+0x5c
	syscall() at netbsd:syscall+0x1ed
	--- syscall (number 133) ---
	7f7ff790173a:

Reported by Paul Ripke
This commit is contained in:
ozaki-r 2018-11-06 04:27:41 +00:00
parent d482d53137
commit 1266a13d1c
1 changed files with 6 additions and 2 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: udp6_usrreq.c,v 1.142 2018/11/04 08:48:01 mlelstv Exp $ */
/* $NetBSD: udp6_usrreq.c,v 1.143 2018/11/06 04:27:41 ozaki-r Exp $ */
/* $KAME: udp6_usrreq.c,v 1.86 2001/05/27 17:33:00 itojun Exp $ */
/* $KAME: udp6_output.c,v 1.43 2001/10/15 09:19:52 itojun Exp $ */
@ -63,7 +63,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: udp6_usrreq.c,v 1.142 2018/11/04 08:48:01 mlelstv Exp $");
__KERNEL_RCSID(0, "$NetBSD: udp6_usrreq.c,v 1.143 2018/11/06 04:27:41 ozaki-r Exp $");
#ifdef _KERNEL_OPT
#include "opt_inet.h"
@ -668,6 +668,10 @@ udp6_output(struct in6pcb * const in6p, struct mbuf *m,
if (addr6) {
sin6 = addr6;
if (sin6->sin6_len != sizeof(*sin6)) {
error = EINVAL;
goto release;
}
if (sin6->sin6_family != AF_INET6) {
error = EAFNOSUPPORT;
goto release;