]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
liveupdate: safely print untrusted strings
authorPasha Tatashin <pasha.tatashin@soleen.com>
Fri, 27 Mar 2026 03:33:25 +0000 (03:33 +0000)
committerAndrew Morton <akpm@linux-foundation.org>
Sat, 18 Apr 2026 07:10:49 +0000 (00:10 -0700)
Patch series "liveupdate: Fix module unloading and unregister API", v3.

This patch series addresses an issue with how LUO handles module reference
counting and unregistration during a module unload (e.g., via rmmod).

Currently, modules that register live update file handlers are pinned for
the entire duration they are registered.  This prevents the modules from
being unloaded gracefully, even when no live update session is in
progress.

Furthermore, if a module is forcefully unloaded, the unregistration
functions return an error (e.g.  -EBUSY) if a session is active, which is
ignored by the kernel's module unload path, leaving dangling pointers in
the LUO global lists.

To resolve these issues, this series introduces the following changes:
1. Adds a global read-write semaphore (luo_register_rwlock) to protect
   the registration lists for both file handlers and FLBs.
2. Reduces the scope of module reference counting for file handlers and
   FLBs. Instead of pinning modules indefinitely upon registration,
   references are now taken only when they are actively used in a live
   update session (e.g., during preservation, retrieval, or
   deserialization).
3. Removes the global luo_session_quiesce() mechanism since module
   unload behavior now handles active sessions implicitly.
4. Introduces auto-unregistration of FLBs during file handler
   unregistration to prevent leaving dangling resources.
5. Changes the unregistration functions to return void instead of
   an error code.
6. Fixes a data race in luo_flb_get_private() by introducing a spinlock
   for thread-safe lazy initialization.
7. Strengthens security by using %.*s when printing untrusted deserialized
   compatible strings and session names to prevent out-of-bounds reads.

This patch (of 10):

Deserialized strings from KHO data (such as file handler compatible
strings and session names) are provided by the previous kernel and might
not be null-terminated if the data is corrupted or maliciously crafted.

When printing these strings in error messages, use the %.*s format
specifier with the maximum buffer size to prevent out-of-bounds reads into
adjacent kernel memory.

Link: https://lore.kernel.org/20260327033335.696621-1-pasha.tatashin@soleen.com
Link: https://lore.kernel.org/20260327033335.696621-2-pasha.tatashin@soleen.com
Signed-off-by: Pasha Tatashin <pasha.tatashin@soleen.com>
Reviewed-by: Pratyush Yadav (Google) <pratyush@kernel.org>
Cc: David Matlack <dmatlack@google.com>
Cc: Mike Rapoport <rppt@kernel.org>
Cc: Samiullah Khawaja <skhawaja@google.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
kernel/liveupdate/luo_file.c
kernel/liveupdate/luo_session.c

index 09103cf81107bb4718e7b3d202001f1eff4c0f0a..8fcf302c73b656178f3ab4bb32ea8845cfda9acf 100644 (file)
@@ -813,7 +813,8 @@ int luo_file_deserialize(struct luo_file_set *file_set,
                }
 
                if (!handler_found) {
-                       pr_warn("No registered handler for compatible '%s'\n",
+                       pr_warn("No registered handler for compatible '%.*s'\n",
+                               (int)sizeof(file_ser[i].compatible),
                                file_ser[i].compatible);
                        return -ENOENT;
                }
index 7836772956406796db05722afe43ed35745078d1..c68a0041bcf227cb3d9d8a7e548a5a4697ecd40b 100644 (file)
@@ -544,7 +544,8 @@ int luo_session_deserialize(void)
 
                session = luo_session_alloc(sh->ser[i].name);
                if (IS_ERR(session)) {
-                       pr_warn("Failed to allocate session [%s] during deserialization %pe\n",
+                       pr_warn("Failed to allocate session [%.*s] during deserialization %pe\n",
+                               (int)sizeof(sh->ser[i].name),
                                sh->ser[i].name, session);
                        return PTR_ERR(session);
                }