Skip to content
Prev Previous commit
Next Next commit
Added blacklist functionality mail.c
  • Loading branch information
TCGeek authored Nov 25, 2023
commit 440b2ca80a514026063a2def2cc7bd09609cf949
25 changes: 25 additions & 0 deletions ext/standard/mail.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Copy link
Member

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.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, why is this exposed as a PHPAPI? can't it be static

{
const char* blacklist[4] = {"-O", "-C", "-X", "-be"};
Copy link
Member

Choose a reason for hiding this comment

The 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);
Copy link
Member

Choose a reason for hiding this comment

The 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);
Copy link
Member

Choose a reason for hiding this comment

The 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]);
Copy link
Member

Choose a reason for hiding this comment

The 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)
Expand Down Expand Up @@ -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));
}

Expand Down