luo_session_deserialize() calls luo_file_deserialize() but ignores its return value. If file restore fails part-way through, the incoming session still gets inserted and the caller still sees success. Leaving a partially restored session on the incoming list is dangerous because later retrieve or finish operations can walk half-built file state and operate on uninitialized or stale entries. Propagate file deserialization failures back to session restore, remove the partially restored session, and free any struct luo_file objects that were already allocated before returning the error. Signed-off-by: Oskar Gerlicz Kowalczuk --- kernel/liveupdate/luo_file.c | 45 ++++++++++++++++++++------------- kernel/liveupdate/luo_session.c | 27 +++++++------------- 2 files changed, 36 insertions(+), 36 deletions(-) diff --git a/kernel/liveupdate/luo_file.c b/kernel/liveupdate/luo_file.c index 5acee4174bf0..cc0fd7e9c332 100644 --- a/kernel/liveupdate/luo_file.c +++ b/kernel/liveupdate/luo_file.c @@ -717,6 +717,22 @@ int luo_file_finish(struct luo_file_set *file_set) return 0; } +static void luo_file_discard_deserialized(struct luo_file_set *file_set) +{ + struct luo_file *luo_file; + + while (!list_empty(&file_set->files_list)) { + luo_file = list_last_entry(&file_set->files_list, + struct luo_file, list); + list_del(&luo_file->list); + mutex_destroy(&luo_file->mutex); + kfree(luo_file); + } + + file_set->count = 0; + file_set->files = NULL; +} + /** * luo_file_deserialize - Reconstructs the list of preserved files in the new kernel. * @file_set: The incoming file_set to fill with deserialized data. @@ -747,6 +763,7 @@ int luo_file_deserialize(struct luo_file_set *file_set, { struct luo_file_ser *file_ser; u64 i; + int err; if (!file_set_ser->files) { WARN_ON(file_set_ser->count); @@ -756,21 +773,6 @@ int luo_file_deserialize(struct luo_file_set *file_set, file_set->count = file_set_ser->count; file_set->files = phys_to_virt(file_set_ser->files); - /* - * Note on error handling: - * - * If deserialization fails (e.g., allocation failure or corrupt data), - * we intentionally skip cleanup of files that were already restored. - * - * A partial failure leaves the preserved state inconsistent. - * Implementing a safe "undo" to unwind complex dependencies (sessions, - * files, hardware state) is error-prone and provides little value, as - * the system is effectively in a broken state. - * - * We treat these resources as leaked. The expected recovery path is for - * userspace to detect the failure and trigger a reboot, which will - * reliably reset devices and reclaim memory. - */ file_ser = file_set->files; for (i = 0; i < file_set->count; i++) { struct liveupdate_file_handler *fh; @@ -787,12 +789,15 @@ int luo_file_deserialize(struct luo_file_set *file_set, if (!handler_found) { pr_warn("No registered handler for compatible '%s'\n", file_ser[i].compatible); - return -ENOENT; + err = -ENOENT; + goto err_discard; } luo_file = kzalloc_obj(*luo_file); - if (!luo_file) - return -ENOMEM; + if (!luo_file) { + err = -ENOMEM; + goto err_discard; + } luo_file->fh = fh; luo_file->file = NULL; @@ -803,6 +808,10 @@ int luo_file_deserialize(struct luo_file_set *file_set, } return 0; + +err_discard: + luo_file_discard_deserialized(file_set); + return err; } void luo_file_set_init(struct luo_file_set *file_set) diff --git a/kernel/liveupdate/luo_session.c b/kernel/liveupdate/luo_session.c index 39215e5eda7a..77afa913d6c7 100644 --- a/kernel/liveupdate/luo_session.c +++ b/kernel/liveupdate/luo_session.c @@ -565,21 +565,6 @@ int luo_session_deserialize(void) if (!sh->active) return 0; - /* - * Note on error handling: - * - * If deserialization fails (e.g., allocation failure or corrupt data), - * we intentionally skip cleanup of sessions that were already restored. - * - * A partial failure leaves the preserved state inconsistent. - * Implementing a safe "undo" to unwind complex dependencies (sessions, - * files, hardware state) is error-prone and provides little value, as - * the system is effectively in a broken state. - * - * We treat these resources as leaked. The expected recovery path is for - * userspace to detect the failure and trigger a reboot, which will - * reliably reset devices and reclaim memory. - */ for (int i = 0; i < sh->header_ser->count; i++) { struct luo_session *session; @@ -598,9 +583,15 @@ int luo_session_deserialize(void) return err; } - scoped_guard(mutex, &session->mutex) { - luo_file_deserialize(&session->file_set, - &sh->ser[i].file_set_ser); + scoped_guard(mutex, &session->mutex) + err = luo_file_deserialize(&session->file_set, + &sh->ser[i].file_set_ser); + if (err) { + pr_warn("Failed to deserialize session [%s] files %pe\n", + session->name, ERR_PTR(err)); + luo_session_remove(sh, session); + luo_session_free(session); + return err; } } -- 2.53.0