kern/138860: [linux] linux_socketcall() causing buffer overflow
Mateusz Guzik
mjguzik at gmail.com
Fri Jan 22 19:40:04 UTC 2010
The following reply was made to PR kern/138860; it has been noted by GNATS.
From: Mateusz Guzik <mjguzik at gmail.com>
To: bug-followup at FreeBSD.org, alexbestms at 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
More information about the freebsd-emulation
mailing list