From 5e26e10dfea1b25cea1bce37d6e7d9d2f82c86aa Mon Sep 17 00:00:00 2001 From: George Liu Date: Fri, 30 Apr 2021 12:49:05 +1000 Subject: [PATCH] backport PHP 7.3.28 security fix to PHP 5.6, 7.0, 7.1 & 7.2 in 123.09beta01 - backport security fix from PHP 7.3.28+ https://bugs.php.net/bug.php?id=80710 to PHP 5.6.40, 7.0.33, 7.1.33, 7.2.34 EOL versions - folks should however update to latest active PHP version branches for PHP 7.3.28+, 7.4.18+ or 8.0.5+ --- centmin-cli.sh | 2 +- centmin.sh | 2 +- inc/php_patch.inc | 18 +- patches/php/php5640-80710.patch | 371 +++++++++++++++++++++++++++++++ patches/php/php7033-80710.patch | 373 ++++++++++++++++++++++++++++++++ patches/php/php7133-80710.patch | 373 ++++++++++++++++++++++++++++++++ patches/php/php7234-80710.patch | 371 +++++++++++++++++++++++++++++++ 7 files changed, 1505 insertions(+), 5 deletions(-) create mode 100644 patches/php/php5640-80710.patch create mode 100644 patches/php/php7033-80710.patch create mode 100644 patches/php/php7133-80710.patch create mode 100644 patches/php/php7234-80710.patch diff --git a/centmin-cli.sh b/centmin-cli.sh index d752f39c..2eadfb66 100755 --- a/centmin-cli.sh +++ b/centmin-cli.sh @@ -27,7 +27,7 @@ DT=$(date +"%d%m%y-%H%M%S") branchname='123.09beta01' SCRIPT_MAJORVER='1.2.3' SCRIPT_MINORVER='09' -SCRIPT_INCREMENTVER='667' +SCRIPT_INCREMENTVER='668' SCRIPT_VERSIONSHORT="${branchname}" SCRIPT_VERSION="${SCRIPT_VERSIONSHORT}.b${SCRIPT_INCREMENTVER}" SCRIPT_DATE='30/06/2021' diff --git a/centmin.sh b/centmin.sh index b2c4b22d..8c21a52e 100755 --- a/centmin.sh +++ b/centmin.sh @@ -27,7 +27,7 @@ DT=$(date +"%d%m%y-%H%M%S") branchname='123.09beta01' SCRIPT_MAJORVER='1.2.3' SCRIPT_MINORVER='09' -SCRIPT_INCREMENTVER='667' +SCRIPT_INCREMENTVER='668' SCRIPT_VERSIONSHORT="${branchname}" SCRIPT_VERSION="${SCRIPT_VERSIONSHORT}.b${SCRIPT_INCREMENTVER}" SCRIPT_DATE='30/06/2021' diff --git a/inc/php_patch.inc b/inc/php_patch.inc index 20b4fba4..5471221b 100644 --- a/inc/php_patch.inc +++ b/inc/php_patch.inc @@ -391,6 +391,16 @@ php_patches() { dos2unix php5640-80672.patch patch -p1 < php5640-80672.patch fi + # PHP 5.6 bug #80710 https://bugs.php.net/bug.php?id=80710 + if [ ! -f php5640-80710.patch ]; then + echo + echo "patching PHP 5.6 for bug #80710" + echo "https://bugs.php.net/bug.php?id=80710" + echo + cp -a $CUR_DIR/patches/php/php5640-80710.patch php5640-80710.patch + dos2unix php5640-80710.patch + patch -p1 < php5640-80710.patch + fi fi if [[ "$PHPVER_ID" = '70213' || "$PHPVER_ID" = '70125' ]]; then @@ -468,7 +478,7 @@ php_patches() { # PHP bug #79877 https://bugs.php.net/bug.php?id=79877 # PHP bug #79699 https://bugs.php.net/bug.php?id=79699 # PHP bug #77423 https://bugs.php.net/bug.php?id=77423 - phpseven_bugids='77369 77370 77371 77381 77418 77247 77242 77380 77540 77563 77396 77431 77630 76846 php-openssl-cert 77753 77831 sqlite3-defensive 77950 77967 77988 78069 77919 78222 78256 75457 78380 78599 78862 78863 78793 78878 78910 79037 79099 77569 79221 79082 php-openssl-cert2 79282 79329 79330 79465 78875 78876 79797 79877 79699 mysqlnd-fix 77423 80672' + phpseven_bugids='77369 77370 77371 77381 77418 77247 77242 77380 77540 77563 77396 77431 77630 76846 php-openssl-cert 77753 77831 sqlite3-defensive 77950 77967 77988 78069 77919 78222 78256 75457 78380 78599 78862 78863 78793 78878 78910 79037 79099 77569 79221 79082 php-openssl-cert2 79282 79329 79330 79465 78875 78876 79797 79877 79699 mysqlnd-fix 77423 80672 80710' for bugid in $phpseven_bugids; do if [[ ! -f "php7033-${bugid}.patch" && -f "$CUR_DIR/patches/php/php7033-${bugid}.patch" ]]; then echo @@ -522,7 +532,8 @@ php_patches() { # PHP bug #79601 https://bugs.php.net/bug.php?id=79601 # PHP bug #77423 https://bugs.php.net/bug.php?id=77423 # PHP bug #80672 https://bugs.php.net/bug.php?id=80672 - phpseven_bugids='78862 78863 78793 78878 78910 79037 79091 79099 77569 79221 79082 php-openssl-cert 79282 79329 79330 79465 78875 78876 79797 79877 79699 79601 mysqlnd-fix 77423 80672' + # PHP bug #80710 https://bugs.php.net/bug.php?id=80710 + phpseven_bugids='78862 78863 78793 78878 78910 79037 79091 79099 77569 79221 79082 php-openssl-cert 79282 79329 79330 79465 78875 78876 79797 79877 79699 79601 mysqlnd-fix 77423 80672 80710' for bugid in $phpseven_bugids; do if [[ ! -f "php7133-${bugid}.patch" && -f "$CUR_DIR/patches/php/php7133-${bugid}.patch" ]]; then echo @@ -574,7 +585,8 @@ php_patches() { # backport security bug patch from PHP 7.3. to 7.2.34 # PHP bug #77423 https://bugs.php.net/bug.php?id=77423 # PHP bug #80672 https://bugs.php.net/bug.php?id=80672 - phpseven_bugids='77423 80672' + # PHP bug #80710 https://bugs.php.net/bug.php?id=80710 + phpseven_bugids='77423 80672 80710' for bugid in $phpseven_bugids; do if [[ ! -f "php7234-${bugid}.patch" && -f "$CUR_DIR/patches/php/php7234-${bugid}.patch" ]]; then echo diff --git a/patches/php/php5640-80710.patch b/patches/php/php5640-80710.patch new file mode 100644 index 00000000..e4ba190b --- /dev/null +++ b/patches/php/php5640-80710.patch @@ -0,0 +1,371 @@ +From 72e14c75c5bae99a13369bf6c25c87e9c1489317 Mon Sep 17 00:00:00 2001 +From: "Christoph M. Becker" +Date: Fri, 5 Feb 2021 22:51:41 +0100 +Subject: [PATCH 1/2] Fix #80710: imap_mail_compose() header injection + +Like `mail()` and `mb_send_mail()`, `imap_mail_compose()` must prevent +header injection. For maximum backward compatibility, we still allow +header folding for general headers, and still accept trailing line +breaks for address lists. + +(cherry picked from commit 37962c61d29794645ec45d45d78123382d82c2e5) +(cherry picked from commit 9017896cccefe000938f80b49361b1c183849922) +--- + ext/imap/php_imap.c | 54 ++++++++++++++++++++++++++++++++++ + ext/imap/tests/bug80710_1.phpt | 37 +++++++++++++++++++++++ + ext/imap/tests/bug80710_2.phpt | 37 +++++++++++++++++++++++ + 3 files changed, 128 insertions(+) + create mode 100644 ext/imap/tests/bug80710_1.phpt + create mode 100644 ext/imap/tests/bug80710_2.phpt + +diff --git a/ext/imap/php_imap.c b/ext/imap/php_imap.c +index b30440f000..5dfe1220ed 100644 +--- a/ext/imap/php_imap.c ++++ b/ext/imap/php_imap.c +@@ -3491,6 +3491,21 @@ PHP_FUNCTION(imap_fetch_overview) + } + /* }}} */ + ++static zend_bool header_injection(char *p, zend_bool adrlist) ++{ ++ while ((p = strpbrk(p, "\r\n")) != NULL) { ++ if (!(p[0] == '\r' && p[1] == '\n') ++ /* adrlists do not support folding, but swallow trailing line breaks */ ++ && !((adrlist && p[1] == '\0') ++ /* other headers support folding */ ++ || !adrlist && (p[1] == ' ' || p[1] == '\t'))) { ++ return 1; ++ } ++ p++; ++ } ++ return 0; ++} ++ + /* {{{ proto string imap_mail_compose(array envelope, array body) + Create a MIME message based on given envelope and body sections */ + PHP_FUNCTION(imap_mail_compose) +@@ -3511,6 +3526,13 @@ PHP_FUNCTION(imap_mail_compose) + return; + } + ++#define CHECK_HEADER_INJECTION(zstr, adrlist, header) \ ++ if (header_injection(zstr, adrlist)) { \ ++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "header injection attempt in " header); \ ++ RETVAL_FALSE; \ ++ goto done; \ ++ } ++ + #define PHP_RFC822_PARSE_ADRLIST(target, value) \ + str_copy = estrndup(Z_STRVAL_PP(value), Z_STRLEN_PP(value)); \ + rfc822_parse_adrlist(target, str_copy, "NO HOST"); \ +@@ -3519,46 +3541,57 @@ PHP_FUNCTION(imap_mail_compose) + env = mail_newenvelope(); + if (zend_hash_find(Z_ARRVAL_P(envelope), "remail", sizeof("remail"), (void **) &pvalue)== SUCCESS) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STRVAL_PP(pvalue), 0, "remail"); + env->remail = cpystr(Z_STRVAL_PP(pvalue)); + } + if (zend_hash_find(Z_ARRVAL_P(envelope), "return_path", sizeof("return_path"), (void **) &pvalue)== SUCCESS) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STRVAL_PP(pvalue), 1, "return_path"); + PHP_RFC822_PARSE_ADRLIST(&env->return_path, pvalue); + } + if (zend_hash_find(Z_ARRVAL_P(envelope), "date", sizeof("date"), (void **) &pvalue)== SUCCESS) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STRVAL_PP(pvalue), 0, "date"); + env->date = cpystr(Z_STRVAL_PP(pvalue)); + } + if (zend_hash_find(Z_ARRVAL_P(envelope), "from", sizeof("from"), (void **) &pvalue)== SUCCESS) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STRVAL_PP(pvalue), 1, "from"); + PHP_RFC822_PARSE_ADRLIST(&env->from, pvalue); + } + if (zend_hash_find(Z_ARRVAL_P(envelope), "reply_to", sizeof("reply_to"), (void **) &pvalue)== SUCCESS) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STRVAL_PP(pvalue), 1, "reply_to"); + PHP_RFC822_PARSE_ADRLIST(&env->reply_to, pvalue); + } + if (zend_hash_find(Z_ARRVAL_P(envelope), "in_reply_to", sizeof("in_reply_to"), (void **) &pvalue)== SUCCESS) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STRVAL_PP(pvalue), 0, "in_reply_to"); + env->in_reply_to = cpystr(Z_STRVAL_PP(pvalue)); + } + if (zend_hash_find(Z_ARRVAL_P(envelope), "subject", sizeof("subject"), (void **) &pvalue)== SUCCESS) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STRVAL_PP(pvalue), 0, "subject"); + env->subject = cpystr(Z_STRVAL_PP(pvalue)); + } + if (zend_hash_find(Z_ARRVAL_P(envelope), "to", sizeof("to"), (void **) &pvalue)== SUCCESS) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STRVAL_PP(pvalue), 1, "to"); + PHP_RFC822_PARSE_ADRLIST(&env->to, pvalue); + } + if (zend_hash_find(Z_ARRVAL_P(envelope), "cc", sizeof("cc"), (void **) &pvalue)== SUCCESS) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STRVAL_PP(pvalue), 1, "cc"); + PHP_RFC822_PARSE_ADRLIST(&env->cc, pvalue); + } + if (zend_hash_find(Z_ARRVAL_P(envelope), "bcc", sizeof("bcc"), (void **) &pvalue)== SUCCESS) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STRVAL_PP(pvalue), 1, "bcc"); + PHP_RFC822_PARSE_ADRLIST(&env->bcc, pvalue); + } + if (zend_hash_find(Z_ARRVAL_P(envelope), "message_id", sizeof("message_id"), (void **) &pvalue)== SUCCESS) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STRVAL_PP(pvalue), 0, "message_id"); + env->message_id=cpystr(Z_STRVAL_PP(pvalue)); + } + +@@ -3568,6 +3601,7 @@ PHP_FUNCTION(imap_mail_compose) + while (zend_hash_get_current_data(Z_ARRVAL_PP(pvalue), (void **) &env_data) == SUCCESS) { + custom_headers_param = mail_newbody_parameter(); + convert_to_string_ex(env_data); ++ CHECK_HEADER_INJECTION(Z_STRVAL_PP(env_data), 0, "custom_headers"); + custom_headers_param->value = (char *) fs_get(Z_STRLEN_PP(env_data) + 1); + custom_headers_param->attribute = NULL; + memcpy(custom_headers_param->value, Z_STRVAL_PP(env_data), Z_STRLEN_PP(env_data) + 1); +@@ -3598,6 +3632,7 @@ PHP_FUNCTION(imap_mail_compose) + } + if (zend_hash_find(Z_ARRVAL_PP(data), "charset", sizeof("charset"), (void **) &pvalue)== SUCCESS) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STRVAL_PP(pvalue), 0, "body charset"); + tmp_param = mail_newbody_parameter(); + tmp_param->value = cpystr(Z_STRVAL_PP(pvalue)); + tmp_param->attribute = cpystr("CHARSET"); +@@ -3608,10 +3643,12 @@ PHP_FUNCTION(imap_mail_compose) + if(Z_TYPE_PP(pvalue) == IS_ARRAY) { + disp_param = tmp_param = NULL; + while (zend_hash_get_current_data(Z_ARRVAL_PP(pvalue), (void **) &disp_data) == SUCCESS) { ++ CHECK_HEADER_INJECTION(key, 0, "body disposition key"); + disp_param = mail_newbody_parameter(); + zend_hash_get_current_key(Z_ARRVAL_PP(pvalue), &key, &ind, 0); + disp_param->attribute = cpystr(key); + convert_to_string_ex(disp_data); ++ CHECK_HEADER_INJECTION(Z_STRVAL_PP(disp_data), 0, "body disposition value"); + disp_param->value = (char *) fs_get(Z_STRLEN_PP(disp_data) + 1); + memcpy(disp_param->value, Z_STRVAL_PP(disp_data), Z_STRLEN_PP(disp_data) + 1); + zend_hash_move_forward(Z_ARRVAL_PP(pvalue)); +@@ -3623,18 +3660,22 @@ PHP_FUNCTION(imap_mail_compose) + } + if (zend_hash_find(Z_ARRVAL_PP(data), "subtype", sizeof("subtype"), (void **) &pvalue)== SUCCESS) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STRVAL_PP(pvalue), 0, "body subtype"); + bod->subtype = cpystr(Z_STRVAL_PP(pvalue)); + } + if (zend_hash_find(Z_ARRVAL_PP(data), "id", sizeof("id"), (void **) &pvalue)== SUCCESS) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STRVAL_PP(pvalue), 0, "body id"); + bod->id = cpystr(Z_STRVAL_PP(pvalue)); + } + if (zend_hash_find(Z_ARRVAL_PP(data), "description", sizeof("description"), (void **) &pvalue)== SUCCESS) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STRVAL_PP(pvalue), 0, "body description"); + bod->description = cpystr(Z_STRVAL_PP(pvalue)); + } + if (zend_hash_find(Z_ARRVAL_PP(data), "disposition.type", sizeof("disposition.type"), (void **) &pvalue)== SUCCESS) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STRVAL_PP(pvalue), 0, "body disposition.type"); + bod->disposition.type = (char *) fs_get(Z_STRLEN_PP(pvalue) + 1); + memcpy(bod->disposition.type, Z_STRVAL_PP(pvalue), Z_STRLEN_PP(pvalue)+1); + } +@@ -3642,10 +3683,12 @@ PHP_FUNCTION(imap_mail_compose) + if (Z_TYPE_PP(pvalue) == IS_ARRAY) { + disp_param = tmp_param = NULL; + while (zend_hash_get_current_data(Z_ARRVAL_PP(pvalue), (void **) &disp_data) == SUCCESS) { ++ CHECK_HEADER_INJECTION(key, 0, "body type.parameters key"); + disp_param = mail_newbody_parameter(); + zend_hash_get_current_key(Z_ARRVAL_PP(pvalue), &key, &ind, 0); + disp_param->attribute = cpystr(key); + convert_to_string_ex(disp_data); ++ CHECK_HEADER_INJECTION(Z_STRVAL_PP(disp_data), 0, "body type.parameters value"); + disp_param->value = (char *) fs_get(Z_STRLEN_PP(disp_data) + 1); + memcpy(disp_param->value, Z_STRVAL_PP(disp_data), Z_STRLEN_PP(disp_data) + 1); + zend_hash_move_forward(Z_ARRVAL_PP(pvalue)); +@@ -3675,6 +3718,7 @@ PHP_FUNCTION(imap_mail_compose) + } + if (zend_hash_find(Z_ARRVAL_PP(data), "md5", sizeof("md5"), (void **) &pvalue)== SUCCESS) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STRVAL_PP(pvalue), 0, "body md5"); + bod->md5 = cpystr(Z_STRVAL_PP(pvalue)); + } + } +@@ -3710,6 +3754,7 @@ PHP_FUNCTION(imap_mail_compose) + } + if (zend_hash_find(Z_ARRVAL_PP(data), "charset", sizeof("charset"), (void **) &pvalue)== SUCCESS) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STRVAL_PP(pvalue), 0, "body charset"); + tmp_param = mail_newbody_parameter(); + tmp_param->value = (char *) fs_get(Z_STRLEN_PP(pvalue) + 1); + memcpy(tmp_param->value, Z_STRVAL_PP(pvalue), Z_STRLEN_PP(pvalue) + 1); +@@ -3723,8 +3768,10 @@ PHP_FUNCTION(imap_mail_compose) + while (zend_hash_get_current_data(Z_ARRVAL_PP(pvalue), (void **) &disp_data) == SUCCESS) { + disp_param = mail_newbody_parameter(); + zend_hash_get_current_key(Z_ARRVAL_PP(pvalue), &key, &ind, 0); ++ CHECK_HEADER_INJECTION(key, 0, "body type.parameters key"); + disp_param->attribute = cpystr(key); + convert_to_string_ex(disp_data); ++ CHECK_HEADER_INJECTION(Z_STRVAL_PP(disp_data), 0, "body type.parameters value"); + disp_param->value = (char *) fs_get(Z_STRLEN_PP(disp_data) + 1); + memcpy(disp_param->value, Z_STRVAL_PP(disp_data), Z_STRLEN_PP(disp_data) + 1); + zend_hash_move_forward(Z_ARRVAL_PP(pvalue)); +@@ -3736,18 +3783,22 @@ PHP_FUNCTION(imap_mail_compose) + } + if (zend_hash_find(Z_ARRVAL_PP(data), "subtype", sizeof("subtype"), (void **) &pvalue)== SUCCESS) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STRVAL_PP(pvalue), 0, "body subtype"); + bod->subtype = cpystr(Z_STRVAL_PP(pvalue)); + } + if (zend_hash_find(Z_ARRVAL_PP(data), "id", sizeof("id"), (void **) &pvalue)== SUCCESS) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STRVAL_PP(pvalue), 0, "body id"); + bod->id = cpystr(Z_STRVAL_PP(pvalue)); + } + if (zend_hash_find(Z_ARRVAL_PP(data), "description", sizeof("description"), (void **) &pvalue)== SUCCESS) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STRVAL_PP(pvalue), 0, "body description"); + bod->description = cpystr(Z_STRVAL_PP(pvalue)); + } + if (zend_hash_find(Z_ARRVAL_PP(data), "disposition.type", sizeof("disposition.type"), (void **) &pvalue)== SUCCESS) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STRVAL_PP(pvalue), 0, "body disposition.type"); + bod->disposition.type = (char *) fs_get(Z_STRLEN_PP(pvalue) + 1); + memcpy(bod->disposition.type, Z_STRVAL_PP(pvalue), Z_STRLEN_PP(pvalue)+1); + } +@@ -3757,8 +3808,10 @@ PHP_FUNCTION(imap_mail_compose) + while (zend_hash_get_current_data(Z_ARRVAL_PP(pvalue), (void **) &disp_data) == SUCCESS) { + disp_param = mail_newbody_parameter(); + zend_hash_get_current_key(Z_ARRVAL_PP(pvalue), &key, &ind, 0); ++ CHECK_HEADER_INJECTION(key, 0, "body disposition key"); + disp_param->attribute = cpystr(key); + convert_to_string_ex(disp_data); ++ CHECK_HEADER_INJECTION(Z_STRVAL_PP(disp_data), 0, "body disposition value"); + disp_param->value = (char *) fs_get(Z_STRLEN_PP(disp_data) + 1); + memcpy(disp_param->value, Z_STRVAL_PP(disp_data), Z_STRLEN_PP(disp_data) + 1); + zend_hash_move_forward(Z_ARRVAL_PP(pvalue)); +@@ -3788,6 +3841,7 @@ PHP_FUNCTION(imap_mail_compose) + } + if (zend_hash_find(Z_ARRVAL_PP(data), "md5", sizeof("md5"), (void **) &pvalue)== SUCCESS) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STRVAL_PP(pvalue), 0, "body md5"); + bod->md5 = cpystr(Z_STRVAL_PP(pvalue)); + } + } +diff --git a/ext/imap/tests/bug80710_1.phpt b/ext/imap/tests/bug80710_1.phpt +new file mode 100644 +index 0000000000..5cdee03401 +--- /dev/null ++++ b/ext/imap/tests/bug80710_1.phpt +@@ -0,0 +1,37 @@ ++--TEST-- ++Bug #80710 (imap_mail_compose() header injection) - MIME Splitting Attack ++--SKIPIF-- ++ ++--FILE-- ++ ++--EXPECTF-- ++Warning: imap_mail_compose(): header injection attempt in from in %s on line %d +diff --git a/ext/imap/tests/bug80710_2.phpt b/ext/imap/tests/bug80710_2.phpt +new file mode 100644 +index 0000000000..b9f2fa8544 +--- /dev/null ++++ b/ext/imap/tests/bug80710_2.phpt +@@ -0,0 +1,37 @@ ++--TEST-- ++Bug #80710 (imap_mail_compose() header injection) - Remail ++--SKIPIF-- ++ ++--FILE-- ++ ++--EXPECTF-- ++Warning: imap_mail_compose(): header injection attempt in remail in %s on line %d +-- +2.30.2 + +From 7cad4f2d9f69a8725b3c3d8a8e1af8a1676e1aa5 Mon Sep 17 00:00:00 2001 +From: "Christoph M. Becker" +Date: Tue, 27 Apr 2021 13:38:39 +0200 +Subject: [PATCH 2/2] Add missing NEWS entry for #80710 + +(cherry picked from commit 60a68a45c3e9f63585151221e7fe9ddff78bd71f) +(cherry picked from commit f16c623ec8ae3f3cdc73ab3fa05ae6bb0a77d1f3) +--- + NEWS | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/NEWS b/NEWS +index 8e9bd9648e..659bab855a 100644 +--- a/NEWS ++++ b/NEWS +@@ -1,6 +1,11 @@ + PHP NEWS + ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| + ++Backported from 7.3.28 ++ ++- Imap: ++ . Fixed bug #80710 (imap_mail_compose() header injection). (cmb, Stas) ++ + Backported from 7.3.27 + + - SOAP: +-- +2.30.2 + diff --git a/patches/php/php7033-80710.patch b/patches/php/php7033-80710.patch new file mode 100644 index 00000000..d66dd070 --- /dev/null +++ b/patches/php/php7033-80710.patch @@ -0,0 +1,373 @@ +From bfa81ac72836e53a75665eb1f78a6d67489da2e3 Mon Sep 17 00:00:00 2001 +From: "Christoph M. Becker" +Date: Fri, 5 Feb 2021 22:51:41 +0100 +Subject: [PATCH 1/2] Fix #80710: imap_mail_compose() header injection + +Like `mail()` and `mb_send_mail()`, `imap_mail_compose()` must prevent +header injection. For maximum backward compatibility, we still allow +header folding for general headers, and still accept trailing line +breaks for address lists. + +(cherry picked from commit 37962c61d29794645ec45d45d78123382d82c2e5) +(cherry picked from commit 9017896cccefe000938f80b49361b1c183849922) +--- + ext/imap/php_imap.c | 56 ++++++++++++++++++++++++++++++++++ + ext/imap/tests/bug80710_1.phpt | 37 ++++++++++++++++++++++ + ext/imap/tests/bug80710_2.phpt | 37 ++++++++++++++++++++++ + 3 files changed, 130 insertions(+) + create mode 100644 ext/imap/tests/bug80710_1.phpt + create mode 100644 ext/imap/tests/bug80710_2.phpt + +diff --git a/ext/imap/php_imap.c b/ext/imap/php_imap.c +index 011cbc0dfd..5f8c0da79a 100644 +--- a/ext/imap/php_imap.c ++++ b/ext/imap/php_imap.c +@@ -3531,6 +3531,23 @@ PHP_FUNCTION(imap_fetch_overview) + } + /* }}} */ + ++static zend_bool header_injection(zend_string *str, zend_bool adrlist) ++{ ++ char *p = ZSTR_VAL(str); ++ ++ while ((p = strpbrk(p, "\r\n")) != NULL) { ++ if (!(p[0] == '\r' && p[1] == '\n') ++ /* adrlists do not support folding, but swallow trailing line breaks */ ++ && !((adrlist && p[1] == '\0') ++ /* other headers support folding */ ++ || !adrlist && (p[1] == ' ' || p[1] == '\t'))) { ++ return 1; ++ } ++ p++; ++ } ++ return 0; ++} ++ + /* {{{ proto string imap_mail_compose(array envelope, array body) + Create a MIME message based on given envelope and body sections */ + PHP_FUNCTION(imap_mail_compose) +@@ -3551,6 +3568,13 @@ PHP_FUNCTION(imap_mail_compose) + return; + } + ++#define CHECK_HEADER_INJECTION(zstr, adrlist, header) \ ++ if (header_injection(zstr, adrlist)) { \ ++ php_error_docref(NULL, E_WARNING, "header injection attempt in " header); \ ++ RETVAL_FALSE; \ ++ goto done; \ ++ } ++ + #define PHP_RFC822_PARSE_ADRLIST(target, value) \ + str_copy = estrndup(Z_STRVAL_P(value), Z_STRLEN_P(value)); \ + rfc822_parse_adrlist(target, str_copy, "NO HOST"); \ +@@ -3559,46 +3583,57 @@ PHP_FUNCTION(imap_mail_compose) + env = mail_newenvelope(); + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "remail", sizeof("remail") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "remail"); + env->remail = cpystr(Z_STRVAL_P(pvalue)); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "return_path", sizeof("return_path") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 1, "return_path"); + PHP_RFC822_PARSE_ADRLIST(&env->return_path, pvalue); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "date", sizeof("date") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "date"); + env->date = (unsigned char*)cpystr(Z_STRVAL_P(pvalue)); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "from", sizeof("from") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 1, "from"); + PHP_RFC822_PARSE_ADRLIST(&env->from, pvalue); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "reply_to", sizeof("reply_to") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 1, "reply_to"); + PHP_RFC822_PARSE_ADRLIST(&env->reply_to, pvalue); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "in_reply_to", sizeof("in_reply_to") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "in_reply_to"); + env->in_reply_to = cpystr(Z_STRVAL_P(pvalue)); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "subject", sizeof("subject") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "subject"); + env->subject = cpystr(Z_STRVAL_P(pvalue)); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "to", sizeof("to") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 1, "to"); + PHP_RFC822_PARSE_ADRLIST(&env->to, pvalue); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "cc", sizeof("cc") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 1, "cc"); + PHP_RFC822_PARSE_ADRLIST(&env->cc, pvalue); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "bcc", sizeof("bcc") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 1, "bcc"); + PHP_RFC822_PARSE_ADRLIST(&env->bcc, pvalue); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "message_id", sizeof("message_id") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "message_id"); + env->message_id=cpystr(Z_STRVAL_P(pvalue)); + } + +@@ -3608,6 +3643,7 @@ PHP_FUNCTION(imap_mail_compose) + ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(pvalue), env_data) { + custom_headers_param = mail_newbody_parameter(); + convert_to_string_ex(env_data); ++ CHECK_HEADER_INJECTION(Z_STR_P(env_data), 0, "custom_headers"); + custom_headers_param->value = (char *) fs_get(Z_STRLEN_P(env_data) + 1); + custom_headers_param->attribute = NULL; + memcpy(custom_headers_param->value, Z_STRVAL_P(env_data), Z_STRLEN_P(env_data) + 1); +@@ -3640,6 +3676,7 @@ PHP_FUNCTION(imap_mail_compose) + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "charset", sizeof("charset") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body charset"); + tmp_param = mail_newbody_parameter(); + tmp_param->value = cpystr(Z_STRVAL_P(pvalue)); + tmp_param->attribute = cpystr("CHARSET"); +@@ -3650,9 +3687,11 @@ PHP_FUNCTION(imap_mail_compose) + if(Z_TYPE_P(pvalue) == IS_ARRAY) { + disp_param = tmp_param = NULL; + ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(pvalue), key, disp_data) { ++ CHECK_HEADER_INJECTION(key, 0, "body disposition key"); + disp_param = mail_newbody_parameter(); + disp_param->attribute = cpystr(ZSTR_VAL(key)); + convert_to_string_ex(disp_data); ++ CHECK_HEADER_INJECTION(Z_STR_P(disp_data), 0, "body disposition value"); + disp_param->value = (char *) fs_get(Z_STRLEN_P(disp_data) + 1); + memcpy(disp_param->value, Z_STRVAL_P(disp_data), Z_STRLEN_P(disp_data) + 1); + disp_param->next = tmp_param; +@@ -3663,18 +3702,22 @@ PHP_FUNCTION(imap_mail_compose) + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "subtype", sizeof("subtype") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body subtype"); + bod->subtype = cpystr(Z_STRVAL_P(pvalue)); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "id", sizeof("id") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body id"); + bod->id = cpystr(Z_STRVAL_P(pvalue)); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "description", sizeof("description") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body description"); + bod->description = cpystr(Z_STRVAL_P(pvalue)); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "disposition.type", sizeof("disposition.type") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body disposition.type"); + bod->disposition.type = (char *) fs_get(Z_STRLEN_P(pvalue) + 1); + memcpy(bod->disposition.type, Z_STRVAL_P(pvalue), Z_STRLEN_P(pvalue)+1); + } +@@ -3682,9 +3725,11 @@ PHP_FUNCTION(imap_mail_compose) + if (Z_TYPE_P(pvalue) == IS_ARRAY) { + disp_param = tmp_param = NULL; + ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(pvalue), key, disp_data) { ++ CHECK_HEADER_INJECTION(key, 0, "body type.parameters key"); + disp_param = mail_newbody_parameter(); + disp_param->attribute = cpystr(ZSTR_VAL(key)); + convert_to_string_ex(disp_data); ++ CHECK_HEADER_INJECTION(Z_STR_P(disp_data), 0, "body type.parameters value"); + disp_param->value = (char *) fs_get(Z_STRLEN_P(disp_data) + 1); + memcpy(disp_param->value, Z_STRVAL_P(disp_data), Z_STRLEN_P(disp_data) + 1); + disp_param->next = tmp_param; +@@ -3713,6 +3758,7 @@ PHP_FUNCTION(imap_mail_compose) + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "md5", sizeof("md5") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body md5"); + bod->md5 = cpystr(Z_STRVAL_P(pvalue)); + } + } else if (Z_TYPE_P(data) == IS_ARRAY) { +@@ -3743,6 +3789,7 @@ PHP_FUNCTION(imap_mail_compose) + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "charset", sizeof("charset") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body charset"); + tmp_param = mail_newbody_parameter(); + tmp_param->value = (char *) fs_get(Z_STRLEN_P(pvalue) + 1); + memcpy(tmp_param->value, Z_STRVAL_P(pvalue), Z_STRLEN_P(pvalue) + 1); +@@ -3754,9 +3801,11 @@ PHP_FUNCTION(imap_mail_compose) + if (Z_TYPE_P(pvalue) == IS_ARRAY) { + disp_param = tmp_param = NULL; + ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(pvalue), key, disp_data) { ++ CHECK_HEADER_INJECTION(key, 0, "body type.parameters key"); + disp_param = mail_newbody_parameter(); + disp_param->attribute = cpystr(ZSTR_VAL(key)); + convert_to_string_ex(disp_data); ++ CHECK_HEADER_INJECTION(Z_STR_P(disp_data), 0, "body type.parameters value"); + disp_param->value = (char *)fs_get(Z_STRLEN_P(disp_data) + 1); + memcpy(disp_param->value, Z_STRVAL_P(disp_data), Z_STRLEN_P(disp_data) + 1); + disp_param->next = tmp_param; +@@ -3767,18 +3816,22 @@ PHP_FUNCTION(imap_mail_compose) + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "subtype", sizeof("subtype") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body subtype"); + bod->subtype = cpystr(Z_STRVAL_P(pvalue)); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "id", sizeof("id") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body id"); + bod->id = cpystr(Z_STRVAL_P(pvalue)); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "description", sizeof("description") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body description"); + bod->description = cpystr(Z_STRVAL_P(pvalue)); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "disposition.type", sizeof("disposition.type") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body disposition.type"); + bod->disposition.type = (char *) fs_get(Z_STRLEN_P(pvalue) + 1); + memcpy(bod->disposition.type, Z_STRVAL_P(pvalue), Z_STRLEN_P(pvalue)+1); + } +@@ -3786,9 +3839,11 @@ PHP_FUNCTION(imap_mail_compose) + if (Z_TYPE_P(pvalue) == IS_ARRAY) { + disp_param = tmp_param = NULL; + ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(pvalue), key, disp_data) { ++ CHECK_HEADER_INJECTION(key, 0, "body disposition key"); + disp_param = mail_newbody_parameter(); + disp_param->attribute = cpystr(ZSTR_VAL(key)); + convert_to_string_ex(disp_data); ++ CHECK_HEADER_INJECTION(Z_STR_P(disp_data), 0, "body disposition value"); + disp_param->value = (char *) fs_get(Z_STRLEN_P(disp_data) + 1); + memcpy(disp_param->value, Z_STRVAL_P(disp_data), Z_STRLEN_P(disp_data) + 1); + disp_param->next = tmp_param; +@@ -3817,6 +3872,7 @@ PHP_FUNCTION(imap_mail_compose) + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "md5", sizeof("md5") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body md5"); + bod->md5 = cpystr(Z_STRVAL_P(pvalue)); + } + } +diff --git a/ext/imap/tests/bug80710_1.phpt b/ext/imap/tests/bug80710_1.phpt +new file mode 100644 +index 0000000000..5cdee03401 +--- /dev/null ++++ b/ext/imap/tests/bug80710_1.phpt +@@ -0,0 +1,37 @@ ++--TEST-- ++Bug #80710 (imap_mail_compose() header injection) - MIME Splitting Attack ++--SKIPIF-- ++ ++--FILE-- ++ ++--EXPECTF-- ++Warning: imap_mail_compose(): header injection attempt in from in %s on line %d +diff --git a/ext/imap/tests/bug80710_2.phpt b/ext/imap/tests/bug80710_2.phpt +new file mode 100644 +index 0000000000..b9f2fa8544 +--- /dev/null ++++ b/ext/imap/tests/bug80710_2.phpt +@@ -0,0 +1,37 @@ ++--TEST-- ++Bug #80710 (imap_mail_compose() header injection) - Remail ++--SKIPIF-- ++ ++--FILE-- ++ ++--EXPECTF-- ++Warning: imap_mail_compose(): header injection attempt in remail in %s on line %d +-- +2.30.2 + +From 5a31584debadbb8e7195d768edece32b249e14bb Mon Sep 17 00:00:00 2001 +From: "Christoph M. Becker" +Date: Tue, 27 Apr 2021 13:38:39 +0200 +Subject: [PATCH 2/2] Add missing NEWS entry for #80710 + +(cherry picked from commit 60a68a45c3e9f63585151221e7fe9ddff78bd71f) +(cherry picked from commit f16c623ec8ae3f3cdc73ab3fa05ae6bb0a77d1f3) +--- + NEWS | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/NEWS b/NEWS +index fe5564de15..9eff4bd7ae 100644 +--- a/NEWS ++++ b/NEWS +@@ -1,6 +1,11 @@ + PHP NEWS + ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| + ++Backported from 7.3.28 ++ ++- Imap: ++ . Fixed bug #80710 (imap_mail_compose() header injection). (cmb, Stas) ++ + Backported from 7.3.27 + + - SOAP: +-- +2.30.2 + diff --git a/patches/php/php7133-80710.patch b/patches/php/php7133-80710.patch new file mode 100644 index 00000000..b24ac429 --- /dev/null +++ b/patches/php/php7133-80710.patch @@ -0,0 +1,373 @@ +From b259bf84d8ee47c5d0fd990dbf67d3930572f49d Mon Sep 17 00:00:00 2001 +From: "Christoph M. Becker" +Date: Fri, 5 Feb 2021 22:51:41 +0100 +Subject: [PATCH 1/2] Fix #80710: imap_mail_compose() header injection + +Like `mail()` and `mb_send_mail()`, `imap_mail_compose()` must prevent +header injection. For maximum backward compatibility, we still allow +header folding for general headers, and still accept trailing line +breaks for address lists. + +(cherry picked from commit 37962c61d29794645ec45d45d78123382d82c2e5) +(cherry picked from commit 9017896cccefe000938f80b49361b1c183849922) +--- + ext/imap/php_imap.c | 56 ++++++++++++++++++++++++++++++++++ + ext/imap/tests/bug80710_1.phpt | 37 ++++++++++++++++++++++ + ext/imap/tests/bug80710_2.phpt | 37 ++++++++++++++++++++++ + 3 files changed, 130 insertions(+) + create mode 100644 ext/imap/tests/bug80710_1.phpt + create mode 100644 ext/imap/tests/bug80710_2.phpt + +diff --git a/ext/imap/php_imap.c b/ext/imap/php_imap.c +index 6ce4b78179..7de074aeeb 100644 +--- a/ext/imap/php_imap.c ++++ b/ext/imap/php_imap.c +@@ -3531,6 +3531,23 @@ PHP_FUNCTION(imap_fetch_overview) + } + /* }}} */ + ++static zend_bool header_injection(zend_string *str, zend_bool adrlist) ++{ ++ char *p = ZSTR_VAL(str); ++ ++ while ((p = strpbrk(p, "\r\n")) != NULL) { ++ if (!(p[0] == '\r' && p[1] == '\n') ++ /* adrlists do not support folding, but swallow trailing line breaks */ ++ && !((adrlist && p[1] == '\0') ++ /* other headers support folding */ ++ || !adrlist && (p[1] == ' ' || p[1] == '\t'))) { ++ return 1; ++ } ++ p++; ++ } ++ return 0; ++} ++ + /* {{{ proto string imap_mail_compose(array envelope, array body) + Create a MIME message based on given envelope and body sections */ + PHP_FUNCTION(imap_mail_compose) +@@ -3551,6 +3568,13 @@ PHP_FUNCTION(imap_mail_compose) + return; + } + ++#define CHECK_HEADER_INJECTION(zstr, adrlist, header) \ ++ if (header_injection(zstr, adrlist)) { \ ++ php_error_docref(NULL, E_WARNING, "header injection attempt in " header); \ ++ RETVAL_FALSE; \ ++ goto done; \ ++ } ++ + #define PHP_RFC822_PARSE_ADRLIST(target, value) \ + str_copy = estrndup(Z_STRVAL_P(value), Z_STRLEN_P(value)); \ + rfc822_parse_adrlist(target, str_copy, "NO HOST"); \ +@@ -3559,46 +3583,57 @@ PHP_FUNCTION(imap_mail_compose) + env = mail_newenvelope(); + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "remail", sizeof("remail") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "remail"); + env->remail = cpystr(Z_STRVAL_P(pvalue)); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "return_path", sizeof("return_path") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 1, "return_path"); + PHP_RFC822_PARSE_ADRLIST(&env->return_path, pvalue); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "date", sizeof("date") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "date"); + env->date = (unsigned char*)cpystr(Z_STRVAL_P(pvalue)); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "from", sizeof("from") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 1, "from"); + PHP_RFC822_PARSE_ADRLIST(&env->from, pvalue); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "reply_to", sizeof("reply_to") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 1, "reply_to"); + PHP_RFC822_PARSE_ADRLIST(&env->reply_to, pvalue); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "in_reply_to", sizeof("in_reply_to") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "in_reply_to"); + env->in_reply_to = cpystr(Z_STRVAL_P(pvalue)); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "subject", sizeof("subject") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "subject"); + env->subject = cpystr(Z_STRVAL_P(pvalue)); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "to", sizeof("to") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 1, "to"); + PHP_RFC822_PARSE_ADRLIST(&env->to, pvalue); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "cc", sizeof("cc") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 1, "cc"); + PHP_RFC822_PARSE_ADRLIST(&env->cc, pvalue); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "bcc", sizeof("bcc") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 1, "bcc"); + PHP_RFC822_PARSE_ADRLIST(&env->bcc, pvalue); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "message_id", sizeof("message_id") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "message_id"); + env->message_id=cpystr(Z_STRVAL_P(pvalue)); + } + +@@ -3608,6 +3643,7 @@ PHP_FUNCTION(imap_mail_compose) + ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(pvalue), env_data) { + custom_headers_param = mail_newbody_parameter(); + convert_to_string_ex(env_data); ++ CHECK_HEADER_INJECTION(Z_STR_P(env_data), 0, "custom_headers"); + custom_headers_param->value = (char *) fs_get(Z_STRLEN_P(env_data) + 1); + custom_headers_param->attribute = NULL; + memcpy(custom_headers_param->value, Z_STRVAL_P(env_data), Z_STRLEN_P(env_data) + 1); +@@ -3640,6 +3676,7 @@ PHP_FUNCTION(imap_mail_compose) + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "charset", sizeof("charset") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body charset"); + tmp_param = mail_newbody_parameter(); + tmp_param->value = cpystr(Z_STRVAL_P(pvalue)); + tmp_param->attribute = cpystr("CHARSET"); +@@ -3650,9 +3687,11 @@ PHP_FUNCTION(imap_mail_compose) + if(Z_TYPE_P(pvalue) == IS_ARRAY) { + disp_param = tmp_param = NULL; + ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(pvalue), key, disp_data) { ++ CHECK_HEADER_INJECTION(key, 0, "body disposition key"); + disp_param = mail_newbody_parameter(); + disp_param->attribute = cpystr(ZSTR_VAL(key)); + convert_to_string_ex(disp_data); ++ CHECK_HEADER_INJECTION(Z_STR_P(disp_data), 0, "body disposition value"); + disp_param->value = (char *) fs_get(Z_STRLEN_P(disp_data) + 1); + memcpy(disp_param->value, Z_STRVAL_P(disp_data), Z_STRLEN_P(disp_data) + 1); + disp_param->next = tmp_param; +@@ -3663,18 +3702,22 @@ PHP_FUNCTION(imap_mail_compose) + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "subtype", sizeof("subtype") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body subtype"); + bod->subtype = cpystr(Z_STRVAL_P(pvalue)); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "id", sizeof("id") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body id"); + bod->id = cpystr(Z_STRVAL_P(pvalue)); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "description", sizeof("description") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body description"); + bod->description = cpystr(Z_STRVAL_P(pvalue)); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "disposition.type", sizeof("disposition.type") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body disposition.type"); + bod->disposition.type = (char *) fs_get(Z_STRLEN_P(pvalue) + 1); + memcpy(bod->disposition.type, Z_STRVAL_P(pvalue), Z_STRLEN_P(pvalue)+1); + } +@@ -3682,9 +3725,11 @@ PHP_FUNCTION(imap_mail_compose) + if (Z_TYPE_P(pvalue) == IS_ARRAY) { + disp_param = tmp_param = NULL; + ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(pvalue), key, disp_data) { ++ CHECK_HEADER_INJECTION(key, 0, "body type.parameters key"); + disp_param = mail_newbody_parameter(); + disp_param->attribute = cpystr(ZSTR_VAL(key)); + convert_to_string_ex(disp_data); ++ CHECK_HEADER_INJECTION(Z_STR_P(disp_data), 0, "body type.parameters value"); + disp_param->value = (char *) fs_get(Z_STRLEN_P(disp_data) + 1); + memcpy(disp_param->value, Z_STRVAL_P(disp_data), Z_STRLEN_P(disp_data) + 1); + disp_param->next = tmp_param; +@@ -3713,6 +3758,7 @@ PHP_FUNCTION(imap_mail_compose) + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "md5", sizeof("md5") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body md5"); + bod->md5 = cpystr(Z_STRVAL_P(pvalue)); + } + } else if (Z_TYPE_P(data) == IS_ARRAY) { +@@ -3743,6 +3789,7 @@ PHP_FUNCTION(imap_mail_compose) + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "charset", sizeof("charset") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body charset"); + tmp_param = mail_newbody_parameter(); + tmp_param->value = (char *) fs_get(Z_STRLEN_P(pvalue) + 1); + memcpy(tmp_param->value, Z_STRVAL_P(pvalue), Z_STRLEN_P(pvalue) + 1); +@@ -3754,9 +3801,11 @@ PHP_FUNCTION(imap_mail_compose) + if (Z_TYPE_P(pvalue) == IS_ARRAY) { + disp_param = tmp_param = NULL; + ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(pvalue), key, disp_data) { ++ CHECK_HEADER_INJECTION(key, 0, "body type.parameters key"); + disp_param = mail_newbody_parameter(); + disp_param->attribute = cpystr(ZSTR_VAL(key)); + convert_to_string_ex(disp_data); ++ CHECK_HEADER_INJECTION(Z_STR_P(disp_data), 0, "body type.parameters value"); + disp_param->value = (char *)fs_get(Z_STRLEN_P(disp_data) + 1); + memcpy(disp_param->value, Z_STRVAL_P(disp_data), Z_STRLEN_P(disp_data) + 1); + disp_param->next = tmp_param; +@@ -3767,18 +3816,22 @@ PHP_FUNCTION(imap_mail_compose) + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "subtype", sizeof("subtype") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body subtype"); + bod->subtype = cpystr(Z_STRVAL_P(pvalue)); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "id", sizeof("id") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body id"); + bod->id = cpystr(Z_STRVAL_P(pvalue)); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "description", sizeof("description") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body description"); + bod->description = cpystr(Z_STRVAL_P(pvalue)); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "disposition.type", sizeof("disposition.type") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body disposition.type"); + bod->disposition.type = (char *) fs_get(Z_STRLEN_P(pvalue) + 1); + memcpy(bod->disposition.type, Z_STRVAL_P(pvalue), Z_STRLEN_P(pvalue)+1); + } +@@ -3786,9 +3839,11 @@ PHP_FUNCTION(imap_mail_compose) + if (Z_TYPE_P(pvalue) == IS_ARRAY) { + disp_param = tmp_param = NULL; + ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(pvalue), key, disp_data) { ++ CHECK_HEADER_INJECTION(key, 0, "body disposition key"); + disp_param = mail_newbody_parameter(); + disp_param->attribute = cpystr(ZSTR_VAL(key)); + convert_to_string_ex(disp_data); ++ CHECK_HEADER_INJECTION(Z_STR_P(disp_data), 0, "body disposition value"); + disp_param->value = (char *) fs_get(Z_STRLEN_P(disp_data) + 1); + memcpy(disp_param->value, Z_STRVAL_P(disp_data), Z_STRLEN_P(disp_data) + 1); + disp_param->next = tmp_param; +@@ -3817,6 +3872,7 @@ PHP_FUNCTION(imap_mail_compose) + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "md5", sizeof("md5") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body md5"); + bod->md5 = cpystr(Z_STRVAL_P(pvalue)); + } + } +diff --git a/ext/imap/tests/bug80710_1.phpt b/ext/imap/tests/bug80710_1.phpt +new file mode 100644 +index 0000000000..5cdee03401 +--- /dev/null ++++ b/ext/imap/tests/bug80710_1.phpt +@@ -0,0 +1,37 @@ ++--TEST-- ++Bug #80710 (imap_mail_compose() header injection) - MIME Splitting Attack ++--SKIPIF-- ++ ++--FILE-- ++ ++--EXPECTF-- ++Warning: imap_mail_compose(): header injection attempt in from in %s on line %d +diff --git a/ext/imap/tests/bug80710_2.phpt b/ext/imap/tests/bug80710_2.phpt +new file mode 100644 +index 0000000000..b9f2fa8544 +--- /dev/null ++++ b/ext/imap/tests/bug80710_2.phpt +@@ -0,0 +1,37 @@ ++--TEST-- ++Bug #80710 (imap_mail_compose() header injection) - Remail ++--SKIPIF-- ++ ++--FILE-- ++ ++--EXPECTF-- ++Warning: imap_mail_compose(): header injection attempt in remail in %s on line %d +-- +2.30.2 + +From 82d71819333bf5483e31e7b9f41e9d25526c3c84 Mon Sep 17 00:00:00 2001 +From: "Christoph M. Becker" +Date: Tue, 27 Apr 2021 13:38:39 +0200 +Subject: [PATCH 2/2] Add missing NEWS entry for #80710 + +(cherry picked from commit 60a68a45c3e9f63585151221e7fe9ddff78bd71f) +(cherry picked from commit f16c623ec8ae3f3cdc73ab3fa05ae6bb0a77d1f3) +--- + NEWS | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/NEWS b/NEWS +index 9f4bcd9faf..63295d3b76 100644 +--- a/NEWS ++++ b/NEWS +@@ -1,6 +1,11 @@ + PHP NEWS + ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| + ++Backported from 7.3.28 ++ ++- Imap: ++ . Fixed bug #80710 (imap_mail_compose() header injection). (cmb, Stas) ++ + Backported from 7.3.27 + + - SOAP: +-- +2.30.2 + diff --git a/patches/php/php7234-80710.patch b/patches/php/php7234-80710.patch new file mode 100644 index 00000000..2dd68f07 --- /dev/null +++ b/patches/php/php7234-80710.patch @@ -0,0 +1,371 @@ +From 9017896cccefe000938f80b49361b1c183849922 Mon Sep 17 00:00:00 2001 +From: "Christoph M. Becker" +Date: Fri, 5 Feb 2021 22:51:41 +0100 +Subject: [PATCH 1/2] Fix #80710: imap_mail_compose() header injection + +Like `mail()` and `mb_send_mail()`, `imap_mail_compose()` must prevent +header injection. For maximum backward compatibility, we still allow +header folding for general headers, and still accept trailing line +breaks for address lists. + +(cherry picked from commit 37962c61d29794645ec45d45d78123382d82c2e5) +--- + ext/imap/php_imap.c | 56 ++++++++++++++++++++++++++++++++++ + ext/imap/tests/bug80710_1.phpt | 37 ++++++++++++++++++++++ + ext/imap/tests/bug80710_2.phpt | 37 ++++++++++++++++++++++ + 3 files changed, 130 insertions(+) + create mode 100644 ext/imap/tests/bug80710_1.phpt + create mode 100644 ext/imap/tests/bug80710_2.phpt + +diff --git a/ext/imap/php_imap.c b/ext/imap/php_imap.c +index 37eb5e1296..9cac2264fb 100644 +--- a/ext/imap/php_imap.c ++++ b/ext/imap/php_imap.c +@@ -3528,6 +3528,23 @@ PHP_FUNCTION(imap_fetch_overview) + } + /* }}} */ + ++static zend_bool header_injection(zend_string *str, zend_bool adrlist) ++{ ++ char *p = ZSTR_VAL(str); ++ ++ while ((p = strpbrk(p, "\r\n")) != NULL) { ++ if (!(p[0] == '\r' && p[1] == '\n') ++ /* adrlists do not support folding, but swallow trailing line breaks */ ++ && !((adrlist && p[1] == '\0') ++ /* other headers support folding */ ++ || !adrlist && (p[1] == ' ' || p[1] == '\t'))) { ++ return 1; ++ } ++ p++; ++ } ++ return 0; ++} ++ + /* {{{ proto string imap_mail_compose(array envelope, array body) + Create a MIME message based on given envelope and body sections */ + PHP_FUNCTION(imap_mail_compose) +@@ -3548,6 +3565,13 @@ PHP_FUNCTION(imap_mail_compose) + return; + } + ++#define CHECK_HEADER_INJECTION(zstr, adrlist, header) \ ++ if (header_injection(zstr, adrlist)) { \ ++ php_error_docref(NULL, E_WARNING, "header injection attempt in " header); \ ++ RETVAL_FALSE; \ ++ goto done; \ ++ } ++ + #define PHP_RFC822_PARSE_ADRLIST(target, value) \ + str_copy = estrndup(Z_STRVAL_P(value), Z_STRLEN_P(value)); \ + rfc822_parse_adrlist(target, str_copy, "NO HOST"); \ +@@ -3556,46 +3580,57 @@ PHP_FUNCTION(imap_mail_compose) + env = mail_newenvelope(); + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "remail", sizeof("remail") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "remail"); + env->remail = cpystr(Z_STRVAL_P(pvalue)); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "return_path", sizeof("return_path") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 1, "return_path"); + PHP_RFC822_PARSE_ADRLIST(&env->return_path, pvalue); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "date", sizeof("date") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "date"); + env->date = (unsigned char*)cpystr(Z_STRVAL_P(pvalue)); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "from", sizeof("from") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 1, "from"); + PHP_RFC822_PARSE_ADRLIST(&env->from, pvalue); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "reply_to", sizeof("reply_to") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 1, "reply_to"); + PHP_RFC822_PARSE_ADRLIST(&env->reply_to, pvalue); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "in_reply_to", sizeof("in_reply_to") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "in_reply_to"); + env->in_reply_to = cpystr(Z_STRVAL_P(pvalue)); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "subject", sizeof("subject") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "subject"); + env->subject = cpystr(Z_STRVAL_P(pvalue)); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "to", sizeof("to") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 1, "to"); + PHP_RFC822_PARSE_ADRLIST(&env->to, pvalue); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "cc", sizeof("cc") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 1, "cc"); + PHP_RFC822_PARSE_ADRLIST(&env->cc, pvalue); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "bcc", sizeof("bcc") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 1, "bcc"); + PHP_RFC822_PARSE_ADRLIST(&env->bcc, pvalue); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "message_id", sizeof("message_id") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "message_id"); + env->message_id=cpystr(Z_STRVAL_P(pvalue)); + } + +@@ -3605,6 +3640,7 @@ PHP_FUNCTION(imap_mail_compose) + ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(pvalue), env_data) { + custom_headers_param = mail_newbody_parameter(); + convert_to_string_ex(env_data); ++ CHECK_HEADER_INJECTION(Z_STR_P(env_data), 0, "custom_headers"); + custom_headers_param->value = (char *) fs_get(Z_STRLEN_P(env_data) + 1); + custom_headers_param->attribute = NULL; + memcpy(custom_headers_param->value, Z_STRVAL_P(env_data), Z_STRLEN_P(env_data) + 1); +@@ -3637,6 +3673,7 @@ PHP_FUNCTION(imap_mail_compose) + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "charset", sizeof("charset") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body charset"); + tmp_param = mail_newbody_parameter(); + tmp_param->value = cpystr(Z_STRVAL_P(pvalue)); + tmp_param->attribute = cpystr("CHARSET"); +@@ -3647,9 +3684,11 @@ PHP_FUNCTION(imap_mail_compose) + if(Z_TYPE_P(pvalue) == IS_ARRAY) { + disp_param = tmp_param = NULL; + ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(pvalue), key, disp_data) { ++ CHECK_HEADER_INJECTION(key, 0, "body disposition key"); + disp_param = mail_newbody_parameter(); + disp_param->attribute = cpystr(ZSTR_VAL(key)); + convert_to_string_ex(disp_data); ++ CHECK_HEADER_INJECTION(Z_STR_P(disp_data), 0, "body disposition value"); + disp_param->value = (char *) fs_get(Z_STRLEN_P(disp_data) + 1); + memcpy(disp_param->value, Z_STRVAL_P(disp_data), Z_STRLEN_P(disp_data) + 1); + disp_param->next = tmp_param; +@@ -3660,18 +3699,22 @@ PHP_FUNCTION(imap_mail_compose) + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "subtype", sizeof("subtype") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body subtype"); + bod->subtype = cpystr(Z_STRVAL_P(pvalue)); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "id", sizeof("id") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body id"); + bod->id = cpystr(Z_STRVAL_P(pvalue)); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "description", sizeof("description") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body description"); + bod->description = cpystr(Z_STRVAL_P(pvalue)); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "disposition.type", sizeof("disposition.type") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body disposition.type"); + bod->disposition.type = (char *) fs_get(Z_STRLEN_P(pvalue) + 1); + memcpy(bod->disposition.type, Z_STRVAL_P(pvalue), Z_STRLEN_P(pvalue)+1); + } +@@ -3679,9 +3722,11 @@ PHP_FUNCTION(imap_mail_compose) + if (Z_TYPE_P(pvalue) == IS_ARRAY) { + disp_param = tmp_param = NULL; + ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(pvalue), key, disp_data) { ++ CHECK_HEADER_INJECTION(key, 0, "body type.parameters key"); + disp_param = mail_newbody_parameter(); + disp_param->attribute = cpystr(ZSTR_VAL(key)); + convert_to_string_ex(disp_data); ++ CHECK_HEADER_INJECTION(Z_STR_P(disp_data), 0, "body type.parameters value"); + disp_param->value = (char *) fs_get(Z_STRLEN_P(disp_data) + 1); + memcpy(disp_param->value, Z_STRVAL_P(disp_data), Z_STRLEN_P(disp_data) + 1); + disp_param->next = tmp_param; +@@ -3710,6 +3755,7 @@ PHP_FUNCTION(imap_mail_compose) + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "md5", sizeof("md5") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body md5"); + bod->md5 = cpystr(Z_STRVAL_P(pvalue)); + } + } else if (Z_TYPE_P(data) == IS_ARRAY) { +@@ -3740,6 +3786,7 @@ PHP_FUNCTION(imap_mail_compose) + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "charset", sizeof("charset") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body charset"); + tmp_param = mail_newbody_parameter(); + tmp_param->value = (char *) fs_get(Z_STRLEN_P(pvalue) + 1); + memcpy(tmp_param->value, Z_STRVAL_P(pvalue), Z_STRLEN_P(pvalue) + 1); +@@ -3751,9 +3798,11 @@ PHP_FUNCTION(imap_mail_compose) + if (Z_TYPE_P(pvalue) == IS_ARRAY) { + disp_param = tmp_param = NULL; + ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(pvalue), key, disp_data) { ++ CHECK_HEADER_INJECTION(key, 0, "body type.parameters key"); + disp_param = mail_newbody_parameter(); + disp_param->attribute = cpystr(ZSTR_VAL(key)); + convert_to_string_ex(disp_data); ++ CHECK_HEADER_INJECTION(Z_STR_P(disp_data), 0, "body type.parameters value"); + disp_param->value = (char *)fs_get(Z_STRLEN_P(disp_data) + 1); + memcpy(disp_param->value, Z_STRVAL_P(disp_data), Z_STRLEN_P(disp_data) + 1); + disp_param->next = tmp_param; +@@ -3764,18 +3813,22 @@ PHP_FUNCTION(imap_mail_compose) + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "subtype", sizeof("subtype") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body subtype"); + bod->subtype = cpystr(Z_STRVAL_P(pvalue)); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "id", sizeof("id") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body id"); + bod->id = cpystr(Z_STRVAL_P(pvalue)); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "description", sizeof("description") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body description"); + bod->description = cpystr(Z_STRVAL_P(pvalue)); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "disposition.type", sizeof("disposition.type") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body disposition.type"); + bod->disposition.type = (char *) fs_get(Z_STRLEN_P(pvalue) + 1); + memcpy(bod->disposition.type, Z_STRVAL_P(pvalue), Z_STRLEN_P(pvalue)+1); + } +@@ -3783,9 +3836,11 @@ PHP_FUNCTION(imap_mail_compose) + if (Z_TYPE_P(pvalue) == IS_ARRAY) { + disp_param = tmp_param = NULL; + ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(pvalue), key, disp_data) { ++ CHECK_HEADER_INJECTION(key, 0, "body disposition key"); + disp_param = mail_newbody_parameter(); + disp_param->attribute = cpystr(ZSTR_VAL(key)); + convert_to_string_ex(disp_data); ++ CHECK_HEADER_INJECTION(Z_STR_P(disp_data), 0, "body disposition value"); + disp_param->value = (char *) fs_get(Z_STRLEN_P(disp_data) + 1); + memcpy(disp_param->value, Z_STRVAL_P(disp_data), Z_STRLEN_P(disp_data) + 1); + disp_param->next = tmp_param; +@@ -3814,6 +3869,7 @@ PHP_FUNCTION(imap_mail_compose) + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "md5", sizeof("md5") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body md5"); + bod->md5 = cpystr(Z_STRVAL_P(pvalue)); + } + } +diff --git a/ext/imap/tests/bug80710_1.phpt b/ext/imap/tests/bug80710_1.phpt +new file mode 100644 +index 0000000000..5cdee03401 +--- /dev/null ++++ b/ext/imap/tests/bug80710_1.phpt +@@ -0,0 +1,37 @@ ++--TEST-- ++Bug #80710 (imap_mail_compose() header injection) - MIME Splitting Attack ++--SKIPIF-- ++ ++--FILE-- ++ ++--EXPECTF-- ++Warning: imap_mail_compose(): header injection attempt in from in %s on line %d +diff --git a/ext/imap/tests/bug80710_2.phpt b/ext/imap/tests/bug80710_2.phpt +new file mode 100644 +index 0000000000..b9f2fa8544 +--- /dev/null ++++ b/ext/imap/tests/bug80710_2.phpt +@@ -0,0 +1,37 @@ ++--TEST-- ++Bug #80710 (imap_mail_compose() header injection) - Remail ++--SKIPIF-- ++ ++--FILE-- ++ ++--EXPECTF-- ++Warning: imap_mail_compose(): header injection attempt in remail in %s on line %d +-- +2.30.2 + +From f16c623ec8ae3f3cdc73ab3fa05ae6bb0a77d1f3 Mon Sep 17 00:00:00 2001 +From: "Christoph M. Becker" +Date: Tue, 27 Apr 2021 13:38:39 +0200 +Subject: [PATCH 2/2] Add missing NEWS entry for #80710 + +(cherry picked from commit 60a68a45c3e9f63585151221e7fe9ddff78bd71f) +--- + NEWS | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/NEWS b/NEWS +index 884285f05f..e331598176 100644 +--- a/NEWS ++++ b/NEWS +@@ -1,6 +1,11 @@ + PHP NEWS + ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| + ++Backported from 7.3.28 ++ ++- Imap: ++ . Fixed bug #80710 (imap_mail_compose() header injection). (cmb, Stas) ++ + Backported from 7.3.27 + + - SOAP: +-- +2.30.2 +