From 73b5c300b8fde5e7a4824baa83a04931279abb37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A1szl=C3=B3=20V=C3=A1rady?= Date: Sat, 20 Aug 2022 12:42:38 +0200 Subject: [PATCH] CVE-2022-38725 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: László Várady Signed-off-by: Balazs Scheidler Upstream-Status: Backport from [https://github.com/syslog-ng/syslog-ng/commit/b5a060f2ebb8d794f508436a12e4d4163f94b1b8 && https://github.com/syslog-ng/syslog-ng/commit/81a07263f1e522a376d3a30f96f51df3f2879f8a && https://github.com/syslog-ng/syslog-ng/commit/4b8dc56ca8eaeac4c8751a305eb7eeefab8dc89d && https://github.com/syslog-ng/syslog-ng/commit/73b5c300b8fde5e7a4824baa83a04931279abb37 && https://github.com/syslog-ng/syslog-ng/commit/45f051239312e43bd4f92b9339fe67c6798a0321 && https://github.com/syslog-ng/syslog-ng/commit/09f489c89c826293ff8cbd282cfc866ab56054c4 && https://github.com/syslog-ng/syslog-ng/commit/8c6e2c1c41b0fcc5fbd464c35f4dac7102235396 && https://github.com/syslog-ng/syslog-ng/commit/56f881c5eaa3d8c02c96607c4b9e4eaf959a044d] CVE: CVE-2022-38725 Signed-off-by: Hitendra Prajapati --- lib/timeutils/scan-timestamp.c | 68 +++++---- lib/timeutils/tests/test_scan-timestamp.c | 133 ++++++++++++++++-- modules/syslogformat/CMakeLists.txt | 2 + modules/syslogformat/Makefile.am | 2 + modules/syslogformat/syslog-format.c | 12 +- modules/syslogformat/tests/CMakeLists.txt | 1 + modules/syslogformat/tests/Makefile.am | 9 ++ .../syslogformat/tests/test_syslog_format.c | 104 ++++++++++++++ 8 files changed, 284 insertions(+), 47 deletions(-) create mode 100644 modules/syslogformat/tests/CMakeLists.txt create mode 100644 modules/syslogformat/tests/Makefile.am create mode 100644 modules/syslogformat/tests/test_syslog_format.c diff --git a/lib/timeutils/scan-timestamp.c b/lib/timeutils/scan-timestamp.c index 41ead1a..ec9746b 100644 --- a/lib/timeutils/scan-timestamp.c +++ b/lib/timeutils/scan-timestamp.c @@ -34,41 +34,43 @@ scan_day_abbrev(const gchar **buf, gint *left, gint *wday) { *wday = -1; - if (*left < 3) + const gsize abbrev_length = 3; + + if (*left < abbrev_length) return FALSE; switch (**buf) { case 'S': - if (strncasecmp(*buf, "Sun", 3) == 0) + if (strncasecmp(*buf, "Sun", abbrev_length) == 0) *wday = 0; - else if (strncasecmp(*buf, "Sat", 3) == 0) + else if (strncasecmp(*buf, "Sat", abbrev_length) == 0) *wday = 6; break; case 'M': - if (strncasecmp(*buf, "Mon", 3) == 0) + if (strncasecmp(*buf, "Mon", abbrev_length) == 0) *wday = 1; break; case 'T': - if (strncasecmp(*buf, "Tue", 3) == 0) + if (strncasecmp(*buf, "Tue", abbrev_length) == 0) *wday = 2; - else if (strncasecmp(*buf, "Thu", 3) == 0) + else if (strncasecmp(*buf, "Thu", abbrev_length) == 0) *wday = 4; break; case 'W': - if (strncasecmp(*buf, "Wed", 3) == 0) + if (strncasecmp(*buf, "Wed", abbrev_length) == 0) *wday = 3; break; case 'F': - if (strncasecmp(*buf, "Fri", 3) == 0) + if (strncasecmp(*buf, "Fri", abbrev_length) == 0) *wday = 5; break; default: return FALSE; } - (*buf) += 3; - (*left) -= 3; + (*buf) += abbrev_length; + (*left) -= abbrev_length; return TRUE; } @@ -77,57 +79,59 @@ scan_month_abbrev(const gchar **buf, gint *left, gint *mon) { *mon = -1; - if (*left < 3) + const gsize abbrev_length = 3; + + if (*left < abbrev_length) return FALSE; switch (**buf) { case 'J': - if (strncasecmp(*buf, "Jan", 3) == 0) + if (strncasecmp(*buf, "Jan", abbrev_length) == 0) *mon = 0; - else if (strncasecmp(*buf, "Jun", 3) == 0) + else if (strncasecmp(*buf, "Jun", abbrev_length) == 0) *mon = 5; - else if (strncasecmp(*buf, "Jul", 3) == 0) + else if (strncasecmp(*buf, "Jul", abbrev_length) == 0) *mon = 6; break; case 'F': - if (strncasecmp(*buf, "Feb", 3) == 0) + if (strncasecmp(*buf, "Feb", abbrev_length) == 0) *mon = 1; break; case 'M': - if (strncasecmp(*buf, "Mar", 3) == 0) + if (strncasecmp(*buf, "Mar", abbrev_length) == 0) *mon = 2; - else if (strncasecmp(*buf, "May", 3) == 0) + else if (strncasecmp(*buf, "May", abbrev_length) == 0) *mon = 4; break; case 'A': - if (strncasecmp(*buf, "Apr", 3) == 0) + if (strncasecmp(*buf, "Apr", abbrev_length) == 0) *mon = 3; - else if (strncasecmp(*buf, "Aug", 3) == 0) + else if (strncasecmp(*buf, "Aug", abbrev_length) == 0) *mon = 7; break; case 'S': - if (strncasecmp(*buf, "Sep", 3) == 0) + if (strncasecmp(*buf, "Sep", abbrev_length) == 0) *mon = 8; break; case 'O': - if (strncasecmp(*buf, "Oct", 3) == 0) + if (strncasecmp(*buf, "Oct", abbrev_length) == 0) *mon = 9; break; case 'N': - if (strncasecmp(*buf, "Nov", 3) == 0) + if (strncasecmp(*buf, "Nov", abbrev_length) == 0) *mon = 10; break; case 'D': - if (strncasecmp(*buf, "Dec", 3) == 0) + if (strncasecmp(*buf, "Dec", abbrev_length) == 0) *mon = 11; break; default: return FALSE; } - (*buf) += 3; - (*left) -= 3; + (*buf) += abbrev_length; + (*left) -= abbrev_length; return TRUE; } @@ -302,7 +306,7 @@ __parse_usec(const guchar **data, gint *length) src++; (*length)--; } - while (isdigit(*src)) + while (*length > 0 && isdigit(*src)) { src++; (*length)--; @@ -316,19 +320,21 @@ __parse_usec(const guchar **data, gint *length) static gboolean __has_iso_timezone(const guchar *src, gint length) { - return (length >= 5) && + return (length >= 6) && (*src == '+' || *src == '-') && isdigit(*(src+1)) && isdigit(*(src+2)) && *(src+3) == ':' && isdigit(*(src+4)) && isdigit(*(src+5)) && - !isdigit(*(src+6)); + (length < 7 || !isdigit(*(src+6))); } static guint32 __parse_iso_timezone(const guchar **data, gint *length) { + g_assert(*length >= 6); + gint hours, mins; const guchar *src = *data; guint32 tz = 0; @@ -338,8 +344,10 @@ __parse_iso_timezone(const guchar **data, gint *length) hours = (*(src + 1) - '0') * 10 + *(src + 2) - '0'; mins = (*(src + 4) - '0') * 10 + *(src + 5) - '0'; tz = sign * (hours * 3600 + mins * 60); + src += 6; (*length) -= 6; + *data = src; return tz; } @@ -393,7 +401,7 @@ __parse_bsd_timestamp(const guchar **data, gint *length, WallClockTime *wct) if (!scan_pix_timestamp((const gchar **) &src, &left, wct)) return FALSE; - if (*src == ':') + if (left && *src == ':') { src++; left--; @@ -444,7 +452,7 @@ scan_rfc3164_timestamp(const guchar **data, gint *length, WallClockTime *wct) * looking at you, skip that as well, so we can reliably detect IPv6 * addresses as hostnames, which would be using ":" as well. */ - if (*src == ':') + if (left && *src == ':') { ++src; --left; diff --git a/lib/timeutils/tests/test_scan-timestamp.c b/lib/timeutils/tests/test_scan-timestamp.c index 4508139..ad657c6 100644 --- a/lib/timeutils/tests/test_scan-timestamp.c +++ b/lib/timeutils/tests/test_scan-timestamp.c @@ -49,17 +49,21 @@ fake_time_add(time_t diff) } static gboolean -_parse_rfc3164(const gchar *ts, gchar isotimestamp[32]) +_parse_rfc3164(const gchar *ts, gint len, gchar isotimestamp[32]) { UnixTime stamp; - const guchar *data = (const guchar *) ts; - gint length = strlen(ts); + const guchar *tsu = (const guchar *) ts; + gint tsu_len = len < 0 ? strlen(ts) : len; GString *result = g_string_new(""); WallClockTime wct = WALL_CLOCK_TIME_INIT; - + const guchar *data = tsu; + gint length = tsu_len; gboolean success = scan_rfc3164_timestamp(&data, &length, &wct); + cr_assert(length >= 0); + cr_assert(data == &tsu[tsu_len - length]); + unix_time_unset(&stamp); convert_wall_clock_time_to_unix_time(&wct, &stamp); @@ -70,16 +74,21 @@ _parse_rfc3164(const gchar *ts, gchar isotimestamp[32]) } static gboolean -_parse_rfc5424(const gchar *ts, gchar isotimestamp[32]) +_parse_rfc5424(const gchar *ts, gint len, gchar isotimestamp[32]) { UnixTime stamp; - const guchar *data = (const guchar *) ts; - gint length = strlen(ts); + const guchar *tsu = (const guchar *) ts; + gint tsu_len = len < 0 ? strlen(ts) : len; GString *result = g_string_new(""); WallClockTime wct = WALL_CLOCK_TIME_INIT; + const guchar *data = tsu; + gint length = tsu_len; gboolean success = scan_rfc5424_timestamp(&data, &length, &wct); + cr_assert(length >= 0); + cr_assert(data == &tsu[tsu_len - length]); + unix_time_unset(&stamp); convert_wall_clock_time_to_unix_time(&wct, &stamp); @@ -90,31 +99,60 @@ _parse_rfc5424(const gchar *ts, gchar isotimestamp[32]) } static gboolean -_rfc3164_timestamp_eq(const gchar *ts, const gchar *expected, gchar converted[32]) +_rfc3164_timestamp_eq(const gchar *ts, gint len, const gchar *expected, gchar converted[32]) { - cr_assert(_parse_rfc3164(ts, converted)); + cr_assert(_parse_rfc3164(ts, len, converted)); return strcmp(converted, expected) == 0; } static gboolean -_rfc5424_timestamp_eq(const gchar *ts, const gchar *expected, gchar converted[32]) +_rfc5424_timestamp_eq(const gchar *ts, gint len, const gchar *expected, gchar converted[32]) { - cr_assert(_parse_rfc5424(ts, converted)); + cr_assert(_parse_rfc5424(ts, len, converted)); return strcmp(converted, expected) == 0; } #define _expect_rfc3164_timestamp_eq(ts, expected) \ ({ \ gchar converted[32]; \ - cr_expect(_rfc3164_timestamp_eq(ts, expected, converted), "Parsed RFC3164 timestamp does not equal expected, ts=%s, converted=%s, expected=%s", ts, converted, expected); \ + cr_expect(_rfc3164_timestamp_eq(ts, -1, expected, converted), "Parsed RFC3164 timestamp does not equal expected, ts=%s, converted=%s, expected=%s", ts, converted, expected); \ + }) + +#define _expect_rfc3164_timestamp_len_eq(ts, len, expected) \ + ({ \ + gchar converted[32]; \ + cr_expect(_rfc3164_timestamp_eq(ts, len, expected, converted), "Parsed RFC3164 timestamp does not equal expected, ts=%s, converted=%s, expected=%s", ts, converted, expected); \ + }) + +#define _expect_rfc3164_fails(ts, len) \ + ({ \ + WallClockTime wct = WALL_CLOCK_TIME_INIT; \ + const guchar *data = (guchar *) ts; \ + gint length = len < 0 ? strlen(ts) : len; \ + cr_assert_not(scan_rfc3164_timestamp(&data, &length, &wct)); \ }) #define _expect_rfc5424_timestamp_eq(ts, expected) \ ({ \ gchar converted[32]; \ - cr_expect(_rfc5424_timestamp_eq(ts, expected, converted), "Parsed RFC5424 timestamp does not equal expected, ts=%s, converted=%s, expected=%s", ts, converted, expected); \ + cr_expect(_rfc5424_timestamp_eq(ts, -1, expected, converted), "Parsed RFC5424 timestamp does not equal expected, ts=%s, converted=%s, expected=%s", ts, converted, expected); \ + }) + +#define _expect_rfc5424_timestamp_len_eq(ts, len, expected) \ + ({ \ + gchar converted[32]; \ + cr_expect(_rfc5424_timestamp_eq(ts, len, expected, converted), "Parsed RFC5424 timestamp does not equal expected, ts=%s, converted=%s, expected=%s", ts, converted, expected); \ }) +#define _expect_rfc5424_fails(ts, len) \ + ({ \ + WallClockTime wct = WALL_CLOCK_TIME_INIT; \ + const guchar *data = (guchar *) ts; \ + gint length = len < 0 ? strlen(ts) : len; \ + cr_assert_not(scan_rfc5424_timestamp(&data, &length, &wct)); \ + }) + + Test(parse_timestamp, standard_bsd_format) { _expect_rfc3164_timestamp_eq("Oct 1 17:46:12", "2017-10-01T17:46:12.000+02:00"); @@ -148,6 +186,75 @@ Test(parse_timestamp, standard_bsd_format_year_in_the_past) _expect_rfc3164_timestamp_eq("Dec 31 17:46:12", "2017-12-31T17:46:12.000+01:00"); } +Test(parse_timestamp, non_zero_terminated_rfc3164_iso_input_is_handled_properly) +{ + gchar *ts = "2022-08-17T05:02:28.417Z whatever"; + gint ts_len = 24; + + _expect_rfc3164_timestamp_len_eq(ts, strlen(ts), "2022-08-17T05:02:28.417+00:00"); + _expect_rfc3164_timestamp_len_eq(ts, ts_len + 5, "2022-08-17T05:02:28.417+00:00"); + _expect_rfc3164_timestamp_len_eq(ts, ts_len, "2022-08-17T05:02:28.417+00:00"); + + /* no "Z" parsed, timezone defaults to local, forced CET */ + _expect_rfc3164_timestamp_len_eq(ts, ts_len - 1, "2022-08-17T05:02:28.417+02:00"); + + /* msec is partially parsed as we trim the string from the right */ + _expect_rfc3164_timestamp_len_eq(ts, ts_len - 2, "2022-08-17T05:02:28.410+02:00"); + _expect_rfc3164_timestamp_len_eq(ts, ts_len - 3, "2022-08-17T05:02:28.400+02:00"); + _expect_rfc3164_timestamp_len_eq(ts, ts_len - 4, "2022-08-17T05:02:28.000+02:00"); + _expect_rfc3164_timestamp_len_eq(ts, ts_len - 5, "2022-08-17T05:02:28.000+02:00"); + + for (gint i = 6; i < ts_len; i++) + _expect_rfc3164_fails(ts, ts_len - i); + +} + +Test(parse_timestamp, non_zero_terminated_rfc3164_bsd_pix_or_asa_input_is_handled_properly) +{ + gchar *ts = "Aug 17 2022 05:02:28: whatever"; + gint ts_len = 21; + + _expect_rfc3164_timestamp_len_eq(ts, strlen(ts), "2022-08-17T05:02:28.000+02:00"); + _expect_rfc3164_timestamp_len_eq(ts, ts_len + 5, "2022-08-17T05:02:28.000+02:00"); + _expect_rfc3164_timestamp_len_eq(ts, ts_len, "2022-08-17T05:02:28.000+02:00"); + + /* no ":" at the end, that's a problem, unrecognized */ + _expect_rfc3164_fails(ts, ts_len - 1); + + for (gint i = 1; i < ts_len; i++) + _expect_rfc3164_fails(ts, ts_len - i); +} + +Test(parse_timestamp, non_zero_terminated_rfc5424_input_is_handled_properly) +{ + gchar *ts = "2022-08-17T05:02:28.417Z whatever"; + gint ts_len = 24; + + _expect_rfc5424_timestamp_len_eq(ts, strlen(ts), "2022-08-17T05:02:28.417+00:00"); + _expect_rfc5424_timestamp_len_eq(ts, ts_len + 5, "2022-08-17T05:02:28.417+00:00"); + _expect_rfc5424_timestamp_len_eq(ts, ts_len, "2022-08-17T05:02:28.417+00:00"); + + /* no "Z" parsed, timezone defaults to local, forced CET */ + _expect_rfc5424_timestamp_len_eq(ts, ts_len - 1, "2022-08-17T05:02:28.417+02:00"); + + /* msec is partially parsed as we trim the string from the right */ + _expect_rfc5424_timestamp_len_eq(ts, ts_len - 2, "2022-08-17T05:02:28.410+02:00"); + _expect_rfc5424_timestamp_len_eq(ts, ts_len - 3, "2022-08-17T05:02:28.400+02:00"); + _expect_rfc5424_timestamp_len_eq(ts, ts_len - 4, "2022-08-17T05:02:28.000+02:00"); + _expect_rfc5424_timestamp_len_eq(ts, ts_len - 5, "2022-08-17T05:02:28.000+02:00"); + + for (gint i = 6; i < ts_len; i++) + _expect_rfc5424_fails(ts, ts_len - i); + +} + +Test(parse_timestamp, non_zero_terminated_rfc5424_timestamp_only) +{ + const gchar *ts = "2022-08-17T05:02:28.417+03:00"; + gint ts_len = strlen(ts); + _expect_rfc5424_timestamp_len_eq(ts, ts_len, ts); +} + Test(parse_timestamp, daylight_saving_behavior_at_spring_with_explicit_timezones) { diff --git a/modules/syslogformat/CMakeLists.txt b/modules/syslogformat/CMakeLists.txt index fb55ea4..a2a92bb 100644 --- a/modules/syslogformat/CMakeLists.txt +++ b/modules/syslogformat/CMakeLists.txt @@ -24,4 +24,6 @@ target_include_directories(syslogformat ) target_link_libraries(syslogformat PRIVATE syslog-ng) +add_test_subdirectory(tests) + install(TARGETS syslogformat LIBRARY DESTINATION lib/syslog-ng/) diff --git a/modules/syslogformat/Makefile.am b/modules/syslogformat/Makefile.am index f13f88c..14cdf58 100644 --- a/modules/syslogformat/Makefile.am +++ b/modules/syslogformat/Makefile.am @@ -31,3 +31,5 @@ modules_syslogformat_libsyslogformat_la_DEPENDENCIES = \ modules/syslogformat modules/syslogformat/ mod-syslogformat: \ modules/syslogformat/libsyslogformat.la .PHONY: modules/syslogformat/ mod-syslogformat + +include modules/syslogformat/tests/Makefile.am diff --git a/modules/syslogformat/syslog-format.c b/modules/syslogformat/syslog-format.c index 6d53a32..a69f39f 100644 --- a/modules/syslogformat/syslog-format.c +++ b/modules/syslogformat/syslog-format.c @@ -200,7 +200,7 @@ log_msg_parse_cisco_sequence_id(LogMessage *self, const guchar **data, gint *len /* if the next char is not space, then we may try to read a date */ - if (*src != ' ') + if (!left || *src != ' ') return; log_msg_set_value(self, handles.cisco_seqid, (gchar *) *data, *length - left - 1); @@ -216,6 +216,9 @@ log_msg_parse_cisco_timestamp_attributes(LogMessage *self, const guchar **data, const guchar *src = *data; gint left = *length; + if (!left) + return; + /* Cisco timestamp extensions, the first '*' indicates that the clock is * unsynced, '.' if it is known to be synced */ if (G_UNLIKELY(src[0] == '*')) @@ -564,7 +567,7 @@ log_msg_parse_sd(LogMessage *self, const guchar **data, gint *length, const MsgF open_sd++; do { - if (!isascii(*src) || *src == '=' || *src == ' ' || *src == ']' || *src == '"') + if (!left || !isascii(*src) || *src == '=' || *src == ' ' || *src == ']' || *src == '"') goto error; /* read sd_id */ pos = 0; @@ -598,7 +601,8 @@ log_msg_parse_sd(LogMessage *self, const guchar **data, gint *length, const MsgF strcpy(sd_value_name, logmsg_sd_prefix); /* this strcat is safe, as sd_id_name is at most 32 chars */ strncpy(sd_value_name + logmsg_sd_prefix_len, sd_id_name, sizeof(sd_value_name) - logmsg_sd_prefix_len); - if (*src == ']') + + if (left && *src == ']') { log_msg_set_value_by_name(self, sd_value_name, "", 0); } @@ -615,7 +619,7 @@ log_msg_parse_sd(LogMessage *self, const guchar **data, gint *length, const MsgF else goto error; - if (!isascii(*src) || *src == '=' || *src == ' ' || *src == ']' || *src == '"') + if (!left || !isascii(*src) || *src == '=' || *src == ' ' || *src == ']' || *src == '"') goto error; /* read sd-param */ diff --git a/modules/syslogformat/tests/CMakeLists.txt b/modules/syslogformat/tests/CMakeLists.txt new file mode 100644 index 0000000..2e45b71 --- /dev/null +++ b/modules/syslogformat/tests/CMakeLists.txt @@ -0,0 +1 @@ +add_unit_test(CRITERION TARGET test_syslog_format DEPENDS syslogformat) diff --git a/modules/syslogformat/tests/Makefile.am b/modules/syslogformat/tests/Makefile.am new file mode 100644 index 0000000..7ee66a5 --- /dev/null +++ b/modules/syslogformat/tests/Makefile.am @@ -0,0 +1,9 @@ +modules_syslogformat_tests_TESTS = \ + modules/syslogformat/tests/test_syslog_format + +check_PROGRAMS += ${modules_syslogformat_tests_TESTS} + +EXTRA_DIST += modules/syslogformat/tests/CMakeLists.txt + +modules_syslogformat_tests_test_syslog_format_CFLAGS = $(TEST_CFLAGS) -I$(top_srcdir)/modules/syslogformat +modules_syslogformat_tests_test_syslog_format_LDADD = $(TEST_LDADD) $(PREOPEN_SYSLOGFORMAT) diff --git a/modules/syslogformat/tests/test_syslog_format.c b/modules/syslogformat/tests/test_syslog_format.c new file mode 100644 index 0000000..d0f5b40 --- /dev/null +++ b/modules/syslogformat/tests/test_syslog_format.c @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2022 One Identity + * Copyright (c) 2022 László Várady + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As an additional exemption you are allowed to compile & link against the + * OpenSSL libraries as published by the OpenSSL project. See the file + * COPYING for details. + * + */ + +#include + +#include "apphook.h" +#include "cfg.h" +#include "syslog-format.h" +#include "logmsg/logmsg.h" +#include "msg-format.h" +#include "scratch-buffers.h" + +#include + +GlobalConfig *cfg; +MsgFormatOptions parse_options; + +static void +setup(void) +{ + app_startup(); + syslog_format_init(); + + cfg = cfg_new_snippet(); + msg_format_options_defaults(&parse_options); +} + +static void +teardown(void) +{ + scratch_buffers_explicit_gc(); + app_shutdown(); + cfg_free(cfg); +} + +TestSuite(syslog_format, .init = setup, .fini = teardown); + +Test(syslog_format, parser_should_not_spin_on_non_zero_terminated_input, .timeout = 10) +{ + const gchar *data = "<182>2022-08-17T05:02:28.217 mymachine su: 'su root' failed for lonvick on /dev/pts/8"; + /* chosen carefully to reproduce a bug */ + gsize data_length = 27; + + msg_format_options_init(&parse_options, cfg); + LogMessage *msg = msg_format_construct_message(&parse_options, (const guchar *) data, data_length); + + gsize problem_position; + cr_assert(syslog_format_handler(&parse_options, msg, (const guchar *) data, data_length, &problem_position)); + + msg_format_options_destroy(&parse_options); + log_msg_unref(msg); +} + +Test(syslog_format, cisco_sequence_id_non_zero_termination) +{ + const gchar *data = "<189>65536: "; + gsize data_length = strlen(data); + + msg_format_options_init(&parse_options, cfg); + LogMessage *msg = msg_format_construct_message(&parse_options, (const guchar *) data, data_length); + + gsize problem_position; + cr_assert(syslog_format_handler(&parse_options, msg, (const guchar *) data, data_length, &problem_position)); + cr_assert_str_eq(log_msg_get_value_by_name(msg, ".SDATA.meta.sequenceId", NULL), "65536"); + + msg_format_options_destroy(&parse_options); + log_msg_unref(msg); +} + +Test(syslog_format, minimal_non_zero_terminated_numeric_message_is_parsed_as_program_name) +{ + const gchar *data = "<189>65536"; + gsize data_length = strlen(data); + + msg_format_options_init(&parse_options, cfg); + LogMessage *msg = msg_format_construct_message(&parse_options, (const guchar *) data, data_length); + + gsize problem_position; + cr_assert(syslog_format_handler(&parse_options, msg, (const guchar *) data, data_length, &problem_position)); + cr_assert_str_eq(log_msg_get_value_by_name(msg, "PROGRAM", NULL), "65536"); + + msg_format_options_destroy(&parse_options); + log_msg_unref(msg); +} -- 2.25.1