From 531fe59e3d8a75f9b19379a6abdf2768c345de28 Mon Sep 17 00:00:00 2001 From: Yury Kirsanov Date: Sat, 25 Jul 2026 16:46:51 +1000 Subject: [PATCH] core: do not crash setting the log level before the process table exists set_proc_log_level() and reset_proc_log_level() segfault when called from a module's mod_init(). init_modules() runs several steps before init_multi_proc_support(), so pt is still NULL, and __set_proc_log_level() writes pt[proc_idx].log_level unconditionally. reset_proc_log_level() fails the same way one level down: default_log_level is a static pointer that init_log_level() has not filled in yet, so it dereferences NULL. This is easy to hit. Temporarily lowering the log level around a call that is expected to fail is the natural way for a module to keep an expected error out of its startup output, and the API gives no hint that it is unusable at the point most modules would reach for it. Guards each of the affected setters. Where the intent can still be honoured it is, rather than silently dropping the request: log_level already points at the static holder before init_log_level() runs, and there is only one process at that stage, so __set_proc_log_level() sets the level through it and reset_proc_log_level() restores the value logging started with. __set_proc_default_log_level() updates that same holder. set_global_log_level() additionally guards log_level_global, which init_log_level() allocates - before that, counted_max_processes is 0 so its loop is a no-op and the shared value does not exist yet, so it applies the level to the current process instead. suppress_proc_log_event() and reset_proc_log_event() return early: the event consumer they guard is not running yet either. Verified by calling set_proc_log_level() followed by reset_proc_log_level() from a module mod_init(): the same module segfaults on an unpatched core and starts normally on a patched one. --- dprint.c | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/dprint.c b/dprint.c index f3885cb0fd4..e657a0ca712 100644 --- a/dprint.c +++ b/dprint.c @@ -944,6 +944,14 @@ void cleanup_log_level(void) void reset_proc_log_level(void) { + /* Before init_log_level() runs - e.g. from a module's mod_init(), which + * is invoked well before init_multi_proc_support() - default_log_level + * is still NULL, so fall back to the value logging started with. */ + if (!default_log_level) { + *log_level = log_level_holder; + return; + } + *log_level = *default_log_level; } @@ -954,11 +962,26 @@ void reset_proc_log_level(void) */ void __set_proc_log_level(int proc_idx, int level) { + /* The process table is allocated by init_multi_proc_support(), which runs + * after init_modules() - so pt is NULL during every module's mod_init(). + * There is only one process at that point and log_level already points at + * the static holder, so honour the request instead of crashing. */ + if (!pt) { + *log_level = level; + return; + } + pt[proc_idx].log_level = level; } void __set_proc_default_log_level(int proc_idx, int level) { + /* see __set_proc_log_level() - pt does not exist yet during mod_init() */ + if (!pt) { + log_level_holder = level; + return; + } + pt[proc_idx].default_log_level = level; } @@ -971,6 +994,16 @@ void set_global_log_level(int level) __set_proc_default_log_level(i, level); __set_proc_log_level(i, level); } + + /* allocated by init_log_level(); before that there is nothing shared to + * update, and counted_max_processes is still 0 so the loop above was a + * no-op - apply the level to this process instead */ + if (!log_level_global) { + __set_proc_default_log_level(0, level); + __set_proc_log_level(0, level); + return; + } + *log_level_global = level; } @@ -982,10 +1015,18 @@ void set_proc_log_level(int level) void suppress_proc_log_event(void) { + /* no process table yet (mod_init) - nothing to suppress, and the event + * consumer it guards is not running either */ + if (!pt) + return; + pt[process_no].suppress_log_event = 1; } void reset_proc_log_event(void) { + if (!pt) + return; + pt[process_no].suppress_log_event = 0; }