-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Fix memory leaks in ext/tidy basedir restriction code #15046
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
<p>my epic string</p> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
--TEST-- | ||
Tidy with basedir restriction failure on configuration file | ||
--EXTENSIONS-- | ||
tidy | ||
--INI-- | ||
open_basedir={PWD}/open_basedir | ||
--FILE-- | ||
<?php | ||
echo "=== repairString ===\n"; | ||
$tidy = new tidy; | ||
$tidy->repairString('my epic string', 'my_config_file.ini'); | ||
|
||
echo "=== tidy_parse_string ===\n"; | ||
tidy_parse_string('my epic string', 'my_config_file.ini'); | ||
|
||
echo "=== tidy_parse_file ===\n"; | ||
tidy_parse_file(__DIR__.'/open_basedir/test.html', 'my_config_file.ini'); | ||
|
||
echo "=== __construct ===\n"; | ||
$tidy = new tidy(__DIR__.'/open_basedir/test.html', 'my_config_file.ini'); | ||
|
||
echo "=== parseFile ===\n"; | ||
$tidy = new tidy; | ||
$tidy->parseFile(__DIR__.'/open_basedir/test.html', 'my_config_file.ini'); | ||
|
||
echo "=== parseString ===\n"; | ||
$tidy = new tidy; | ||
$tidy->parseString('my epic string', 'my_config_file.ini'); | ||
?> | ||
--EXPECTF-- | ||
=== repairString === | ||
|
||
Warning: tidy::repairString(): open_basedir restriction in effect. File(my_config_file.ini) is not within the allowed path(s): (%sopen_basedir) in %s on line %d | ||
=== tidy_parse_string === | ||
|
||
Warning: tidy_parse_string(): open_basedir restriction in effect. File(my_config_file.ini) is not within the allowed path(s): (%sopen_basedir) in %s on line %d | ||
=== tidy_parse_file === | ||
|
||
Warning: tidy_parse_file(): open_basedir restriction in effect. File(my_config_file.ini) is not within the allowed path(s): (%sopen_basedir) in %s on line %d | ||
=== __construct === | ||
|
||
Warning: tidy::__construct(): open_basedir restriction in effect. File(my_config_file.ini) is not within the allowed path(s): (%sopen_basedir) in %s on line %d | ||
=== parseFile === | ||
|
||
Warning: tidy::parseFile(): open_basedir restriction in effect. File(my_config_file.ini) is not within the allowed path(s): (%sopen_basedir) in %s on line %d | ||
=== parseString === | ||
|
||
Warning: tidy::parseString(): open_basedir restriction in effect. File(my_config_file.ini) is not within the allowed path(s): (%sopen_basedir) in %s on line %d |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -74,19 +74,6 @@ | |
} \ | ||
obj = Z_TIDY_P(object); \ | ||
|
||
#define TIDY_APPLY_CONFIG(_doc, _val_str, _val_ht) \ | ||
if (_val_ht) { \ | ||
_php_tidy_apply_config_array(_doc, _val_ht); \ | ||
} else if (_val_str) { \ | ||
TIDY_OPEN_BASE_DIR_CHECK(ZSTR_VAL(_val_str)); \ | ||
php_tidy_load_config(_doc, ZSTR_VAL(_val_str)); \ | ||
} | ||
|
||
#define TIDY_OPEN_BASE_DIR_CHECK(filename) \ | ||
if (php_check_open_basedir(filename)) { \ | ||
RETURN_FALSE; \ | ||
} \ | ||
|
||
#define TIDY_SET_DEFAULT_CONFIG(_doc) \ | ||
if (TG(default_config) && TG(default_config)[0]) { \ | ||
php_tidy_load_config(_doc, TG(default_config)); \ | ||
|
@@ -221,6 +208,19 @@ static void php_tidy_load_config(TidyDoc doc, const char *path) | |
} | ||
} | ||
|
||
static zend_result php_tidy_apply_config(TidyDoc doc, zend_string *str_string, HashTable *ht_options) | ||
{ | ||
if (ht_options) { | ||
return _php_tidy_apply_config_array(doc, ht_options); | ||
} else if (str_string) { | ||
if (php_check_open_basedir(ZSTR_VAL(str_string))) { | ||
return FAILURE; | ||
} | ||
php_tidy_load_config(doc, ZSTR_VAL(str_string)); | ||
} | ||
Comment on lines
+213
to
+220
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note to myself, see if the HashTable and underlying char pointer can be made const. |
||
return SUCCESS; | ||
} | ||
|
||
static int _php_tidy_set_tidy_opt(TidyDoc doc, char *optname, zval *value) | ||
{ | ||
TidyOption opt = tidyGetOptionByName(doc, optname); | ||
|
@@ -329,9 +329,9 @@ static void php_tidy_quick_repair(INTERNAL_FUNCTION_PARAMETERS, bool is_file) | |
|
||
TIDY_SET_DEFAULT_CONFIG(doc); | ||
|
||
TIDY_APPLY_CONFIG(doc, config_str, config_ht); | ||
|
||
if(enc_len) { | ||
if (php_tidy_apply_config(doc, config_str, config_ht) != SUCCESS) { | ||
RETVAL_FALSE; | ||
} else if (enc_len) { | ||
if (tidySetCharEncoding(doc, enc) < 0) { | ||
php_error_docref(NULL, E_WARNING, "Could not set encoding \"%s\"", enc); | ||
RETVAL_FALSE; | ||
|
@@ -1024,9 +1024,8 @@ PHP_FUNCTION(tidy_parse_string) | |
tidy_instantiate(tidy_ce_doc, return_value); | ||
obj = Z_TIDY_P(return_value); | ||
|
||
TIDY_APPLY_CONFIG(obj->ptdoc->doc, options_str, options_ht); | ||
|
||
if (php_tidy_parse_string(obj, ZSTR_VAL(input), (uint32_t)ZSTR_LEN(input), enc) == FAILURE) { | ||
if (php_tidy_apply_config(obj->ptdoc->doc, options_str, options_ht) != SUCCESS | ||
|| php_tidy_parse_string(obj, ZSTR_VAL(input), (uint32_t)ZSTR_LEN(input), enc) == FAILURE) { | ||
Comment on lines
+1027
to
+1028
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is one |
||
zval_ptr_dtor(return_value); | ||
RETURN_FALSE; | ||
} | ||
|
@@ -1093,9 +1092,8 @@ PHP_FUNCTION(tidy_parse_file) | |
tidy_instantiate(tidy_ce_doc, return_value); | ||
obj = Z_TIDY_P(return_value); | ||
|
||
TIDY_APPLY_CONFIG(obj->ptdoc->doc, options_str, options_ht); | ||
|
||
if (php_tidy_parse_string(obj, ZSTR_VAL(contents), (uint32_t)ZSTR_LEN(contents), enc) == FAILURE) { | ||
if (php_tidy_apply_config(obj->ptdoc->doc, options_str, options_ht) != SUCCESS | ||
|| php_tidy_parse_string(obj, ZSTR_VAL(contents), (uint32_t)ZSTR_LEN(contents), enc) == FAILURE) { | ||
Comment on lines
+1095
to
+1096
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ditto |
||
zval_ptr_dtor(return_value); | ||
RETVAL_FALSE; | ||
} | ||
|
@@ -1388,7 +1386,11 @@ PHP_METHOD(tidy, __construct) | |
RETURN_THROWS(); | ||
} | ||
|
||
TIDY_APPLY_CONFIG(obj->ptdoc->doc, options_str, options_ht); | ||
if (php_tidy_apply_config(obj->ptdoc->doc, options_str, options_ht) != SUCCESS) { | ||
/* TODO: this is the constructor, we should throw probably... */ | ||
zend_string_release_ex(contents, 0); | ||
RETURN_FALSE; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. not sure about this indeed. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This keeps the existing behaviour of calling There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes this should, especially if the constructor can emit a warning |
||
} | ||
|
||
php_tidy_parse_string(obj, ZSTR_VAL(contents), (uint32_t)ZSTR_LEN(contents), enc); | ||
|
||
|
@@ -1427,9 +1429,8 @@ PHP_METHOD(tidy, parseFile) | |
RETURN_THROWS(); | ||
} | ||
|
||
TIDY_APPLY_CONFIG(obj->ptdoc->doc, options_str, options_ht); | ||
|
||
if (php_tidy_parse_string(obj, ZSTR_VAL(contents), (uint32_t)ZSTR_LEN(contents), enc) == FAILURE) { | ||
if (php_tidy_apply_config(obj->ptdoc->doc, options_str, options_ht) != SUCCESS | ||
|| php_tidy_parse_string(obj, ZSTR_VAL(contents), (uint32_t)ZSTR_LEN(contents), enc) == FAILURE) { | ||
Comment on lines
+1432
to
+1433
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ditto There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also not for a follow-up PR that this could use |
||
RETVAL_FALSE; | ||
} else { | ||
RETVAL_TRUE; | ||
|
@@ -1461,9 +1462,8 @@ PHP_METHOD(tidy, parseString) | |
TIDY_SET_CONTEXT; | ||
obj = Z_TIDY_P(object); | ||
|
||
TIDY_APPLY_CONFIG(obj->ptdoc->doc, options_str, options_ht); | ||
|
||
if(php_tidy_parse_string(obj, ZSTR_VAL(input), (uint32_t)ZSTR_LEN(input), enc) == SUCCESS) { | ||
if (php_tidy_apply_config(obj->ptdoc->doc, options_str, options_ht) == SUCCESS | ||
&& php_tidy_parse_string(obj, ZSTR_VAL(input), (uint32_t)ZSTR_LEN(input), enc) == SUCCESS) { | ||
RETURN_TRUE; | ||
} | ||
Comment on lines
+1465
to
1468
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note for a follow-up PR, this could just use a |
||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This definitely needs to be addressed in master, as constructors must always throw an exception when they fail.