diff options
Diffstat (limited to 'php-bug80710.patch')
-rw-r--r-- | php-bug80710.patch | 371 |
1 files changed, 371 insertions, 0 deletions
diff --git a/php-bug80710.patch b/php-bug80710.patch new file mode 100644 index 0000000..e4ba190 --- /dev/null +++ b/php-bug80710.patch @@ -0,0 +1,371 @@ +From 72e14c75c5bae99a13369bf6c25c87e9c1489317 Mon Sep 17 00:00:00 2001 +From: "Christoph M. Becker" <cmbecker69@gmx.de> +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-- ++<?php ++if (!extension_loaded("imap")) die("skip imap extension not available"); ++?> ++--FILE-- ++<?php ++$envelope["from"]= "joe@example.com\n From : X-INJECTED"; ++$envelope["to"] = "foo@example.com\nFrom: X-INJECTED"; ++$envelope["cc"] = "bar@example.com\nFrom: X-INJECTED"; ++$envelope["subject"] = "bar@example.com\n\n From : X-INJECTED"; ++$envelope["x-remail"] = "bar@example.com\nFrom: X-INJECTED"; ++$envelope["something"] = "bar@example.com\nFrom: X-INJECTED"; ++ ++$part1["type"] = TYPEMULTIPART; ++$part1["subtype"] = "mixed"; ++ ++$part2["type"] = TYPEAPPLICATION; ++$part2["encoding"] = ENCBINARY; ++$part2["subtype"] = "octet-stream\nContent-Type: X-INJECTED"; ++$part2["description"] = "some file\nContent-Type: X-INJECTED"; ++$part2["contents.data"] = "ABC\nContent-Type: X-INJECTED"; ++ ++$part3["type"] = TYPETEXT; ++$part3["subtype"] = "plain"; ++$part3["description"] = "description3"; ++$part3["contents.data"] = "contents.data3\n\n\n\t"; ++ ++$body[1] = $part1; ++$body[2] = $part2; ++$body[3] = $part3; ++ ++echo imap_mail_compose($envelope, $body); ++?> ++--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-- ++<?php ++if (!extension_loaded("imap")) die("skip imap extension not available"); ++?> ++--FILE-- ++<?php ++$envelope["from"]= "joe@example.com\n From : X-INJECTED"; ++$envelope["to"] = "foo@example.com\nFrom: X-INJECTED"; ++$envelope["cc"] = "bar@example.com\nFrom: X-INJECTED"; ++$envelope["subject"] = "bar@example.com\n\n From : X-INJECTED"; ++$envelope["remail"] = "X-INJECTED-REMAIL: X-INJECTED\nFrom: X-INJECTED-REMAIL-FROM"; //<--- Injected as first hdr ++$envelope["something"] = "bar@example.com\nFrom: X-INJECTED"; ++ ++$part1["type"] = TYPEMULTIPART; ++$part1["subtype"] = "mixed"; ++ ++$part2["type"] = TYPEAPPLICATION; ++$part2["encoding"] = ENCBINARY; ++$part2["subtype"] = "octet-stream\nContent-Type: X-INJECTED"; ++$part2["description"] = "some file\nContent-Type: X-INJECTED"; ++$part2["contents.data"] = "ABC\nContent-Type: X-INJECTED"; ++ ++$part3["type"] = TYPETEXT; ++$part3["subtype"] = "plain"; ++$part3["description"] = "description3"; ++$part3["contents.data"] = "contents.data3\n\n\n\t"; ++ ++$body[1] = $part1; ++$body[2] = $part2; ++$body[3] = $part3; ++ ++echo imap_mail_compose($envelope, $body); ++?> ++--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" <cmbecker69@gmx.de> +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 + |