]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
journal: make security label always NUL-terminated
authorYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 28 Jan 2026 03:20:07 +0000 (12:20 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 3 Feb 2026 12:43:17 +0000 (21:43 +0900)
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.

src/journal/fuzz-journald-native-fd.c
src/journal/fuzz-journald-util.c
src/journal/fuzz-journald-util.h
src/journal/journald-context.c
src/journal/journald-context.h
src/journal/journald-manager.c
src/journal/journald-native.c
src/journal/journald-native.h
src/journal/journald-stream.c
src/journal/journald-syslog.c
src/journal/journald-syslog.h

index 36a94b7b92144e39af5f326d22827ef1ec2195e4..66afd97049369e4b6bce5b245b2e4ac76ad59a84 100644 (file)
@@ -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;
 }
index 7080b9412d9c792f5885cb9f2fc155c0a7e59c96..99f11e4c4252383023688e1e460b5b8f4e511d43 100644 (file)
@@ -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);
 }
index 7eb491f36adf938344cd69bbfeb1d780cb7e41dd..0f9b2812e4ef04d62daf3b5b0a7b189617219c6d 100644 (file)
@@ -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);
 
index 5889adc2cec6b87aa96eb18a711bcc5d07aae153..1eb142887d749f54844dfa5e4e9de9cb05a89f81 100644 (file)
@@ -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");
index e731b7c72578dc42c514cc9d8ed43e74b86b66a5..22c544fa55fb766ff4d1f2f5fe2d0ecf78b53890 100644 (file)
@@ -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);
 
index 8ed31f0061d279cc90a213166f3710900114a31c..8d95280fc61c78ee56f2afe5b11f4c8a4e89db28 100644 (file)
@@ -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.");
index d9c6fad4f63509e354f2521246ba3f5e89cff355..25b842a58ffc897981b8ebd86a408a34ed92138d 100644 (file)
@@ -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;
 }
index 6c44ddac7637c80bca7ea85e24ffd383899ea168..9bda5d1b9e723d1dc64282cba0115dab1f910785 100644 (file)
@@ -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);
index 00b1fa2e423bb44cec45059a3e9ac8312101150f..677fb93b7597f538b311eec752187813d4ca6772 100644 (file)
@@ -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");
index 277146d5932c93c8d27b1e45b2881d01512a1496..7f89373800133f2e35e8beb18a7744bc0eba1db9 100644 (file)
@@ -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",
index 6c016dc2bd32589d5346f6d684eebcafda8ff164..896f950c38f913aab6c7b2a08e186a9c4fec4041 100644 (file)
@@ -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);