Skip to content
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!