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;
}

Reply via email to