Merge pull request #9346 from keszybz/journald-exact2

Store a copy of the input message if any stripping or truncation occurs
This commit is contained in:
Lennart Poettering 2018-07-18 21:00:43 +02:00 committed by GitHub
commit 8d568e8d3e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 101 additions and 42 deletions

View file

@ -103,16 +103,34 @@
<term><varname>SYSLOG_FACILITY=</varname></term> <term><varname>SYSLOG_FACILITY=</varname></term>
<term><varname>SYSLOG_IDENTIFIER=</varname></term> <term><varname>SYSLOG_IDENTIFIER=</varname></term>
<term><varname>SYSLOG_PID=</varname></term> <term><varname>SYSLOG_PID=</varname></term>
<term><varname>SYSLOG_TIMESTAMP=</varname></term>
<listitem> <listitem>
<para>Syslog compatibility fields containing the facility <para>Syslog compatibility fields containing the facility (formatted as
(formatted as decimal string), the identifier string (i.e. decimal string), the identifier string (i.e. "tag"), the client PID, and
"tag"), and the client PID. (Note that the tag is usually the timestamp as specified in the original datagram. (Note that the tag is
derived from glibc's usually derived from glibc's
<varname>program_invocation_short_name</varname> variable, <varname>program_invocation_short_name</varname> variable, see
see
<citerefentry project='die-net'><refentrytitle>program_invocation_short_name</refentrytitle><manvolnum>3</manvolnum></citerefentry>.)</para> <citerefentry project='die-net'><refentrytitle>program_invocation_short_name</refentrytitle><manvolnum>3</manvolnum></citerefentry>.)</para>
</listitem> </listitem>
</varlistentry>
<varlistentry>
<term><varname>SYSLOG_RAW=</varname></term>
<listitem>
<para>The original contents of the syslog line as received in the syslog
datagram. This field is only included if the <varname>MESSAGE=</varname>
field was modified compared to the original payload or the timestamp could
not be located properly and is not included in
<varname>SYSLOG_TIMESTAMP=</varname>. Message truncation occurs when when
the message contains leading or trailing whitespace (trailing and leading
whitespace is stripped), or it contains an embedded
<constant>NUL</constant> byte (the <constant>NUL</constant> byte and
anything after it is not included). Thus, the original syslog line is
either stored as <varname>SYSLOG_RAW=</varname> or it can be recreated
based on the stored priority and facility, timestamp, identifier, and the
message payload in <varname>MESSAGE=</varname>.
</para>
</listitem>
</varlistentry> </varlistentry>
</variablelist> </variablelist>
</refsect1> </refsect1>

View file

