From 253a83ea44c4a45ff6b362ba17bd58964b183d17 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 23 Feb 2023 11:42:11 +0900 Subject: [PATCH 1/4] io-util: introduce iovec_array_free() It will be used in later commits. --- src/basic/io-util.c | 10 ++++++++++ src/basic/io-util.h | 2 ++ 2 files changed, 12 insertions(+) diff --git a/src/basic/io-util.c b/src/basic/io-util.c index f642beca3a..6f6fb8068c 100644 --- a/src/basic/io-util.c +++ b/src/basic/io-util.c @@ -362,3 +362,13 @@ size_t iovw_size(struct iovec_wrapper *iovw) { return n; } + +void iovec_array_free(struct iovec *iov, size_t n) { + if (!iov) + return; + + for (size_t i = 0; i < n; i++) + free(iov[i].iov_base); + + free(iov); +} diff --git a/src/basic/io-util.h b/src/basic/io-util.h index 3afb134266..e7e78e9121 100644 --- a/src/basic/io-util.h +++ b/src/basic/io-util.h @@ -105,3 +105,5 @@ int iovw_put_string_field(struct iovec_wrapper *iovw, const char *field, const c int iovw_put_string_field_free(struct iovec_wrapper *iovw, const char *field, char *value); void iovw_rebase(struct iovec_wrapper *iovw, char *old, char *new); size_t iovw_size(struct iovec_wrapper *iovw); + +void iovec_array_free(struct iovec *iov, size_t n); From 65e7d565e45ca9b87fb3e978cdb4b850d635cb63 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 23 Feb 2023 13:09:46 +0900 Subject: [PATCH 2/4] io-util: introduce IOVEC_NULL --- src/basic/io-util.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/basic/io-util.h b/src/basic/io-util.h index e7e78e9121..767c8af8fe 100644 --- a/src/basic/io-util.h +++ b/src/basic/io-util.h @@ -74,6 +74,7 @@ static inline bool FILE_SIZE_VALID_OR_INFINITY(uint64_t l) { } +#define IOVEC_NULL (struct iovec) {} #define IOVEC_INIT(base, len) { .iov_base = (base), .iov_len = (len) } #define IOVEC_MAKE(base, len) (struct iovec) IOVEC_INIT(base, len) #define IOVEC_INIT_STRING(string) IOVEC_INIT((char*) string, strlen(string)) From de5cc016b595d0c3ad18fb3e5fdf011b3ed3363c Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 23 Feb 2023 13:10:31 +0900 Subject: [PATCH 3/4] io-util: drop double evaluation in IOVEC_INIT_STRING() This also makes IOVEC_INIT_STRING() and IOVEC_MAKE_STRING() identical. --- src/basic/io-util.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/basic/io-util.h b/src/basic/io-util.h index 767c8af8fe..a5c1f89a8d 100644 --- a/src/basic/io-util.h +++ b/src/basic/io-util.h @@ -77,8 +77,12 @@ static inline bool FILE_SIZE_VALID_OR_INFINITY(uint64_t l) { #define IOVEC_NULL (struct iovec) {} #define IOVEC_INIT(base, len) { .iov_base = (base), .iov_len = (len) } #define IOVEC_MAKE(base, len) (struct iovec) IOVEC_INIT(base, len) -#define IOVEC_INIT_STRING(string) IOVEC_INIT((char*) string, strlen(string)) -#define IOVEC_MAKE_STRING(string) (struct iovec) IOVEC_INIT_STRING(string) +#define IOVEC_INIT_STRING(string) \ + ({ \ + char *_s = (char*) (string); \ + IOVEC_MAKE(_s, strlen(_s)); \ + }) +#define IOVEC_MAKE_STRING(string) IOVEC_INIT_STRING(string) char* set_iovec_string_field(struct iovec *iovec, size_t *n_iovec, const char *field, const char *value); char* set_iovec_string_field_free(struct iovec *iovec, size_t *n_iovec, const char *field, char *value); From 5648ebaf403dd2614a7cc72e892f4d29eaca46ef Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 23 Feb 2023 11:39:42 +0900 Subject: [PATCH 4/4] sd-journal: fix memleak and freeing invalid pointers This also makes - use GREEDY_REALLOC() or GREEDY_REALLOC0(), - use CLEANUP_ARRAY() macro. --- src/libsystemd/sd-journal/journal-send.c | 109 ++++++++--------------- 1 file changed, 39 insertions(+), 70 deletions(-) diff --git a/src/libsystemd/sd-journal/journal-send.c b/src/libsystemd/sd-journal/journal-send.c index 00c53f6d5b..c360d0e182 100644 --- a/src/libsystemd/sd-journal/journal-send.c +++ b/src/libsystemd/sd-journal/journal-send.c @@ -148,93 +148,64 @@ _public_ int sd_journal_printv(int priority, const char *format, va_list ap) { return sd_journal_sendv(iov, 2); } -_printf_(1, 0) static int fill_iovec_sprintf(const char *format, va_list ap, int extra, struct iovec **_iov) { +_printf_(1, 0) static int fill_iovec_sprintf(const char *format, va_list ap, size_t extra, struct iovec **ret_iov, size_t *ret_n_iov) { PROTECT_ERRNO; - int r, n = 0, i = 0, j; struct iovec *iov = NULL; + size_t n = 0; - assert(_iov); + assert(ret_iov); + assert(ret_n_iov); if (extra > 0) { - n = MAX(extra * 2, extra + 4); - iov = malloc0(n * sizeof(struct iovec)); - if (!iov) { - r = -ENOMEM; - goto fail; - } + if (!GREEDY_REALLOC0(iov, extra)) + return -ENOMEM; - i = extra; + n = extra; } + CLEANUP_ARRAY(iov, n, iovec_array_free); + while (format) { - struct iovec *c; - char *buffer; + _cleanup_free_ char *buffer = NULL; va_list aq; - if (i >= n) { - n = MAX(i*2, 4); - c = reallocarray(iov, n, sizeof(struct iovec)); - if (!c) { - r = -ENOMEM; - goto fail; - } - - iov = c; - } - va_copy(aq, ap); if (vasprintf(&buffer, format, aq) < 0) { va_end(aq); - r = -ENOMEM; - goto fail; + return -ENOMEM; } va_end(aq); VA_FORMAT_ADVANCE(format, ap); - - (void) strstrip(buffer); /* strip trailing whitespace, keep prefixing whitespace */ - - iov[i++] = IOVEC_MAKE_STRING(buffer); - format = va_arg(ap, char *); + + if (!GREEDY_REALLOC(iov, n + 1)) + return -ENOMEM; + + /* strip trailing whitespace, keep prefixing whitespace */ + iov[n++] = IOVEC_MAKE_STRING(delete_trailing_chars(TAKE_PTR(buffer), NULL)); } - *_iov = iov; - - return i; - -fail: - for (j = 0; j < i; j++) - free(iov[j].iov_base); - - free(iov); - - return r; + *ret_iov = TAKE_PTR(iov); + *ret_n_iov = n; + return 0; } _public_ int sd_journal_send(const char *format, ...) { - int r, i, j; - va_list ap; struct iovec *iov = NULL; + size_t n_iov = 0; + va_list ap; + int r; + + CLEANUP_ARRAY(iov, n_iov, iovec_array_free); va_start(ap, format); - i = fill_iovec_sprintf(format, ap, 0, &iov); + r = fill_iovec_sprintf(format, ap, 0, &iov, &n_iov); va_end(ap); + if (r < 0) + return r; - if (_unlikely_(i < 0)) { - r = i; - goto finish; - } - - r = sd_journal_sendv(iov, i); - -finish: - for (j = 0; j < i; j++) - free(iov[j].iov_base); - - free(iov); - - return r; + return sd_journal_sendv(iov, n_iov); } _public_ int sd_journal_sendv(const struct iovec *iov, int n) { @@ -529,19 +500,19 @@ _public_ int sd_journal_printv_with_location(int priority, const char *file, con } _public_ int sd_journal_send_with_location(const char *file, const char *line, const char *func, const char *format, ...) { - _cleanup_free_ struct iovec *iov = NULL; - int r, i, j; + struct iovec *iov = NULL; + size_t n_iov = 0; va_list ap; char *f; + int r; + + CLEANUP_ARRAY(iov, n_iov, iovec_array_free); va_start(ap, format); - i = fill_iovec_sprintf(format, ap, 3, &iov); + r = fill_iovec_sprintf(format, ap, 3, &iov, &n_iov); va_end(ap); - - if (_unlikely_(i < 0)) { - r = i; - goto finish; - } + if (r < 0) + return r; ALLOCA_CODE_FUNC(f, func); @@ -549,11 +520,9 @@ _public_ int sd_journal_send_with_location(const char *file, const char *line, c iov[1] = IOVEC_MAKE_STRING(line); iov[2] = IOVEC_MAKE_STRING(f); - r = sd_journal_sendv(iov, i); + r = sd_journal_sendv(iov, n_iov); -finish: - for (j = 3; j < i; j++) - free(iov[j].iov_base); + iov[0] = iov[1] = iov[2] = IOVEC_NULL; return r; }