On Mon, Jun 02, 2014 at 07:07:50AM -0400, Jiri B wrote: > Hi, > > I got wpa_supplicant core dump. Strange is it is not always > reproducible, it core dumps mostly but sometimes it does not.
> CTRL_IFACE monitor attached > /tmp/wpa_ctrl_9659-2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0 > 0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0 > Abort trap (core dumped) > > (gdb) where > #0 0x00001545475b9fea in kill () at <stdin>:2 > #1 0x00001545475f34bc in __stack_smash_handler (func=0x1543451838c0 > "wpa_supplicant_ctrl_iface_attach", damaged=Variable "damaged" is not > available. > ) at /usr/src/lib/libc/sys/stack_protector.c:61 > #2 0x0000154345056971 in wpa_supplicant_ctrl_iface_attach () from > /usr/local/sbin/wpa_supplicant > #3 0x000015434505789d in wpa_supplicant_ctrl_iface_receive () from > /usr/local/sbin/wpa_supplicant > #4 0x000015434501297a in eloop_sock_table_dispatch () from > /usr/local/sbin/wpa_supplicant > #5 0x0000154345013428 in eloop_run () from /usr/local/sbin/wpa_supplicant > #6 0x0000154345059e11 in wpa_supplicant_run () from > /usr/local/sbin/wpa_supplicant > #7 0x0000154345066fda in main () from /usr/local/sbin/wpa_supplicant The stack smash protector found an off-by-one. It happens when the printf_encode() function writes a NUL to the byte past the output buffer. Attached is a test case which crashes whenever txt - end == 4 during the last loop iteration: [...] data[i]=0x8, end - txt = 13 data[i]=0x4c, end - txt = 9 data[i]=0xff, end - txt = 8 data[i]=0xff, end - txt = 4 Abort trap (core dumped) Fix: Index: Makefile =================================================================== RCS file: /cvs/ports/security/wpa_supplicant/Makefile,v retrieving revision 1.14 diff -u -p -r1.14 Makefile --- Makefile 18 Mar 2014 05:57:22 -0000 1.14 +++ Makefile 2 Jun 2014 12:11:45 -0000 @@ -3,6 +3,7 @@ COMMENT= IEEE 802.1X supplicant DISTNAME= wpa_supplicant-2.1 +REVISION= 0 CATEGORIES= security net HOMEPAGE= http://hostap.epitest.fi/wpa_supplicant/ Index: patches/patch-src_utils_common_c =================================================================== RCS file: patches/patch-src_utils_common_c diff -N patches/patch-src_utils_common_c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ patches/patch-src_utils_common_c 2 Jun 2014 12:14:04 -0000 @@ -0,0 +1,12 @@ +$OpenBSD$ +--- src/utils/common.c.orig Mon Jun 2 14:12:42 2014 ++++ src/utils/common.c Mon Jun 2 14:12:52 2014 +@@ -350,7 +350,7 @@ void printf_encode(char *txt, size_t maxlen, const u8 + size_t i; + + for (i = 0; i < len; i++) { +- if (txt + 4 > end) ++ if (txt + 4 >= end) + break; + + switch (data[i]) {
/* Off-by-one reproduction based on code from wpa_supplicant. * * wpa_supplicant/hostapd / common helper functions, etc. * Copyright (c) 2002-2007, Jouni Malinen <j...@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #include <stddef.h> #include <stdio.h> #include <string.h> #include <sys/socket.h> #include <sys/un.h> void printf_encode(char *txt, size_t maxlen, const unsigned char *data, size_t len) { char *end = txt + maxlen; size_t i; for (i = 0; i < len; i++) { #ifdef DO_NOT_OVERFLOW if (txt + 4 >= end) #else if (txt + 4 > end) #endif break; printf("data[i]=0x%x, end - txt = %d\n", data[i], end - txt); switch (data[i]) { case '\"': *txt++ = '\\'; *txt++ = '\"'; break; case '\\': *txt++ = '\\'; *txt++ = '\\'; break; case '\e': *txt++ = '\\'; *txt++ = 'e'; break; case '\n': *txt++ = '\\'; *txt++ = 'n'; break; case '\r': *txt++ = '\\'; *txt++ = 'r'; break; case '\t': *txt++ = '\\'; *txt++ = 't'; break; default: if (data[i] >= 32 && data[i] <= 127) { *txt++ = data[i]; } else { txt += snprintf(txt, end - txt, "\\x%02x", data[i]); } break; } } *txt = '\0'; } void foo(struct sockaddr_un *from, socklen_t fromlen) { char encoded[200]; memset(encoded, 0, sizeof(encoded)); printf_encode(encoded, sizeof(encoded), (unsigned char *) from->sun_path, fromlen - offsetof(struct sockaddr_un, sun_path)); printf("%s", encoded); } int main() { struct sockaddr_un from; socklen_t fromlen = sizeof(from); strlcpy(from.sun_path, "/tmp/wpa_ctrl_9659-2", sizeof(from.sun_path)); foo(&from, fromlen); return 0; }