From: Yu Watanabe Date: Wed, 28 Jan 2026 03:20:07 +0000 (+0900) Subject: journal: make security label always NUL-terminated X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8d607f93b7b445171ec54b65f8ecccc5f4c0667c;p=thirdparty%2Fsystemd.git journal: make security label always NUL-terminated Then, we can drop label_len or label_size arguments at various places. While doing this, SCM_SECURITY is now ignored when SELinux is disabled or when it contains embedded NUL. --- diff --git a/src/journal/fuzz-journald-native-fd.c b/src/journal/fuzz-journald-native-fd.c index 36a94b7b921..66afd970493 100644 --- a/src/journal/fuzz-journald-native-fd.c +++ b/src/journal/fuzz-journald-native-fd.c @@ -14,8 +14,6 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { _cleanup_(manager_freep) Manager *m = NULL; _cleanup_close_ int sealed_fd = -EBADF, unsealed_fd = -EBADF; _cleanup_(unlink_tempfilep) char name[] = "/tmp/fuzz-journald-native-fd.XXXXXX"; - char *label = NULL; - size_t label_len = 0; struct ucred ucred; struct timeval *tv = NULL; @@ -30,13 +28,13 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { .uid = geteuid(), .gid = getegid(), }; - (void) manager_process_native_file(m, sealed_fd, &ucred, tv, label, label_len); + (void) manager_process_native_file(m, sealed_fd, &ucred, tv, /* label= */ NULL); unsealed_fd = mkostemp_safe(name); assert_se(unsealed_fd >= 0); assert_se(write(unsealed_fd, data, size) == (ssize_t) size); assert_se(lseek(unsealed_fd, 0, SEEK_SET) == 0); - (void) manager_process_native_file(m, unsealed_fd, &ucred, tv, label, label_len); + (void) manager_process_native_file(m, unsealed_fd, &ucred, tv, /* label= */ NULL); return 0; } diff --git a/src/journal/fuzz-journald-util.c b/src/journal/fuzz-journald-util.c index 7080b9412d9..99f11e4c425 100644 --- a/src/journal/fuzz-journald-util.c +++ b/src/journal/fuzz-journald-util.c @@ -33,5 +33,5 @@ void fuzz_journald_processing_function( _cleanup_(manager_freep) Manager *m = NULL; dummy_manager_new(&m, data, size); - f(m, m->buffer, size, /* ucred= */ NULL, /* tv= */ NULL, /* label= */ NULL, /* label_len= */ 0); + f(m, m->buffer, size, /* ucred= */ NULL, /* tv= */ NULL, /* label= */ NULL); } diff --git a/src/journal/fuzz-journald-util.h b/src/journal/fuzz-journald-util.h index 7eb491f36ad..0f9b2812e4e 100644 --- a/src/journal/fuzz-journald-util.h +++ b/src/journal/fuzz-journald-util.h @@ -9,8 +9,7 @@ typedef void (*journal_process_t)( size_t raw_len, const struct ucred *ucred, const struct timeval *tv, - const char *label, - size_t label_len); + const char *label); void dummy_manager_new(Manager **ret, const uint8_t *buffer, size_t size); diff --git a/src/journal/journald-context.c b/src/journal/journald-context.c index 5889adc2cec..1eb142887d7 100644 --- a/src/journal/journald-context.c +++ b/src/journal/journald-context.c @@ -176,7 +176,6 @@ static void client_context_reset(Manager *m, ClientContext *c) { c->invocation_id = SD_ID128_NULL; c->label = mfree(c->label); - c->label_size = 0; c->extra_fields_iovec = mfree(c->extra_fields_iovec); c->extra_fields_n_iovec = 0; @@ -248,26 +247,21 @@ static void client_context_read_basic(ClientContext *c) { static int client_context_read_label( ClientContext *c, - const char *label, size_t label_size) { + const char *label) { + + int r; assert(c); assert(pid_is_valid(c->pid)); - assert(label_size == 0 || label); if (!mac_selinux_use()) return 0; - if (label_size > 0) { - char *l; - + if (label) { /* If we got an SELinux label passed in it counts. */ - - l = newdup_suffix0(char, label, label_size); - if (!l) + r = free_and_strdup(&c->label, label); + if (r < 0) return -ENOMEM; - - free_and_replace(c->label, l); - c->label_size = label_size; } #if HAVE_SELINUX else { @@ -275,10 +269,8 @@ static int client_context_read_label( /* If we got no SELinux label passed in, let's try to acquire one */ - if (sym_getpidcon_raw(c->pid, &con) >= 0 && con) { + if (sym_getpidcon_raw(c->pid, &con) >= 0 && con) free_and_replace(c->label, con); - c->label_size = strlen(c->label); - } } #endif @@ -533,7 +525,7 @@ static void client_context_really_refresh( Manager *m, ClientContext *c, const struct ucred *ucred, - const char *label, size_t label_size, + const char *label, const char *unit_id, usec_t timestamp) { @@ -546,7 +538,7 @@ static void client_context_really_refresh( client_context_read_uid_gid(c, ucred); client_context_read_basic(c); - (void) client_context_read_label(c, label, label_size); + (void) client_context_read_label(c, label); (void) audit_session_from_pid(&PIDREF_MAKE_FROM_PID(c->pid), &c->auditid); (void) audit_loginuid_from_pid(&PIDREF_MAKE_FROM_PID(c->pid), &c->loginuid); @@ -570,7 +562,7 @@ void client_context_maybe_refresh( Manager *m, ClientContext *c, const struct ucred *ucred, - const char *label, size_t label_size, + const char *label, const char *unit_id, usec_t timestamp) { @@ -602,13 +594,13 @@ void client_context_maybe_refresh( if (ucred && gid_is_valid(ucred->gid) && c->gid != ucred->gid) goto refresh; - if (label_size > 0 && (label_size != c->label_size || memcmp(label, c->label, label_size) != 0)) + if (label && !streq_ptr(label, c->label)) goto refresh; return; refresh: - client_context_really_refresh(m, c, ucred, label, label_size, unit_id, timestamp); + client_context_really_refresh(m, c, ucred, label, unit_id, timestamp); } static void client_context_refresh_on_reload(Manager *m, ClientContext *c) { @@ -710,7 +702,7 @@ static int client_context_get_internal( Manager *m, pid_t pid, const struct ucred *ucred, - const char *label, size_t label_len, + const char *label, const char *unit_id, bool add_ref, ClientContext **ret) { @@ -738,7 +730,7 @@ static int client_context_get_internal( c->n_ref++; } - client_context_maybe_refresh(m, c, ucred, label, label_len, unit_id, USEC_INFINITY); + client_context_maybe_refresh(m, c, ucred, label, unit_id, USEC_INFINITY); *ret = c; return 0; @@ -762,7 +754,7 @@ static int client_context_get_internal( c->in_lru = true; } - client_context_really_refresh(m, c, ucred, label, label_len, unit_id, USEC_INFINITY); + client_context_really_refresh(m, c, ucred, label, unit_id, USEC_INFINITY); *ret = c; return 0; @@ -772,22 +764,22 @@ int client_context_get( Manager *m, pid_t pid, const struct ucred *ucred, - const char *label, size_t label_len, + const char *label, const char *unit_id, ClientContext **ret) { - return client_context_get_internal(m, pid, ucred, label, label_len, unit_id, false, ret); + return client_context_get_internal(m, pid, ucred, label, unit_id, /* add_ref= */ false, ret); } int client_context_acquire( Manager *m, pid_t pid, const struct ucred *ucred, - const char *label, size_t label_len, + const char *label, const char *unit_id, ClientContext **ret) { - return client_context_get_internal(m, pid, ucred, label, label_len, unit_id, true, ret); + return client_context_get_internal(m, pid, ucred, label, unit_id, /* add_ref= */ true, ret); }; ClientContext *client_context_release(Manager *m, ClientContext *c) { @@ -829,7 +821,7 @@ void client_context_acquire_default(Manager *m) { .gid = getgid(), }; - r = client_context_acquire(m, ucred.pid, &ucred, NULL, 0, NULL, &m->my_context); + r = client_context_acquire(m, ucred.pid, &ucred, /* label= */ NULL, /* unit_id= */ NULL, &m->my_context); if (r < 0) log_ratelimit_warning_errno(r, JOURNAL_LOG_RATELIMIT, "Failed to acquire our own context, ignoring: %m"); @@ -839,7 +831,7 @@ void client_context_acquire_default(Manager *m) { /* Acquire PID1's context, but only if we are in non-namespaced mode, since PID 1 is only * going to log to the non-namespaced journal instance. */ - r = client_context_acquire(m, 1, NULL, NULL, 0, NULL, &m->pid1_context); + r = client_context_acquire(m, 1, /* ucred= */ NULL, /* label= */ NULL, /* unit_id= */ NULL, &m->pid1_context); if (r < 0) log_ratelimit_warning_errno(r, JOURNAL_LOG_RATELIMIT, "Failed to acquire PID1's context, ignoring: %m"); diff --git a/src/journal/journald-context.h b/src/journal/journald-context.h index e731b7c7257..22c544fa55f 100644 --- a/src/journal/journald-context.h +++ b/src/journal/journald-context.h @@ -39,7 +39,6 @@ typedef struct ClientContext { sd_id128_t invocation_id; char *label; - size_t label_size; int log_level_max; @@ -61,7 +60,7 @@ int client_context_get( Manager *m, pid_t pid, const struct ucred *ucred, - const char *label, size_t label_len, + const char *label, const char *unit_id, ClientContext **ret); @@ -69,7 +68,7 @@ int client_context_acquire( Manager *m, pid_t pid, const struct ucred *ucred, - const char *label, size_t label_len, + const char *label, const char *unit_id, ClientContext **ret); @@ -79,7 +78,7 @@ void client_context_maybe_refresh( Manager *m, ClientContext *c, const struct ucred *ucred, - const char *label, size_t label_size, + const char *label, const char *unit_id, usec_t timestamp); diff --git a/src/journal/journald-manager.c b/src/journal/journald-manager.c index 8ed31f0061d..8d95280fc61 100644 --- a/src/journal/journald-manager.c +++ b/src/journal/journald-manager.c @@ -56,6 +56,7 @@ #include "process-util.h" #include "rm-rf.h" #include "set.h" +#include "selinux-util.h" #include "signal-util.h" #include "socket-util.h" #include "stdio-util.h" @@ -1058,14 +1059,6 @@ static void manager_write_to_journal( iovec[n++] = IOVEC_MAKE_STRING(k); \ } -#define IOVEC_ADD_SIZED_FIELD(iovec, n, value, value_size, field) \ - if (value_size > 0) { \ - char *k; \ - k = newa(char, STRLEN(field "=") + value_size + 1); \ - *mempcpy_typesafe(stpcpy(k, field "="), value, value_size) = 0; \ - iovec[n++] = IOVEC_MAKE_STRING(k); \ - } - static void manager_dispatch_message_real( Manager *m, struct iovec *iovec, size_t n, size_t mm, @@ -1101,7 +1094,7 @@ static void manager_dispatch_message_real( cmdline1 = set_iovec_string_field(iovec, &n, "_CMDLINE=", c->cmdline); IOVEC_ADD_NUMERIC_FIELD(iovec, n, c->capability_quintet.effective, uint64_t, capability_is_set, "%" PRIx64, "_CAP_EFFECTIVE"); - IOVEC_ADD_SIZED_FIELD(iovec, n, c->label, c->label_size, "_SELINUX_CONTEXT"); + IOVEC_ADD_STRING_FIELD(iovec, n, c->label, "_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"); @@ -1123,7 +1116,7 @@ static void manager_dispatch_message_real( assert(n <= mm); - if (pid_is_valid(object_pid) && client_context_get(m, object_pid, NULL, NULL, 0, NULL, &o) >= 0) { + if (pid_is_valid(object_pid) && client_context_get(m, object_pid, /* ucred= */ NULL, /* label= */ NULL, /* unit_id= */ NULL, &o) >= 0) { IOVEC_ADD_NUMERIC_FIELD(iovec, n, o->pid, pid_t, pid_is_valid, PID_FMT, "OBJECT_PID"); IOVEC_ADD_NUMERIC_FIELD(iovec, n, o->uid, uid_t, uid_is_valid, UID_FMT, "OBJECT_UID"); @@ -1136,7 +1129,7 @@ static void manager_dispatch_message_real( cmdline2 = set_iovec_string_field(iovec, &n, "OBJECT_CMDLINE=", o->cmdline); IOVEC_ADD_NUMERIC_FIELD(iovec, n, o->capability_quintet.effective, uint64_t, capability_is_set, "%" PRIx64, "OBJECT_CAP_EFFECTIVE"); - IOVEC_ADD_SIZED_FIELD(iovec, n, o->label, o->label_size, "OBJECT_SELINUX_CONTEXT"); + IOVEC_ADD_STRING_FIELD(iovec, n, o->label, "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"); @@ -1482,12 +1475,12 @@ int manager_process_datagram( uint32_t revents, void *userdata) { - size_t label_len = 0, mm; + size_t mm; Manager *m = ASSERT_PTR(userdata); struct ucred *ucred = NULL; struct timeval tv_buf, *tv = NULL; struct cmsghdr *cmsg; - char *label = NULL; + _cleanup_free_ char *label = NULL; struct iovec iovec; ssize_t n; int *fds = NULL, v = 0; @@ -1561,10 +1554,11 @@ int manager_process_datagram( cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) { assert(!ucred); ucred = CMSG_TYPED_DATA(cmsg, struct ucred); - } else if (cmsg->cmsg_type == SCM_SECURITY) { + } else if (cmsg->cmsg_type == SCM_SECURITY && mac_selinux_use()) { assert(!label); - label = CMSG_TYPED_DATA(cmsg, char); - label_len = cmsg->cmsg_len - CMSG_LEN(0); + /* Here, we ignore any errors including OOM, as the field is optional. */ + (void) make_cstring(CMSG_TYPED_DATA(cmsg, char), cmsg->cmsg_len - CMSG_LEN(0), + MAKE_CSTRING_ALLOW_TRAILING_NUL, &label); } else if (cmsg->cmsg_type == SCM_TIMESTAMP && cmsg->cmsg_len == CMSG_LEN(sizeof(struct timeval))) { assert(!tv); @@ -1581,7 +1575,7 @@ int manager_process_datagram( if (fd == m->syslog_fd) { if (n > 0 && n_fds == 0) - manager_process_syslog_message(m, m->buffer, n, ucred, tv, label, label_len); + manager_process_syslog_message(m, m->buffer, n, ucred, tv, label); else if (n_fds > 0) log_ratelimit_warning(JOURNAL_LOG_RATELIMIT, "Got file descriptors via syslog socket. Ignoring."); @@ -1591,9 +1585,9 @@ int manager_process_datagram( } else if (fd == m->native_fd) { if (n > 0 && n_fds == 0) - manager_process_native_message(m, m->buffer, n, ucred, tv, label, label_len); + manager_process_native_message(m, m->buffer, n, ucred, tv, label); else if (n == 0 && n_fds == 1) - (void) manager_process_native_file(m, fds[0], ucred, tv, label, label_len); + (void) manager_process_native_file(m, fds[0], ucred, tv, label); else if (n_fds > 0) log_ratelimit_warning(JOURNAL_LOG_RATELIMIT, "Got too many file descriptors via native socket. Ignoring."); diff --git a/src/journal/journald-native.c b/src/journal/journald-native.c index d9c6fad4f63..25b842a58ff 100644 --- a/src/journal/journald-native.c +++ b/src/journal/journald-native.c @@ -98,7 +98,7 @@ static int manager_process_entry( ClientContext *context, const struct ucred *ucred, const struct timeval *tv, - const char *label, size_t label_len) { + const char *label) { /* Process a single entry from a native message. Returns 0 if nothing special happened and the message * processing should continue, and a negative or positive value otherwise. @@ -304,7 +304,7 @@ void manager_process_native_message( const char *buffer, size_t buffer_size, const struct ucred *ucred, const struct timeval *tv, - const char *label, size_t label_len) { + const char *label) { size_t remaining = buffer_size; ClientContext *context = NULL; @@ -314,7 +314,7 @@ void manager_process_native_message( assert(buffer || buffer_size == 0); if (ucred && pid_is_valid(ucred->pid)) { - r = client_context_get(m, ucred->pid, ucred, label, label_len, NULL, &context); + r = client_context_get(m, ucred->pid, ucred, label, /* unit_id= */ NULL, &context); if (r < 0) log_ratelimit_warning_errno(r, JOURNAL_LOG_RATELIMIT, "Failed to retrieve credentials for PID " PID_FMT ", ignoring: %m", @@ -324,7 +324,7 @@ void manager_process_native_message( do { r = manager_process_entry(m, (const uint8_t*) buffer + (buffer_size - remaining), &remaining, - context, ucred, tv, label, label_len); + context, ucred, tv, label); } while (r == 0); } @@ -333,7 +333,7 @@ int manager_process_native_file( int fd, const struct ucred *ucred, const struct timeval *tv, - const char *label, size_t label_len) { + const char *label) { struct stat st; bool sealed; @@ -410,7 +410,7 @@ int manager_process_native_file( return log_ratelimit_error_errno(errno, JOURNAL_LOG_RATELIMIT, "Failed to map memfd: %m"); - manager_process_native_message(m, p, st.st_size, ucred, tv, label, label_len); + manager_process_native_message(m, p, st.st_size, ucred, tv, label); assert_se(munmap(p, ps) >= 0); return 0; @@ -451,7 +451,7 @@ int manager_process_native_file( return log_ratelimit_error_errno(errno, JOURNAL_LOG_RATELIMIT, "Failed to read file: %m"); if (n > 0) - manager_process_native_message(m, p, n, ucred, tv, label, label_len); + manager_process_native_message(m, p, n, ucred, tv, label); return 0; } diff --git a/src/journal/journald-native.h b/src/journal/journald-native.h index 6c44ddac763..9bda5d1b9e7 100644 --- a/src/journal/journald-native.h +++ b/src/journal/journald-native.h @@ -9,15 +9,13 @@ void manager_process_native_message( size_t buffer_size, const struct ucred *ucred, const struct timeval *tv, - const char *label, - size_t label_len); + const char *label); int manager_process_native_file( Manager *m, int fd, const struct ucred *ucred, const struct timeval *tv, - const char *label, - size_t label_len); + const char *label); int manager_open_native_socket(Manager *m, const char *native_socket); diff --git a/src/journal/journald-stream.c b/src/journal/journald-stream.c index 00b1fa2e423..677fb93b759 100644 --- a/src/journal/journald-stream.c +++ b/src/journal/journald-stream.c @@ -228,9 +228,9 @@ static int stdout_stream_log( assert(line_break < _LINE_BREAK_MAX); if (s->context) - client_context_maybe_refresh(s->manager, s->context, NULL, NULL, 0, NULL, USEC_INFINITY); + client_context_maybe_refresh(s->manager, s->context, /* ucred= */ NULL, /* label= */ NULL, /* unit_id= */ NULL, USEC_INFINITY); else if (pid_is_valid(s->ucred.pid)) { - r = client_context_acquire(s->manager, s->ucred.pid, &s->ucred, s->label, strlen_ptr(s->label), s->unit_id, &s->context); + r = client_context_acquire(s->manager, s->ucred.pid, &s->ucred, s->label, s->unit_id, &s->context); if (r < 0) log_ratelimit_warning_errno(r, JOURNAL_LOG_RATELIMIT, "Failed to acquire client context, ignoring: %m"); diff --git a/src/journal/journald-syslog.c b/src/journal/journald-syslog.c index 277146d5932..7f893738001 100644 --- a/src/journal/journald-syslog.c +++ b/src/journal/journald-syslog.c @@ -328,8 +328,7 @@ void manager_process_syslog_message( size_t raw_len, const struct ucred *ucred, const struct timeval *tv, - const char *label, - size_t label_len) { + const char *label) { char *t, syslog_priority[STRLEN("PRIORITY=") + DECIMAL_STR_MAX(int)], syslog_facility[STRLEN("SYSLOG_FACILITY=") + DECIMAL_STR_MAX(int)]; @@ -351,7 +350,7 @@ void manager_process_syslog_message( assert(buf[raw_len] == '\0'); if (ucred && pid_is_valid(ucred->pid)) { - r = client_context_get(m, ucred->pid, ucred, label, label_len, NULL, &context); + r = client_context_get(m, ucred->pid, ucred, label, /* unit_id= */ NULL, &context); if (r < 0) log_ratelimit_warning_errno(r, JOURNAL_LOG_RATELIMIT, "Failed to retrieve credentials for PID " PID_FMT ", ignoring: %m", diff --git a/src/journal/journald-syslog.h b/src/journal/journald-syslog.h index 6c016dc2bd3..896f950c38f 100644 --- a/src/journal/journald-syslog.h +++ b/src/journal/journald-syslog.h @@ -9,7 +9,7 @@ size_t syslog_parse_identifier(const char **buf, char **identifier, char **pid); void manager_forward_syslog(Manager *m, int priority, const char *identifier, const char *message, const struct ucred *ucred, const struct timeval *tv); -void manager_process_syslog_message(Manager *m, const char *buf, size_t raw_len, const struct ucred *ucred, const struct timeval *tv, const char *label, size_t label_len); +void manager_process_syslog_message(Manager *m, const char *buf, size_t raw_len, const struct ucred *ucred, const struct timeval *tv, const char *label); int manager_open_syslog_socket(Manager *m, const char *syslog_socket); void manager_maybe_warn_forward_syslog_missed(Manager *m);