Make syslog() binary safe

Closes GH-7245

Co-authored-by: Nikita Popov <nikita.ppv@googlemail.com>
This commit is contained in:
George Peter Banyard 2021-07-15 19:08:26 +02:00
parent fae7cec6fb
commit 0ba155cd57
6 changed files with 87 additions and 45 deletions

View file

@ -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
========================================

View file

@ -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;
}
/* }}} */

View file

@ -0,0 +1,19 @@
--TEST--
Test syslog() function : new line in message
--SKIPIF--
<?php
if(substr(PHP_OS, 0, 3) == "WIN")
die("skip Won't run on Windows");
?>
--FILE--
<?php
$priority = LOG_WARNING;
$message = "First line\nSecond line";
openlog('PHPT', LOG_PERROR, LOG_USER);
syslog($priority, $message);
?>
--EXPECTF--
%SPHPT%S%r(:|-)%r First line
%SPHPT%S%r(:|-)%r Second line

View file

@ -0,0 +1,18 @@
--TEST--
Test syslog() function : nul byte in message
--SKIPIF--
<?php
if(substr(PHP_OS, 0, 3) == "WIN")
die("skip Won't run on Windows");
?>
--FILE--
<?php
$priority = LOG_WARNING;
$message = "A simple \0 message";
openlog('PHPT', LOG_PERROR, LOG_USER);
syslog($priority, $message);
?>
--EXPECTF--
%SPHPT%S%r(:|-)%r A simple \x00 message

View file

@ -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

View file

@ -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()