From owner-freebsd-emulation@FreeBSD.ORG Fri Jan 22 19:40:04 2010 Return-Path: Delivered-To: freebsd-emulation@hub.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 2188B1065672 for ; Fri, 22 Jan 2010 19:40:04 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:4f8:fff6::28]) by mx1.freebsd.org (Postfix) with ESMTP id 0F7708FC16 for ; Fri, 22 Jan 2010 19:40:04 +0000 (UTC) Received: from freefall.freebsd.org (localhost [127.0.0.1]) by freefall.freebsd.org (8.14.3/8.14.3) with ESMTP id o0MJe3Wh000722 for ; Fri, 22 Jan 2010 19:40:03 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.3/8.14.3/Submit) id o0MJe3oI000707; Fri, 22 Jan 2010 19:40:03 GMT (envelope-from gnats) Date: Fri, 22 Jan 2010 19:40:03 GMT Message-Id: <201001221940.o0MJe3oI000707@freefall.freebsd.org> To: freebsd-emulation@FreeBSD.org From: Mateusz Guzik Cc: Subject: Re: kern/138860: [linux] linux_socketcall() causing buffer overflow X-BeenThere: freebsd-emulation@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list Reply-To: Mateusz Guzik List-Id: Development of Emulators of other operating systems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 22 Jan 2010 19:40:04 -0000 The following reply was made to PR kern/138860; it has been noted by GNATS. From: Mateusz Guzik 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