socat security advisory 8: stack overflow in nestlex()

This commit is contained in:
Gerhard Rieger 2016-01-26 19:08:18 +01:00
parent eab3c89f2d
commit 226c555edb
4 changed files with 92 additions and 10 deletions

15
CHANGES
View file

@ -1,5 +1,18 @@
security: 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 Socat security advisory 7
MSVR-1499 MSVR-1499
In the OpenSSL address implementation the hard coded 1024 bit DH p In the OpenSSL address implementation the hard coded 1024 bit DH p
@ -18,7 +31,7 @@ security:
security: security:
Socat security advisory 6 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 Fixed problems with signal handling caused by use of not async signal
safe functions in signal handlers that could freeze socat, allowing safe functions in signal handlers that could freeze socat, allowing
denial of service attacks. denial of service attacks.

View file

@ -1,5 +1,5 @@
/* source: nestlex.c */ /* source: nestlex.c */
/* Copyright Gerhard Rieger 2006-2010 */ /* Copyright Gerhard Rieger */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
/* a function for lexical scanning of nested character patterns */ /* a function for lexical scanning of nested character patterns */
@ -9,6 +9,17 @@
#include "sysincludes.h" #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 /* sub: scan a string and copy its value to output string
end scanning when an unescaped, unnested string from ends array is found 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 c_esc, /* solve C char escapes: \n \t \0 etc */
bool html_esc /* solve HTML char escapes: %0d %08 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 *in = *addr; /* pointer into input string */
const char **endx; /* loops over end patterns */ const char **endx; /* loops over end patterns */
const char **quotx; /* loops over quote 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; } if (--*len <= 0) { *addr = in; *token = out; return -1; }
} }
} }
/* we call nestlex recursively */ /* we call _nestlex recursively */
endnest[0] = *quotx; endnest[0] = *quotx;
endnest[1] = NULL; endnest[1] = NULL;
result = result =
nestlex(&in, &out, len, endnest, NULL/*hquotes*/, _nestlex(&in, &out, len, endnest, NULL/*hquotes*/,
NULL/*squotes*/, NULL/*nests*/, NULL/*squotes*/, NULL/*nests*/,
false, c_esc, html_esc); false, c_esc, html_esc);
if (result == 0 && dropquotes) { if (result == 0 && dropquotes) {
/* we strip this quote */ /* we strip this quote */
in += strlen(*quotx); in += strlen(*quotx);
} else if (result < 0) {
*addr = in; *token = out; return result;
} else { } else {
/* we copy the trailing quote */ /* we copy the trailing quote */
for (i = strlen(*quotx); i > 0; --i) { 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))) { if (!strncmp(in, *quotx, strlen(*quotx))) {
/* this quote pattern matches */ /* this quote pattern matches */
/* we strip this quote */ /* we strip this quote */
/* we call nestlex recursively */ /* we call _nestlex recursively */
const char *endnest[2]; const char *endnest[2];
if (dropquotes) { if (dropquotes) {
/* we strip this quote */ /* we strip this quote */
@ -124,13 +153,15 @@ int nestlex(const char **addr, /* input string; aft points to end token */
endnest[0] = *quotx; endnest[0] = *quotx;
endnest[1] = NULL; endnest[1] = NULL;
result = result =
nestlex(&in, &out, len, endnest, hquotes, _nestlex(&in, &out, len, endnest, hquotes,
squotes, nests, squotes, nests,
false, c_esc, html_esc); false, c_esc, html_esc);
if (result == 0 && dropquotes) { if (result == 0 && dropquotes) {
/* we strip the trailing quote */ /* we strip the trailing quote */
in += strlen(*quotx); in += strlen(*quotx);
} else if (result < 0) {
*addr = in; *token = out; return result;
} else { } else {
/* we copy the trailing quote */ /* we copy the trailing quote */
for (i = strlen(*quotx); i > 0; --i) { for (i = strlen(*quotx); i > 0; --i) {
@ -162,7 +193,7 @@ int nestlex(const char **addr, /* input string; aft points to end token */
} }
result = result =
nestlex(&in, &out, len, endnest, hquotes, squotes, nests, _nestlex(&in, &out, len, endnest, hquotes, squotes, nests,
false, c_esc, html_esc); false, c_esc, html_esc);
if (result == 0) { if (result == 0) {
/* copy endnest */ /* copy endnest */
@ -175,6 +206,8 @@ int nestlex(const char **addr, /* input string; aft points to end token */
} }
--i; --i;
} }
} else if (result < 0) {
*addr = in; *token = out; return result;
} }
break; break;
} }
@ -211,7 +244,7 @@ int nestlex(const char **addr, /* input string; aft points to end token */
} }
*out++ = c; *out++ = c;
--*len; --*len;
if (*len == 0) { if (*len <= 0) {
*addr = in; *addr = in;
*token = out; *token = out;
return -1; /* output overflow */ return -1; /* output overflow */
@ -222,7 +255,7 @@ int nestlex(const char **addr, /* input string; aft points to end token */
/* just a simple char */ /* just a simple char */
*out++ = c; *out++ = c;
--*len; --*len;
if (*len == 0) { if (*len <= 0) {
*addr = in; *addr = in;
*token = out; *token = out;
return -1; /* output overflow */ return -1; /* output overflow */

View file

@ -1,5 +1,5 @@
/* source: nestlex.h */ /* source: nestlex.h */
/* Copyright Gerhard Rieger 2006 */ /* Copyright Gerhard Rieger */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __nestlex_h_included #ifndef __nestlex_h_included

36
test.sh
View file

@ -10989,6 +10989,42 @@ esac
PORT=$((PORT+1)) PORT=$((PORT+1))
N=$((N+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 </dev/null 1>&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 # test for a bug in gopen that lead to crash or warning when opening a unix
# domain socket with GOPEN # domain socket with GOPEN