diff options
Diffstat (limited to 'bug71039.patch')
-rw-r--r-- | bug71039.patch | 300 |
1 files changed, 300 insertions, 0 deletions
diff --git a/bug71039.patch b/bug71039.patch new file mode 100644 index 0000000..343364c --- /dev/null +++ b/bug71039.patch @@ -0,0 +1,300 @@ +Backported from 5.5 for 5.4 by Remi Collet + +From f4d7bbf4ace4ea21c8f95c2d1177bd56a21b86b9 Mon Sep 17 00:00:00 2001 +From: Anatol Belski <ab@php.net> +Date: Thu, 28 Jan 2016 13:45:43 +0100 +Subject: [PATCH] backport the escapeshell* functions hardening branch + +--- + ext/standard/basic_functions.c | 1 + + ext/standard/exec.c | 76 +++++++++++++++++++++++++++++++++++++++--- + ext/standard/exec.h | 1 + + 3 files changed, 73 insertions(+), 5 deletions(-) + +diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c +index f8cb91e..50b6bc7 100644 +--- a/ext/standard/basic_functions.c ++++ b/ext/standard/basic_functions.c +@@ -3613,6 +3613,7 @@ + #ifdef PHP_CAN_SUPPORT_PROC_OPEN + PHP_MINIT(proc_open)(INIT_FUNC_ARGS_PASSTHRU); + #endif ++ PHP_MINIT(exec)(INIT_FUNC_ARGS_PASSTHRU); + + PHP_MINIT(user_streams)(INIT_FUNC_ARGS_PASSTHRU); + PHP_MINIT(imagetypes)(INIT_FUNC_ARGS_PASSTHRU); +diff --git a/ext/standard/exec.c b/ext/standard/exec.c +index 66d4537..461bef4 100644 +--- a/ext/standard/exec.c ++++ b/ext/standard/exec.c +@@ -46,10 +46,42 @@ + #include <fcntl.h> + #endif + +-#if HAVE_NICE && HAVE_UNISTD_H ++#if HAVE_UNISTD_H + #include <unistd.h> + #endif + ++#ifdef PHP_WIN32 ++# include "win32/php_stdint.h" ++#else ++# if HAVE_INTTYPES_H ++# include <inttypes.h> ++# elif HAVE_STDINT_H ++# include <stdint.h> ++# endif ++#endif ++ ++static int cmd_max_len; ++ ++/* {{{ PHP_MINIT_FUNCTION(exec) */ ++PHP_MINIT_FUNCTION(exec) ++{ ++#ifdef _SC_ARG_MAX ++ cmd_max_len = sysconf(_SC_ARG_MAX); ++#elif defined(ARG_MAX) ++ cmd_max_len = ARG_MAX; ++#elif defined(PHP_WIN32) ++ /* Executed commands will run through cmd.exe. As long as it's the case, ++ it's just the constant limit.*/ ++ cmd_max_len = 8192; ++#else ++ /* This is just an arbitrary value for the fallback case. */ ++ cmd_max_len = 4096; ++#endif ++ ++ return SUCCESS; ++} ++/* }}} */ ++ + /* {{{ php_exec + * If type==0, only last line of output is returned (exec) + * If type==1, all lines will be printed and last lined returned (system) +@@ -244,13 +276,20 @@ PHP_FUNCTION(passthru) + */ + PHPAPI char *php_escape_shell_cmd(char *str) + { +- register int x, y, l = strlen(str); ++ register int x, y; ++ size_t l = strlen(str); ++ uint64_t estimate = (2 * (uint64_t)l) + 1; + char *cmd; + char *p = NULL; +- size_t estimate = (2 * l) + 1; + + TSRMLS_FETCH(); + ++ /* max command line length - two single quotes - \0 byte length */ ++ if (l > cmd_max_len - 2 - 1) { ++ php_error_docref(NULL TSRMLS_CC, E_ERROR, "Command exceeds the allowed length of %d bytes", cmd_max_len); ++ return NULL; ++ } ++ + cmd = safe_emalloc(2, l, 1); + + for (x = 0, y = 0; x < l; x++) { +@@ -322,6 +361,12 @@ PHPAPI char *php_escape_shell_cmd(char *str) + } + cmd[y] = '\0'; + ++ if (y - 1 > cmd_max_len) { ++ php_error_docref(NULL TSRMLS_CC, E_ERROR, "Escaped command exceeds the allowed length of %d bytes", cmd_max_len); ++ efree(cmd); ++ return NULL; ++ } ++ + if ((estimate - y) > 4096) { + /* realloc if the estimate was way overill + * Arbitrary cutoff point of 4096 */ +@@ -336,12 +381,19 @@ PHPAPI char *php_escape_shell_cmd(char *str) + */ + PHPAPI char *php_escape_shell_arg(char *str) + { +- int x, y = 0, l = strlen(str); ++ int x, y = 0; ++ size_t l = strlen(str); + char *cmd; +- size_t estimate = (4 * l) + 3; ++ uint64_t estimate = (4 * (uint64_t)l) + 3; + + TSRMLS_FETCH(); + ++ /* max command line length - two single quotes - \0 byte length */ ++ if (l > cmd_max_len - 2 - 1) { ++ php_error_docref(NULL TSRMLS_CC, E_ERROR, "Argument exceeds the allowed length of %d bytes", cmd_max_len); ++ return NULL; ++ } ++ + cmd = safe_emalloc(4, l, 3); /* worst case */ + + #ifdef PHP_WIN32 +@@ -396,6 +448,12 @@ PHPAPI char *php_escape_shell_arg(char *str) + #endif + cmd[y] = '\0'; + ++ if (y - 1 > cmd_max_len) { ++ php_error_docref(NULL TSRMLS_CC, E_ERROR, "Escaped argument exceeds the allowed length of %d bytes", cmd_max_len); ++ efree(cmd); ++ return NULL; ++ } ++ + if ((estimate - y) > 4096) { + /* realloc if the estimate was way overill + * Arbitrary cutoff point of 4096 */ +@@ -418,6 +476,10 @@ PHP_FUNCTION(escapeshellcmd) + } + + if (command_len) { ++ if (command_len != strlen(command)) { ++ php_error_docref(NULL TSRMLS_CC, E_ERROR, "Input string contains NULL bytes"); ++ return; ++ } + cmd = php_escape_shell_cmd(command); + RETVAL_STRING(cmd, 0); + } else { +@@ -439,6 +501,10 @@ PHP_FUNCTION(escapeshellarg) + } + + if (argument) { ++ if (argument_len != strlen(argument)) { ++ php_error_docref(NULL TSRMLS_CC, E_ERROR, "Input string contains NULL bytes"); ++ return; ++ } + cmd = php_escape_shell_arg(argument); + RETVAL_STRING(cmd, 0); + } +diff --git a/ext/standard/exec.h b/ext/standard/exec.h +index 399325c..b106838 100644 +--- a/ext/standard/exec.h ++++ b/ext/standard/exec.h +@@ -33,6 +33,7 @@ PHP_FUNCTION(proc_close); + PHP_FUNCTION(proc_terminate); + PHP_FUNCTION(proc_nice); + PHP_MINIT_FUNCTION(proc_open); ++PHP_MINIT_FUNCTION(exec); + + PHPAPI char *php_escape_shell_cmd(char *); + PHPAPI char *php_escape_shell_arg(char *); +From 828364e59ca08c2ff3328a648522f9eb05ebbaa3 Mon Sep 17 00:00:00 2001 +From: Anatol Belski <ab@php.net> +Date: Thu, 28 Jan 2016 13:27:26 +0100 +Subject: [PATCH] add tests + +--- + .../tests/general_functions/escapeshellarg_bug71039.phpt | 10 ++++++++++ + .../tests/general_functions/escapeshellarg_bug71270.phpt | 12 ++++++++++++ + .../tests/general_functions/escapeshellcmd_bug71039.phpt | 10 ++++++++++ + .../tests/general_functions/escapeshellcmd_bug71270.phpt | 12 ++++++++++++ + 4 files changed, 44 insertions(+) + create mode 100644 ext/standard/tests/general_functions/escapeshellarg_bug71039.phpt + create mode 100644 ext/standard/tests/general_functions/escapeshellarg_bug71270.phpt + create mode 100644 ext/standard/tests/general_functions/escapeshellcmd_bug71039.phpt + create mode 100644 ext/standard/tests/general_functions/escapeshellcmd_bug71270.phpt + +diff --git a/ext/standard/tests/general_functions/escapeshellarg_bug71039.phpt b/ext/standard/tests/general_functions/escapeshellarg_bug71039.phpt +new file mode 100644 +index 0000000..cbb3f6f +--- /dev/null ++++ b/ext/standard/tests/general_functions/escapeshellarg_bug71039.phpt +@@ -0,0 +1,10 @@ ++--TEST-- ++Test escapeshellarg() string with \0 bytes ++--FILE-- ++<?php ++escapeshellarg("hello\0world"); ++ ++?> ++===DONE=== ++--EXPECTF-- ++Fatal error: escapeshellarg(): Input string contains NULL bytes in %s on line %d +diff --git a/ext/standard/tests/general_functions/escapeshellarg_bug71270.phpt b/ext/standard/tests/general_functions/escapeshellarg_bug71270.phpt +new file mode 100644 +index 0000000..c57da36 +--- /dev/null ++++ b/ext/standard/tests/general_functions/escapeshellarg_bug71270.phpt +@@ -0,0 +1,12 @@ ++--TEST-- ++Test escapeshellarg() allowed argument length ++--FILE-- ++<?php ++ini_set('memory_limit', -1); ++$var_2 = str_repeat('A', 1024*1024*64); ++escapeshellarg($var_2); ++ ++?> ++===DONE=== ++--EXPECTF-- ++Fatal error: escapeshellarg(): Argument exceeds the allowed length of %d bytes in %s on line %d +diff --git a/ext/standard/tests/general_functions/escapeshellcmd_bug71039.phpt b/ext/standard/tests/general_functions/escapeshellcmd_bug71039.phpt +new file mode 100644 +index 0000000..0a4d7ea +--- /dev/null ++++ b/ext/standard/tests/general_functions/escapeshellcmd_bug71039.phpt +@@ -0,0 +1,10 @@ ++--TEST-- ++Test escapeshellcmd() string with \0 bytes ++--FILE-- ++<?php ++escapeshellcmd("hello\0world"); ++ ++?> ++===DONE=== ++--EXPECTF-- ++Fatal error: escapeshellcmd(): Input string contains NULL bytes in %s on line %d +diff --git a/ext/standard/tests/general_functions/escapeshellcmd_bug71270.phpt b/ext/standard/tests/general_functions/escapeshellcmd_bug71270.phpt +new file mode 100644 +index 0000000..4686193 +--- /dev/null ++++ b/ext/standard/tests/general_functions/escapeshellcmd_bug71270.phpt +@@ -0,0 +1,12 @@ ++--TEST-- ++Test escapeshellcmd() allowed argument length ++--FILE-- ++<?php ++ini_set('memory_limit', -1); ++$var_2 = str_repeat('A', 1024*1024*64); ++escapeshellcmd($var_2); ++ ++?> ++===DONE=== ++--EXPECTF-- ++Fatal error: escapeshellcmd(): Command exceeds the allowed length of %d bytes in %s on line %d +From 377d353c9f8aad6f79f3cf84aad3e2f6d65fa456 Mon Sep 17 00:00:00 2001 +From: Anatol Belski <ab@php.net> +Date: Tue, 2 Feb 2016 14:19:10 +0100 +Subject: [PATCH] add error check to sysconf call + +--- + ext/standard/exec.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/ext/standard/exec.c b/ext/standard/exec.c +index 461bef4..329066e 100644 +--- a/ext/standard/exec.c ++++ b/ext/standard/exec.c +@@ -50,6 +50,10 @@ + #include <unistd.h> + #endif + ++#if HAVE_LIMITS_H ++#include <limits.h> ++#endif ++ + #ifdef PHP_WIN32 + # include "win32/php_stdint.h" + #else +@@ -67,6 +71,13 @@ PHP_MINIT_FUNCTION(exec) + { + #ifdef _SC_ARG_MAX + cmd_max_len = sysconf(_SC_ARG_MAX); ++ if (-1 == cmd_max_len) { ++#ifdef _POSIX_ARG_MAX ++ cmd_max_len = _POSIX_ARG_MAX; ++#else ++ cmd_max_len = 4096; ++#endif ++ } + #elif defined(ARG_MAX) + cmd_max_len = ARG_MAX; + #elif defined(PHP_WIN32) |