summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog10
-rw-r--r--src/haserl.c136
-rw-r--r--src/sliding_buffer.c57
3 files changed, 118 insertions, 85 deletions
diff --git a/ChangeLog b/ChangeLog
index 75c1066..a5a4bf3 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2014-06-07
+ 0.9.33
+ * Fix various security vulnerabilities - most serious is a
+ Heap Overflow Vulnerability in sliding_buffer.c
+ Reported by Stephen Röttger
+ * Allow PUT and DELETE method (But prefix is still POST/GET)
+ * On POST/PUT, Content-Type is not x-www-urlencoded, then
+ the body of the message is stored verbatim in POST_body=
+
+
2013-20-09
0.9.32
* Regression causing Lua always to be linked, never used
diff --git a/src/haserl.c b/src/haserl.c
index 6b346c0..6514604 100644
--- a/src/haserl.c
+++ b/src/haserl.c
@@ -1,5 +1,5 @@
/* --------------------------------------------------------------------------
- * Copyright 2003-2011 (inclusive) Nathan Angelacos
+ * Copyright 2003-2014 (inclusive) Nathan Angelacos
* (nangel@users.sourceforge.net)
*
* This file is part of haserl.
@@ -461,92 +461,108 @@ ReadCGIQueryString (list_t * env)
*/
int
-ReadCGIPOSTValues (list_t * env)
+ReadCGIPOSTValues (list_t * env )
{
size_t content_length = 0;
size_t max_len;
+ int urldecoding = 0;
+ char *matchstr = "";
size_t i, j, x;
sliding_buffer_t sbuf;
buffer_t token;
unsigned char *data;
const char *CONTENT_LENGTH = "CONTENT_LENGTH";
+ const char *CONTENT_TYPE = "CONTENT_TYPE";
if ((getenv (CONTENT_LENGTH) == NULL) ||
(strtoul (getenv (CONTENT_LENGTH), NULL, 10) == 0))
return (0);
- if (getenv ("CONTENT_TYPE"))
- {
- if (strncasecmp (getenv ("CONTENT_TYPE"), "multipart/form-data", 19)
- == 0)
- {
+ if (strncasecmp (getenv (CONTENT_TYPE) , "multipart/form-data", 19)
+ == 0)
+ {
/* This is a mime request, we need to go to the mime handler */
i = rfc2388_handler (env);
return (i);
- }
- }
+ }
- s_buffer_init (&sbuf, 32768);
- sbuf.fh = STDIN;
- if (getenv (CONTENT_LENGTH))
- {
- sbuf.maxread = strtoul (getenv (CONTENT_LENGTH), NULL, 10);
- }
- haserl_buffer_init (&token);
+ /* at this point its either urlencoded or some other blob */
+
+ if ( strncasecmp (getenv (CONTENT_TYPE), "x-www-form-urlencoded", 21) ||
+ (getenv (CONTENT_TYPE) == NULL ) ) {
+ urldecoding = 1;
+ matchstr = "&";
+ }
/* Allow 2MB content, unless they have a global upload set */
max_len = ((global.uploadkb == 0) ? 2048 : global.uploadkb) *1024;
- do
- {
- /* x is true if this token ends with a matchstr or is at the end of stream */
- x = s_buffer_read (&sbuf, "&");
- content_length += sbuf.len;
- if (content_length > max_len)
- {
- die_with_message (NULL, NULL,
- "Attempted to send content larger than allowed limits.");
- }
-
- if ((x == 0) || (token.data))
- {
- buffer_add (&token, (char *) sbuf.segment, sbuf.len);
- }
+ s_buffer_init (&sbuf, 32768);
+ sbuf.fh = STDIN;
- if (x)
- {
- data = sbuf.segment;
- sbuf.segment[sbuf.len] = '\0';
- if (token.data)
+ if (getenv (CONTENT_LENGTH))
{
- /* add the ASCIIZ */
- buffer_add (&token, sbuf.segment + sbuf.len, 1);
- data = token.data;
+ sbuf.maxread = strtoul (getenv (CONTENT_LENGTH), NULL, 10);
}
+ haserl_buffer_init (&token);
+
+ if ( urldecoding == 0 ) {
+ buffer_add( &token, "body=", 5 );
+ }
- /* change plusses into spaces */
- j = strlen ((char *) data);
- for (i = 0; i <= j; i++)
+
+ do
{
- if (data[i] == '+')
+ /* x is true if this token ends with a matchstr or is at the end of stream */
+ x = s_buffer_read (&sbuf, matchstr);
+ content_length += sbuf.len;
+ if (content_length > max_len)
{
- data[i] = ' ';
+ die_with_message (NULL, NULL,
+ "Attempted to send content larger than allowed limits.");
+ }
+
+ if ((x == 0) || (token.data))
+ {
+ buffer_add (&token, (char *) sbuf.segment, sbuf.len);
+ }
+
+ if (x)
+ {
+ data = sbuf.segment;
+ sbuf.segment[sbuf.len] = '\0';
+ if (token.data)
+ {
+ /* add the ASCIIZ */
+ buffer_add (&token, sbuf.segment + sbuf.len, 1);
+ data = token.data;
+ }
+
+ if (urldecoding) {
+ /* change plusses into spaces */
+ j = strlen ((char *) data);
+ for (i = 0; i <= j; i++)
+ {
+ if (data[i] == '+')
+ {
+ data[i] = ' ';
+ }
+ }
+ unescape_url ((char *) data);
+ }
+ myputenv (env, (char *) data, global.var_prefix);
+ myputenv (env, (char *) data, global.post_prefix);
+ if (token.data)
+ {
+ buffer_reset (&token);
+ }
}
}
- unescape_url ((char *) data);
- myputenv (env, (char *) data, global.var_prefix);
- myputenv (env, (char *) data, global.post_prefix);
- if (token.data)
- {
- buffer_reset (&token);
- }
- }
- }
- while (!sbuf.eof);
- s_buffer_destroy (&sbuf);
- buffer_destroy (&token);
- return (0);
+ while (!sbuf.eof);
+ s_buffer_destroy (&sbuf);
+ buffer_destroy (&token);
+ return (0);
}
@@ -867,14 +883,16 @@ main (int argc, char *argv[])
CookieVars (env);
if (getenv ("REQUEST_METHOD"))
{
- if (strcasecmp (getenv ("REQUEST_METHOD"), "GET") == 0)
+ if ( (strcasecmp (getenv ("REQUEST_METHOD"), "GET") == 0) ||
+ (strcasecmp (getenv ("REQUEST_METHOD"), "DELETE") == 0) )
{
if (global.acceptall == TRUE)
ReadCGIPOSTValues (env);
ReadCGIQueryString (env);
}
- if (strcasecmp (getenv ("REQUEST_METHOD"), "POST") == 0)
+ if ( (strcasecmp (getenv ("REQUEST_METHOD"), "POST") == 0) ||
+ (strcasecmp (getenv ("REQUEST_METHOD"), "PUT") == 0) )
{
if (global.acceptall == TRUE)
ReadCGIQueryString (env);
diff --git a/src/sliding_buffer.c b/src/sliding_buffer.c
index 1adade5..70d64a5 100644
--- a/src/sliding_buffer.c
+++ b/src/sliding_buffer.c
@@ -129,32 +129,37 @@ s_buffer_read (sliding_buffer_t * sbuf, char *matchstr)
*/
pos = 0;
len = sbuf->bufsize - (int) (sbuf->ptr - sbuf->buf) - strlen (matchstr);
- /* On a short read or very long matchstr, its possible to force len < 0 - That is bad. */
- if ( len < 0 )
- {
- die_with_message ( NULL, NULL, "Short Read or MIME decode failure" );
- }
- while (memcmp (matchstr, sbuf->ptr + pos, strlen (matchstr)) && (pos < len))
- {
- pos++;
- }
-
- /*
- * if we found it
- */
- if (pos < len)
- {
- sbuf->len = pos;
- sbuf->segment = sbuf->ptr;
- sbuf->ptr = sbuf->segment + pos + strlen (matchstr);
- return -1;
- }
-
- if (sbuf->eof)
- {
- len += strlen (matchstr);
- }
-
+ /* a malicious client can send a matchstr longer than the actual content body
+ do not allow reads beyond the buffer limits
+ */
+ len = ( len < 0 ) ? 0 : len;
+
+ /* if have a matchstr, look for it, otherwise return the chunk */
+ if ( strlen(matchstr) > 0 ) {
+
+ while (memcmp (matchstr, sbuf->ptr + pos, strlen (matchstr)) && (pos < len))
+ {
+ pos++;
+ }
+
+ /*
+ * if we found it
+ */
+ if (pos < len)
+ {
+ sbuf->len = pos;
+ sbuf->segment = sbuf->ptr;
+ sbuf->ptr = sbuf->segment + pos + strlen (matchstr);
+ return -1;
+ }
+
+
+ if (sbuf->eof)
+ {
+ len += strlen (matchstr);
+ }
+
+ }
/*
* ran off the end, didn't find the matchstr
*/