David Brazdil | 0f672f6 | 2019-12-10 10:32:29 +0000 | [diff] [blame] | 1 | #!/bin/bash |
| 2 | # SPDX-License-Identifier: GPL-2.0 |
| 3 | # Copyright (C) 2018 Joe Lawrence <joe.lawrence@redhat.com> |
| 4 | |
| 5 | . $(dirname $0)/functions.sh |
| 6 | |
| 7 | MOD_LIVEPATCH=test_klp_callbacks_demo |
| 8 | MOD_LIVEPATCH2=test_klp_callbacks_demo2 |
| 9 | MOD_TARGET=test_klp_callbacks_mod |
| 10 | MOD_TARGET_BUSY=test_klp_callbacks_busy |
| 11 | |
Olivier Deprez | 157378f | 2022-04-04 15:47:50 +0200 | [diff] [blame^] | 12 | setup_config |
David Brazdil | 0f672f6 | 2019-12-10 10:32:29 +0000 | [diff] [blame] | 13 | |
| 14 | |
David Brazdil | 0f672f6 | 2019-12-10 10:32:29 +0000 | [diff] [blame] | 15 | # Test a combination of loading a kernel module and a livepatch that |
| 16 | # patches a function in the first module. Load the target module |
| 17 | # before the livepatch module. Unload them in the same order. |
| 18 | # |
| 19 | # - On livepatch enable, before the livepatch transition starts, |
| 20 | # pre-patch callbacks are executed for vmlinux and $MOD_TARGET (those |
| 21 | # klp_objects currently loaded). After klp_objects are patched |
| 22 | # according to the klp_patch, their post-patch callbacks run and the |
| 23 | # transition completes. |
| 24 | # |
| 25 | # - Similarly, on livepatch disable, pre-patch callbacks run before the |
| 26 | # unpatching transition starts. klp_objects are reverted, post-patch |
| 27 | # callbacks execute and the transition completes. |
| 28 | |
Olivier Deprez | 157378f | 2022-04-04 15:47:50 +0200 | [diff] [blame^] | 29 | start_test "target module before livepatch" |
David Brazdil | 0f672f6 | 2019-12-10 10:32:29 +0000 | [diff] [blame] | 30 | |
| 31 | load_mod $MOD_TARGET |
| 32 | load_lp $MOD_LIVEPATCH |
| 33 | disable_lp $MOD_LIVEPATCH |
| 34 | unload_lp $MOD_LIVEPATCH |
| 35 | unload_mod $MOD_TARGET |
| 36 | |
| 37 | check_result "% modprobe $MOD_TARGET |
| 38 | $MOD_TARGET: ${MOD_TARGET}_init |
| 39 | % modprobe $MOD_LIVEPATCH |
| 40 | livepatch: enabling patch '$MOD_LIVEPATCH' |
| 41 | livepatch: '$MOD_LIVEPATCH': initializing patching transition |
| 42 | $MOD_LIVEPATCH: pre_patch_callback: vmlinux |
| 43 | $MOD_LIVEPATCH: pre_patch_callback: $MOD_TARGET -> [MODULE_STATE_LIVE] Normal state |
| 44 | livepatch: '$MOD_LIVEPATCH': starting patching transition |
| 45 | livepatch: '$MOD_LIVEPATCH': completing patching transition |
| 46 | $MOD_LIVEPATCH: post_patch_callback: vmlinux |
| 47 | $MOD_LIVEPATCH: post_patch_callback: $MOD_TARGET -> [MODULE_STATE_LIVE] Normal state |
| 48 | livepatch: '$MOD_LIVEPATCH': patching complete |
| 49 | % echo 0 > /sys/kernel/livepatch/$MOD_LIVEPATCH/enabled |
| 50 | livepatch: '$MOD_LIVEPATCH': initializing unpatching transition |
| 51 | $MOD_LIVEPATCH: pre_unpatch_callback: vmlinux |
| 52 | $MOD_LIVEPATCH: pre_unpatch_callback: $MOD_TARGET -> [MODULE_STATE_LIVE] Normal state |
| 53 | livepatch: '$MOD_LIVEPATCH': starting unpatching transition |
| 54 | livepatch: '$MOD_LIVEPATCH': completing unpatching transition |
| 55 | $MOD_LIVEPATCH: post_unpatch_callback: vmlinux |
| 56 | $MOD_LIVEPATCH: post_unpatch_callback: $MOD_TARGET -> [MODULE_STATE_LIVE] Normal state |
| 57 | livepatch: '$MOD_LIVEPATCH': unpatching complete |
| 58 | % rmmod $MOD_LIVEPATCH |
| 59 | % rmmod $MOD_TARGET |
| 60 | $MOD_TARGET: ${MOD_TARGET}_exit" |
| 61 | |
| 62 | |
David Brazdil | 0f672f6 | 2019-12-10 10:32:29 +0000 | [diff] [blame] | 63 | # This test is similar to the previous test, but (un)load the livepatch |
| 64 | # module before the target kernel module. This tests the livepatch |
| 65 | # core's module_coming handler. |
| 66 | # |
| 67 | # - On livepatch enable, only pre/post-patch callbacks are executed for |
| 68 | # currently loaded klp_objects, in this case, vmlinux. |
| 69 | # |
| 70 | # - When a targeted module is subsequently loaded, only its |
| 71 | # pre/post-patch callbacks are executed. |
| 72 | # |
| 73 | # - On livepatch disable, all currently loaded klp_objects' (vmlinux and |
| 74 | # $MOD_TARGET) pre/post-unpatch callbacks are executed. |
| 75 | |
Olivier Deprez | 157378f | 2022-04-04 15:47:50 +0200 | [diff] [blame^] | 76 | start_test "module_coming notifier" |
David Brazdil | 0f672f6 | 2019-12-10 10:32:29 +0000 | [diff] [blame] | 77 | |
| 78 | load_lp $MOD_LIVEPATCH |
| 79 | load_mod $MOD_TARGET |
| 80 | disable_lp $MOD_LIVEPATCH |
| 81 | unload_lp $MOD_LIVEPATCH |
| 82 | unload_mod $MOD_TARGET |
| 83 | |
| 84 | check_result "% modprobe $MOD_LIVEPATCH |
| 85 | livepatch: enabling patch '$MOD_LIVEPATCH' |
| 86 | livepatch: '$MOD_LIVEPATCH': initializing patching transition |
| 87 | $MOD_LIVEPATCH: pre_patch_callback: vmlinux |
| 88 | livepatch: '$MOD_LIVEPATCH': starting patching transition |
| 89 | livepatch: '$MOD_LIVEPATCH': completing patching transition |
| 90 | $MOD_LIVEPATCH: post_patch_callback: vmlinux |
| 91 | livepatch: '$MOD_LIVEPATCH': patching complete |
| 92 | % modprobe $MOD_TARGET |
| 93 | livepatch: applying patch '$MOD_LIVEPATCH' to loading module '$MOD_TARGET' |
| 94 | $MOD_LIVEPATCH: pre_patch_callback: $MOD_TARGET -> [MODULE_STATE_COMING] Full formed, running module_init |
| 95 | $MOD_LIVEPATCH: post_patch_callback: $MOD_TARGET -> [MODULE_STATE_COMING] Full formed, running module_init |
| 96 | $MOD_TARGET: ${MOD_TARGET}_init |
| 97 | % echo 0 > /sys/kernel/livepatch/$MOD_LIVEPATCH/enabled |
| 98 | livepatch: '$MOD_LIVEPATCH': initializing unpatching transition |
| 99 | $MOD_LIVEPATCH: pre_unpatch_callback: vmlinux |
| 100 | $MOD_LIVEPATCH: pre_unpatch_callback: $MOD_TARGET -> [MODULE_STATE_LIVE] Normal state |
| 101 | livepatch: '$MOD_LIVEPATCH': starting unpatching transition |
| 102 | livepatch: '$MOD_LIVEPATCH': completing unpatching transition |
| 103 | $MOD_LIVEPATCH: post_unpatch_callback: vmlinux |
| 104 | $MOD_LIVEPATCH: post_unpatch_callback: $MOD_TARGET -> [MODULE_STATE_LIVE] Normal state |
| 105 | livepatch: '$MOD_LIVEPATCH': unpatching complete |
| 106 | % rmmod $MOD_LIVEPATCH |
| 107 | % rmmod $MOD_TARGET |
| 108 | $MOD_TARGET: ${MOD_TARGET}_exit" |
| 109 | |
| 110 | |
David Brazdil | 0f672f6 | 2019-12-10 10:32:29 +0000 | [diff] [blame] | 111 | # Test loading the livepatch after a targeted kernel module, then unload |
| 112 | # the kernel module before disabling the livepatch. This tests the |
| 113 | # livepatch core's module_going handler. |
| 114 | # |
| 115 | # - First load a target module, then the livepatch. |
| 116 | # |
| 117 | # - When a target module is unloaded, the livepatch is only reverted |
| 118 | # from that klp_object ($MOD_TARGET). As such, only its pre and |
| 119 | # post-unpatch callbacks are executed when this occurs. |
| 120 | # |
| 121 | # - When the livepatch is disabled, pre and post-unpatch callbacks are |
| 122 | # run for the remaining klp_object, vmlinux. |
| 123 | |
Olivier Deprez | 157378f | 2022-04-04 15:47:50 +0200 | [diff] [blame^] | 124 | start_test "module_going notifier" |
David Brazdil | 0f672f6 | 2019-12-10 10:32:29 +0000 | [diff] [blame] | 125 | |
| 126 | load_mod $MOD_TARGET |
| 127 | load_lp $MOD_LIVEPATCH |
| 128 | unload_mod $MOD_TARGET |
| 129 | disable_lp $MOD_LIVEPATCH |
| 130 | unload_lp $MOD_LIVEPATCH |
| 131 | |
| 132 | check_result "% modprobe $MOD_TARGET |
| 133 | $MOD_TARGET: ${MOD_TARGET}_init |
| 134 | % modprobe $MOD_LIVEPATCH |
| 135 | livepatch: enabling patch '$MOD_LIVEPATCH' |
| 136 | livepatch: '$MOD_LIVEPATCH': initializing patching transition |
| 137 | $MOD_LIVEPATCH: pre_patch_callback: vmlinux |
| 138 | $MOD_LIVEPATCH: pre_patch_callback: $MOD_TARGET -> [MODULE_STATE_LIVE] Normal state |
| 139 | livepatch: '$MOD_LIVEPATCH': starting patching transition |
| 140 | livepatch: '$MOD_LIVEPATCH': completing patching transition |
| 141 | $MOD_LIVEPATCH: post_patch_callback: vmlinux |
| 142 | $MOD_LIVEPATCH: post_patch_callback: $MOD_TARGET -> [MODULE_STATE_LIVE] Normal state |
| 143 | livepatch: '$MOD_LIVEPATCH': patching complete |
| 144 | % rmmod $MOD_TARGET |
| 145 | $MOD_TARGET: ${MOD_TARGET}_exit |
| 146 | $MOD_LIVEPATCH: pre_unpatch_callback: $MOD_TARGET -> [MODULE_STATE_GOING] Going away |
| 147 | livepatch: reverting patch '$MOD_LIVEPATCH' on unloading module '$MOD_TARGET' |
| 148 | $MOD_LIVEPATCH: post_unpatch_callback: $MOD_TARGET -> [MODULE_STATE_GOING] Going away |
| 149 | % echo 0 > /sys/kernel/livepatch/$MOD_LIVEPATCH/enabled |
| 150 | livepatch: '$MOD_LIVEPATCH': initializing unpatching transition |
| 151 | $MOD_LIVEPATCH: pre_unpatch_callback: vmlinux |
| 152 | livepatch: '$MOD_LIVEPATCH': starting unpatching transition |
| 153 | livepatch: '$MOD_LIVEPATCH': completing unpatching transition |
| 154 | $MOD_LIVEPATCH: post_unpatch_callback: vmlinux |
| 155 | livepatch: '$MOD_LIVEPATCH': unpatching complete |
| 156 | % rmmod $MOD_LIVEPATCH" |
| 157 | |
| 158 | |
David Brazdil | 0f672f6 | 2019-12-10 10:32:29 +0000 | [diff] [blame] | 159 | # This test is similar to the previous test, however the livepatch is |
| 160 | # loaded first. This tests the livepatch core's module_coming and |
| 161 | # module_going handlers. |
| 162 | # |
| 163 | # - First load the livepatch. |
| 164 | # |
| 165 | # - When a targeted kernel module is subsequently loaded, only its |
| 166 | # pre/post-patch callbacks are executed. |
| 167 | # |
| 168 | # - When the target module is unloaded, the livepatch is only reverted |
| 169 | # from the $MOD_TARGET klp_object. As such, only pre and |
| 170 | # post-unpatch callbacks are executed when this occurs. |
| 171 | |
Olivier Deprez | 157378f | 2022-04-04 15:47:50 +0200 | [diff] [blame^] | 172 | start_test "module_coming and module_going notifiers" |
David Brazdil | 0f672f6 | 2019-12-10 10:32:29 +0000 | [diff] [blame] | 173 | |
| 174 | load_lp $MOD_LIVEPATCH |
| 175 | load_mod $MOD_TARGET |
| 176 | unload_mod $MOD_TARGET |
| 177 | disable_lp $MOD_LIVEPATCH |
| 178 | unload_lp $MOD_LIVEPATCH |
| 179 | |
| 180 | check_result "% modprobe $MOD_LIVEPATCH |
| 181 | livepatch: enabling patch '$MOD_LIVEPATCH' |
| 182 | livepatch: '$MOD_LIVEPATCH': initializing patching transition |
| 183 | $MOD_LIVEPATCH: pre_patch_callback: vmlinux |
| 184 | livepatch: '$MOD_LIVEPATCH': starting patching transition |
| 185 | livepatch: '$MOD_LIVEPATCH': completing patching transition |
| 186 | $MOD_LIVEPATCH: post_patch_callback: vmlinux |
| 187 | livepatch: '$MOD_LIVEPATCH': patching complete |
| 188 | % modprobe $MOD_TARGET |
| 189 | livepatch: applying patch '$MOD_LIVEPATCH' to loading module '$MOD_TARGET' |
| 190 | $MOD_LIVEPATCH: pre_patch_callback: $MOD_TARGET -> [MODULE_STATE_COMING] Full formed, running module_init |
| 191 | $MOD_LIVEPATCH: post_patch_callback: $MOD_TARGET -> [MODULE_STATE_COMING] Full formed, running module_init |
| 192 | $MOD_TARGET: ${MOD_TARGET}_init |
| 193 | % rmmod $MOD_TARGET |
| 194 | $MOD_TARGET: ${MOD_TARGET}_exit |
| 195 | $MOD_LIVEPATCH: pre_unpatch_callback: $MOD_TARGET -> [MODULE_STATE_GOING] Going away |
| 196 | livepatch: reverting patch '$MOD_LIVEPATCH' on unloading module '$MOD_TARGET' |
| 197 | $MOD_LIVEPATCH: post_unpatch_callback: $MOD_TARGET -> [MODULE_STATE_GOING] Going away |
| 198 | % echo 0 > /sys/kernel/livepatch/$MOD_LIVEPATCH/enabled |
| 199 | livepatch: '$MOD_LIVEPATCH': initializing unpatching transition |
| 200 | $MOD_LIVEPATCH: pre_unpatch_callback: vmlinux |
| 201 | livepatch: '$MOD_LIVEPATCH': starting unpatching transition |
| 202 | livepatch: '$MOD_LIVEPATCH': completing unpatching transition |
| 203 | $MOD_LIVEPATCH: post_unpatch_callback: vmlinux |
| 204 | livepatch: '$MOD_LIVEPATCH': unpatching complete |
| 205 | % rmmod $MOD_LIVEPATCH" |
| 206 | |
| 207 | |
David Brazdil | 0f672f6 | 2019-12-10 10:32:29 +0000 | [diff] [blame] | 208 | # A simple test of loading a livepatch without one of its patch target |
| 209 | # klp_objects ever loaded ($MOD_TARGET). |
| 210 | # |
| 211 | # - Load the livepatch. |
| 212 | # |
| 213 | # - As expected, only pre/post-(un)patch handlers are executed for |
| 214 | # vmlinux. |
| 215 | |
Olivier Deprez | 157378f | 2022-04-04 15:47:50 +0200 | [diff] [blame^] | 216 | start_test "target module not present" |
David Brazdil | 0f672f6 | 2019-12-10 10:32:29 +0000 | [diff] [blame] | 217 | |
| 218 | load_lp $MOD_LIVEPATCH |
| 219 | disable_lp $MOD_LIVEPATCH |
| 220 | unload_lp $MOD_LIVEPATCH |
| 221 | |
| 222 | check_result "% modprobe $MOD_LIVEPATCH |
| 223 | livepatch: enabling patch '$MOD_LIVEPATCH' |
| 224 | livepatch: '$MOD_LIVEPATCH': initializing patching transition |
| 225 | $MOD_LIVEPATCH: pre_patch_callback: vmlinux |
| 226 | livepatch: '$MOD_LIVEPATCH': starting patching transition |
| 227 | livepatch: '$MOD_LIVEPATCH': completing patching transition |
| 228 | $MOD_LIVEPATCH: post_patch_callback: vmlinux |
| 229 | livepatch: '$MOD_LIVEPATCH': patching complete |
| 230 | % echo 0 > /sys/kernel/livepatch/$MOD_LIVEPATCH/enabled |
| 231 | livepatch: '$MOD_LIVEPATCH': initializing unpatching transition |
| 232 | $MOD_LIVEPATCH: pre_unpatch_callback: vmlinux |
| 233 | livepatch: '$MOD_LIVEPATCH': starting unpatching transition |
| 234 | livepatch: '$MOD_LIVEPATCH': completing unpatching transition |
| 235 | $MOD_LIVEPATCH: post_unpatch_callback: vmlinux |
| 236 | livepatch: '$MOD_LIVEPATCH': unpatching complete |
| 237 | % rmmod $MOD_LIVEPATCH" |
| 238 | |
| 239 | |
David Brazdil | 0f672f6 | 2019-12-10 10:32:29 +0000 | [diff] [blame] | 240 | # Test a scenario where a vmlinux pre-patch callback returns a non-zero |
| 241 | # status (ie, failure). |
| 242 | # |
| 243 | # - First load a target module. |
| 244 | # |
| 245 | # - Load the livepatch module, setting its 'pre_patch_ret' value to -19 |
| 246 | # (-ENODEV). When its vmlinux pre-patch callback executes, this |
| 247 | # status code will propagate back to the module-loading subsystem. |
| 248 | # The result is that the insmod command refuses to load the livepatch |
| 249 | # module. |
| 250 | |
Olivier Deprez | 157378f | 2022-04-04 15:47:50 +0200 | [diff] [blame^] | 251 | start_test "pre-patch callback -ENODEV" |
David Brazdil | 0f672f6 | 2019-12-10 10:32:29 +0000 | [diff] [blame] | 252 | |
| 253 | load_mod $MOD_TARGET |
| 254 | load_failing_mod $MOD_LIVEPATCH pre_patch_ret=-19 |
| 255 | unload_mod $MOD_TARGET |
| 256 | |
| 257 | check_result "% modprobe $MOD_TARGET |
| 258 | $MOD_TARGET: ${MOD_TARGET}_init |
| 259 | % modprobe $MOD_LIVEPATCH pre_patch_ret=-19 |
| 260 | livepatch: enabling patch '$MOD_LIVEPATCH' |
| 261 | livepatch: '$MOD_LIVEPATCH': initializing patching transition |
| 262 | test_klp_callbacks_demo: pre_patch_callback: vmlinux |
| 263 | livepatch: pre-patch callback failed for object 'vmlinux' |
| 264 | livepatch: failed to enable patch '$MOD_LIVEPATCH' |
| 265 | livepatch: '$MOD_LIVEPATCH': canceling patching transition, going to unpatch |
| 266 | livepatch: '$MOD_LIVEPATCH': completing unpatching transition |
| 267 | livepatch: '$MOD_LIVEPATCH': unpatching complete |
| 268 | modprobe: ERROR: could not insert '$MOD_LIVEPATCH': No such device |
| 269 | % rmmod $MOD_TARGET |
| 270 | $MOD_TARGET: ${MOD_TARGET}_exit" |
| 271 | |
| 272 | |
David Brazdil | 0f672f6 | 2019-12-10 10:32:29 +0000 | [diff] [blame] | 273 | # Similar to the previous test, setup a livepatch such that its vmlinux |
| 274 | # pre-patch callback returns success. However, when a targeted kernel |
| 275 | # module is later loaded, have the livepatch return a failing status |
| 276 | # code. |
| 277 | # |
| 278 | # - Load the livepatch, vmlinux pre-patch callback succeeds. |
| 279 | # |
| 280 | # - Set a trap so subsequent pre-patch callbacks to this livepatch will |
| 281 | # return -ENODEV. |
| 282 | # |
| 283 | # - The livepatch pre-patch callback for subsequently loaded target |
| 284 | # modules will return failure, so the module loader refuses to load |
| 285 | # the kernel module. No post-patch or pre/post-unpatch callbacks are |
| 286 | # executed for this klp_object. |
| 287 | # |
| 288 | # - Pre/post-unpatch callbacks are run for the vmlinux klp_object. |
| 289 | |
Olivier Deprez | 157378f | 2022-04-04 15:47:50 +0200 | [diff] [blame^] | 290 | start_test "module_coming + pre-patch callback -ENODEV" |
David Brazdil | 0f672f6 | 2019-12-10 10:32:29 +0000 | [diff] [blame] | 291 | |
| 292 | load_lp $MOD_LIVEPATCH |
| 293 | set_pre_patch_ret $MOD_LIVEPATCH -19 |
| 294 | load_failing_mod $MOD_TARGET |
| 295 | disable_lp $MOD_LIVEPATCH |
| 296 | unload_lp $MOD_LIVEPATCH |
| 297 | |
| 298 | check_result "% modprobe $MOD_LIVEPATCH |
| 299 | livepatch: enabling patch '$MOD_LIVEPATCH' |
| 300 | livepatch: '$MOD_LIVEPATCH': initializing patching transition |
| 301 | $MOD_LIVEPATCH: pre_patch_callback: vmlinux |
| 302 | livepatch: '$MOD_LIVEPATCH': starting patching transition |
| 303 | livepatch: '$MOD_LIVEPATCH': completing patching transition |
| 304 | $MOD_LIVEPATCH: post_patch_callback: vmlinux |
| 305 | livepatch: '$MOD_LIVEPATCH': patching complete |
| 306 | % echo -19 > /sys/module/$MOD_LIVEPATCH/parameters/pre_patch_ret |
| 307 | % modprobe $MOD_TARGET |
| 308 | livepatch: applying patch '$MOD_LIVEPATCH' to loading module '$MOD_TARGET' |
| 309 | $MOD_LIVEPATCH: pre_patch_callback: $MOD_TARGET -> [MODULE_STATE_COMING] Full formed, running module_init |
| 310 | livepatch: pre-patch callback failed for object '$MOD_TARGET' |
| 311 | livepatch: patch '$MOD_LIVEPATCH' failed for module '$MOD_TARGET', refusing to load module '$MOD_TARGET' |
| 312 | modprobe: ERROR: could not insert '$MOD_TARGET': No such device |
| 313 | % echo 0 > /sys/kernel/livepatch/$MOD_LIVEPATCH/enabled |
| 314 | livepatch: '$MOD_LIVEPATCH': initializing unpatching transition |
| 315 | $MOD_LIVEPATCH: pre_unpatch_callback: vmlinux |
| 316 | livepatch: '$MOD_LIVEPATCH': starting unpatching transition |
| 317 | livepatch: '$MOD_LIVEPATCH': completing unpatching transition |
| 318 | $MOD_LIVEPATCH: post_unpatch_callback: vmlinux |
| 319 | livepatch: '$MOD_LIVEPATCH': unpatching complete |
| 320 | % rmmod $MOD_LIVEPATCH" |
| 321 | |
| 322 | |
David Brazdil | 0f672f6 | 2019-12-10 10:32:29 +0000 | [diff] [blame] | 323 | # Test loading multiple targeted kernel modules. This test-case is |
| 324 | # mainly for comparing with the next test-case. |
| 325 | # |
| 326 | # - Load a target "busy" kernel module which kicks off a worker function |
| 327 | # that immediately exits. |
| 328 | # |
| 329 | # - Proceed with loading the livepatch and another ordinary target |
| 330 | # module. Post-patch callbacks are executed and the transition |
| 331 | # completes quickly. |
| 332 | |
Olivier Deprez | 157378f | 2022-04-04 15:47:50 +0200 | [diff] [blame^] | 333 | start_test "multiple target modules" |
David Brazdil | 0f672f6 | 2019-12-10 10:32:29 +0000 | [diff] [blame] | 334 | |
Olivier Deprez | 157378f | 2022-04-04 15:47:50 +0200 | [diff] [blame^] | 335 | load_mod $MOD_TARGET_BUSY block_transition=N |
David Brazdil | 0f672f6 | 2019-12-10 10:32:29 +0000 | [diff] [blame] | 336 | load_lp $MOD_LIVEPATCH |
| 337 | load_mod $MOD_TARGET |
| 338 | unload_mod $MOD_TARGET |
| 339 | disable_lp $MOD_LIVEPATCH |
| 340 | unload_lp $MOD_LIVEPATCH |
| 341 | unload_mod $MOD_TARGET_BUSY |
| 342 | |
Olivier Deprez | 157378f | 2022-04-04 15:47:50 +0200 | [diff] [blame^] | 343 | check_result "% modprobe $MOD_TARGET_BUSY block_transition=N |
David Brazdil | 0f672f6 | 2019-12-10 10:32:29 +0000 | [diff] [blame] | 344 | $MOD_TARGET_BUSY: ${MOD_TARGET_BUSY}_init |
Olivier Deprez | 157378f | 2022-04-04 15:47:50 +0200 | [diff] [blame^] | 345 | $MOD_TARGET_BUSY: busymod_work_func enter |
David Brazdil | 0f672f6 | 2019-12-10 10:32:29 +0000 | [diff] [blame] | 346 | $MOD_TARGET_BUSY: busymod_work_func exit |
| 347 | % modprobe $MOD_LIVEPATCH |
| 348 | livepatch: enabling patch '$MOD_LIVEPATCH' |
| 349 | livepatch: '$MOD_LIVEPATCH': initializing patching transition |
| 350 | $MOD_LIVEPATCH: pre_patch_callback: vmlinux |
| 351 | $MOD_LIVEPATCH: pre_patch_callback: $MOD_TARGET_BUSY -> [MODULE_STATE_LIVE] Normal state |
| 352 | livepatch: '$MOD_LIVEPATCH': starting patching transition |
| 353 | livepatch: '$MOD_LIVEPATCH': completing patching transition |
| 354 | $MOD_LIVEPATCH: post_patch_callback: vmlinux |
| 355 | $MOD_LIVEPATCH: post_patch_callback: $MOD_TARGET_BUSY -> [MODULE_STATE_LIVE] Normal state |
| 356 | livepatch: '$MOD_LIVEPATCH': patching complete |
| 357 | % modprobe $MOD_TARGET |
| 358 | livepatch: applying patch '$MOD_LIVEPATCH' to loading module '$MOD_TARGET' |
| 359 | $MOD_LIVEPATCH: pre_patch_callback: $MOD_TARGET -> [MODULE_STATE_COMING] Full formed, running module_init |
| 360 | $MOD_LIVEPATCH: post_patch_callback: $MOD_TARGET -> [MODULE_STATE_COMING] Full formed, running module_init |
| 361 | $MOD_TARGET: ${MOD_TARGET}_init |
| 362 | % rmmod $MOD_TARGET |
| 363 | $MOD_TARGET: ${MOD_TARGET}_exit |
| 364 | $MOD_LIVEPATCH: pre_unpatch_callback: $MOD_TARGET -> [MODULE_STATE_GOING] Going away |
| 365 | livepatch: reverting patch '$MOD_LIVEPATCH' on unloading module '$MOD_TARGET' |
| 366 | $MOD_LIVEPATCH: post_unpatch_callback: $MOD_TARGET -> [MODULE_STATE_GOING] Going away |
| 367 | % echo 0 > /sys/kernel/livepatch/$MOD_LIVEPATCH/enabled |
| 368 | livepatch: '$MOD_LIVEPATCH': initializing unpatching transition |
| 369 | $MOD_LIVEPATCH: pre_unpatch_callback: vmlinux |
| 370 | $MOD_LIVEPATCH: pre_unpatch_callback: $MOD_TARGET_BUSY -> [MODULE_STATE_LIVE] Normal state |
| 371 | livepatch: '$MOD_LIVEPATCH': starting unpatching transition |
| 372 | livepatch: '$MOD_LIVEPATCH': completing unpatching transition |
| 373 | $MOD_LIVEPATCH: post_unpatch_callback: vmlinux |
| 374 | $MOD_LIVEPATCH: post_unpatch_callback: $MOD_TARGET_BUSY -> [MODULE_STATE_LIVE] Normal state |
| 375 | livepatch: '$MOD_LIVEPATCH': unpatching complete |
| 376 | % rmmod $MOD_LIVEPATCH |
| 377 | % rmmod $MOD_TARGET_BUSY |
| 378 | $MOD_TARGET_BUSY: ${MOD_TARGET_BUSY}_exit" |
| 379 | |
| 380 | |
David Brazdil | 0f672f6 | 2019-12-10 10:32:29 +0000 | [diff] [blame] | 381 | # A similar test as the previous one, but force the "busy" kernel module |
Olivier Deprez | 157378f | 2022-04-04 15:47:50 +0200 | [diff] [blame^] | 382 | # to block the livepatch transition. |
David Brazdil | 0f672f6 | 2019-12-10 10:32:29 +0000 | [diff] [blame] | 383 | # |
| 384 | # The livepatching core will refuse to patch a task that is currently |
| 385 | # executing a to-be-patched function -- the consistency model stalls the |
| 386 | # current patch transition until this safety-check is met. Test a |
| 387 | # scenario where one of a livepatch's target klp_objects sits on such a |
| 388 | # function for a long time. Meanwhile, load and unload other target |
| 389 | # kernel modules while the livepatch transition is in progress. |
| 390 | # |
Olivier Deprez | 157378f | 2022-04-04 15:47:50 +0200 | [diff] [blame^] | 391 | # - Load the "busy" kernel module, this time make its work function loop |
David Brazdil | 0f672f6 | 2019-12-10 10:32:29 +0000 | [diff] [blame] | 392 | # |
| 393 | # - Meanwhile, the livepatch is loaded. Notice that the patch |
| 394 | # transition does not complete as the targeted "busy" module is |
| 395 | # sitting on a to-be-patched function. |
| 396 | # |
| 397 | # - Load a second target module (this one is an ordinary idle kernel |
| 398 | # module). Note that *no* post-patch callbacks will be executed while |
| 399 | # the livepatch is still in transition. |
| 400 | # |
| 401 | # - Request an unload of the simple kernel module. The patch is still |
| 402 | # transitioning, so its pre-unpatch callbacks are skipped. |
| 403 | # |
| 404 | # - Finally the livepatch is disabled. Since none of the patch's |
| 405 | # klp_object's post-patch callbacks executed, the remaining |
| 406 | # klp_object's pre-unpatch callbacks are skipped. |
| 407 | |
Olivier Deprez | 157378f | 2022-04-04 15:47:50 +0200 | [diff] [blame^] | 408 | start_test "busy target module" |
David Brazdil | 0f672f6 | 2019-12-10 10:32:29 +0000 | [diff] [blame] | 409 | |
Olivier Deprez | 157378f | 2022-04-04 15:47:50 +0200 | [diff] [blame^] | 410 | load_mod $MOD_TARGET_BUSY block_transition=Y |
David Brazdil | 0f672f6 | 2019-12-10 10:32:29 +0000 | [diff] [blame] | 411 | load_lp_nowait $MOD_LIVEPATCH |
Olivier Deprez | 157378f | 2022-04-04 15:47:50 +0200 | [diff] [blame^] | 412 | |
| 413 | # Wait until the livepatch reports in-transition state, i.e. that it's |
| 414 | # stalled on $MOD_TARGET_BUSY::busymod_work_func() |
| 415 | loop_until 'grep -q '^1$' /sys/kernel/livepatch/$MOD_LIVEPATCH/transition' || |
| 416 | die "failed to stall transition" |
| 417 | |
David Brazdil | 0f672f6 | 2019-12-10 10:32:29 +0000 | [diff] [blame] | 418 | load_mod $MOD_TARGET |
| 419 | unload_mod $MOD_TARGET |
| 420 | disable_lp $MOD_LIVEPATCH |
| 421 | unload_lp $MOD_LIVEPATCH |
| 422 | unload_mod $MOD_TARGET_BUSY |
| 423 | |
Olivier Deprez | 157378f | 2022-04-04 15:47:50 +0200 | [diff] [blame^] | 424 | check_result "% modprobe $MOD_TARGET_BUSY block_transition=Y |
David Brazdil | 0f672f6 | 2019-12-10 10:32:29 +0000 | [diff] [blame] | 425 | $MOD_TARGET_BUSY: ${MOD_TARGET_BUSY}_init |
Olivier Deprez | 157378f | 2022-04-04 15:47:50 +0200 | [diff] [blame^] | 426 | $MOD_TARGET_BUSY: busymod_work_func enter |
David Brazdil | 0f672f6 | 2019-12-10 10:32:29 +0000 | [diff] [blame] | 427 | % modprobe $MOD_LIVEPATCH |
| 428 | livepatch: enabling patch '$MOD_LIVEPATCH' |
| 429 | livepatch: '$MOD_LIVEPATCH': initializing patching transition |
| 430 | $MOD_LIVEPATCH: pre_patch_callback: vmlinux |
| 431 | $MOD_LIVEPATCH: pre_patch_callback: $MOD_TARGET_BUSY -> [MODULE_STATE_LIVE] Normal state |
| 432 | livepatch: '$MOD_LIVEPATCH': starting patching transition |
| 433 | % modprobe $MOD_TARGET |
| 434 | livepatch: applying patch '$MOD_LIVEPATCH' to loading module '$MOD_TARGET' |
| 435 | $MOD_LIVEPATCH: pre_patch_callback: $MOD_TARGET -> [MODULE_STATE_COMING] Full formed, running module_init |
| 436 | $MOD_TARGET: ${MOD_TARGET}_init |
| 437 | % rmmod $MOD_TARGET |
| 438 | $MOD_TARGET: ${MOD_TARGET}_exit |
| 439 | livepatch: reverting patch '$MOD_LIVEPATCH' on unloading module '$MOD_TARGET' |
| 440 | $MOD_LIVEPATCH: post_unpatch_callback: $MOD_TARGET -> [MODULE_STATE_GOING] Going away |
| 441 | % echo 0 > /sys/kernel/livepatch/$MOD_LIVEPATCH/enabled |
| 442 | livepatch: '$MOD_LIVEPATCH': reversing transition from patching to unpatching |
| 443 | livepatch: '$MOD_LIVEPATCH': starting unpatching transition |
| 444 | livepatch: '$MOD_LIVEPATCH': completing unpatching transition |
| 445 | $MOD_LIVEPATCH: post_unpatch_callback: vmlinux |
| 446 | $MOD_LIVEPATCH: post_unpatch_callback: $MOD_TARGET_BUSY -> [MODULE_STATE_LIVE] Normal state |
| 447 | livepatch: '$MOD_LIVEPATCH': unpatching complete |
| 448 | % rmmod $MOD_LIVEPATCH |
| 449 | % rmmod $MOD_TARGET_BUSY |
| 450 | $MOD_TARGET_BUSY: busymod_work_func exit |
| 451 | $MOD_TARGET_BUSY: ${MOD_TARGET_BUSY}_exit" |
| 452 | |
| 453 | |
David Brazdil | 0f672f6 | 2019-12-10 10:32:29 +0000 | [diff] [blame] | 454 | # Test loading multiple livepatches. This test-case is mainly for comparing |
| 455 | # with the next test-case. |
| 456 | # |
| 457 | # - Load and unload two livepatches, pre and post (un)patch callbacks |
| 458 | # execute as each patch progresses through its (un)patching |
| 459 | # transition. |
| 460 | |
Olivier Deprez | 157378f | 2022-04-04 15:47:50 +0200 | [diff] [blame^] | 461 | start_test "multiple livepatches" |
David Brazdil | 0f672f6 | 2019-12-10 10:32:29 +0000 | [diff] [blame] | 462 | |
| 463 | load_lp $MOD_LIVEPATCH |
| 464 | load_lp $MOD_LIVEPATCH2 |
| 465 | disable_lp $MOD_LIVEPATCH2 |
| 466 | disable_lp $MOD_LIVEPATCH |
| 467 | unload_lp $MOD_LIVEPATCH2 |
| 468 | unload_lp $MOD_LIVEPATCH |
| 469 | |
| 470 | check_result "% modprobe $MOD_LIVEPATCH |
| 471 | livepatch: enabling patch '$MOD_LIVEPATCH' |
| 472 | livepatch: '$MOD_LIVEPATCH': initializing patching transition |
| 473 | $MOD_LIVEPATCH: pre_patch_callback: vmlinux |
| 474 | livepatch: '$MOD_LIVEPATCH': starting patching transition |
| 475 | livepatch: '$MOD_LIVEPATCH': completing patching transition |
| 476 | $MOD_LIVEPATCH: post_patch_callback: vmlinux |
| 477 | livepatch: '$MOD_LIVEPATCH': patching complete |
| 478 | % modprobe $MOD_LIVEPATCH2 |
| 479 | livepatch: enabling patch '$MOD_LIVEPATCH2' |
| 480 | livepatch: '$MOD_LIVEPATCH2': initializing patching transition |
| 481 | $MOD_LIVEPATCH2: pre_patch_callback: vmlinux |
| 482 | livepatch: '$MOD_LIVEPATCH2': starting patching transition |
| 483 | livepatch: '$MOD_LIVEPATCH2': completing patching transition |
| 484 | $MOD_LIVEPATCH2: post_patch_callback: vmlinux |
| 485 | livepatch: '$MOD_LIVEPATCH2': patching complete |
| 486 | % echo 0 > /sys/kernel/livepatch/$MOD_LIVEPATCH2/enabled |
| 487 | livepatch: '$MOD_LIVEPATCH2': initializing unpatching transition |
| 488 | $MOD_LIVEPATCH2: pre_unpatch_callback: vmlinux |
| 489 | livepatch: '$MOD_LIVEPATCH2': starting unpatching transition |
| 490 | livepatch: '$MOD_LIVEPATCH2': completing unpatching transition |
| 491 | $MOD_LIVEPATCH2: post_unpatch_callback: vmlinux |
| 492 | livepatch: '$MOD_LIVEPATCH2': unpatching complete |
| 493 | % echo 0 > /sys/kernel/livepatch/$MOD_LIVEPATCH/enabled |
| 494 | livepatch: '$MOD_LIVEPATCH': initializing unpatching transition |
| 495 | $MOD_LIVEPATCH: pre_unpatch_callback: vmlinux |
| 496 | livepatch: '$MOD_LIVEPATCH': starting unpatching transition |
| 497 | livepatch: '$MOD_LIVEPATCH': completing unpatching transition |
| 498 | $MOD_LIVEPATCH: post_unpatch_callback: vmlinux |
| 499 | livepatch: '$MOD_LIVEPATCH': unpatching complete |
| 500 | % rmmod $MOD_LIVEPATCH2 |
| 501 | % rmmod $MOD_LIVEPATCH" |
| 502 | |
| 503 | |
David Brazdil | 0f672f6 | 2019-12-10 10:32:29 +0000 | [diff] [blame] | 504 | # Load multiple livepatches, but the second as an 'atomic-replace' |
| 505 | # patch. When the latter loads, the original livepatch should be |
| 506 | # disabled and *none* of its pre/post-unpatch callbacks executed. On |
| 507 | # the other hand, when the atomic-replace livepatch is disabled, its |
| 508 | # pre/post-unpatch callbacks *should* be executed. |
| 509 | # |
| 510 | # - Load and unload two livepatches, the second of which has its |
| 511 | # .replace flag set true. |
| 512 | # |
| 513 | # - Pre and post patch callbacks are executed for both livepatches. |
| 514 | # |
| 515 | # - Once the atomic replace module is loaded, only its pre and post |
| 516 | # unpatch callbacks are executed. |
| 517 | |
Olivier Deprez | 157378f | 2022-04-04 15:47:50 +0200 | [diff] [blame^] | 518 | start_test "atomic replace" |
David Brazdil | 0f672f6 | 2019-12-10 10:32:29 +0000 | [diff] [blame] | 519 | |
| 520 | load_lp $MOD_LIVEPATCH |
| 521 | load_lp $MOD_LIVEPATCH2 replace=1 |
| 522 | disable_lp $MOD_LIVEPATCH2 |
| 523 | unload_lp $MOD_LIVEPATCH2 |
| 524 | unload_lp $MOD_LIVEPATCH |
| 525 | |
| 526 | check_result "% modprobe $MOD_LIVEPATCH |
| 527 | livepatch: enabling patch '$MOD_LIVEPATCH' |
| 528 | livepatch: '$MOD_LIVEPATCH': initializing patching transition |
| 529 | $MOD_LIVEPATCH: pre_patch_callback: vmlinux |
| 530 | livepatch: '$MOD_LIVEPATCH': starting patching transition |
| 531 | livepatch: '$MOD_LIVEPATCH': completing patching transition |
| 532 | $MOD_LIVEPATCH: post_patch_callback: vmlinux |
| 533 | livepatch: '$MOD_LIVEPATCH': patching complete |
| 534 | % modprobe $MOD_LIVEPATCH2 replace=1 |
| 535 | livepatch: enabling patch '$MOD_LIVEPATCH2' |
| 536 | livepatch: '$MOD_LIVEPATCH2': initializing patching transition |
| 537 | $MOD_LIVEPATCH2: pre_patch_callback: vmlinux |
| 538 | livepatch: '$MOD_LIVEPATCH2': starting patching transition |
| 539 | livepatch: '$MOD_LIVEPATCH2': completing patching transition |
| 540 | $MOD_LIVEPATCH2: post_patch_callback: vmlinux |
| 541 | livepatch: '$MOD_LIVEPATCH2': patching complete |
| 542 | % echo 0 > /sys/kernel/livepatch/$MOD_LIVEPATCH2/enabled |
| 543 | livepatch: '$MOD_LIVEPATCH2': initializing unpatching transition |
| 544 | $MOD_LIVEPATCH2: pre_unpatch_callback: vmlinux |
| 545 | livepatch: '$MOD_LIVEPATCH2': starting unpatching transition |
| 546 | livepatch: '$MOD_LIVEPATCH2': completing unpatching transition |
| 547 | $MOD_LIVEPATCH2: post_unpatch_callback: vmlinux |
| 548 | livepatch: '$MOD_LIVEPATCH2': unpatching complete |
| 549 | % rmmod $MOD_LIVEPATCH2 |
| 550 | % rmmod $MOD_LIVEPATCH" |
| 551 | |
| 552 | |
| 553 | exit 0 |