From: Luca Boccassi Date: Thu, 9 Jul 2026 10:30:02 +0000 (+0100) Subject: log: add upper bound to journal iovec accounting X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=f5e35f72cf8d930022cf9999664da3eb10251720;p=thirdparty%2Fsystemd.git log: add upper bound to journal iovec accounting Use checked arithmetic before clamping the journal iovec length. Stop copying input iovecs once the fixed journal vector is full. Follow-up for e69cc9eb36fd6e76710b4d5f4bb7013980fb5174 --- diff --git a/src/basic/log.c b/src/basic/log.c index 29702abd44e..17ea26d8a41 100644 --- a/src/basic/log.c +++ b/src/basic/log.c @@ -726,7 +726,11 @@ static int write_to_journal( if (LOG_PRI(level) > log_target_max_level[LOG_TARGET_JOURNAL]) return 0; - iovec_len = MIN(6 + log_context_num_fields() * 3, IOVEC_MAX); + if (!MUL_SAFE(&iovec_len, log_context_num_fields(), 3) || + !ADD_SAFE(&iovec_len, iovec_len, 6)) + iovec_len = IOVEC_MAX; + else + iovec_len = MIN(iovec_len, IOVEC_MAX); iovec = newa(struct iovec, iovec_len); log_do_header(header, sizeof(header), level, error, file, line, func, object_field, object, extra_field, extra); @@ -1024,7 +1028,11 @@ int log_struct_internal( int r; bool fallback = false; - iovec_len = MIN(17 + log_context_num_fields() * 3, IOVEC_MAX); + if (!MUL_SAFE(&iovec_len, log_context_num_fields(), 3) || + !ADD_SAFE(&iovec_len, iovec_len, 17)) + iovec_len = IOVEC_MAX; + else + iovec_len = MIN(iovec_len, IOVEC_MAX); iovec = newa(struct iovec, iovec_len); /* If the journal is available do structured logging. @@ -1123,15 +1131,21 @@ int log_struct_iovec_internal( char header[LINE_MAX]; struct iovec *iovec; - size_t n = 0, iovec_len; + size_t n = 0, iovec_len, n_context_iovec, n_input_iovec_expanded; - iovec_len = MIN(1 + n_input_iovec * 2 + log_context_num_fields() * 3, IOVEC_MAX); + if (!MUL_SAFE(&n_input_iovec_expanded, n_input_iovec, 2) || + !MUL_SAFE(&n_context_iovec, log_context_num_fields(), 3) || + !ADD_SAFE(&iovec_len, 1, n_input_iovec_expanded) || + !ADD_SAFE(&iovec_len, iovec_len, n_context_iovec)) + iovec_len = IOVEC_MAX; + else + iovec_len = MIN(iovec_len, IOVEC_MAX); iovec = newa(struct iovec, iovec_len); log_do_header(header, sizeof(header), level, error, file, line, func, NULL, NULL, NULL, NULL); iovec[n++] = IOVEC_MAKE_STRING(header); - for (size_t i = 0; i < n_input_iovec; i++) { + for (size_t i = 0; i < n_input_iovec && n + 2 <= iovec_len; i++) { iovec[n++] = input_iovec[i]; iovec[n++] = IOVEC_MAKE_STRING("\n"); } diff --git a/src/test/test-log.c b/src/test/test-log.c index fb23776b211..61468a3229c 100644 --- a/src/test/test-log.c +++ b/src/test/test-log.c @@ -145,6 +145,28 @@ TEST(log_format_iovec) { LOG_ITEM("FOOFOO=%hu-%llu", (unsigned short) 4, (long long unsigned) 3)); } +TEST(log_struct_iovec_many_fields) { + LogTarget old_target = log_get_target(); + struct iovec iovec[1024]; + + log_set_target(LOG_TARGET_JOURNAL); + log_open(); + if (log_on_console()) { + log_set_target(old_target); + log_open(); + return (void) log_tests_skipped("journal socket is not available"); + } + + iovec[0] = IOVEC_MAKE_STRING("MESSAGE=many fields"); + for (size_t i = 1; i < ELEMENTSOF(iovec); i++) + iovec[i] = IOVEC_MAKE_STRING("FIELD=value"); + + ASSERT_OK(log_struct_iovec(LOG_INFO, iovec, ELEMENTSOF(iovec))); + + log_set_target(old_target); + log_open(); +} + static void test_log_struct(void) { log_struct(LOG_INFO, "MESSAGE=Waldo PID="PID_FMT" (no errno)", getpid_cached(),