@ -224,7 +224,7 @@ size_t syslog_parse_identifier(const char **buf, char **identifier, char **pid)
return e; return e;
} }
static void syslog_skip_date(char **buf) { static int syslog_skip_timestamp(const char **buf) {
enum { enum {
LETTER, LETTER,
SPACE, SPACE,
@ -244,24 +244,21 @@ static void syslog_skip_date(char **buf) {
SPACE SPACE
}; };
char *p; const char *p, *t;
unsigned i; unsigned i;
assert(buf); assert(buf);
assert(*buf); assert(*buf);
p = *buf; for (i = 0, p = *buf; i < ELEMENTSOF(sequence); i++, p++) {
for (i = 0; i < ELEMENTSOF(sequence); i++, p++) {
if (!*p) if (!*p)
return; return 0;
switch (sequence[i]) { switch (sequence[i]) {
case SPACE: case SPACE:
if (*p != ' ') if (*p != ' ')
return; return 0;
break; break;
case SPACE_OR_NUMBER: case SPACE_OR_NUMBER:
@ -271,48 +268,56 @@ static void syslog_skip_date(char **buf) {
_fallthrough_; _fallthrough_;
case NUMBER: case NUMBER:
if (*p < '0' || *p > '9') if (*p < '0' || *p > '9')
return; return 0;
break; break;
case LETTER: case LETTER:
if (!(*p >= 'A' && *p <= 'Z') && if (!(*p >= 'A' && *p <= 'Z') &&
!(*p >= 'a' && *p <= 'z')) !(*p >= 'a' && *p <= 'z'))
return; return 0;
break; break;
case COLON: case COLON:
if (*p != ':') if (*p != ':')
return; return 0;
break; break;
} }
} }
t = *buf;
*buf = p; *buf = p;
return p - t;
} }
void server_process_syslog_message( void server_process_syslog_message(
Server *s, Server *s,
const char *buf, const char *buf,
size_t buf_len, size_t raw_len,
const struct ucred *ucred, const struct ucred *ucred,
const struct timeval *tv, const struct timeval *tv,
const char *label, const char *label,
size_t label_len) { size_t label_len) {
char syslog_priority[sizeof("PRIORITY=") + DECIMAL_STR_MAX(int)], char *t, syslog_priority[sizeof("PRIORITY=") + DECIMAL_STR_MAX(int)],
syslog_facility[sizeof("SYSLOG_FACILITY=") + DECIMAL_STR_MAX(int)], *msg; syslog_facility[sizeof("SYSLOG_FACILITY=") + DECIMAL_STR_MAX(int)];
const char *message = NULL, *syslog_identifier = NULL, *syslog_pid = NULL; const char *msg, *syslog_ts, *a;
_cleanup_free_ char *identifier = NULL, *pid = NULL; _cleanup_free_ char *identifier = NULL, *pid = NULL;
int priority = LOG_USER | LOG_INFO, r; int priority = LOG_USER | LOG_INFO, r;
ClientContext *context = NULL; ClientContext *context = NULL;
struct iovec *iovec; struct iovec *iovec;
size_t n = 0, m, i; size_t n = 0, m, i, leading_ws, syslog_ts_len;
bool store_raw;
assert(s); assert(s);
assert(buf); assert(buf);
/* The message cannot be empty. */
assert(raw_len > 0);
/* The buffer NUL-terminated and can be used a string. raw_len is the length
* without the terminating NUL byte, the buffer is actually one bigger. */
assert(buf[raw_len] == '\0');
if (ucred && pid_is_valid(ucred->pid)) { if (ucred && pid_is_valid(ucred->pid)) {
r = client_context_get(s, ucred->pid, ucred, label, label_len, NULL, &context); r = client_context_get(s, ucred->pid, ucred, label, label_len, NULL, &context);
@ -320,26 +325,42 @@ void server_process_syslog_message(
log_warning_errno(r, "Failed to retrieve credentials for PID " PID_FMT ", ignoring: %m", ucred->pid); log_warning_errno(r, "Failed to retrieve credentials for PID " PID_FMT ", ignoring: %m", ucred->pid);
} }
/* We are creating copy of the message because we want to forward original message verbatim to the legacy /* We are creating a copy of the message because we want to forward the original message
syslog implementation */ verbatim to the legacy syslog implementation */
for (i = buf_len; i > 0; i--) for (i = raw_len; i > 0; i--)
if (!strchr(WHITESPACE, buf[i-1])) if (!strchr(WHITESPACE, buf[i-1]))
break; break;
msg = newa(char, i + 1); leading_ws = strspn(buf, WHITESPACE);
*((char *) mempcpy(msg, buf, i)) = 0;
msg = skip_leading_chars(msg, WHITESPACE);
syslog_parse_priority((const char **)&msg, &priority, true); if (i == raw_len)
/* Nice! No need to strip anything on the end, let's optimize this a bit */
msg = buf + leading_ws;
else {
msg = t = newa(char, i - leading_ws + 1);
memcpy(t, buf + leading_ws, i - leading_ws);
t[i - leading_ws] = 0;
}
/* We will add the SYSLOG_RAW= field when we stripped anything
* _or_ if the input message contained NUL bytes. */
store_raw = msg != buf || strlen(msg) != raw_len;
syslog_parse_priority(&msg, &priority, true);
if (!client_context_test_priority(context, priority)) if (!client_context_test_priority(context, priority))
return; return;
if (s->forward_to_syslog) syslog_ts = msg;
forward_syslog_raw(s, priority, buf, buf_len, ucred, tv); syslog_ts_len = syslog_skip_timestamp(&msg);
if (syslog_ts_len == 0)
/* We failed to parse the full timestamp, store the raw message too */
store_raw = true;
syslog_skip_date(&msg); syslog_parse_identifier(&msg, &identifier, &pid);
syslog_parse_identifier((const char**)&msg, &identifier, &pid);
if (s->forward_to_syslog)
forward_syslog_raw(s, priority, buf, raw_len, ucred, tv);
if (s->forward_to_kmsg) if (s->forward_to_kmsg)
server_forward_kmsg(s, priority, identifier, msg, ucred); server_forward_kmsg(s, priority, identifier, msg, ucred);
@ -350,7 +371,7 @@ void server_process_syslog_message(
if (s->forward_to_wall) if (s->forward_to_wall)
server_forward_wall(s, priority, identifier, msg, ucred); server_forward_wall(s, priority, identifier, msg, ucred);
m = N_IOVEC_META_FIELDS + 6 + client_context_extra_fields_n_iovec(context); m = N_IOVEC_META_FIELDS + 8 + client_context_extra_fields_n_iovec(context);
iovec = newa(struct iovec, m); iovec = newa(struct iovec, m);
iovec[n++] = IOVEC_MAKE_STRING("_TRANSPORT=syslog"); iovec[n++] = IOVEC_MAKE_STRING("_TRANSPORT=syslog");
@ -364,18 +385,37 @@ void server_process_syslog_message(
} }
if (identifier) { if (identifier) {
syslog_identifier = strjoina("SYSLOG_IDENTIFIER=", identifier); a = strjoina("SYSLOG_IDENTIFIER=", identifier);
iovec[n++] = IOVEC_MAKE_STRING(syslog_identifier); iovec[n++] = IOVEC_MAKE_STRING(a);
} }
if (pid) { if (pid) {
syslog_pid = strjoina("SYSLOG_PID=", pid); a = strjoina("SYSLOG_PID=", pid);
iovec[n++] = IOVEC_MAKE_STRING(syslog_pid); iovec[n++] = IOVEC_MAKE_STRING(a);
} }
message = strjoina("MESSAGE=", msg); if (syslog_ts_len > 0) {
if (message) const size_t hlen = strlen("SYSLOG_TIMESTAMP=");
iovec[n++] = IOVEC_MAKE_STRING(message);
t = newa(char, hlen + raw_len);
memcpy(t, "SYSLOG_TIMESTAMP=", hlen);
memcpy(t + hlen, syslog_ts, syslog_ts_len);
iovec[n++] = IOVEC_MAKE(t, hlen + syslog_ts_len);
}
a = strjoina("MESSAGE=", msg);
iovec[n++] = IOVEC_MAKE_STRING(a);
if (store_raw) {
const size_t hlen = strlen("SYSLOG_RAW=");
t = newa(char, hlen + raw_len);
memcpy(t, "SYSLOG_RAW=", hlen);
memcpy(t + hlen, buf, raw_len);
iovec[n++] = IOVEC_MAKE(t, hlen + raw_len);
}
server_dispatch_message(s, iovec, n, m, context, tv, priority, 0); server_dispatch_message(s, iovec, n, m, context, tv, priority, 0);
} }

View file

@ -7838,7 +7838,8 @@ static int parse_shutdown_time_spec(const char *t, usec_t *_u) {
tm.tm_min = (int) minute; tm.tm_min = (int) minute;
tm.tm_sec = 0; tm.tm_sec = 0;
assert_se(s = mktime(&tm)); s = mktime(&tm);
assert(s >= 0);
*_u = (usec_t) s * USEC_PER_SEC; *_u = (usec_t) s * USEC_PER_SEC;