summaryrefslogtreecommitdiff
path: root/ext/standard/exec.c
diff options
context:
space:
mode:
authorAnatol Belski <ab@php.net>2016-01-12 14:41:44 +0100
committerAnatol Belski <ab@php.net>2016-01-12 14:41:44 +0100
commit22a5ccab720fdff4bb56f2af6efe9ca7d3045a48 (patch)
tree45d97338d3f674a7b34a5d5f1cae39fc3e85dc8f /ext/standard/exec.c
parent4e7cb057a0a9f1b585af52f35e4c34940c88a553 (diff)
downloadphp-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.c56
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 */