From 7670e669c000f835169dd9b85af6d2f45f303040 Mon Sep 17 00:00:00 2001 From: Stefan Esser Date: Wed, 20 May 2015 11:59:13 +0200 Subject: Fix high CPU consumption DOS through many newlines in RFC1867 MIME headers --- Changelog | 2 ++ php_suhosin.h | 1 + rfc1867_new.c | 8 ++++++++ suhosin.c | 1 + suhosin.ini | 10 ++++++++++ 5 files changed, 22 insertions(+) diff --git a/Changelog b/Changelog index a6b7e3a..53dba31 100644 --- a/Changelog +++ b/Changelog @@ -2,6 +2,8 @@ - removed code compatibility for PHP <5.4 (lots of code + ifdefs) - allow https location for suhosin.filter.action - fixed newline detection for suhosin.mail.protect + - Added suhosin.upload.max_newlines to protect againt DOS attack via many + MIME headers in RFC1867 uploads 2014-12-12 - 0.9.37.1 - Changed version string to 0.9.37.1 (without -dev) diff --git a/php_suhosin.h b/php_suhosin.h index 7b86e7a..fd61a0a 100644 --- a/php_suhosin.h +++ b/php_suhosin.h @@ -203,6 +203,7 @@ ZEND_BEGIN_MODULE_GLOBALS(suhosin) /* fileupload */ long upload_limit; + long upload_max_newlines; long num_uploads; zend_bool upload_disallow_elf; zend_bool upload_disallow_binary; diff --git a/rfc1867_new.c b/rfc1867_new.c index 2a8b3ab..dfdc1d9 100644 --- a/rfc1867_new.c +++ b/rfc1867_new.c @@ -387,6 +387,7 @@ static int multipart_buffer_headers(multipart_buffer *self, zend_llist *header T char *line; mime_header_entry prev_entry = {0}, entry; int prev_len, cur_len; + int newlines = 0; /* didn't find boundary, abort */ if (!find_boundary(self, self->boundary TSRMLS_CC)) { @@ -416,6 +417,7 @@ static int multipart_buffer_headers(multipart_buffer *self, zend_llist *header T entry.value = estrdup(value); entry.key = estrdup(key); + newlines = 0; } else if (zend_llist_count(header)) { /* If no ':' on the line, add to previous line */ @@ -428,6 +430,12 @@ static int multipart_buffer_headers(multipart_buffer *self, zend_llist *header T entry.value[cur_len + prev_len] = '\0'; entry.key = estrdup(prev_entry.key); + newlines++; + if (newlines > SUHOSIN_G(upload_max_newlines)) { + SUHOSIN_G(abort_request) = 1; + suhosin_log(S_FILES, "configured maximum number of newlines in RFC1867 MIME headers limit exceeded - dropping rest of upload"); + return 0; + } zend_llist_remove_tail(header); } else { diff --git a/suhosin.c b/suhosin.c index f91bb30..9e2d017 100644 --- a/suhosin.c +++ b/suhosin.c @@ -856,6 +856,7 @@ PHP_INI_BEGIN() STD_PHP_INI_ENTRY("suhosin.post.disallow_ws", "0", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdatePostBool, disallow_post_ws, zend_suhosin_globals, suhosin_globals) STD_PHP_INI_ENTRY("suhosin.upload.max_uploads", "25", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateUploadLong, upload_limit, zend_suhosin_globals, suhosin_globals) + STD_PHP_INI_ENTRY("suhosin.upload.max_newlines", "100", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateUploadLong, upload_max_newlines, zend_suhosin_globals, suhosin_globals) STD_PHP_INI_ENTRY("suhosin.upload.disallow_elf", "1", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateUploadBool, upload_disallow_elf, zend_suhosin_globals, suhosin_globals) STD_PHP_INI_ENTRY("suhosin.upload.disallow_binary", "0", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateUploadBool, upload_disallow_binary, zend_suhosin_globals, suhosin_globals) STD_PHP_INI_ENTRY("suhosin.upload.remove_binary", "0", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateUploadBool, upload_remove_binary, zend_suhosin_globals, suhosin_globals) diff --git a/suhosin.ini b/suhosin.ini index b37013b..4dfbf43 100644 --- a/suhosin.ini +++ b/suhosin.ini @@ -1334,6 +1334,16 @@ ;suhosin.upload.max_uploads = 25 ; +; suhosin.upload.max_newlines +; -------------------------- +; * Type: Integer +; * Default: 100 +; +; Defines the maximum number of newlines in rfc1867 mime headers. +; +;suhosin.upload.max_newlines = 100 +; + ; suhosin.upload.disallow_elf ; --------------------------- ; * Type: Boolean -- cgit v1.3