Follow up on bug #71270

Using the max allowed command line length for an underlying OS.
This commit is contained in:
Anatol Belski 2016-01-12 14:41:44 +01:00
parent 4e7cb057a0
commit 22a5ccab72
5 changed files with 77 additions and 5 deletions

View file

@ -3657,6 +3657,7 @@ PHP_MINIT_FUNCTION(basic) /* {{{ */
#ifdef PHP_CAN_SUPPORT_PROC_OPEN #ifdef PHP_CAN_SUPPORT_PROC_OPEN
BASIC_MINIT_SUBMODULE(proc_open) BASIC_MINIT_SUBMODULE(proc_open)
#endif #endif
BASIC_MINIT_SUBMODULE(exec)
BASIC_MINIT_SUBMODULE(user_streams) BASIC_MINIT_SUBMODULE(user_streams)
BASIC_MINIT_SUBMODULE(imagetypes) BASIC_MINIT_SUBMODULE(imagetypes)

View file

@ -46,10 +46,32 @@
#include <fcntl.h> #include <fcntl.h>
#endif #endif
#if HAVE_NICE && HAVE_UNISTD_H #if (HAVE_NICE || defined(__linux__)) && HAVE_UNISTD_H
#include <unistd.h> #include <unistd.h>
#endif #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 /* {{{ php_exec
* If type==0, only last line of output is returned (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) * 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) PHPAPI zend_string *php_escape_shell_cmd(char *str)
{ {
register int x, y, l = (int)strlen(str); register int x, y;
size_t estimate = (2 * l) + 1; size_t l = strlen(str);
uint64_t estimate = (2 * (uint64_t)l) + 1;
zend_string *cmd; zend_string *cmd;
#ifndef PHP_WIN32 #ifndef PHP_WIN32
char *p = NULL; char *p = NULL;
#endif #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); 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'; 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) { if ((estimate - y) > 4096) {
/* realloc if the estimate was way overill /* realloc if the estimate was way overill
* Arbitrary cutoff point of 4096 */ * 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) 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; 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 */ 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 #endif
ZSTR_VAL(cmd)[y] = '\0'; 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) { if ((estimate - y) > 4096) {
/* realloc if the estimate was way overill /* realloc if the estimate was way overill
* Arbitrary cutoff point of 4096 */ * Arbitrary cutoff point of 4096 */

View file

@ -33,6 +33,7 @@ PHP_FUNCTION(proc_close);
PHP_FUNCTION(proc_terminate); PHP_FUNCTION(proc_terminate);
PHP_FUNCTION(proc_nice); PHP_FUNCTION(proc_nice);
PHP_MINIT_FUNCTION(proc_open); PHP_MINIT_FUNCTION(proc_open);
PHP_MINIT_FUNCTION(exec);
PHPAPI zend_string *php_escape_shell_cmd(char *); PHPAPI zend_string *php_escape_shell_cmd(char *);
PHPAPI zend_string *php_escape_shell_arg(char *); PHPAPI zend_string *php_escape_shell_arg(char *);

View file

@ -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

View file

@ -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