diff --git a/ext/filter/sanitizing_filters.c b/ext/filter/sanitizing_filters.c index cceb1270bbc77..cbaf830dcbd85 100644 --- a/ext/filter/sanitizing_filters.c +++ b/ext/filter/sanitizing_filters.c @@ -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)); @@ -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); diff --git a/ext/standard/php_string.h b/ext/standard/php_string.h index fa1ebe4411233..ee5c533fe951a 100644 --- a/ext/standard/php_string.h +++ b/ext/standard/php_string.h @@ -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); diff --git a/ext/standard/string.c b/ext/standard/string.c index cb371762735b1..f6d9101397e20 100644 --- a/ext/standard/string.c +++ b/ext/standard/string.c @@ -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) @@ -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); } /* }}} */ @@ -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 @@ -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 = 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++; @@ -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, "<", _PHP_STRIP_TAGS_SIZE_TRIANGULAR_BRACKETS); + tp+=4; + break; + } + if (in_q) { break; } @@ -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, ">", _PHP_STRIP_TAGS_SIZE_TRIANGULAR_BRACKETS); + tp+=4; + break; + } + if (in_q) { break; } @@ -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; @@ -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; @@ -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; } @@ -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 '"': @@ -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; } @@ -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; } /* }}} */ diff --git a/ext/standard/tests/strings/Fix bug #80565.phpt b/ext/standard/tests/strings/Fix bug #80565.phpt new file mode 100644 index 0000000000000..e860d0661d3e2 --- /dev/null +++ b/ext/standard/tests/strings/Fix bug #80565.phpt @@ -0,0 +1,22 @@ +--TEST-- +Bug #XXXXX: strip_tags strip >< in attributes with allow tag +--FILE-- +', '').\PHP_EOL; +echo strip_tags('', '').\PHP_EOL; + +$lts = ''; +$gts = ''; +for ($i=0;$i<10;$i++) +{ + $lts.=" $i(<) "; + $gts.=" $i(>) "; +} +echo strip_tags(' xxx yyy hello!', '').\PHP_EOL; +echo strip_tags(' xxx yyy hello!', '').\PHP_EOL; +?> +--EXPECT-- + + + xxx yyy hello! + xxx yyy hello!