summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2019-01-10 01:12:22 +0100
committerGitHub <noreply@github.com>2019-01-10 01:12:22 +0100
commita685c049c04036e12371a05702f5570d74340d55 (patch)
treea0b35f676645c254dba01a4642f6aca22e38122f
parentd253a45e1c147f5174265d71d7419da7bd52a88b (diff)
parentef4d6abe7c7fab6cbff975b32e76b09feee56074 (diff)
downloadsystemd-a685c049c04036e12371a05702f5570d74340d55.tar.gz
Merge pull request #11374 from keszybz/journal-fixes
Journal/journal-remote/coredump fixes
-rw-r--r--src/basic/io-util.c10
-rw-r--r--src/basic/io-util.h2
-rw-r--r--src/basic/process-util.c73
-rw-r--r--src/coredump/coredump.c40
-rw-r--r--src/journal-remote/journal-gatewayd.c53
-rw-r--r--src/journal-remote/journal-remote-main.c39
-rw-r--r--src/journal-remote/journal-remote.c3
-rw-r--r--src/journal-remote/microhttpd-util.c11
-rw-r--r--src/journal-remote/microhttpd-util.h1
-rw-r--r--src/journal/journald-native.c74
-rw-r--r--src/journal/journald-server.c29
-rw-r--r--src/shared/journal-importer.c5
-rw-r--r--src/shared/journal-importer.h3
13 files changed, 170 insertions, 173 deletions
diff --git a/src/basic/io-util.c b/src/basic/io-util.c
index 1f64cc933b..575398fbe6 100644
--- a/src/basic/io-util.c
+++ b/src/basic/io-util.c
@@ -8,6 +8,7 @@
#include <unistd.h>
#include "io-util.h"
+#include "string-util.h"
#include "time-util.h"
int flush_fd(int fd) {
@@ -252,3 +253,12 @@ ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length) {
return q - (const uint8_t*) p;
}
+
+char* set_iovec_string_field(struct iovec *iovec, size_t *n_iovec, const char *field, const char *value) {
+ char *x;
+
+ x = strappend(field, value);
+ if (x)
+ iovec[(*n_iovec)++] = IOVEC_MAKE_STRING(x);
+ return x;
+}
diff --git a/src/basic/io-util.h b/src/basic/io-util.h
index ed189b5820..792a64ad5e 100644
--- a/src/basic/io-util.h
+++ b/src/basic/io-util.h
@@ -71,3 +71,5 @@ static inline bool FILE_SIZE_VALID_OR_INFINITY(uint64_t l) {
#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)
+
+char* set_iovec_string_field(struct iovec *iovec, size_t *n_iovec, const char *field, const char *value);
diff --git a/src/basic/process-util.c b/src/basic/process-util.c
index 448503409b..31fdbd9346 100644
--- a/src/basic/process-util.c
+++ b/src/basic/process-util.c
@@ -129,6 +129,13 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char *
(void) __fsetlocking(f, FSETLOCKING_BYCALLER);
+ if (max_length == 0) {
+ /* This is supposed to be a safety guard against runaway command lines. */
+ long l = sysconf(_SC_ARG_MAX);
+ assert(l > 0);
+ max_length = l;
+ }
+
if (max_length == 1) {
/* If there's only room for one byte, return the empty string */
@@ -139,32 +146,6 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char *
*line = ans;
return 0;
- } else if (max_length == 0) {
- size_t len = 0, allocated = 0;
-
- while ((c = getc(f)) != EOF) {
-
- if (!GREEDY_REALLOC(ans, allocated, len+3)) {
- free(ans);
- return -ENOMEM;
- }
-
- if (isprint(c)) {
- if (space) {
- ans[len++] = ' ';
- space = false;
- }
-
- ans[len++] = c;
- } else if (len > 0)
- space = true;
- }
-
- if (len > 0)
- ans[len] = '\0';
- else
- ans = mfree(ans);
-
} else {
bool dotdotdot = false;
size_t left;
@@ -236,34 +217,30 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char *
if (h < 0)
return h;
- if (max_length == 0)
- ans = strjoin("[", t, "]");
- else {
- size_t l;
+ size_t l = strlen(t);
- l = strlen(t);
-
- if (l + 3 <= max_length)
- ans = strjoin("[", t, "]");
- else if (max_length <= 6) {
+ if (l + 3 <= max_length) {
+ ans = strjoin("[", t, "]");
+ if (!ans)
+ return -ENOMEM;
- ans = new(char, max_length);
- if (!ans)
- return -ENOMEM;
+ } else if (max_length <= 6) {
+ ans = new(char, max_length);
+ if (!ans)
+ return -ENOMEM;
- memcpy(ans, "[...]", max_length-1);
- ans[max_length-1] = 0;
- } else {
- t[max_length - 6] = 0;
+ memcpy(ans, "[...]", max_length-1);
+ ans[max_length-1] = 0;
+ } else {
+ t[max_length - 6] = 0;
- /* Chop off final spaces */
- delete_trailing_chars(t, WHITESPACE);
+ /* Chop off final spaces */
+ delete_trailing_chars(t, WHITESPACE);
- ans = strjoin("[", t, "...]");
- }
+ ans = strjoin("[", t, "...]");
+ if (!ans)
+ return -ENOMEM;
}
- if (!ans)
- return -ENOMEM;
}
*line = ans;
diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c
index 0c888b26f9..516f63d3e0 100644
--- a/src/coredump/coredump.c
+++ b/src/coredump/coredump.c
@@ -794,15 +794,16 @@ log:
core_message = strjoin("MESSAGE=Process ", context[CONTEXT_PID],
" (", context[CONTEXT_COMM], ") of user ",
context[CONTEXT_UID], " dumped core.",
- journald_crash ? "\nCoredump diverted to " : NULL,
- journald_crash ? filename : NULL);
+ journald_crash && filename ? "\nCoredump diverted to " : NULL,
+ journald_crash && filename ? filename : NULL);
if (!core_message)
return log_oom();
if (journald_crash) {
- /* We cannot log to the journal, so just print the MESSAGE.
+ /* We cannot log to the journal, so just print the message.
* The target was set previously to something safe. */
- log_dispatch(LOG_ERR, 0, core_message);
+ assert(startswith(core_message, "MESSAGE="));
+ log_dispatch(LOG_ERR, 0, core_message + strlen("MESSAGE="));
return 0;
}
@@ -1062,19 +1063,10 @@ static int send_iovec(const struct iovec iovec[], size_t n_iovec, int input_fd)
return 0;
}
-static char* set_iovec_field(struct iovec *iovec, size_t *n_iovec, const char *field, const char *value) {
- char *x;
-
- x = strappend(field, value);
- if (x)
- iovec[(*n_iovec)++] = IOVEC_MAKE_STRING(x);
- return x;
-}
-
static char* set_iovec_field_free(struct iovec *iovec, size_t *n_iovec, const char *field, char *value) {
char *x;
- x = set_iovec_field(iovec, n_iovec, field, value);
+ x = set_iovec_string_field(iovec, n_iovec, field, value);
free(value);
return x;
}
@@ -1124,36 +1116,36 @@ static int gather_pid_metadata(
disable_coredumps();
}
- set_iovec_field(iovec, n_iovec, "COREDUMP_UNIT=", context[CONTEXT_UNIT]);
+ set_iovec_string_field(iovec, n_iovec, "COREDUMP_UNIT=", context[CONTEXT_UNIT]);
}
if (cg_pid_get_user_unit(pid, &t) >= 0)
set_iovec_field_free(iovec, n_iovec, "COREDUMP_USER_UNIT=", t);
/* The next few are mandatory */
- if (!set_iovec_field(iovec, n_iovec, "COREDUMP_PID=", context[CONTEXT_PID]))
+ if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_PID=", context[CONTEXT_PID]))
return log_oom();
- if (!set_iovec_field(iovec, n_iovec, "COREDUMP_UID=", context[CONTEXT_UID]))
+ if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_UID=", context[CONTEXT_UID]))
return log_oom();
- if (!set_iovec_field(iovec, n_iovec, "COREDUMP_GID=", context[CONTEXT_GID]))
+ if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_GID=", context[CONTEXT_GID]))
return log_oom();
- if (!set_iovec_field(iovec, n_iovec, "COREDUMP_SIGNAL=", context[CONTEXT_SIGNAL]))
+ if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_SIGNAL=", context[CONTEXT_SIGNAL]))
return log_oom();
- if (!set_iovec_field(iovec, n_iovec, "COREDUMP_RLIMIT=", context[CONTEXT_RLIMIT]))
+ if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_RLIMIT=", context[CONTEXT_RLIMIT]))
return log_oom();
- if (!set_iovec_field(iovec, n_iovec, "COREDUMP_HOSTNAME=", context[CONTEXT_HOSTNAME]))
+ if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_HOSTNAME=", context[CONTEXT_HOSTNAME]))
return log_oom();
- if (!set_iovec_field(iovec, n_iovec, "COREDUMP_COMM=", context[CONTEXT_COMM]))
+ if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_COMM=", context[CONTEXT_COMM]))
return log_oom();
if (context[CONTEXT_EXE] &&
- !set_iovec_field(iovec, n_iovec, "COREDUMP_EXE=", context[CONTEXT_EXE]))
+ !set_iovec_string_field(iovec, n_iovec, "COREDUMP_EXE=", context[CONTEXT_EXE]))
return log_oom();
if (sd_pid_get_session(pid, &t) >= 0)
@@ -1221,7 +1213,7 @@ static int gather_pid_metadata(
iovec[(*n_iovec)++] = IOVEC_MAKE_STRING(t);
if (safe_atoi(context[CONTEXT_SIGNAL], &signo) >= 0 && SIGNAL_VALID(signo))
- set_iovec_field(iovec, n_iovec, "COREDUMP_SIGNAL_NAME=SIG", signal_to_string(signo));
+ set_iovec_string_field(iovec, n_iovec, "COREDUMP_SIGNAL_NAME=SIG", signal_to_string(signo));
return 0; /* we successfully acquired all metadata */
}
diff --git a/src/journal-remote/journal-gatewayd.c b/src/journal-remote/journal-gatewayd.c
index 4185af63e1..af45fa549a 100644
--- a/src/journal-remote/journal-gatewayd.c
+++ b/src/journal-remote/journal-gatewayd.c
@@ -461,7 +461,7 @@ static int request_handler_entries(
struct MHD_Connection *connection,
void *connection_cls) {
- struct MHD_Response *response;
+ _cleanup_(MHD_destroy_responsep) struct MHD_Response *response = NULL;
RequestMeta *m = connection_cls;
int r;
@@ -503,11 +503,7 @@ static int request_handler_entries(
return respond_oom(connection);
MHD_add_response_header(response, "Content-Type", mime_types[m->mode]);
-
- r = MHD_queue_response(connection, MHD_HTTP_OK, response);
- MHD_destroy_response(response);
-
- return r;
+ return MHD_queue_response(connection, MHD_HTTP_OK, response);
}
static int output_field(FILE *f, OutputMode m, const char *d, size_t l) {
@@ -619,7 +615,7 @@ static int request_handler_fields(
const char *field,
void *connection_cls) {
- struct MHD_Response *response;
+ _cleanup_(MHD_destroy_responsep) struct MHD_Response *response = NULL;
RequestMeta *m = connection_cls;
int r;
@@ -642,11 +638,7 @@ static int request_handler_fields(
return respond_oom(connection);
MHD_add_response_header(response, "Content-Type", mime_types[m->mode == OUTPUT_JSON ? OUTPUT_JSON : OUTPUT_SHORT]);
-
- r = MHD_queue_response(connection, MHD_HTTP_OK, response);
- MHD_destroy_response(response);
-
- return r;
+ return MHD_queue_response(connection, MHD_HTTP_OK, response);
}
static int request_handler_redirect(
@@ -654,8 +646,7 @@ static int request_handler_redirect(
const char *target) {
char *page;
- struct MHD_Response *response;
- int ret;
+ _cleanup_(MHD_destroy_responsep) struct MHD_Response *response = NULL;
assert(connection);
assert(target);
@@ -671,11 +662,7 @@ static int request_handler_redirect(
MHD_add_response_header(response, "Content-Type", "text/html");
MHD_add_response_header(response, "Location", target);
-
- ret = MHD_queue_response(connection, MHD_HTTP_MOVED_PERMANENTLY, response);
- MHD_destroy_response(response);
-
- return ret;
+ return MHD_queue_response(connection, MHD_HTTP_MOVED_PERMANENTLY, response);
}
static int request_handler_file(
@@ -683,8 +670,7 @@ static int request_handler_file(
const char *path,
const char *mime_type) {
- struct MHD_Response *response;
- int ret;
+ _cleanup_(MHD_destroy_responsep) struct MHD_Response *response = NULL;
_cleanup_close_ int fd = -1;
struct stat st;
@@ -702,15 +688,10 @@ static int request_handler_file(
response = MHD_create_response_from_fd_at_offset64(st.st_size, fd, 0);
if (!response)
return respond_oom(connection);
-
- fd = -1;
+ TAKE_FD(fd);
MHD_add_response_header(response, "Content-Type", mime_type);
-
- ret = MHD_queue_response(connection, MHD_HTTP_OK, response);
- MHD_destroy_response(response);
-
- return ret;
+ return MHD_queue_response(connection, MHD_HTTP_OK, response);
}
static int get_virtualization(char **v) {
@@ -747,14 +728,13 @@ static int request_handler_machine(
struct MHD_Connection *connection,
void *connection_cls) {
- struct MHD_Response *response;
+ _cleanup_(MHD_destroy_responsep) struct MHD_Response *response = NULL;
RequestMeta *m = connection_cls;
int r;
_cleanup_free_ char* hostname = NULL, *os_name = NULL;
uint64_t cutoff_from = 0, cutoff_to = 0, usage = 0;
- char *json;
sd_id128_t mid, bid;
- _cleanup_free_ char *v = NULL;
+ _cleanup_free_ char *v = NULL, *json = NULL;
assert(connection);
assert(m);
@@ -803,21 +783,16 @@ static int request_handler_machine(
usage,
cutoff_from,
cutoff_to);
-
if (r < 0)
return respond_oom(connection);
response = MHD_create_response_from_buffer(strlen(json), json, MHD_RESPMEM_MUST_FREE);
- if (!response) {
- free(json);
+ if (!response)
return respond_oom(connection);
- }
+ TAKE_PTR(json);
MHD_add_response_header(response, "Content-Type", "application/json");
- r = MHD_queue_response(connection, MHD_HTTP_OK, response);
- MHD_destroy_response(response);
-
- return r;
+ return MHD_queue_response(connection, MHD_HTTP_OK, response);
}
static int request_handler(
diff --git a/src/journal-remote/journal-remote-main.c b/src/journal-remote/journal-remote-main.c
index e1748cb46b..802c3ea608 100644
--- a/src/journal-remote/journal-remote-main.c
+++ b/src/journal-remote/journal-remote-main.c
@@ -221,16 +221,17 @@ static int process_http_upload(
journal_remote_server_global->seal);
if (r == -EAGAIN)
break;
- else if (r < 0) {
- log_warning("Failed to process data for connection %p", connection);
- if (r == -E2BIG)
- return mhd_respondf(connection,
- r, MHD_HTTP_PAYLOAD_TOO_LARGE,
- "Entry is too large, maximum is " STRINGIFY(DATA_SIZE_MAX) " bytes.");
+ if (r < 0) {
+ if (r == -ENOBUFS)
+ log_warning_errno(r, "Entry is above the maximum of %u, aborting connection %p.",
+ DATA_SIZE_MAX, connection);
+ else if (r == -E2BIG)
+ log_warning_errno(r, "Entry with more fields than the maximum of %u, aborting connection %p.",
+ ENTRY_FIELD_COUNT_MAX, connection);
else
- return mhd_respondf(connection,
- r, MHD_HTTP_UNPROCESSABLE_ENTITY,
- "Processing failed: %m.");
+ log_warning_errno(r, "Failed to process data, aborting connection %p: %m",
+ connection);
+ return MHD_NO;
}
}
@@ -264,6 +265,7 @@ static int request_handler(
const char *header;
int r, code, fd;
_cleanup_free_ char *hostname = NULL;
+ size_t len;
assert(connection);
assert(connection_cls);
@@ -283,12 +285,27 @@ static int request_handler(
if (!streq(url, "/upload"))
return mhd_respond(connection, MHD_HTTP_NOT_FOUND, "Not found.");
- header = MHD_lookup_connection_value(connection,
- MHD_HEADER_KIND, "Content-Type");
+ header = MHD_lookup_connection_value(connection, MHD_HEADER_KIND, "Content-Type");
if (!header || !streq(header, "application/vnd.fdo.journal"))
return mhd_respond(connection, MHD_HTTP_UNSUPPORTED_MEDIA_TYPE,
"Content-Type: application/vnd.fdo.journal is required.");
+ header = MHD_lookup_connection_value(connection, MHD_HEADER_KIND, "Content-Length");
+ if (!header)
+ return mhd_respond(connection, MHD_HTTP_LENGTH_REQUIRED,
+ "Content-Length header is required.");
+ r = safe_atozu(header, &len);
+ if (r < 0)
+ return mhd_respondf(connection, r, MHD_HTTP_LENGTH_REQUIRED,
+ "Content-Length: %s cannot be parsed: %m", header);
+
+ if (len > ENTRY_SIZE_MAX)
+ /* When serialized, an entry of maximum size might be slightly larger,
+ * so this does not correspond exactly to the limit in journald. Oh well.
+ */
+ return mhd_respondf(connection, 0, MHD_HTTP_PAYLOAD_TOO_LARGE,
+ "Payload larger than maximum size of %u bytes", ENTRY_SIZE_MAX);
+
{
const union MHD_ConnectionInfo *ci;
diff --git a/src/journal-remote/journal-remote.c b/src/journal-remote/journal-remote.c
index 3c0916c438..1da32c5f85 100644
--- a/src/journal-remote/journal-remote.c
+++ b/src/journal-remote/journal-remote.c
@@ -407,6 +407,9 @@ int journal_remote_handle_raw_source(
log_debug("%zu active sources remaining", s->active);
return 0;
} else if (r == -E2BIG) {
+ log_notice("Entry with too many fields, skipped");
+ return 1;
+ } else if (r == -ENOBUFS) {
log_notice("Entry too big, skipped");
return 1;
} else if (r == -EAGAIN) {
diff --git a/src/journal-remote/microhttpd-util.c b/src/journal-remote/microhttpd-util.c
index adf40b5abd..6d049d11f7 100644
--- a/src/journal-remote/microhttpd-util.c
+++ b/src/journal-remote/microhttpd-util.c
@@ -32,21 +32,16 @@ static int mhd_respond_internal(struct MHD_Connection *connection,
const char *buffer,
size_t size,
enum MHD_ResponseMemoryMode mode) {
- struct MHD_Response *response;
- int r;
-
assert(connection);
- response = MHD_create_response_from_buffer(size, (char*) buffer, mode);
+ _cleanup_(MHD_destroy_responsep) struct MHD_Response *response
+ = MHD_create_response_from_buffer(size, (char*) buffer, mode);
if (!response)
return MHD_NO;
log_debug("Queueing response %u: %s", code, buffer);
MHD_add_response_header(response, "Content-Type", "text/plain");
- r = MHD_queue_response(connection, code, response);
- MHD_destroy_response(response);
-
- return r;
+ return MHD_queue_response(connection, code, response);
}
int mhd_respond(struct MHD_Connection *connection,
diff --git a/src/journal-remote/microhttpd-util.h b/src/journal-remote/microhttpd-util.h
index 364cd0f7cf..ba51d847e4 100644
--- a/src/journal-remote/microhttpd-util.h
+++ b/src/journal-remote/microhttpd-util.h
@@ -75,3 +75,4 @@ int check_permissions(struct MHD_Connection *connection, int *code, char **hostn
int setup_gnutls_logger(char **categories);
DEFINE_TRIVIAL_CLEANUP_FUNC(struct MHD_Daemon*, MHD_stop_daemon);
+DEFINE_TRIVIAL_CLEANUP_FUNC(struct MHD_Response*, MHD_destroy_response);
diff --git a/src/journal/journald-native.c b/src/journal/journald-native.c
index e86178ed77..221188db16 100644
--- a/src/journal/journald-native.c
+++ b/src/journal/journald-native.c
@@ -110,7 +110,7 @@ static int server_process_entry(
int priority = LOG_INFO;
pid_t object_pid = 0;
const char *p;
- int r = 0;
+ int r = 1;
p = buffer;
@@ -122,8 +122,7 @@ static int server_process_entry(
if (!e) {
/* Trailing noise, let's ignore it, and flush what we collected */
log_debug("Received message with trailing noise, ignoring.");
- r = 1; /* finish processing of the message */
- break;
+ break; /* finish processing of the message */
}
if (e == p) {
@@ -133,14 +132,17 @@ static int server_process_entry(
}
if (IN_SET(*p, '.', '#')) {
- /* Ignore control commands for now, and
- * comments too. */
+ /* Ignore control commands for now, and comments too. */
*remaining -= (e - p) + 1;
p = e + 1;
continue;
}
/* A property follows */
+ if (n > ENTRY_FIELD_COUNT_MAX) {
+ log_debug("Received an entry that has more than " STRINGIFY(ENTRY_FIELD_COUNT_MAX) " fields, ignoring entry.");
+ goto finish;
+ }
/* n existing properties, 1 new, +1 for _TRANSPORT */
if (!GREEDY_REALLOC(iovec, m,
@@ -148,7 +150,7 @@ static int server_process_entry(
N_IOVEC_META_FIELDS + N_IOVEC_OBJECT_FIELDS +
client_context_extra_fields_n_iovec(context))) {
r = log_oom();
- break;
+ goto finish;
}
q = memchr(p, '=', e - p);
@@ -157,6 +159,16 @@ static int server_process_entry(
size_t l;
l = e - p;
+ if (l > DATA_SIZE_MAX) {
+ log_debug("Received text block of %zu bytes is too large, ignoring entry.", l);
+ goto finish;
+ }
+
+ if (entry_size + l + n + 1 > ENTRY_SIZE_MAX) { /* data + separators + trailer */
+ log_debug("Entry is too big (%zu bytes after processing %zu entries), ignoring entry.",
+ entry_size + l, n + 1);
+ goto finish;
+ }
/* If the field name starts with an underscore, skip the variable, since that indicates
* a trusted field */
@@ -174,7 +186,7 @@ static int server_process_entry(
p = e + 1;
continue;
} else {
- uint64_t l;
+ uint64_t l, total;
char *k;
if (*remaining < e - p + 1 + sizeof(uint64_t) + 1) {
@@ -183,10 +195,16 @@ static int server_process_entry(
}
l = unaligned_read_le64(e + 1);
-
if (l > DATA_SIZE_MAX) {
- log_debug("Received binary data block of %"PRIu64" bytes is too large, ignoring.", l);
- break;
+ log_debug("Received binary data block of %"PRIu64" bytes is too large, ignoring entry.", l);
+ goto finish;
+ }
+
+ total = (e - p) + 1 + l;
+ if (entry_size + total + n + 1 > ENTRY_SIZE_MAX) { /* data + separators + trailer */
+ log_debug("Entry is too big (%"PRIu64"bytes after processing %zu fields), ignoring.",
+ entry_size + total, n + 1);
+ goto finish;
}
if ((uint64_t) *remaining < e - p + 1 + sizeof(uint64_t) + l + 1 ||
@@ -195,7 +213,7 @@ static int server_process_entry(
break;
}
- k = malloc((e - p) + 1 + l);
+ k = malloc(total);
if (!k) {
log_oom();
break;
@@ -223,15 +241,8 @@ static int server_process_entry(
}
}
- if (n <= 0) {
- r = 1;
+ if (n <= 0)
goto finish;
- }
-
- if (!client_context_test_priority(context, priority)) {
- r = 0;
- goto finish;
- }
tn = n++;
iovec[tn] = IOVEC_MAKE_STRING("_TRANSPORT=journal");
@@ -242,6 +253,11 @@ static int server_process_entry(
goto finish;
}
+ r = 0; /* Success, we read the message. */
+
+ if (!client_context_test_priority(context, priority))
+ goto finish;
+
if (message) {
if (s->forward_to_syslog)
server_forward_syslog(s, syslog_fixup_facility(priority), identifier, message, ucred, tv);
@@ -313,15 +329,13 @@ void server_process_native_file(
bool sealed;
int r;
- /* Data is in the passed fd, since it didn't fit in a
- * datagram. */
+ /* Data is in the passed fd, probably it didn't fit in a datagram. */
assert(s);
assert(fd >= 0);
/* If it's a memfd, check if it is sealed. If so, we can just
- * use map it and use it, and do not need to copy the data
- * out. */
+ * mmap it and use it, and do not need to copy the data out. */
sealed = memfd_get_sealed(fd) > 0;
if (!sealed && (!ucred || ucred->uid != 0)) {
@@ -362,8 +376,10 @@ void server_process_native_file(
if (st.st_size <= 0)
return;
- if (st.st_size > ENTRY_SIZE_MAX) {
- log_error("File passed too large. Ignoring.");
+ /* When !sealed, set a lower memory limit. We have to read the file,
+ * effectively doubling memory use. */
+ if (st.st_size > ENTRY_SIZE_MAX / (sealed ? 1 : 2)) {
+ log_error("File passed too large (%"PRIu64" bytes). Ignoring.", (uint64_t) st.st_size);
return;
}
@@ -388,7 +404,7 @@ void server_process_native_file(
ssize_t n;
if (fstatvfs(fd, &vfs) < 0) {
- log_error_errno(errno, "Failed to stat file system of passed file, ignoring: %m");
+ log_error_errno(errno, "Failed to stat file system of passed file, not processing it: %m");
return;
}
@@ -398,7 +414,7 @@ void server_process_native_file(
* https://github.com/systemd/systemd/issues/1822
*/
if (vfs.f_flag & ST_MANDLOCK) {
- log_error("Received file descriptor from file system with mandatory locking enabled, refusing.");
+ log_error("Received file descriptor from file system with mandatory locking enabled, not processing it.");
return;
}
@@ -411,13 +427,13 @@ void server_process_native_file(
* and so is SMB. */
r = fd_nonblock(fd, true);
if (r < 0) {
- log_error_errno(r, "Failed to make fd non-blocking, ignoring: %m");
+ log_error_errno(r, "Failed to make fd non-blocking, not processing it: %m");
return;
}
/* The file is not sealed, we can't map the file here, since
* clients might then truncate it and trigger a SIGBUS for
- * us. So let's stupidly read it */
+ * us. So let's stupidly read it. */
p = malloc(st.st_size);
if (!p) {
diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c
index 434325c179..2a960ebb3e 100644
--- a/src/journal/journald-server.c
+++ b/src/journal/journald-server.c
@@ -905,6 +905,7 @@ static void dispatch_message_real(
pid_t object_pid) {
char source_time[sizeof("_SOURCE_REALTIME_TIMESTAMP=") + DECIMAL_STR_MAX(usec_t)];
+ _cleanup_free_ char *cmdline1 = NULL, *cmdline2 = NULL;
uid_t journal_uid;
ClientContext *o;
@@ -921,20 +922,23 @@ static void dispatch_message_real(
IOVEC_ADD_NUMERIC_FIELD(iovec, n, c->uid, uid_t, uid_is_valid, UID_FMT, "_UID");
IOVEC_ADD_NUMERIC_FIELD(iovec, n, c->gid, gid_t, gid_is_valid, GID_FMT, "_GID");
- IOVEC_ADD_STRING_FIELD(iovec, n, c->comm, "_COMM");
- IOVEC_ADD_STRING_FIELD(iovec, n, c->exe, "_EXE");
- IOVEC_ADD_STRING_FIELD(iovec, n, c->cmdline, "_CMDLINE");
- IOVEC_ADD_STRING_FIELD(iovec, n, c->capeff, "_CAP_EFFECTIVE");
+ IOVEC_ADD_STRING_FIELD(iovec, n, c->comm, "_COMM"); /* At most TASK_COMM_LENGTH (16 bytes) */
+ IOVEC_ADD_STRING_FIELD(iovec, n, c->exe, "_EXE"); /* A path, so at most PATH_MAX (4096 bytes) */
- IOVEC_ADD_SIZED_FIELD(iovec, n, c->label, c->label_size, "_SELINUX_CONTEXT");
+ if (c->cmdline)
+ /* At most _SC_ARG_MAX (2MB usually), which is too much to put on stack.
+ * Let's use a heap allocation for this one. */
+ cmdline1 = set_iovec_string_field(iovec, &n, "_CMDLINE=", c->cmdline);
+ IOVEC_ADD_STRING_FIELD(iovec, n, c->capeff, "_CAP_EFFECTIVE"); /* Read from /proc/.../status */
+ IOVEC_ADD_SIZED_FIELD(iovec, n, c->label, c->label_size, "_SELINUX_CONTEXT");
IOVEC_ADD_NUMERIC_FIELD(iovec, n, c->auditid, uint32_t, audit_session_is_valid, "%" PRIu32, "_AUDIT_SESSION");
IOVEC_ADD_NUMERIC_FIELD(iovec, n, c->loginuid, uid_t, uid_is_valid, UID_FMT, "_AUDIT_LOGINUID");
- IOVEC_ADD_STRING_FIELD(iovec, n, c->cgroup, "_SYSTEMD_CGROUP");
+ IOVEC_ADD_STRING_FIELD(iovec, n, c->cgroup, "_SYSTEMD_CGROUP"); /* A path */
IOVEC_ADD_STRING_FIELD(iovec, n, c->session, "_SYSTEMD_SESSION");
IOVEC_ADD_NUMERIC_FIELD(iovec, n, c->owner_uid, uid_t, uid_is_valid, UID_FMT, "_SYSTEMD_OWNER_UID");
- IOVEC_ADD_STRING_FIELD(iovec, n, c->unit, "_SYSTEMD_UNIT");
+ IOVEC_ADD_STRING_FIELD(iovec, n, c->unit, "_SYSTEMD_UNIT"); /* Unit names are bounded by UNIT_NAME_MAX */
IOVEC_ADD_STRING_FIELD(iovec, n, c->user_unit, "_SYSTEMD_USER_UNIT");
IOVEC_ADD_STRING_FIELD(iovec, n, c->slice, "_SYSTEMD_SLICE");
IOVEC_ADD_STRING_FIELD(iovec, n, c->user_slice, "_SYSTEMD_USER_SLICE");
@@ -955,13 +959,14 @@ static void dispatch_message_real(
IOVEC_ADD_NUMERIC_FIELD(iovec, n, o->uid, uid_t, uid_is_valid, UID_FMT, "OBJECT_UID");
IOVEC_ADD_NUMERIC_FIELD(iovec, n, o->gid, gid_t, gid_is_valid, GID_FMT, "OBJECT_GID");
+ /* See above for size limits, only ->cmdline may be large, so use a heap allocation for it. */
IOVEC_ADD_STRING_FIELD(iovec, n, o->comm, "OBJECT_COMM");
IOVEC_ADD_STRING_FIELD(iovec, n, o->exe, "OBJECT_EXE");
- IOVEC_ADD_STRING_FIELD(iovec, n, o->cmdline, "OBJECT_CMDLINE");
- IOVEC_ADD_STRING_FIELD(iovec, n, o->capeff, "OBJECT_CAP_EFFECTIVE");
+ if (o->cmdline)
+ cmdline2 = set_iovec_string_field(iovec, &n, "OBJECT_CMDLINE=", o->cmdline);
+ IOVEC_ADD_STRING_FIELD(iovec, n, o->capeff, "OBJECT_CAP_EFFECTIVE");
IOVEC_ADD_SIZED_FIELD(iovec, n, o->label, o->label_size, "OBJECT_SELINUX_CONTEXT");
-
IOVEC_ADD_NUMERIC_FIELD(iovec, n, o->auditid, uint32_t, audit_session_is_valid, "%" PRIu32, "OBJECT_AUDIT_SESSION");
IOVEC_ADD_NUMERIC_FIELD(iovec, n, o->loginuid, uid_t, uid_is_valid, UID_FMT, "OBJECT_AUDIT_LOGINUID");
@@ -1276,8 +1281,7 @@ int server_process_datagram(sd_event_source *es, int fd, uint32_t revents, void
return log_error_errno(errno, "recvmsg() failed: %m");
}
- CMSG_FOREACH(cmsg, &msghdr) {
-
+ CMSG_FOREACH(cmsg, &msghdr)
if (cmsg->cmsg_level == SOL_SOCKET &&
cmsg->cmsg_type == SCM_CREDENTIALS &&
cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred)))
@@ -1295,7 +1299,6 @@ int server_process_datagram(sd_event_source *es, int fd, uint32_t revents, void
fds = (int*) CMSG_DATA(cmsg);
n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
}
- }
/* And a trailing NUL, just in case */
s->buffer[n] = 0;
diff --git a/src/shared/journal-importer.c b/src/shared/journal-importer.c
index b0e619205d..8638cd3cc9 100644
--- a/src/shared/journal-importer.c
+++ b/src/shared/journal-importer.c
@@ -23,6 +23,9 @@ enum {
};
static int iovw_put(struct iovec_wrapper *iovw, void* data, size_t len) {
+ if (iovw->count >= ENTRY_FIELD_COUNT_MAX)
+ return -E2BIG;
+
if (!GREEDY_REALLOC(iovw->iovec, iovw->size_bytes, iovw->count + 1))
return log_oom();
@@ -97,7 +100,7 @@ static int get_line(JournalImporter *imp, char **line, size_t *size) {
imp->scanned = imp->filled;
if (imp->scanned >= DATA_SIZE_MAX)
- return log_error_errno(SYNTHETIC_ERRNO(E2BIG),
+ return log_error_errno(SYNTHETIC_ERRNO(ENOBUFS),
"Entry is bigger than %u bytes.",
DATA_SIZE_MAX);
diff --git a/src/shared/journal-importer.h b/src/shared/journal-importer.h
index 53354b7c78..7914c0cf5f 100644
--- a/src/shared/journal-importer.h
+++ b/src/shared/journal-importer.h
@@ -21,6 +21,9 @@
#endif
#define LINE_CHUNK 8*1024u
+/* The maximum number of fields in an entry */
+#define ENTRY_FIELD_COUNT_MAX 1024
+
struct iovec_wrapper {
struct iovec *iovec;
size_t size_bytes;