diff options
author | Anatol Belski <ab@php.net> | 2016-01-12 14:41:44 +0100 |
---|---|---|
committer | Anatol Belski <ab@php.net> | 2016-01-12 14:41:44 +0100 |
commit | 22a5ccab720fdff4bb56f2af6efe9ca7d3045a48 (patch) | |
tree | 45d97338d3f674a7b34a5d5f1cae39fc3e85dc8f /ext/standard/exec.c | |
parent | 4e7cb057a0a9f1b585af52f35e4c34940c88a553 (diff) | |
download | php-git-22a5ccab720fdff4bb56f2af6efe9ca7d3045a48.tar.gz |
Follow up on bug #71270
Using the max allowed command line length for an underlying OS.
Diffstat (limited to 'ext/standard/exec.c')
-rw-r--r-- | ext/standard/exec.c | 56 |
1 files changed, 51 insertions, 5 deletions
diff --git a/ext/standard/exec.c b/ext/standard/exec.c index c4afce3337..747f765dd4 100644 --- a/ext/standard/exec.c +++ b/ext/standard/exec.c @@ -46,10 +46,32 @@ #include <fcntl.h> #endif -#if HAVE_NICE && HAVE_UNISTD_H +#if (HAVE_NICE || defined(__linux__)) && HAVE_UNISTD_H #include <unistd.h> #endif +static int cmd_max_len; + +/* {{{ PHP_MINIT_FUNCTION(exec) */ +PHP_MINIT_FUNCTION(exec) +{ +#ifdef __linux__ + 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) @@ -245,13 +267,19 @@ PHP_FUNCTION(passthru) */ PHPAPI zend_string *php_escape_shell_cmd(char *str) { - register int x, y, l = (int)strlen(str); - size_t estimate = (2 * l) + 1; + register int x, y; + size_t l = strlen(str); + uint64_t estimate = (2 * (uint64_t)l) + 1; zend_string *cmd; #ifndef PHP_WIN32 char *p = NULL; #endif + /* max command line length - two single quotes - \0 byte length */ + if (l > cmd_max_len - 2 - 1) { + php_error_docref(NULL, E_ERROR, "Command exceeds the allowed length of %d bytes", cmd_max_len); + return ZSTR_EMPTY_ALLOC(); + } cmd = zend_string_safe_alloc(2, l, 0, 0); @@ -324,6 +352,12 @@ PHPAPI zend_string *php_escape_shell_cmd(char *str) } ZSTR_VAL(cmd)[y] = '\0'; + if (y - 1 > cmd_max_len) { + php_error_docref(NULL, E_ERROR, "Escaped command exceeds the allowed length of %d bytes", cmd_max_len); + zend_string_release(cmd); + return ZSTR_EMPTY_ALLOC(); + } + if ((estimate - y) > 4096) { /* realloc if the estimate was way overill * Arbitrary cutoff point of 4096 */ @@ -340,10 +374,16 @@ PHPAPI zend_string *php_escape_shell_cmd(char *str) */ PHPAPI zend_string *php_escape_shell_arg(char *str) { - int x, y = 0, l = (int)strlen(str); + int x, y = 0; + size_t l = strlen(str); zend_string *cmd; - size_t estimate = (4 * l) + 3; + uint64_t estimate = (4 * (uint64_t)l) + 3; + /* max command line length - two single quotes - \0 byte length */ + if (l > cmd_max_len - 2 - 1) { + php_error_docref(NULL, E_ERROR, "Argument exceeds the allowed length of %d bytes", cmd_max_len); + return ZSTR_EMPTY_ALLOC(); + } cmd = zend_string_safe_alloc(4, l, 2, 0); /* worst case */ @@ -399,6 +439,12 @@ PHPAPI zend_string *php_escape_shell_arg(char *str) #endif ZSTR_VAL(cmd)[y] = '\0'; + if (y - 1 > cmd_max_len) { + php_error_docref(NULL, E_ERROR, "Escaped argument exceeds the allowed length of %d bytes", cmd_max_len); + zend_string_release(cmd); + return ZSTR_EMPTY_ALLOC(); + } + if ((estimate - y) > 4096) { /* realloc if the estimate was way overill * Arbitrary cutoff point of 4096 */ |