diff --git a/CHANGES b/CHANGES index 4724080..efac2c3 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,18 @@ security: + Socat security advisory 8 + A stack overflow in vulnerability was found that can be triggered when + command line arguments (complete address specifications, host names, + file names) are longer than 512 bytes. + Successful exploitation might allow an attacker to execute arbitrary + code with the privileges of the socat process. + This vulnerability can only be exploited when an attacker is able to + inject data into socat's command line. + A vulnerable scenario would be a CGI script that reads data from clients + and uses (parts of) this data as hostname for a Socat invocation. + Test: NESTEDOVFL + Credits to Takumi Akiyama for finding and reporting this issue. + Socat security advisory 7 MSVR-1499 In the OpenSSL address implementation the hard coded 1024 bit DH p @@ -18,7 +31,7 @@ security: security: Socat security advisory 6 - CVE-2015-1379 + CVE-2015-1379: Possible DoS with fork Fixed problems with signal handling caused by use of not async signal safe functions in signal handlers that could freeze socat, allowing denial of service attacks. diff --git a/nestlex.c b/nestlex.c index 97778bc..f4a8962 100644 --- a/nestlex.c +++ b/nestlex.c @@ -1,5 +1,5 @@ /* source: nestlex.c */ -/* Copyright Gerhard Rieger 2006-2010 */ +/* Copyright Gerhard Rieger */ /* Published under the GNU General Public License V.2, see file COPYING */ /* a function for lexical scanning of nested character patterns */ @@ -9,6 +9,17 @@ #include "sysincludes.h" +static int _nestlex(const char **addr, + char **token, + ptrdiff_t *len, + const char *ends[], + const char *hquotes[], + const char *squotes[], + const char *nests[], + bool dropquotes, + bool c_esc, + bool html_esc + ); /* sub: scan a string and copy its value to output string end scanning when an unescaped, unnested string from ends array is found @@ -33,6 +44,22 @@ int nestlex(const char **addr, /* input string; aft points to end token */ bool c_esc, /* solve C char escapes: \n \t \0 etc */ bool html_esc /* solve HTML char escapes: %0d %08 etc */ ) { + return + _nestlex(addr, token, (ptrdiff_t *)len, ends, hquotes, squotes, nests, + dropquotes, c_esc, html_esc); +} + +static int _nestlex(const char **addr, + char **token, + ptrdiff_t *len, + const char *ends[], + const char *hquotes[], + const char *squotes[], + const char *nests[], + bool dropquotes, + bool c_esc, + bool html_esc + ) { const char *in = *addr; /* pointer into input string */ const char **endx; /* loops over end patterns */ const char **quotx; /* loops over quote patterns */ @@ -77,16 +104,18 @@ int nestlex(const char **addr, /* input string; aft points to end token */ if (--*len <= 0) { *addr = in; *token = out; return -1; } } } - /* we call nestlex recursively */ + /* we call _nestlex recursively */ endnest[0] = *quotx; endnest[1] = NULL; result = - nestlex(&in, &out, len, endnest, NULL/*hquotes*/, + _nestlex(&in, &out, len, endnest, NULL/*hquotes*/, NULL/*squotes*/, NULL/*nests*/, false, c_esc, html_esc); if (result == 0 && dropquotes) { /* we strip this quote */ in += strlen(*quotx); + } else if (result < 0) { + *addr = in; *token = out; return result; } else { /* we copy the trailing quote */ for (i = strlen(*quotx); i > 0; --i) { @@ -110,7 +139,7 @@ int nestlex(const char **addr, /* input string; aft points to end token */ if (!strncmp(in, *quotx, strlen(*quotx))) { /* this quote pattern matches */ /* we strip this quote */ - /* we call nestlex recursively */ + /* we call _nestlex recursively */ const char *endnest[2]; if (dropquotes) { /* we strip this quote */ @@ -124,13 +153,15 @@ int nestlex(const char **addr, /* input string; aft points to end token */ endnest[0] = *quotx; endnest[1] = NULL; result = - nestlex(&in, &out, len, endnest, hquotes, + _nestlex(&in, &out, len, endnest, hquotes, squotes, nests, false, c_esc, html_esc); if (result == 0 && dropquotes) { /* we strip the trailing quote */ in += strlen(*quotx); + } else if (result < 0) { + *addr = in; *token = out; return result; } else { /* we copy the trailing quote */ for (i = strlen(*quotx); i > 0; --i) { @@ -162,7 +193,7 @@ int nestlex(const char **addr, /* input string; aft points to end token */ } result = - nestlex(&in, &out, len, endnest, hquotes, squotes, nests, + _nestlex(&in, &out, len, endnest, hquotes, squotes, nests, false, c_esc, html_esc); if (result == 0) { /* copy endnest */ @@ -175,6 +206,8 @@ int nestlex(const char **addr, /* input string; aft points to end token */ } --i; } + } else if (result < 0) { + *addr = in; *token = out; return result; } break; } @@ -211,7 +244,7 @@ int nestlex(const char **addr, /* input string; aft points to end token */ } *out++ = c; --*len; - if (*len == 0) { + if (*len <= 0) { *addr = in; *token = out; return -1; /* output overflow */ @@ -222,7 +255,7 @@ int nestlex(const char **addr, /* input string; aft points to end token */ /* just a simple char */ *out++ = c; --*len; - if (*len == 0) { + if (*len <= 0) { *addr = in; *token = out; return -1; /* output overflow */ diff --git a/nestlex.h b/nestlex.h index fc2b134..8281ef3 100644 --- a/nestlex.h +++ b/nestlex.h @@ -1,5 +1,5 @@ /* source: nestlex.h */ -/* Copyright Gerhard Rieger 2006 */ +/* Copyright Gerhard Rieger */ /* Published under the GNU General Public License V.2, see file COPYING */ #ifndef __nestlex_h_included diff --git a/test.sh b/test.sh index e3febe1..d1a93b3 100755 --- a/test.sh +++ b/test.sh @@ -10989,6 +10989,42 @@ esac PORT=$((PORT+1)) N=$((N+1)) +# socat up to 1.7.3.0 had a stack overflow vulnerability that occurred when +# command line arguments (whole addresses, host names, file names) were longer +# than 512 bytes and specially crafted. +NAME=NESTEDOVFL +case "$TESTS" in +*%$N%*|*%functions%*|*%bugs%*|*%security%*|*%exec%*|*%$NAME%*) +TEST="$NAME: stack overflow on overly long nested arg" +# provide a long host name to TCP-CONNECT and check socats exit code +if ! eval $NUMCOND; then :; else +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +da="test$N $(date) $RANDOM" +# prepare long data - perl might not be installed +rm -f "$td/test$N.dat" +i=0; while [ $i -lt 64 ]; do echo -n "AAAAAAAAAAAAAAAA" >>"$td/test$N.dat"; i=$((i+1)); done +CMD0="$TRACE $SOCAT $opts EXEC:[$(cat "$td/test$N.dat")] STDIO" +printf "test $F_n $TEST... " $N +$CMD0 &0 2>"${te}0" +rc0=$? +if [ $rc0 -lt 128 ] || [ $rc0 -eq 255 ]; then + $PRINTF "$OK\n" + numOK=$((numOK+1)) +else + $PRINTF "$FAILED\n" + echo "$CMD0" + cat "${te}0" + numFAIL=$((numFAIL+1)) + listFAIL="$listFAIL $N" +fi +fi # NUMCOND + ;; +esac +PORT=$((PORT+1)) +N=$((N+1)) + # test for a bug in gopen that lead to crash or warning when opening a unix # domain socket with GOPEN