diff --git a/UPGRADING b/UPGRADING index b9cc1e2b80a..35e388b939f 100644 --- a/UPGRADING +++ b/UPGRADING @@ -471,6 +471,9 @@ PHP 8.1 UPGRADE NOTES accessible through reflection. RFC: https://wiki.php.net/rfc/make-reflection-setaccessible-no-op +- Standard: + . syslog() is now binary safe. + ======================================== 6. New Functions ======================================== diff --git a/ext/standard/syslog.c b/ext/standard/syslog.c index ab7be9d5b96..d2cfcab9ded 100644 --- a/ext/standard/syslog.c +++ b/ext/standard/syslog.c @@ -174,15 +174,14 @@ PHP_FUNCTION(closelog) PHP_FUNCTION(syslog) { zend_long priority; - char *message; - size_t message_len; + zend_string *message; ZEND_PARSE_PARAMETERS_START(2, 2) Z_PARAM_LONG(priority) - Z_PARAM_STRING(message, message_len) + Z_PARAM_STR(message) ZEND_PARSE_PARAMETERS_END(); - php_syslog(priority, "%s", message); + php_syslog_str(priority, message); RETURN_TRUE; } /* }}} */ diff --git a/ext/standard/tests/network/syslog_new_line.phpt b/ext/standard/tests/network/syslog_new_line.phpt new file mode 100644 index 00000000000..69eb9c1d67e --- /dev/null +++ b/ext/standard/tests/network/syslog_new_line.phpt @@ -0,0 +1,19 @@ +--TEST-- +Test syslog() function : new line in message +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +%SPHPT%S%r(:|-)%r First line +%SPHPT%S%r(:|-)%r Second line diff --git a/ext/standard/tests/network/syslog_null_byte.phpt b/ext/standard/tests/network/syslog_null_byte.phpt new file mode 100644 index 00000000000..e7cb1fb7a4b --- /dev/null +++ b/ext/standard/tests/network/syslog_null_byte.phpt @@ -0,0 +1,18 @@ +--TEST-- +Test syslog() function : nul byte in message +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +%SPHPT%S%r(:|-)%r A simple \x00 message diff --git a/main/php_syslog.c b/main/php_syslog.c index e51a6a8a04f..54d871c6aca 100644 --- a/main/php_syslog.c +++ b/main/php_syslog.c @@ -32,6 +32,45 @@ #define syslog std_syslog #endif +PHPAPI void php_syslog_str(int priority, const zend_string* message) +{ + smart_string sbuf = {0}; + + if (PG(syslog_filter) == PHP_SYSLOG_FILTER_RAW) { + /* Just send it directly to the syslog */ + syslog(priority, "%s", ZSTR_VAL(message)); + return; + } + + /* We use < because we don't want the final NUL byte to be converted to '\x00' */ + for (size_t i = 0; i < ZSTR_LEN(message); ++i) { + unsigned char c = ZSTR_VAL(message)[i]; + + /* check for NVT ASCII only unless test disabled */ + if (((0x20 <= c) && (c <= 0x7e))) { + smart_string_appendc(&sbuf, c); + } else if ((c >= 0x80) && (PG(syslog_filter) != PHP_SYSLOG_FILTER_ASCII)) { + smart_string_appendc(&sbuf, c); + } else if (c == '\n') { + /* Smart string is not NUL terminated */ + syslog(priority, "%.*s", (int)sbuf.len, sbuf.c); + smart_string_reset(&sbuf); + } else if ((c < 0x20) && (PG(syslog_filter) == PHP_SYSLOG_FILTER_ALL)) { + smart_string_appendc(&sbuf, c); + } else { + const char xdigits[] = "0123456789abcdef"; + + smart_string_appendl(&sbuf, "\\x", 2); + smart_string_appendc(&sbuf, xdigits[c >> 4]); + smart_string_appendc(&sbuf, xdigits[c & 0xf]); + } + } + + /* Smart string is not NUL terminated */ + syslog(priority, "%.*s", (int)sbuf.len, sbuf.c); + smart_string_free(&sbuf); +} + #ifdef PHP_WIN32 PHPAPI void php_syslog(int priority, const char *format, ...) /* {{{ */ { @@ -54,10 +93,7 @@ PHPAPI void php_syslog(int priority, const char *format, ...) /* {{{ */ #else PHPAPI void php_syslog(int priority, const char *format, ...) /* {{{ */ { - const char *ptr; - unsigned char c; - smart_string fbuf = {0}; - smart_string sbuf = {0}; + zend_string *fbuf = NULL; va_list args; /* @@ -70,46 +106,12 @@ PHPAPI void php_syslog(int priority, const char *format, ...) /* {{{ */ } va_start(args, format); - zend_printf_to_smart_string(&fbuf, format, args); - smart_string_0(&fbuf); + fbuf = zend_vstrpprintf(0, format, args); va_end(args); - if (PG(syslog_filter) == PHP_SYSLOG_FILTER_RAW) { - /* Just send it directly to the syslog */ - syslog(priority, "%.*s", (int)fbuf.len, fbuf.c); - smart_string_free(&fbuf); - return; - } + php_syslog_str(priority, fbuf); - for (ptr = fbuf.c; ; ++ptr) { - c = *ptr; - if (c == '\0') { - syslog(priority, "%.*s", (int)sbuf.len, sbuf.c); - break; - } - - /* check for NVT ASCII only unless test disabled */ - if (((0x20 <= c) && (c <= 0x7e))) - smart_string_appendc(&sbuf, c); - else if ((c >= 0x80) && (PG(syslog_filter) != PHP_SYSLOG_FILTER_ASCII)) - smart_string_appendc(&sbuf, c); - else if (c == '\n') { - syslog(priority, "%.*s", (int)sbuf.len, sbuf.c); - smart_string_reset(&sbuf); - } else if ((c < 0x20) && (PG(syslog_filter) == PHP_SYSLOG_FILTER_ALL)) - smart_string_appendc(&sbuf, c); - else { - const char xdigits[] = "0123456789abcdef"; - - smart_string_appendl(&sbuf, "\\x", 2); - smart_string_appendc(&sbuf, xdigits[(c / 0x10)]); - c &= 0x0f; - smart_string_appendc(&sbuf, xdigits[c]); - } - } - - smart_string_free(&fbuf); - smart_string_free(&sbuf); + zend_string_release(fbuf); } /* }}} */ #endif diff --git a/main/php_syslog.h b/main/php_syslog.h index ded7299d8f0..2005a03ef9e 100644 --- a/main/php_syslog.h +++ b/main/php_syslog.h @@ -35,6 +35,7 @@ #define PHP_SYSLOG_FILTER_RAW 3 BEGIN_EXTERN_C() +PHPAPI void php_syslog_str(int priority, const zend_string* message); PHPAPI void php_syslog(int, const char *format, ...); PHPAPI void php_openlog(const char *, int, int); END_EXTERN_C()