Date: Fri, 22 Jan 2010 19:40:03 GMT From: Mateusz Guzik <mjguzik@gmail.com> To: freebsd-emulation@FreeBSD.org Subject: Re: kern/138860: [linux] linux_socketcall() causing buffer overflow Message-ID: <201001221940.o0MJe3oI000707@freefall.freebsd.org>
next in thread | raw e-mail | index | archive | help
The following reply was made to PR kern/138860; it has been noted by GNATS. From: Mateusz Guzik <mjguzik@gmail.com> To: bug-followup@FreeBSD.org, alexbestms@math.uni-muenster.de Cc: Subject: Re: kern/138860: [linux] linux_socketcall() causing buffer overflow Date: Fri, 22 Jan 2010 19:30:25 +0000 Hi, It looks like the problem is caused by this: sys/compat/linux/linux_socket.c : do_sa_get() contains the following code: if (*osalen < 2 || *osalen > UCHAR_MAX || !osa) return (EINVAL); [..] alloclen = *osalen; [..] kosa = malloc(alloclen, mtype, M_WAITOK); // [1] if ((error = copyin(osa, kosa, *osalen))) goto out; bdom = linux_to_bsd_domain(kosa->sa_family); [..] if (bdom == AF_INET) alloclen = sizeof(struct sockaddr_in); // [2] sa = (struct sockaddr *) kosa; sa->sa_family = bdom; sa->sa_len = alloclen; // [3] *sap = sa; *osalen = alloclen; [..] -------- *osalen bytes is allocated in [1]. In [2] we override the old value of alloclen and use it in assignment ([3]). So if *osalen is lower than sizeof(struct sockaddr_in), we return struct that is too small and contains faked length. This defeats checks placed in sys/netinet/in_pcb.c : in_pcbbind_setup() and leads to overflow by this (line 348 as of r202295): [..] bzero(&sin->sin_zero, sizeof(sin->sin_zero)); [..] -------- Proposed patch: http://student.agh.edu.pl/~mjguzik/linux_socket.patch Note: patch also changes return value from EINVAL to EAFNOSUPPORT in case of linux_to_bsd_domain's failure to match behaviour of other callers. Briefly tested with wget, Quake 3 and firefox. -- Mateusz Guzik
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201001221940.o0MJe3oI000707>