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 | |
| 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 |