| 1 | |
| 2 |
|
| 3 | |
| 4 | * Copyright (c) 2025, Google LLC.
|
| 5 | * Pasha Tatashin <[email protected]>
|
| 6 | *
|
| 7 | * A selftest to validate the end-to-end lifecycle of multiple LUO sessions
|
| 8 | * across a kexec reboot, including empty sessions and sessions with multiple
|
| 9 | * files.
|
| 10 |
|
| 11 |
|
| 12 | #include <libliveupdate.h>
|
| 13 |
|
| 14 | #define SESSION_EMPTY_1 "multi-test-empty-1"
|
| 15 | #define SESSION_EMPTY_2 "multi-test-empty-2"
|
| 16 | #define SESSION_FILES_1 "multi-test-files-1"
|
| 17 | #define SESSION_FILES_2 "multi-test-files-2"
|
| 18 |
|
| 19 | #define MFD1_TOKEN 0x1001
|
| 20 | #define MFD2_TOKEN 0x2002
|
| 21 | #define MFD3_TOKEN 0x3003
|
| 22 |
|
| 23 | #define MFD1_DATA "Data for session files 1"
|
| 24 | #define MFD2_DATA "First file for session files 2"
|
| 25 | #define MFD3_DATA "Second file for session files 2"
|
| 26 |
|
| 27 | #define STATE_SESSION_NAME "kexec_multi_state"
|
| 28 | #define STATE_MEMFD_TOKEN 998
|
| 29 |
|
| 30 |
|
| 31 | static void run_stage_1(int luo_fd)
|
| 32 | {
|
| 33 | int s_empty1_fd, s_empty2_fd, s_files1_fd, s_files2_fd;
|
| 34 |
|
| 35 | ksft_print_msg("[STAGE 1] Starting pre-kexec setup for multi-session test...\n");
|
| 36 |
|
| 37 | ksft_print_msg("[STAGE 1] Creating state file for next stage (2)...\n");
|
| 38 | create_state_file(luo_fd, STATE_SESSION_NAME, STATE_MEMFD_TOKEN, 2);
|
| 39 |
|
| 40 | ksft_print_msg("[STAGE 1] Creating empty sessions '%s' and '%s'...\n",
|
| 41 | SESSION_EMPTY_1, SESSION_EMPTY_2);
|
| 42 | s_empty1_fd = luo_create_session(luo_fd, SESSION_EMPTY_1);
|
| 43 | if (s_empty1_fd < 0)
|
| 44 | fail_exit("luo_create_session for '%s'", SESSION_EMPTY_1);
|
| 45 |
|
| 46 | s_empty2_fd = luo_create_session(luo_fd, SESSION_EMPTY_2);
|
| 47 | if (s_empty2_fd < 0)
|
| 48 | fail_exit("luo_create_session for '%s'", SESSION_EMPTY_2);
|
| 49 |
|
| 50 | ksft_print_msg("[STAGE 1] Creating session '%s' with one memfd...\n",
|
| 51 | SESSION_FILES_1);
|
| 52 |
|
| 53 | s_files1_fd = luo_create_session(luo_fd, SESSION_FILES_1);
|
| 54 | if (s_files1_fd < 0)
|
| 55 | fail_exit("luo_create_session for '%s'", SESSION_FILES_1);
|
| 56 | if (create_and_preserve_memfd(s_files1_fd, MFD1_TOKEN, MFD1_DATA) < 0) {
|
| 57 | fail_exit("create_and_preserve_memfd for token %#x",
|
| 58 | MFD1_TOKEN);
|
| 59 | }
|
| 60 |
|
| 61 | ksft_print_msg("[STAGE 1] Creating session '%s' with two memfds...\n",
|
| 62 | SESSION_FILES_2);
|
| 63 |
|
| 64 | s_files2_fd = luo_create_session(luo_fd, SESSION_FILES_2);
|
| 65 | if (s_files2_fd < 0)
|
| 66 | fail_exit("luo_create_session for '%s'", SESSION_FILES_2);
|
| 67 | if (create_and_preserve_memfd(s_files2_fd, MFD2_TOKEN, MFD2_DATA) < 0) {
|
| 68 | fail_exit("create_and_preserve_memfd for token %#x",
|
| 69 | MFD2_TOKEN);
|
| 70 | }
|
| 71 | if (create_and_preserve_memfd(s_files2_fd, MFD3_TOKEN, MFD3_DATA) < 0) {
|
| 72 | fail_exit("create_and_preserve_memfd for token %#x",
|
| 73 | MFD3_TOKEN);
|
| 74 | }
|
| 75 |
|
| 76 | close(luo_fd);
|
| 77 | daemonize_and_wait();
|
| 78 | }
|
| 79 |
|
| 80 |
|
| 81 | static void run_stage_2(int luo_fd, int state_session_fd)
|
| 82 | {
|
| 83 | int s_empty1_fd, s_empty2_fd, s_files1_fd, s_files2_fd;
|
| 84 | int mfd1, mfd2, mfd3, stage;
|
| 85 |
|
| 86 | ksft_print_msg("[STAGE 2] Starting post-kexec verification...\n");
|
| 87 |
|
| 88 | restore_and_read_stage(state_session_fd, STATE_MEMFD_TOKEN, &stage);
|
| 89 | if (stage != 2) {
|
| 90 | fail_exit("Expected stage 2, but state file contains %d",
|
| 91 | stage);
|
| 92 | }
|
| 93 |
|
| 94 | ksft_print_msg("[STAGE 2] Retrieving all sessions...\n");
|
| 95 | s_empty1_fd = luo_retrieve_session(luo_fd, SESSION_EMPTY_1);
|
| 96 | if (s_empty1_fd < 0)
|
| 97 | fail_exit("luo_retrieve_session for '%s'", SESSION_EMPTY_1);
|
| 98 |
|
| 99 | s_empty2_fd = luo_retrieve_session(luo_fd, SESSION_EMPTY_2);
|
| 100 | if (s_empty2_fd < 0)
|
| 101 | fail_exit("luo_retrieve_session for '%s'", SESSION_EMPTY_2);
|
| 102 |
|
| 103 | s_files1_fd = luo_retrieve_session(luo_fd, SESSION_FILES_1);
|
| 104 | if (s_files1_fd < 0)
|
| 105 | fail_exit("luo_retrieve_session for '%s'", SESSION_FILES_1);
|
| 106 |
|
| 107 | s_files2_fd = luo_retrieve_session(luo_fd, SESSION_FILES_2);
|
| 108 | if (s_files2_fd < 0)
|
| 109 | fail_exit("luo_retrieve_session for '%s'", SESSION_FILES_2);
|
| 110 |
|
| 111 | ksft_print_msg("[STAGE 2] Verifying contents of session '%s'...\n",
|
| 112 | SESSION_FILES_1);
|
| 113 | mfd1 = restore_and_verify_memfd(s_files1_fd, MFD1_TOKEN, MFD1_DATA);
|
| 114 | if (mfd1 < 0)
|
| 115 | fail_exit("restore_and_verify_memfd for token %#x", MFD1_TOKEN);
|
| 116 | close(mfd1);
|
| 117 |
|
| 118 | ksft_print_msg("[STAGE 2] Verifying contents of session '%s'...\n",
|
| 119 | SESSION_FILES_2);
|
| 120 |
|
| 121 | mfd2 = restore_and_verify_memfd(s_files2_fd, MFD2_TOKEN, MFD2_DATA);
|
| 122 | if (mfd2 < 0)
|
| 123 | fail_exit("restore_and_verify_memfd for token %#x", MFD2_TOKEN);
|
| 124 | close(mfd2);
|
| 125 |
|
| 126 | mfd3 = restore_and_verify_memfd(s_files2_fd, MFD3_TOKEN, MFD3_DATA);
|
| 127 | if (mfd3 < 0)
|
| 128 | fail_exit("restore_and_verify_memfd for token %#x", MFD3_TOKEN);
|
| 129 | close(mfd3);
|
| 130 |
|
| 131 | ksft_print_msg("[STAGE 2] Test data verified successfully.\n");
|
| 132 |
|
| 133 | ksft_print_msg("[STAGE 2] Finalizing all test sessions...\n");
|
| 134 | if (luo_session_finish(s_empty1_fd) < 0)
|
| 135 | fail_exit("luo_session_finish for '%s'", SESSION_EMPTY_1);
|
| 136 | close(s_empty1_fd);
|
| 137 |
|
| 138 | if (luo_session_finish(s_empty2_fd) < 0)
|
| 139 | fail_exit("luo_session_finish for '%s'", SESSION_EMPTY_2);
|
| 140 | close(s_empty2_fd);
|
| 141 |
|
| 142 | if (luo_session_finish(s_files1_fd) < 0)
|
| 143 | fail_exit("luo_session_finish for '%s'", SESSION_FILES_1);
|
| 144 | close(s_files1_fd);
|
| 145 |
|
| 146 | if (luo_session_finish(s_files2_fd) < 0)
|
| 147 | fail_exit("luo_session_finish for '%s'", SESSION_FILES_2);
|
| 148 | close(s_files2_fd);
|
| 149 |
|
| 150 | ksft_print_msg("[STAGE 2] Finalizing state session...\n");
|
| 151 | if (luo_session_finish(state_session_fd) < 0)
|
| 152 | fail_exit("luo_session_finish for state session");
|
| 153 | close(state_session_fd);
|
| 154 |
|
| 155 | ksft_print_msg("\n--- MULTI-SESSION KEXEC TEST PASSED ---\n");
|
| 156 | }
|
| 157 |
|
| 158 | int main(int argc, char *argv[])
|
| 159 | {
|
| 160 | return luo_test(argc, argv, STATE_SESSION_NAME,
|
| 161 | run_stage_1, run_stage_2);
|
| 162 | }
|