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