-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Add blacklisted command line flags for sendline via mail() #12783
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
1d26b7a
b4a57b9
440b2ca
fae7507
ec0cd1c
7d7eff5
ef0b0ef
10b4625
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -199,6 +199,28 @@ PHPAPI zend_string *php_mail_build_headers(HashTable *headers) | |
return s.s; | ||
} | ||
|
||
/* {{{ php_mail_disable_flags | ||
Remove all dangerous command line flags | ||
from the sendmail shell command | ||
*/ | ||
PHPAPI zend_string *php_mail_disable_flags(const char *str) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also, why is this exposed as a PHPAPI? can't it be |
||
{ | ||
const char* blacklist[4] = {"-O", "-C", "-X", "-be"}; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it might be better to make this configurable as a list of potentially insecure flags changeable using INI. You could keep those as default. |
||
size_t str_length = strlen(str); | ||
char *return_str = emalloc(str_length + 1); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this allocation really needed? You can just allocate the zend_string directly, and iterate on the underlying char pointer. |
||
strcpy(return_str, str); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use memcpy. |
||
for (int i = 0; i < 4; ++i) { | ||
size_t blacklist_length = strlen(blacklist[i]); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm really not a fan of this, those strings are constant and computing the lengths at runtime really feels off |
||
char* position = return_str; | ||
while ((position = strstr(position, blacklist[i])) != NULL) { | ||
memset(position, ' ', blacklist_length); | ||
position += blacklist_length; | ||
} | ||
} | ||
zend_string *cmd = zend_string_init(return_str, str_length, 0); | ||
efree(return_str); | ||
return cmd; | ||
} | ||
|
||
/* {{{ Send an email message */ | ||
PHP_FUNCTION(mail) | ||
|
@@ -278,6 +300,9 @@ PHP_FUNCTION(mail) | |
if (force_extra_parameters) { | ||
extra_cmd = php_escape_shell_cmd(force_extra_parameters); | ||
} else if (extra_cmd) { | ||
if (!PG(allow_additional_sendmail_flags)) { | ||
extra_cmd = php_mail_disable_flags(ZSTR_VAL(extra_cmd)); | ||
} | ||
extra_cmd = php_escape_shell_cmd(ZSTR_VAL(extra_cmd)); | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
--TEST-- | ||
Enable additional command line flags from being passed to sendmail through mail() | ||
--INI-- | ||
sendmail_path=tee mail_blacklist.eml >/dev/null | ||
mail.allow_additional_sendmail_flags = On | ||
--FILE-- | ||
<?php | ||
var_dump(mail('user@example.com', 'Test Subject', 'A Message', 'KHeaders', '-X new')); | ||
?> | ||
--EXPECT-- | ||
tee: invalid option -- 'X' | ||
Try 'tee --help' for more information. | ||
bool(false) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
--TEST-- | ||
Disable additional command line flags from being passed to sendmail through mail() | ||
--INI-- | ||
sendmail_path=tee mail_blacklist.eml >/dev/null | ||
mail.allow_additional_sendmail_flags = Off | ||
--FILE-- | ||
<?php | ||
var_dump(mail('user@example.com', 'Test Subject', 'A Message', 'KHeaders', '-X new')); | ||
?> | ||
--EXPECT-- | ||
bool(true) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -749,6 +749,7 @@ PHP_INI_BEGIN() | |
PHP_INI_ENTRY("smtp_port", "25", PHP_INI_ALL, NULL) | ||
STD_PHP_INI_BOOLEAN("mail.add_x_header", "0", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateBool, mail_x_header, php_core_globals, core_globals) | ||
STD_PHP_INI_BOOLEAN("mail.mixed_lf_and_crlf", "0", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateBool, mail_mixed_lf_and_crlf, php_core_globals, core_globals) | ||
STD_PHP_INI_BOOLEAN("mail.allow_additional_sendmail_flags", "0", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateBool, allow_additional_sendmail_flags, php_core_globals, core_globals) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it would be better to have a mode for this which would either allow, deny or ignore the list of insecure flags. The default should be deny so users get warning if such flag is present. That's better than just silently ignore things IMHO. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We could potentially consider warn mode that would would ignore it but also produce warning so users can catch those changes. That could be potentially default. |
||
STD_PHP_INI_ENTRY("mail.log", NULL, PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateMailLog, mail_log, php_core_globals, core_globals) | ||
PHP_INI_ENTRY("browscap", NULL, PHP_INI_SYSTEM, OnChangeBrowscap) | ||
PHP_INI_ENTRY("memory_limit", "128M", PHP_INI_ALL, OnChangeMemoryLimit) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please pass in the str_length as an argument, we know the size and this prevents a useless computation.
Also, this will just truncate the command if it contains a null byte.