Skip to content

Fix bug #80565 #6492

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

Open
wants to merge 16 commits into
base: master
Choose a base branch
from
13 changes: 10 additions & 3 deletions ext/filter/sanitizing_filters.c
Original file line number Diff line number Diff line change
Expand Up @@ -168,8 +168,9 @@ static void filter_map_apply(zval *value, filter_map *map)
/* {{{ php_filter_string */
void php_filter_string(PHP_INPUT_FILTER_PARAM_DECL)
{
size_t new_len;
unsigned char enc[256] = {0};
zend_string* new_string;
size_t new_len;

if (!Z_REFCOUNTED_P(value)) {
ZVAL_STRINGL(value, Z_STRVAL_P(value), Z_STRLEN_P(value));
Expand All @@ -194,8 +195,14 @@ void php_filter_string(PHP_INPUT_FILTER_PARAM_DECL)
php_filter_encode_html(value, enc);

/* strip tags, implicitly also removes \0 chars */
new_len = php_strip_tags_ex(Z_STRVAL_P(value), Z_STRLEN_P(value), NULL, 0, 1);
Z_STRLEN_P(value) = new_len;
new_string = php_strip_tags_ex(Z_STR_P(value), NULL, 0, 1);
new_len = ZSTR_LEN(new_string);

memcpy(value->value.str->val,ZSTR_VAL(new_string),new_len);
value->value.str->val[new_len] = '\0';
value->value.str->len = new_len;

zend_string_release(new_string);

if (new_len == 0) {
zval_ptr_dtor(value);
Expand Down
4 changes: 2 additions & 2 deletions ext/standard/php_string.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ PHPAPI char *php_stristr(char *s, char *t, size_t s_len, size_t t_len);
PHPAPI zend_string *php_str_to_str(const char *haystack, size_t length, const char *needle,
size_t needle_len, const char *str, size_t str_len);
PHPAPI zend_string *php_trim(zend_string *str, const char *what, size_t what_len, int mode);
PHPAPI size_t php_strip_tags(char *rbuf, size_t len, const char *allow, size_t allow_len);
PHPAPI size_t php_strip_tags_ex(char *rbuf, size_t len, const char *allow, size_t allow_len, bool allow_tag_spaces);
PHPAPI zend_string *php_strip_tags(zend_string *zend_string_r, const char *allow, size_t allow_len);
PHPAPI zend_string *php_strip_tags_ex(zend_string *zend_string_r, const char *allow, size_t allow_len, bool allow_tag_spaces);
PHPAPI void php_implode(const zend_string *delim, HashTable *arr, zval *return_value);
PHPAPI void php_explode(const zend_string *delim, zend_string *str, zval *return_value, zend_long limit);

Expand Down
132 changes: 95 additions & 37 deletions ext/standard/string.c
Original file line number Diff line number Diff line change
Expand Up @@ -4535,6 +4535,7 @@ PHP_FUNCTION(strip_tags)
const char *allowed_tags=NULL;
size_t allowed_tags_len=0;
smart_str tags_ss = {0};
zend_string *stripped_tag_buf;

ZEND_PARSE_PARAMETERS_START(1, 2)
Z_PARAM_STR(str)
Expand Down Expand Up @@ -4564,9 +4565,11 @@ PHP_FUNCTION(strip_tags)
}

buf = zend_string_init(ZSTR_VAL(str), ZSTR_LEN(str), 0);
ZSTR_LEN(buf) = php_strip_tags_ex(ZSTR_VAL(buf), ZSTR_LEN(str), allowed_tags, allowed_tags_len, 0);
stripped_tag_buf = php_strip_tags_ex(buf, allowed_tags, allowed_tags_len, 0);

zend_string_release(buf);
smart_str_free(&tags_ss);
RETURN_NEW_STR(buf);
RETURN_STR(stripped_tag_buf);
}
/* }}} */

Expand Down Expand Up @@ -4772,12 +4775,29 @@ int php_tag_find(char *tag, size_t len, const char *set) {
}
/* }}} */

PHPAPI size_t php_strip_tags(char *rbuf, size_t len, const char *allow, size_t allow_len) /* {{{ */
PHPAPI zend_string* php_strip_tags(zend_string *rbuf, const char *allow, size_t allow_len) /* {{{ */
{
return php_strip_tags_ex(rbuf, len, allow, allow_len, 0);
return php_strip_tags_ex(rbuf, allow, allow_len, 0);
}
/* }}} */

#define _PHP_STRIP_TAGS_SIZE_TRIANGULAR_BRACKETS 4

//in tag && in quote ...
#define _PHP_STRIP_TAGS_WE_ARE_IN_QUOTE_WITH_ALLOW_CHAR(CHAR) \
(state == 1 && in_q>1 && allow && c == CHAR)


#define _PHP_STRIP_TAGS_EXTEND_BUFF(LEN) \
pos = tp - ZSTR_VAL(tbuf); \
if ((pos+LEN) >= ZSTR_LEN(tbuf)) { \
tbuf_max_size+=PHP_TAG_BUF_SIZE; \
tbuf = zend_string_extend(tbuf,tbuf_max_size,0); \
tp = ZSTR_VAL(tbuf); \
tp+=pos; \
}


/* {{{ php_strip_tags

A simple little state-machine to strip out html and php tags
Expand All @@ -4798,29 +4818,38 @@ PHPAPI size_t php_strip_tags(char *rbuf, size_t len, const char *allow, size_t a
swm: Added ability to strip <?xml tags without assuming it PHP
code.
*/
PHPAPI size_t php_strip_tags_ex(char *rbuf, size_t len, const char *allow, size_t allow_len, bool allow_tag_spaces)
PHPAPI zend_string *php_strip_tags_ex(zend_string *zend_string_input, const char *allow, size_t allow_len, bool allow_tag_spaces)
{
char *tbuf, *tp, *rp, c, lc;
char *rp, c, lc;
const char *buf, *p, *end;
int br, depth=0, in_q = 0;
uint8_t state = 0;
size_t pos;
char *allow_free = NULL;
char is_xml = 0;
size_t len = ZSTR_LEN(zend_string_input);
int tbuf_max_size = PHP_TAG_BUF_SIZE;
char *tp;
zend_string *tbuf, *ret_stripped_buffer;

buf = estrndup(rbuf, len);
buf = estrndup(ZSTR_VAL(zend_string_input), len);
p = buf;
end = buf + len;

ret_stripped_buffer = zend_string_dup(zend_string_input,0);
rp = ZSTR_VAL(ret_stripped_buffer);

lc = '\0';
p = buf;
rp = rbuf;
br = 0;

if (allow) {
allow_free = zend_str_tolower_dup_ex(allow, allow_len);
allow = allow_free ? allow_free : allow;
tbuf = emalloc(PHP_TAG_BUF_SIZE + 1);
tp = tbuf;
tbuf = zend_string_alloc(PHP_TAG_BUF_SIZE+1,0);
tp = ZSTR_VAL(tbuf);
} else {
tbuf = tp = NULL;
tbuf = NULL;
tp = NULL;
}

state_0:
Expand All @@ -4832,6 +4861,7 @@ PHPAPI size_t php_strip_tags_ex(char *rbuf, size_t len, const char *allow, size_
case '\0':
break;
case '<':

if (in_q) {
break;
}
Expand All @@ -4842,11 +4872,7 @@ PHPAPI size_t php_strip_tags_ex(char *rbuf, size_t len, const char *allow, size_
lc = '<';
state = 1;
if (allow) {
if (tp - tbuf >= PHP_TAG_BUF_SIZE) {
pos = tp - tbuf;
tbuf = erealloc(tbuf, (tp - tbuf) + PHP_TAG_BUF_SIZE + 1);
tp = tbuf + pos;
}
_PHP_STRIP_TAGS_EXTEND_BUFF(0)
*(tp++) = '<';
}
p++;
Expand Down Expand Up @@ -4879,6 +4905,13 @@ PHPAPI size_t php_strip_tags_ex(char *rbuf, size_t len, const char *allow, size_
case '\0':
break;
case '<':
if (_PHP_STRIP_TAGS_WE_ARE_IN_QUOTE_WITH_ALLOW_CHAR('<')) {
_PHP_STRIP_TAGS_EXTEND_BUFF(_PHP_STRIP_TAGS_SIZE_TRIANGULAR_BRACKETS)
memcpy(tp, "&lt;", _PHP_STRIP_TAGS_SIZE_TRIANGULAR_BRACKETS);
tp+=4;
break;
}

if (in_q) {
break;
}
Expand All @@ -4892,6 +4925,14 @@ PHPAPI size_t php_strip_tags_ex(char *rbuf, size_t len, const char *allow, size_
depth--;
break;
}

if (_PHP_STRIP_TAGS_WE_ARE_IN_QUOTE_WITH_ALLOW_CHAR('>')) {
_PHP_STRIP_TAGS_EXTEND_BUFF(_PHP_STRIP_TAGS_SIZE_TRIANGULAR_BRACKETS)
memcpy(tp, "&gt;", _PHP_STRIP_TAGS_SIZE_TRIANGULAR_BRACKETS);
tp+=4;
break;
}

if (in_q) {
break;
}
Expand All @@ -4902,18 +4943,24 @@ PHPAPI size_t php_strip_tags_ex(char *rbuf, size_t len, const char *allow, size_
}
in_q = state = is_xml = 0;
if (allow) {
if (tp - tbuf >= PHP_TAG_BUF_SIZE) {
pos = tp - tbuf;
tbuf = erealloc(tbuf, (tp - tbuf) + PHP_TAG_BUF_SIZE + 1);
tp = tbuf + pos;
}
_PHP_STRIP_TAGS_EXTEND_BUFF(0)

*(tp++) = '>';
*tp='\0';
if (php_tag_find(tbuf, tp-tbuf, allow)) {
memcpy(rp, tbuf, tp-tbuf);
rp += tp-tbuf;
size_t tpos = tp-ZSTR_VAL(tbuf);
size_t rpos = rp-ZSTR_VAL(ret_stripped_buffer);
if (php_tag_find(ZSTR_VAL(tbuf), tpos, allow)) {

if ((rpos+tpos) >= ZSTR_LEN(ret_stripped_buffer)) {
ret_stripped_buffer = zend_string_extend(ret_stripped_buffer,rpos+tpos+10,0);
}
rp = ZSTR_VAL(ret_stripped_buffer);
rp+=rpos;

memcpy(rp, ZSTR_VAL(tbuf), tpos);
rp+= tpos;
}
tp = tbuf;
tp = ZSTR_VAL(tbuf);
}
p++;
goto state_0;
Expand Down Expand Up @@ -4951,11 +4998,7 @@ PHPAPI size_t php_strip_tags_ex(char *rbuf, size_t len, const char *allow, size_
default:
reg_char_1:
if (allow) {
if (tp - tbuf >= PHP_TAG_BUF_SIZE) {
pos = tp - tbuf;
tbuf = erealloc(tbuf, (tp - tbuf) + PHP_TAG_BUF_SIZE + 1);
tp = tbuf + pos;
}
_PHP_STRIP_TAGS_EXTEND_BUFF(0)
*(tp++) = c;
}
break;
Expand Down Expand Up @@ -4986,13 +5029,14 @@ PHPAPI size_t php_strip_tags_ex(char *rbuf, size_t len, const char *allow, size_
depth--;
break;
}

if (in_q) {
break;
}

if (!br && p >= buf + 1 && lc != '\"' && *(p-1) == '?') {
in_q = state = 0;
tp = tbuf;
tp = ZSTR_VAL(tbuf);
p++;
goto state_0;
}
Expand Down Expand Up @@ -5046,11 +5090,12 @@ PHPAPI size_t php_strip_tags_ex(char *rbuf, size_t len, const char *allow, size_
depth--;
break;
}

if (in_q) {
break;
}
in_q = state = 0;
tp = tbuf;
tp = ZSTR_VAL(tbuf);
p++;
goto state_0;
case '"':
Expand Down Expand Up @@ -5097,7 +5142,7 @@ PHPAPI size_t php_strip_tags_ex(char *rbuf, size_t len, const char *allow, size_
if (c == '>' && !in_q) {
if (p >= buf + 2 && *(p-1) == '-' && *(p-2) == '-') {
in_q = state = 0;
tp = tbuf;
tp = ZSTR_VAL(tbuf);
p++;
goto state_0;
}
Expand All @@ -5106,18 +5151,31 @@ PHPAPI size_t php_strip_tags_ex(char *rbuf, size_t len, const char *allow, size_
}

finish:
if (rp < rbuf + len) {
if (rp < ZSTR_VAL(ret_stripped_buffer) + len) {
*rp = '\0';
}
efree((void *)buf);
if (tbuf) {
efree(tbuf);
zend_string_release(tbuf);
}
if (allow_free) {
efree(allow_free);
}

return (size_t)(rp - rbuf);
size_t lenrbuf = rp-ZSTR_VAL(ret_stripped_buffer);
zend_string *new_string;

if (lenrbuf == 0 ) {
new_string = zend_string_init("\0",lenrbuf,0);
}

if (lenrbuf > 0 ) {
new_string = zend_string_init(ZSTR_VAL(ret_stripped_buffer),lenrbuf,0);
}

zend_string_release(ret_stripped_buffer);

return new_string;
}
/* }}} */

Expand Down
22 changes: 22 additions & 0 deletions ext/standard/tests/strings/Fix bug #80565.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
--TEST--
Bug #XXXXX: strip_tags strip >< in attributes with allow tag
--FILE--
<?php
echo strip_tags('<ta alt="abc< ">', '<ta>').\PHP_EOL;
echo strip_tags('<ta alt="abc> ">', '<ta>').\PHP_EOL;

$lts = '';
$gts = '';
for ($i=0;$i<10;$i++)
{
$lts.=" $i(<) ";
$gts.=" $i(>) ";
}
echo strip_tags('<t y="'.$lts.'" /><pippo> xxx </pippo><pippo> yyy </pippo><k> hello!</k>', '<t><pippo>').\PHP_EOL;
echo strip_tags('<t y="'.$gts.'" /><pippo> xxx </pippo><pippo> yyy </pippo><k> hello!</k>', '<t><pippo>').\PHP_EOL;
?>
--EXPECT--
<ta alt="abc&lt; ">
<ta alt="abc&gt; ">
<t y=" 0(&lt;) 1(&lt;) 2(&lt;) 3(&lt;) 4(&lt;) 5(&lt;) 6(&lt;) 7(&lt;) 8(&lt;) 9(&lt;) " /><pippo> xxx </pippo><pippo> yyy </pippo> hello!
<t y=" 0(&gt;) 1(&gt;) 2(&gt;) 3(&gt;) 4(&gt;) 5(&gt;) 6(&gt;) 7(&gt;) 8(&gt;) 9(&gt;) " /><pippo> xxx </pippo><pippo> yyy </pippo> hello!