From: Luca Boccassi Date: Tue, 7 Jul 2026 10:58:14 +0000 (+0100) Subject: journald: pin the sending client's context across native message dispatch X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=0b4a90765cf034a6c1f9c7967637a98e351c7d56;p=thirdparty%2Fsystemd.git journald: pin the sending client's context across native message dispatch manager_process_native_message() looks up the sender's ClientContext with client_context_get(), which does not pin it. A native message may carry an OBJECT_PID=, which makes manager_dispatch_message_real() perform a nested client_context_get() for that PID. On a cache miss this runs client_context_try_shrink_to(), whose pid-flush branch frees every unpinned cache entry whose PID has already been reaped, including the borrowed sender context. manager_dispatch_message_real() then keeps using it (it reads c->uid, and the built iovecs still alias the context's fields). Pin the sender context with client_context_acquire() for the duration of the dispatch and release it afterwards, mirroring what the stdout stream path already does. Follow-up for 22e3a02b9d618bbebcf987bc1411acda367271ec --- diff --git a/src/journal/journald-native.c b/src/journal/journald-native.c index 1c36ca9434f..01e7d65453d 100644 --- a/src/journal/journald-native.c +++ b/src/journal/journald-native.c @@ -319,7 +319,10 @@ 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, /* unit_id= */ NULL, &context); + /* Pin the sender's context for the whole dispatch below, as processing an entry may look up + * further contexts (e.g. for an OBJECT_PID=), which can flush already reaped entries from + * the cache */ + r = client_context_acquire(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", @@ -331,6 +334,8 @@ void manager_process_native_message( (const uint8_t*) buffer + (buffer_size - remaining), &remaining, context, ucred, tv, label); } while (r == 0); + + client_context_release(m, context); } static size_t entry_size_max_by_ucred(Manager *m, const struct ucred *ucred, const char *label) {