Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests/livepatch: introduce tests

Add a few livepatch modules and simple target modules that the included
regression suite can run tests against:

- basic livepatching (multiple patches, atomic replace)
- pre/post (un)patch callbacks
- shadow variable API

Signed-off-by: Joe Lawrence <joe.lawrence@redhat.com>
Signed-off-by: Petr Mladek <pmladek@suse.com>
Tested-by: Miroslav Benes <mbenes@suse.cz>
Tested-by: Alice Ferrazzi <alice.ferrazzi@gmail.com>
Acked-by: Joe Lawrence <joe.lawrence@redhat.com>
Acked-by: Josh Poimboeuf <jpoimboe@redhat.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>

authored by

Joe Lawrence and committed by
Jiri Kosina
a2818ee4 d67a5372

+1741 -486
+6 -485
Documentation/livepatch/callbacks.txt
··· 118 118 value may need to be updated accordingly.) 119 119 120 120 121 - Test cases 122 - ========== 123 - 124 - What follows is not an exhaustive test suite of every possible livepatch 125 - pre/post-(un)patch combination, but a selection that demonstrates a few 126 - important concepts. Each test case uses the kernel modules located in 127 - the samples/livepatch/ and assumes that no livepatches are loaded at the 128 - beginning of the test. 129 - 130 - 131 - Test 1 132 - ------ 133 - 134 - Test a combination of loading a kernel module and a livepatch that 135 - patches a function in the first module. (Un)load the target module 136 - before the livepatch module: 137 - 138 - - load target module 139 - - load livepatch 140 - - disable livepatch 141 - - unload target module 142 - - unload livepatch 143 - 144 - First load a target module: 145 - 146 - % insmod samples/livepatch/livepatch-callbacks-mod.ko 147 - [ 34.475708] livepatch_callbacks_mod: livepatch_callbacks_mod_init 148 - 149 - On livepatch enable, before the livepatch transition starts, pre-patch 150 - callbacks are executed for vmlinux and livepatch_callbacks_mod (those 151 - klp_objects currently loaded). After klp_objects are patched according 152 - to the klp_patch, their post-patch callbacks run and the transition 153 - completes: 154 - 155 - % insmod samples/livepatch/livepatch-callbacks-demo.ko 156 - [ 36.503719] livepatch: enabling patch 'livepatch_callbacks_demo' 157 - [ 36.504213] livepatch: 'livepatch_callbacks_demo': initializing patching transition 158 - [ 36.504238] livepatch_callbacks_demo: pre_patch_callback: vmlinux 159 - [ 36.504721] livepatch_callbacks_demo: pre_patch_callback: livepatch_callbacks_mod -> [MODULE_STATE_LIVE] Normal state 160 - [ 36.505849] livepatch: 'livepatch_callbacks_demo': starting patching transition 161 - [ 37.727133] livepatch: 'livepatch_callbacks_demo': completing patching transition 162 - [ 37.727232] livepatch_callbacks_demo: post_patch_callback: vmlinux 163 - [ 37.727860] livepatch_callbacks_demo: post_patch_callback: livepatch_callbacks_mod -> [MODULE_STATE_LIVE] Normal state 164 - [ 37.728792] livepatch: 'livepatch_callbacks_demo': patching complete 165 - 166 - Similarly, on livepatch disable, pre-patch callbacks run before the 167 - unpatching transition starts. klp_objects are reverted, post-patch 168 - callbacks execute and the transition completes: 169 - 170 - % echo 0 > /sys/kernel/livepatch/livepatch_callbacks_demo/enabled 171 - [ 38.510209] livepatch: 'livepatch_callbacks_demo': initializing unpatching transition 172 - [ 38.510234] livepatch_callbacks_demo: pre_unpatch_callback: vmlinux 173 - [ 38.510982] livepatch_callbacks_demo: pre_unpatch_callback: livepatch_callbacks_mod -> [MODULE_STATE_LIVE] Normal state 174 - [ 38.512209] livepatch: 'livepatch_callbacks_demo': starting unpatching transition 175 - [ 39.711132] livepatch: 'livepatch_callbacks_demo': completing unpatching transition 176 - [ 39.711210] livepatch_callbacks_demo: post_unpatch_callback: vmlinux 177 - [ 39.711779] livepatch_callbacks_demo: post_unpatch_callback: livepatch_callbacks_mod -> [MODULE_STATE_LIVE] Normal state 178 - [ 39.712735] livepatch: 'livepatch_callbacks_demo': unpatching complete 179 - 180 - % rmmod samples/livepatch/livepatch-callbacks-demo.ko 181 - % rmmod samples/livepatch/livepatch-callbacks-mod.ko 182 - [ 42.534183] livepatch_callbacks_mod: livepatch_callbacks_mod_exit 183 - 184 - 185 - Test 2 186 - ------ 187 - 188 - This test is similar to the previous test, but (un)load the livepatch 189 - module before the target kernel module. This tests the livepatch core's 190 - module_coming handler: 191 - 192 - - load livepatch 193 - - load target module 194 - - disable livepatch 195 - - unload livepatch 196 - - unload target module 197 - 198 - 199 - On livepatch enable, only pre/post-patch callbacks are executed for 200 - currently loaded klp_objects, in this case, vmlinux: 201 - 202 - % insmod samples/livepatch/livepatch-callbacks-demo.ko 203 - [ 44.553328] livepatch: enabling patch 'livepatch_callbacks_demo' 204 - [ 44.553997] livepatch: 'livepatch_callbacks_demo': initializing patching transition 205 - [ 44.554049] livepatch_callbacks_demo: pre_patch_callback: vmlinux 206 - [ 44.554845] livepatch: 'livepatch_callbacks_demo': starting patching transition 207 - [ 45.727128] livepatch: 'livepatch_callbacks_demo': completing patching transition 208 - [ 45.727212] livepatch_callbacks_demo: post_patch_callback: vmlinux 209 - [ 45.727961] livepatch: 'livepatch_callbacks_demo': patching complete 210 - 211 - When a targeted module is subsequently loaded, only its pre/post-patch 212 - callbacks are executed: 213 - 214 - % insmod samples/livepatch/livepatch-callbacks-mod.ko 215 - [ 46.560845] livepatch: applying patch 'livepatch_callbacks_demo' to loading module 'livepatch_callbacks_mod' 216 - [ 46.561988] livepatch_callbacks_demo: pre_patch_callback: livepatch_callbacks_mod -> [MODULE_STATE_COMING] Full formed, running module_init 217 - [ 46.563452] livepatch_callbacks_demo: post_patch_callback: livepatch_callbacks_mod -> [MODULE_STATE_COMING] Full formed, running module_init 218 - [ 46.565495] livepatch_callbacks_mod: livepatch_callbacks_mod_init 219 - 220 - On livepatch disable, all currently loaded klp_objects' (vmlinux and 221 - livepatch_callbacks_mod) pre/post-unpatch callbacks are executed: 222 - 223 - % echo 0 > /sys/kernel/livepatch/livepatch_callbacks_demo/enabled 224 - [ 48.568885] livepatch: 'livepatch_callbacks_demo': initializing unpatching transition 225 - [ 48.568910] livepatch_callbacks_demo: pre_unpatch_callback: vmlinux 226 - [ 48.569441] livepatch_callbacks_demo: pre_unpatch_callback: livepatch_callbacks_mod -> [MODULE_STATE_LIVE] Normal state 227 - [ 48.570502] livepatch: 'livepatch_callbacks_demo': starting unpatching transition 228 - [ 49.759091] livepatch: 'livepatch_callbacks_demo': completing unpatching transition 229 - [ 49.759171] livepatch_callbacks_demo: post_unpatch_callback: vmlinux 230 - [ 49.759742] livepatch_callbacks_demo: post_unpatch_callback: livepatch_callbacks_mod -> [MODULE_STATE_LIVE] Normal state 231 - [ 49.760690] livepatch: 'livepatch_callbacks_demo': unpatching complete 232 - 233 - % rmmod samples/livepatch/livepatch-callbacks-demo.ko 234 - % rmmod samples/livepatch/livepatch-callbacks-mod.ko 235 - [ 52.592283] livepatch_callbacks_mod: livepatch_callbacks_mod_exit 236 - 237 - 238 - Test 3 239 - ------ 240 - 241 - Test loading the livepatch after a targeted kernel module, then unload 242 - the kernel module before disabling the livepatch. This tests the 243 - livepatch core's module_going handler: 244 - 245 - - load target module 246 - - load livepatch 247 - - unload target module 248 - - disable livepatch 249 - - unload livepatch 250 - 251 - First load a target module, then the livepatch: 252 - 253 - % insmod samples/livepatch/livepatch-callbacks-mod.ko 254 - [ 54.607948] livepatch_callbacks_mod: livepatch_callbacks_mod_init 255 - 256 - % insmod samples/livepatch/livepatch-callbacks-demo.ko 257 - [ 56.613919] livepatch: enabling patch 'livepatch_callbacks_demo' 258 - [ 56.614411] livepatch: 'livepatch_callbacks_demo': initializing patching transition 259 - [ 56.614436] livepatch_callbacks_demo: pre_patch_callback: vmlinux 260 - [ 56.614818] livepatch_callbacks_demo: pre_patch_callback: livepatch_callbacks_mod -> [MODULE_STATE_LIVE] Normal state 261 - [ 56.615656] livepatch: 'livepatch_callbacks_demo': starting patching transition 262 - [ 57.759070] livepatch: 'livepatch_callbacks_demo': completing patching transition 263 - [ 57.759147] livepatch_callbacks_demo: post_patch_callback: vmlinux 264 - [ 57.759621] livepatch_callbacks_demo: post_patch_callback: livepatch_callbacks_mod -> [MODULE_STATE_LIVE] Normal state 265 - [ 57.760307] livepatch: 'livepatch_callbacks_demo': patching complete 266 - 267 - When a target module is unloaded, the livepatch is only reverted from 268 - that klp_object (livepatch_callbacks_mod). As such, only its pre and 269 - post-unpatch callbacks are executed when this occurs: 270 - 271 - % rmmod samples/livepatch/livepatch-callbacks-mod.ko 272 - [ 58.623409] livepatch_callbacks_mod: livepatch_callbacks_mod_exit 273 - [ 58.623903] livepatch_callbacks_demo: pre_unpatch_callback: livepatch_callbacks_mod -> [MODULE_STATE_GOING] Going away 274 - [ 58.624658] livepatch: reverting patch 'livepatch_callbacks_demo' on unloading module 'livepatch_callbacks_mod' 275 - [ 58.625305] livepatch_callbacks_demo: post_unpatch_callback: livepatch_callbacks_mod -> [MODULE_STATE_GOING] Going away 276 - 277 - When the livepatch is disabled, pre and post-unpatch callbacks are run 278 - for the remaining klp_object, vmlinux: 279 - 280 - % echo 0 > /sys/kernel/livepatch/livepatch_callbacks_demo/enabled 281 - [ 60.638420] livepatch: 'livepatch_callbacks_demo': initializing unpatching transition 282 - [ 60.638444] livepatch_callbacks_demo: pre_unpatch_callback: vmlinux 283 - [ 60.638996] livepatch: 'livepatch_callbacks_demo': starting unpatching transition 284 - [ 61.727088] livepatch: 'livepatch_callbacks_demo': completing unpatching transition 285 - [ 61.727165] livepatch_callbacks_demo: post_unpatch_callback: vmlinux 286 - [ 61.727985] livepatch: 'livepatch_callbacks_demo': unpatching complete 287 - 288 - % rmmod samples/livepatch/livepatch-callbacks-demo.ko 289 - 290 - 291 - Test 4 292 - ------ 293 - 294 - This test is similar to the previous test, however the livepatch is 295 - loaded first. This tests the livepatch core's module_coming and 296 - module_going handlers: 297 - 298 - - load livepatch 299 - - load target module 300 - - unload target module 301 - - disable livepatch 302 - - unload livepatch 303 - 304 - First load the livepatch: 305 - 306 - % insmod samples/livepatch/livepatch-callbacks-demo.ko 307 - [ 64.661552] livepatch: enabling patch 'livepatch_callbacks_demo' 308 - [ 64.662147] livepatch: 'livepatch_callbacks_demo': initializing patching transition 309 - [ 64.662175] livepatch_callbacks_demo: pre_patch_callback: vmlinux 310 - [ 64.662850] livepatch: 'livepatch_callbacks_demo': starting patching transition 311 - [ 65.695056] livepatch: 'livepatch_callbacks_demo': completing patching transition 312 - [ 65.695147] livepatch_callbacks_demo: post_patch_callback: vmlinux 313 - [ 65.695561] livepatch: 'livepatch_callbacks_demo': patching complete 314 - 315 - When a targeted kernel module is subsequently loaded, only its 316 - pre/post-patch callbacks are executed: 317 - 318 - % insmod samples/livepatch/livepatch-callbacks-mod.ko 319 - [ 66.669196] livepatch: applying patch 'livepatch_callbacks_demo' to loading module 'livepatch_callbacks_mod' 320 - [ 66.669882] livepatch_callbacks_demo: pre_patch_callback: livepatch_callbacks_mod -> [MODULE_STATE_COMING] Full formed, running module_init 321 - [ 66.670744] livepatch_callbacks_demo: post_patch_callback: livepatch_callbacks_mod -> [MODULE_STATE_COMING] Full formed, running module_init 322 - [ 66.672873] livepatch_callbacks_mod: livepatch_callbacks_mod_init 323 - 324 - When the target module is unloaded, the livepatch is only reverted from 325 - the livepatch_callbacks_mod klp_object. As such, only pre and 326 - post-unpatch callbacks are executed when this occurs: 327 - 328 - % rmmod samples/livepatch/livepatch-callbacks-mod.ko 329 - [ 68.680065] livepatch_callbacks_mod: livepatch_callbacks_mod_exit 330 - [ 68.680688] livepatch_callbacks_demo: pre_unpatch_callback: livepatch_callbacks_mod -> [MODULE_STATE_GOING] Going away 331 - [ 68.681452] livepatch: reverting patch 'livepatch_callbacks_demo' on unloading module 'livepatch_callbacks_mod' 332 - [ 68.682094] livepatch_callbacks_demo: post_unpatch_callback: livepatch_callbacks_mod -> [MODULE_STATE_GOING] Going away 333 - 334 - % echo 0 > /sys/kernel/livepatch/livepatch_callbacks_demo/enabled 335 - [ 70.689225] livepatch: 'livepatch_callbacks_demo': initializing unpatching transition 336 - [ 70.689256] livepatch_callbacks_demo: pre_unpatch_callback: vmlinux 337 - [ 70.689882] livepatch: 'livepatch_callbacks_demo': starting unpatching transition 338 - [ 71.711080] livepatch: 'livepatch_callbacks_demo': completing unpatching transition 339 - [ 71.711481] livepatch_callbacks_demo: post_unpatch_callback: vmlinux 340 - [ 71.711988] livepatch: 'livepatch_callbacks_demo': unpatching complete 341 - 342 - % rmmod samples/livepatch/livepatch-callbacks-demo.ko 343 - 344 - 345 - Test 5 346 - ------ 347 - 348 - A simple test of loading a livepatch without one of its patch target 349 - klp_objects ever loaded (livepatch_callbacks_mod): 350 - 351 - - load livepatch 352 - - disable livepatch 353 - - unload livepatch 354 - 355 - Load the livepatch: 356 - 357 - % insmod samples/livepatch/livepatch-callbacks-demo.ko 358 - [ 74.711081] livepatch: enabling patch 'livepatch_callbacks_demo' 359 - [ 74.711595] livepatch: 'livepatch_callbacks_demo': initializing patching transition 360 - [ 74.711639] livepatch_callbacks_demo: pre_patch_callback: vmlinux 361 - [ 74.712272] livepatch: 'livepatch_callbacks_demo': starting patching transition 362 - [ 75.743137] livepatch: 'livepatch_callbacks_demo': completing patching transition 363 - [ 75.743219] livepatch_callbacks_demo: post_patch_callback: vmlinux 364 - [ 75.743867] livepatch: 'livepatch_callbacks_demo': patching complete 365 - 366 - As expected, only pre/post-(un)patch handlers are executed for vmlinux: 367 - 368 - % echo 0 > /sys/kernel/livepatch/livepatch_callbacks_demo/enabled 369 - [ 76.716254] livepatch: 'livepatch_callbacks_demo': initializing unpatching transition 370 - [ 76.716278] livepatch_callbacks_demo: pre_unpatch_callback: vmlinux 371 - [ 76.716666] livepatch: 'livepatch_callbacks_demo': starting unpatching transition 372 - [ 77.727089] livepatch: 'livepatch_callbacks_demo': completing unpatching transition 373 - [ 77.727194] livepatch_callbacks_demo: post_unpatch_callback: vmlinux 374 - [ 77.727907] livepatch: 'livepatch_callbacks_demo': unpatching complete 375 - 376 - % rmmod samples/livepatch/livepatch-callbacks-demo.ko 377 - 378 - 379 - Test 6 380 - ------ 381 - 382 - Test a scenario where a vmlinux pre-patch callback returns a non-zero 383 - status (ie, failure): 384 - 385 - - load target module 386 - - load livepatch -ENODEV 387 - - unload target module 388 - 389 - First load a target module: 390 - 391 - % insmod samples/livepatch/livepatch-callbacks-mod.ko 392 - [ 80.740520] livepatch_callbacks_mod: livepatch_callbacks_mod_init 393 - 394 - Load the livepatch module, setting its 'pre_patch_ret' value to -19 395 - (-ENODEV). When its vmlinux pre-patch callback executed, this status 396 - code will propagate back to the module-loading subsystem. The result is 397 - that the insmod command refuses to load the livepatch module: 398 - 399 - % insmod samples/livepatch/livepatch-callbacks-demo.ko pre_patch_ret=-19 400 - [ 82.747326] livepatch: enabling patch 'livepatch_callbacks_demo' 401 - [ 82.747743] livepatch: 'livepatch_callbacks_demo': initializing patching transition 402 - [ 82.747767] livepatch_callbacks_demo: pre_patch_callback: vmlinux 403 - [ 82.748237] livepatch: pre-patch callback failed for object 'vmlinux' 404 - [ 82.748637] livepatch: failed to enable patch 'livepatch_callbacks_demo' 405 - [ 82.749059] livepatch: 'livepatch_callbacks_demo': canceling transition, going to unpatch 406 - [ 82.749060] livepatch: 'livepatch_callbacks_demo': completing unpatching transition 407 - [ 82.749868] livepatch: 'livepatch_callbacks_demo': unpatching complete 408 - [ 82.765809] insmod: ERROR: could not insert module samples/livepatch/livepatch-callbacks-demo.ko: No such device 409 - 410 - % rmmod samples/livepatch/livepatch-callbacks-mod.ko 411 - [ 84.774238] livepatch_callbacks_mod: livepatch_callbacks_mod_exit 412 - 413 - 414 - Test 7 415 - ------ 416 - 417 - Similar to the previous test, setup a livepatch such that its vmlinux 418 - pre-patch callback returns success. However, when a targeted kernel 419 - module is later loaded, have the livepatch return a failing status code: 420 - 421 - - load livepatch 422 - - setup -ENODEV 423 - - load target module 424 - - disable livepatch 425 - - unload livepatch 426 - 427 - Load the livepatch, notice vmlinux pre-patch callback succeeds: 428 - 429 - % insmod samples/livepatch/livepatch-callbacks-demo.ko 430 - [ 86.787845] livepatch: enabling patch 'livepatch_callbacks_demo' 431 - [ 86.788325] livepatch: 'livepatch_callbacks_demo': initializing patching transition 432 - [ 86.788427] livepatch_callbacks_demo: pre_patch_callback: vmlinux 433 - [ 86.788821] livepatch: 'livepatch_callbacks_demo': starting patching transition 434 - [ 87.711069] livepatch: 'livepatch_callbacks_demo': completing patching transition 435 - [ 87.711143] livepatch_callbacks_demo: post_patch_callback: vmlinux 436 - [ 87.711886] livepatch: 'livepatch_callbacks_demo': patching complete 437 - 438 - Set a trap so subsequent pre-patch callbacks to this livepatch will 439 - return -ENODEV: 440 - 441 - % echo -19 > /sys/module/livepatch_callbacks_demo/parameters/pre_patch_ret 442 - 443 - The livepatch pre-patch callback for subsequently loaded target modules 444 - will return failure, so the module loader refuses to load the kernel 445 - module. Notice that no post-patch or pre/post-unpatch callbacks are 446 - executed for this klp_object: 447 - 448 - % insmod samples/livepatch/livepatch-callbacks-mod.ko 449 - [ 90.796976] livepatch: applying patch 'livepatch_callbacks_demo' to loading module 'livepatch_callbacks_mod' 450 - [ 90.797834] livepatch_callbacks_demo: pre_patch_callback: livepatch_callbacks_mod -> [MODULE_STATE_COMING] Full formed, running module_init 451 - [ 90.798900] livepatch: pre-patch callback failed for object 'livepatch_callbacks_mod' 452 - [ 90.799652] livepatch: patch 'livepatch_callbacks_demo' failed for module 'livepatch_callbacks_mod', refusing to load module 'livepatch_callbacks_mod' 453 - [ 90.819737] insmod: ERROR: could not insert module samples/livepatch/livepatch-callbacks-mod.ko: No such device 454 - 455 - However, pre/post-unpatch callbacks run for the vmlinux klp_object: 456 - 457 - % echo 0 > /sys/kernel/livepatch/livepatch_callbacks_demo/enabled 458 - [ 92.823547] livepatch: 'livepatch_callbacks_demo': initializing unpatching transition 459 - [ 92.823573] livepatch_callbacks_demo: pre_unpatch_callback: vmlinux 460 - [ 92.824331] livepatch: 'livepatch_callbacks_demo': starting unpatching transition 461 - [ 93.727128] livepatch: 'livepatch_callbacks_demo': completing unpatching transition 462 - [ 93.727327] livepatch_callbacks_demo: post_unpatch_callback: vmlinux 463 - [ 93.727861] livepatch: 'livepatch_callbacks_demo': unpatching complete 464 - 465 - % rmmod samples/livepatch/livepatch-callbacks-demo.ko 466 - 467 - 468 - Test 8 469 - ------ 470 - 471 - Test loading multiple targeted kernel modules. This test-case is 472 - mainly for comparing with the next test-case. 473 - 474 - - load busy target module (0s sleep), 475 - - load livepatch 476 - - load target module 477 - - unload target module 478 - - disable livepatch 479 - - unload livepatch 480 - - unload busy target module 481 - 482 - 483 - Load a target "busy" kernel module which kicks off a worker function 484 - that immediately exits: 485 - 486 - % insmod samples/livepatch/livepatch-callbacks-busymod.ko sleep_secs=0 487 - [ 96.910107] livepatch_callbacks_busymod: livepatch_callbacks_mod_init 488 - [ 96.910600] livepatch_callbacks_busymod: busymod_work_func, sleeping 0 seconds ... 489 - [ 96.913024] livepatch_callbacks_busymod: busymod_work_func exit 490 - 491 - Proceed with loading the livepatch and another ordinary target module, 492 - notice that the post-patch callbacks are executed and the transition 493 - completes quickly: 494 - 495 - % insmod samples/livepatch/livepatch-callbacks-demo.ko 496 - [ 98.917892] livepatch: enabling patch 'livepatch_callbacks_demo' 497 - [ 98.918426] livepatch: 'livepatch_callbacks_demo': initializing patching transition 498 - [ 98.918453] livepatch_callbacks_demo: pre_patch_callback: vmlinux 499 - [ 98.918955] livepatch_callbacks_demo: pre_patch_callback: livepatch_callbacks_busymod -> [MODULE_STATE_LIVE] Normal state 500 - [ 98.923835] livepatch: 'livepatch_callbacks_demo': starting patching transition 501 - [ 99.743104] livepatch: 'livepatch_callbacks_demo': completing patching transition 502 - [ 99.743156] livepatch_callbacks_demo: post_patch_callback: vmlinux 503 - [ 99.743679] livepatch_callbacks_demo: post_patch_callback: livepatch_callbacks_busymod -> [MODULE_STATE_LIVE] Normal state 504 - [ 99.744616] livepatch: 'livepatch_callbacks_demo': patching complete 505 - 506 - % insmod samples/livepatch/livepatch-callbacks-mod.ko 507 - [ 100.930955] livepatch: applying patch 'livepatch_callbacks_demo' to loading module 'livepatch_callbacks_mod' 508 - [ 100.931668] livepatch_callbacks_demo: pre_patch_callback: livepatch_callbacks_mod -> [MODULE_STATE_COMING] Full formed, running module_init 509 - [ 100.932645] livepatch_callbacks_demo: post_patch_callback: livepatch_callbacks_mod -> [MODULE_STATE_COMING] Full formed, running module_init 510 - [ 100.934125] livepatch_callbacks_mod: livepatch_callbacks_mod_init 511 - 512 - % rmmod samples/livepatch/livepatch-callbacks-mod.ko 513 - [ 102.942805] livepatch_callbacks_mod: livepatch_callbacks_mod_exit 514 - [ 102.943640] livepatch_callbacks_demo: pre_unpatch_callback: livepatch_callbacks_mod -> [MODULE_STATE_GOING] Going away 515 - [ 102.944585] livepatch: reverting patch 'livepatch_callbacks_demo' on unloading module 'livepatch_callbacks_mod' 516 - [ 102.945455] livepatch_callbacks_demo: post_unpatch_callback: livepatch_callbacks_mod -> [MODULE_STATE_GOING] Going away 517 - 518 - % echo 0 > /sys/kernel/livepatch/livepatch_callbacks_demo/enabled 519 - [ 104.953815] livepatch: 'livepatch_callbacks_demo': initializing unpatching transition 520 - [ 104.953838] livepatch_callbacks_demo: pre_unpatch_callback: vmlinux 521 - [ 104.954431] livepatch_callbacks_demo: pre_unpatch_callback: livepatch_callbacks_busymod -> [MODULE_STATE_LIVE] Normal state 522 - [ 104.955426] livepatch: 'livepatch_callbacks_demo': starting unpatching transition 523 - [ 106.719073] livepatch: 'livepatch_callbacks_demo': completing unpatching transition 524 - [ 106.722633] livepatch_callbacks_demo: post_unpatch_callback: vmlinux 525 - [ 106.723282] livepatch_callbacks_demo: post_unpatch_callback: livepatch_callbacks_busymod -> [MODULE_STATE_LIVE] Normal state 526 - [ 106.724279] livepatch: 'livepatch_callbacks_demo': unpatching complete 527 - 528 - % rmmod samples/livepatch/livepatch-callbacks-demo.ko 529 - % rmmod samples/livepatch/livepatch-callbacks-busymod.ko 530 - [ 108.975660] livepatch_callbacks_busymod: livepatch_callbacks_mod_exit 531 - 532 - 533 - Test 9 534 - ------ 535 - 536 - A similar test as the previous one, but force the "busy" kernel module 537 - to do longer work. 538 - 539 - The livepatching core will refuse to patch a task that is currently 540 - executing a to-be-patched function -- the consistency model stalls the 541 - current patch transition until this safety-check is met. Test a 542 - scenario where one of a livepatch's target klp_objects sits on such a 543 - function for a long time. Meanwhile, load and unload other target 544 - kernel modules while the livepatch transition is in progress. 545 - 546 - - load busy target module (30s sleep) 547 - - load livepatch 548 - - load target module 549 - - unload target module 550 - - disable livepatch 551 - - unload livepatch 552 - - unload busy target module 553 - 554 - 555 - Load the "busy" kernel module, this time make it do 30 seconds worth of 556 - work: 557 - 558 - % insmod samples/livepatch/livepatch-callbacks-busymod.ko sleep_secs=30 559 - [ 110.993362] livepatch_callbacks_busymod: livepatch_callbacks_mod_init 560 - [ 110.994059] livepatch_callbacks_busymod: busymod_work_func, sleeping 30 seconds ... 561 - 562 - Meanwhile, the livepatch is loaded. Notice that the patch transition 563 - does not complete as the targeted "busy" module is sitting on a 564 - to-be-patched function: 565 - 566 - % insmod samples/livepatch/livepatch-callbacks-demo.ko 567 - [ 113.000309] livepatch: enabling patch 'livepatch_callbacks_demo' 568 - [ 113.000764] livepatch: 'livepatch_callbacks_demo': initializing patching transition 569 - [ 113.000791] livepatch_callbacks_demo: pre_patch_callback: vmlinux 570 - [ 113.001289] livepatch_callbacks_demo: pre_patch_callback: livepatch_callbacks_busymod -> [MODULE_STATE_LIVE] Normal state 571 - [ 113.005208] livepatch: 'livepatch_callbacks_demo': starting patching transition 572 - 573 - Load a second target module (this one is an ordinary idle kernel 574 - module). Note that *no* post-patch callbacks will be executed while the 575 - livepatch is still in transition: 576 - 577 - % insmod samples/livepatch/livepatch-callbacks-mod.ko 578 - [ 115.012740] livepatch: applying patch 'livepatch_callbacks_demo' to loading module 'livepatch_callbacks_mod' 579 - [ 115.013406] livepatch_callbacks_demo: pre_patch_callback: livepatch_callbacks_mod -> [MODULE_STATE_COMING] Full formed, running module_init 580 - [ 115.015315] livepatch_callbacks_mod: livepatch_callbacks_mod_init 581 - 582 - Request an unload of the simple kernel module. The patch is still 583 - transitioning, so its pre-unpatch callbacks are skipped: 584 - 585 - % rmmod samples/livepatch/livepatch-callbacks-mod.ko 586 - [ 117.022626] livepatch_callbacks_mod: livepatch_callbacks_mod_exit 587 - [ 117.023376] livepatch: reverting patch 'livepatch_callbacks_demo' on unloading module 'livepatch_callbacks_mod' 588 - [ 117.024533] livepatch_callbacks_demo: post_unpatch_callback: livepatch_callbacks_mod -> [MODULE_STATE_GOING] Going away 589 - 590 - Finally the livepatch is disabled. Since none of the patch's 591 - klp_object's post-patch callbacks executed, the remaining klp_object's 592 - pre-unpatch callbacks are skipped: 593 - 594 - % echo 0 > /sys/kernel/livepatch/livepatch_callbacks_demo/enabled 595 - [ 119.035408] livepatch: 'livepatch_callbacks_demo': reversing transition from patching to unpatching 596 - [ 119.035485] livepatch: 'livepatch_callbacks_demo': starting unpatching transition 597 - [ 119.711166] livepatch: 'livepatch_callbacks_demo': completing unpatching transition 598 - [ 119.714179] livepatch_callbacks_demo: post_unpatch_callback: vmlinux 599 - [ 119.714653] livepatch_callbacks_demo: post_unpatch_callback: livepatch_callbacks_busymod -> [MODULE_STATE_LIVE] Normal state 600 - [ 119.715437] livepatch: 'livepatch_callbacks_demo': unpatching complete 601 - 602 - % rmmod samples/livepatch/livepatch-callbacks-demo.ko 603 - % rmmod samples/livepatch/livepatch-callbacks-busymod.ko 604 - [ 141.279111] livepatch_callbacks_busymod: busymod_work_func exit 605 - [ 141.279760] livepatch_callbacks_busymod: livepatch_callbacks_mod_exit 121 + Other Examples 122 + ============== 123 + 124 + Sample livepatch modules demonstrating the callback API can be found in 125 + samples/livepatch/ directory. These samples were modified for use in 126 + kselftests and can be found in the lib/livepatch directory.
+1
MAINTAINERS
··· 8832 8832 F: Documentation/livepatch/ 8833 8833 F: Documentation/ABI/testing/sysfs-kernel-livepatch 8834 8834 F: samples/livepatch/ 8835 + F: tools/testing/selftests/livepatch/ 8835 8836 L: live-patching@vger.kernel.org 8836 8837 T: git git://git.kernel.org/pub/scm/linux/kernel/git/jikos/livepatching.git 8837 8838
+21 -1
lib/Kconfig.debug
··· 1991 1991 1992 1992 If unsure, say N. 1993 1993 1994 + config TEST_LIVEPATCH 1995 + tristate "Test livepatching" 1996 + default n 1997 + depends on LIVEPATCH 1998 + depends on m 1999 + help 2000 + Test kernel livepatching features for correctness. The tests will 2001 + load test modules that will be livepatched in various scenarios. 2002 + 2003 + To run all the livepatching tests: 2004 + 2005 + make -C tools/testing/selftests TARGETS=livepatch run_tests 2006 + 2007 + Alternatively, individual tests may be invoked: 2008 + 2009 + tools/testing/selftests/livepatch/test-callbacks.sh 2010 + tools/testing/selftests/livepatch/test-livepatch.sh 2011 + tools/testing/selftests/livepatch/test-shadow-vars.sh 2012 + 2013 + If unsure, say N. 2014 + 1994 2015 config TEST_OBJAGG 1995 2016 tristate "Perform selftest on object aggreration manager" 1996 2017 default n ··· 2020 1999 Enable this option to test object aggregation manager on boot 2021 2000 (or module load). 2022 2001 2023 - If unsure, say N. 2024 2002 2025 2003 endif # RUNTIME_TESTING_MENU 2026 2004
+2
lib/Makefile
··· 77 77 obj-$(CONFIG_TEST_MEMCAT_P) += test_memcat_p.o 78 78 obj-$(CONFIG_TEST_OBJAGG) += test_objagg.o 79 79 80 + obj-$(CONFIG_TEST_LIVEPATCH) += livepatch/ 81 + 80 82 ifeq ($(CONFIG_DEBUG_KOBJECT),y) 81 83 CFLAGS_kobject.o += -DDEBUG 82 84 CFLAGS_kobject_uevent.o += -DDEBUG
+15
lib/livepatch/Makefile
··· 1 + # SPDX-License-Identifier: GPL-2.0 2 + # 3 + # Makefile for livepatch test code. 4 + 5 + obj-$(CONFIG_TEST_LIVEPATCH) += test_klp_atomic_replace.o \ 6 + test_klp_callbacks_demo.o \ 7 + test_klp_callbacks_demo2.o \ 8 + test_klp_callbacks_busy.o \ 9 + test_klp_callbacks_mod.o \ 10 + test_klp_livepatch.o \ 11 + test_klp_shadow_vars.o 12 + 13 + # Target modules to be livepatched require CC_FLAGS_FTRACE 14 + CFLAGS_test_klp_callbacks_busy.o += $(CC_FLAGS_FTRACE) 15 + CFLAGS_test_klp_callbacks_mod.o += $(CC_FLAGS_FTRACE)
+57
lib/livepatch/test_klp_atomic_replace.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // Copyright (C) 2018 Joe Lawrence <joe.lawrence@redhat.com> 3 + 4 + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 5 + 6 + #include <linux/module.h> 7 + #include <linux/kernel.h> 8 + #include <linux/livepatch.h> 9 + 10 + static int replace; 11 + module_param(replace, int, 0644); 12 + MODULE_PARM_DESC(replace, "replace (default=0)"); 13 + 14 + #include <linux/seq_file.h> 15 + static int livepatch_meminfo_proc_show(struct seq_file *m, void *v) 16 + { 17 + seq_printf(m, "%s: %s\n", THIS_MODULE->name, 18 + "this has been live patched"); 19 + return 0; 20 + } 21 + 22 + static struct klp_func funcs[] = { 23 + { 24 + .old_name = "meminfo_proc_show", 25 + .new_func = livepatch_meminfo_proc_show, 26 + }, {} 27 + }; 28 + 29 + static struct klp_object objs[] = { 30 + { 31 + /* name being NULL means vmlinux */ 32 + .funcs = funcs, 33 + }, {} 34 + }; 35 + 36 + static struct klp_patch patch = { 37 + .mod = THIS_MODULE, 38 + .objs = objs, 39 + /* set .replace in the init function below for demo purposes */ 40 + }; 41 + 42 + static int test_klp_atomic_replace_init(void) 43 + { 44 + patch.replace = replace; 45 + return klp_enable_patch(&patch); 46 + } 47 + 48 + static void test_klp_atomic_replace_exit(void) 49 + { 50 + } 51 + 52 + module_init(test_klp_atomic_replace_init); 53 + module_exit(test_klp_atomic_replace_exit); 54 + MODULE_LICENSE("GPL"); 55 + MODULE_INFO(livepatch, "Y"); 56 + MODULE_AUTHOR("Joe Lawrence <joe.lawrence@redhat.com>"); 57 + MODULE_DESCRIPTION("Livepatch test: atomic replace");
+43
lib/livepatch/test_klp_callbacks_busy.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // Copyright (C) 2018 Joe Lawrence <joe.lawrence@redhat.com> 3 + 4 + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 5 + 6 + #include <linux/module.h> 7 + #include <linux/kernel.h> 8 + #include <linux/workqueue.h> 9 + #include <linux/delay.h> 10 + 11 + static int sleep_secs; 12 + module_param(sleep_secs, int, 0644); 13 + MODULE_PARM_DESC(sleep_secs, "sleep_secs (default=0)"); 14 + 15 + static void busymod_work_func(struct work_struct *work); 16 + static DECLARE_DELAYED_WORK(work, busymod_work_func); 17 + 18 + static void busymod_work_func(struct work_struct *work) 19 + { 20 + pr_info("%s, sleeping %d seconds ...\n", __func__, sleep_secs); 21 + msleep(sleep_secs * 1000); 22 + pr_info("%s exit\n", __func__); 23 + } 24 + 25 + static int test_klp_callbacks_busy_init(void) 26 + { 27 + pr_info("%s\n", __func__); 28 + schedule_delayed_work(&work, 29 + msecs_to_jiffies(1000 * 0)); 30 + return 0; 31 + } 32 + 33 + static void test_klp_callbacks_busy_exit(void) 34 + { 35 + cancel_delayed_work_sync(&work); 36 + pr_info("%s\n", __func__); 37 + } 38 + 39 + module_init(test_klp_callbacks_busy_init); 40 + module_exit(test_klp_callbacks_busy_exit); 41 + MODULE_LICENSE("GPL"); 42 + MODULE_AUTHOR("Joe Lawrence <joe.lawrence@redhat.com>"); 43 + MODULE_DESCRIPTION("Livepatch test: busy target module");
+121
lib/livepatch/test_klp_callbacks_demo.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // Copyright (C) 2018 Joe Lawrence <joe.lawrence@redhat.com> 3 + 4 + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 5 + 6 + #include <linux/module.h> 7 + #include <linux/kernel.h> 8 + #include <linux/livepatch.h> 9 + 10 + static int pre_patch_ret; 11 + module_param(pre_patch_ret, int, 0644); 12 + MODULE_PARM_DESC(pre_patch_ret, "pre_patch_ret (default=0)"); 13 + 14 + static const char *const module_state[] = { 15 + [MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state", 16 + [MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init", 17 + [MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away", 18 + [MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up", 19 + }; 20 + 21 + static void callback_info(const char *callback, struct klp_object *obj) 22 + { 23 + if (obj->mod) 24 + pr_info("%s: %s -> %s\n", callback, obj->mod->name, 25 + module_state[obj->mod->state]); 26 + else 27 + pr_info("%s: vmlinux\n", callback); 28 + } 29 + 30 + /* Executed on object patching (ie, patch enablement) */ 31 + static int pre_patch_callback(struct klp_object *obj) 32 + { 33 + callback_info(__func__, obj); 34 + return pre_patch_ret; 35 + } 36 + 37 + /* Executed on object unpatching (ie, patch disablement) */ 38 + static void post_patch_callback(struct klp_object *obj) 39 + { 40 + callback_info(__func__, obj); 41 + } 42 + 43 + /* Executed on object unpatching (ie, patch disablement) */ 44 + static void pre_unpatch_callback(struct klp_object *obj) 45 + { 46 + callback_info(__func__, obj); 47 + } 48 + 49 + /* Executed on object unpatching (ie, patch disablement) */ 50 + static void post_unpatch_callback(struct klp_object *obj) 51 + { 52 + callback_info(__func__, obj); 53 + } 54 + 55 + static void patched_work_func(struct work_struct *work) 56 + { 57 + pr_info("%s\n", __func__); 58 + } 59 + 60 + static struct klp_func no_funcs[] = { 61 + {} 62 + }; 63 + 64 + static struct klp_func busymod_funcs[] = { 65 + { 66 + .old_name = "busymod_work_func", 67 + .new_func = patched_work_func, 68 + }, {} 69 + }; 70 + 71 + static struct klp_object objs[] = { 72 + { 73 + .name = NULL, /* vmlinux */ 74 + .funcs = no_funcs, 75 + .callbacks = { 76 + .pre_patch = pre_patch_callback, 77 + .post_patch = post_patch_callback, 78 + .pre_unpatch = pre_unpatch_callback, 79 + .post_unpatch = post_unpatch_callback, 80 + }, 81 + }, { 82 + .name = "test_klp_callbacks_mod", 83 + .funcs = no_funcs, 84 + .callbacks = { 85 + .pre_patch = pre_patch_callback, 86 + .post_patch = post_patch_callback, 87 + .pre_unpatch = pre_unpatch_callback, 88 + .post_unpatch = post_unpatch_callback, 89 + }, 90 + }, { 91 + .name = "test_klp_callbacks_busy", 92 + .funcs = busymod_funcs, 93 + .callbacks = { 94 + .pre_patch = pre_patch_callback, 95 + .post_patch = post_patch_callback, 96 + .pre_unpatch = pre_unpatch_callback, 97 + .post_unpatch = post_unpatch_callback, 98 + }, 99 + }, { } 100 + }; 101 + 102 + static struct klp_patch patch = { 103 + .mod = THIS_MODULE, 104 + .objs = objs, 105 + }; 106 + 107 + static int test_klp_callbacks_demo_init(void) 108 + { 109 + return klp_enable_patch(&patch); 110 + } 111 + 112 + static void test_klp_callbacks_demo_exit(void) 113 + { 114 + } 115 + 116 + module_init(test_klp_callbacks_demo_init); 117 + module_exit(test_klp_callbacks_demo_exit); 118 + MODULE_LICENSE("GPL"); 119 + MODULE_INFO(livepatch, "Y"); 120 + MODULE_AUTHOR("Joe Lawrence <joe.lawrence@redhat.com>"); 121 + MODULE_DESCRIPTION("Livepatch test: livepatch demo");
+93
lib/livepatch/test_klp_callbacks_demo2.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // Copyright (C) 2018 Joe Lawrence <joe.lawrence@redhat.com> 3 + 4 + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 5 + 6 + #include <linux/module.h> 7 + #include <linux/kernel.h> 8 + #include <linux/livepatch.h> 9 + 10 + static int replace; 11 + module_param(replace, int, 0644); 12 + MODULE_PARM_DESC(replace, "replace (default=0)"); 13 + 14 + static const char *const module_state[] = { 15 + [MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state", 16 + [MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init", 17 + [MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away", 18 + [MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up", 19 + }; 20 + 21 + static void callback_info(const char *callback, struct klp_object *obj) 22 + { 23 + if (obj->mod) 24 + pr_info("%s: %s -> %s\n", callback, obj->mod->name, 25 + module_state[obj->mod->state]); 26 + else 27 + pr_info("%s: vmlinux\n", callback); 28 + } 29 + 30 + /* Executed on object patching (ie, patch enablement) */ 31 + static int pre_patch_callback(struct klp_object *obj) 32 + { 33 + callback_info(__func__, obj); 34 + return 0; 35 + } 36 + 37 + /* Executed on object unpatching (ie, patch disablement) */ 38 + static void post_patch_callback(struct klp_object *obj) 39 + { 40 + callback_info(__func__, obj); 41 + } 42 + 43 + /* Executed on object unpatching (ie, patch disablement) */ 44 + static void pre_unpatch_callback(struct klp_object *obj) 45 + { 46 + callback_info(__func__, obj); 47 + } 48 + 49 + /* Executed on object unpatching (ie, patch disablement) */ 50 + static void post_unpatch_callback(struct klp_object *obj) 51 + { 52 + callback_info(__func__, obj); 53 + } 54 + 55 + static struct klp_func no_funcs[] = { 56 + { } 57 + }; 58 + 59 + static struct klp_object objs[] = { 60 + { 61 + .name = NULL, /* vmlinux */ 62 + .funcs = no_funcs, 63 + .callbacks = { 64 + .pre_patch = pre_patch_callback, 65 + .post_patch = post_patch_callback, 66 + .pre_unpatch = pre_unpatch_callback, 67 + .post_unpatch = post_unpatch_callback, 68 + }, 69 + }, { } 70 + }; 71 + 72 + static struct klp_patch patch = { 73 + .mod = THIS_MODULE, 74 + .objs = objs, 75 + /* set .replace in the init function below for demo purposes */ 76 + }; 77 + 78 + static int test_klp_callbacks_demo2_init(void) 79 + { 80 + patch.replace = replace; 81 + return klp_enable_patch(&patch); 82 + } 83 + 84 + static void test_klp_callbacks_demo2_exit(void) 85 + { 86 + } 87 + 88 + module_init(test_klp_callbacks_demo2_init); 89 + module_exit(test_klp_callbacks_demo2_exit); 90 + MODULE_LICENSE("GPL"); 91 + MODULE_INFO(livepatch, "Y"); 92 + MODULE_AUTHOR("Joe Lawrence <joe.lawrence@redhat.com>"); 93 + MODULE_DESCRIPTION("Livepatch test: livepatch demo2");
+24
lib/livepatch/test_klp_callbacks_mod.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // Copyright (C) 2018 Joe Lawrence <joe.lawrence@redhat.com> 3 + 4 + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 5 + 6 + #include <linux/module.h> 7 + #include <linux/kernel.h> 8 + 9 + static int test_klp_callbacks_mod_init(void) 10 + { 11 + pr_info("%s\n", __func__); 12 + return 0; 13 + } 14 + 15 + static void test_klp_callbacks_mod_exit(void) 16 + { 17 + pr_info("%s\n", __func__); 18 + } 19 + 20 + module_init(test_klp_callbacks_mod_init); 21 + module_exit(test_klp_callbacks_mod_exit); 22 + MODULE_LICENSE("GPL"); 23 + MODULE_AUTHOR("Joe Lawrence <joe.lawrence@redhat.com>"); 24 + MODULE_DESCRIPTION("Livepatch test: target module");
+51
lib/livepatch/test_klp_livepatch.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // Copyright (C) 2014 Seth Jennings <sjenning@redhat.com> 3 + 4 + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 5 + 6 + #include <linux/module.h> 7 + #include <linux/kernel.h> 8 + #include <linux/livepatch.h> 9 + 10 + #include <linux/seq_file.h> 11 + static int livepatch_cmdline_proc_show(struct seq_file *m, void *v) 12 + { 13 + seq_printf(m, "%s: %s\n", THIS_MODULE->name, 14 + "this has been live patched"); 15 + return 0; 16 + } 17 + 18 + static struct klp_func funcs[] = { 19 + { 20 + .old_name = "cmdline_proc_show", 21 + .new_func = livepatch_cmdline_proc_show, 22 + }, { } 23 + }; 24 + 25 + static struct klp_object objs[] = { 26 + { 27 + /* name being NULL means vmlinux */ 28 + .funcs = funcs, 29 + }, { } 30 + }; 31 + 32 + static struct klp_patch patch = { 33 + .mod = THIS_MODULE, 34 + .objs = objs, 35 + }; 36 + 37 + static int test_klp_livepatch_init(void) 38 + { 39 + return klp_enable_patch(&patch); 40 + } 41 + 42 + static void test_klp_livepatch_exit(void) 43 + { 44 + } 45 + 46 + module_init(test_klp_livepatch_init); 47 + module_exit(test_klp_livepatch_exit); 48 + MODULE_LICENSE("GPL"); 49 + MODULE_INFO(livepatch, "Y"); 50 + MODULE_AUTHOR("Seth Jennings <sjenning@redhat.com>"); 51 + MODULE_DESCRIPTION("Livepatch test: livepatch module");
+236
lib/livepatch/test_klp_shadow_vars.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // Copyright (C) 2018 Joe Lawrence <joe.lawrence@redhat.com> 3 + 4 + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 5 + 6 + #include <linux/module.h> 7 + #include <linux/kernel.h> 8 + #include <linux/list.h> 9 + #include <linux/livepatch.h> 10 + #include <linux/slab.h> 11 + 12 + /* 13 + * Keep a small list of pointers so that we can print address-agnostic 14 + * pointer values. Use a rolling integer count to differentiate the values. 15 + * Ironically we could have used the shadow variable API to do this, but 16 + * let's not lean too heavily on the very code we're testing. 17 + */ 18 + static LIST_HEAD(ptr_list); 19 + struct shadow_ptr { 20 + void *ptr; 21 + int id; 22 + struct list_head list; 23 + }; 24 + 25 + static void free_ptr_list(void) 26 + { 27 + struct shadow_ptr *sp, *tmp_sp; 28 + 29 + list_for_each_entry_safe(sp, tmp_sp, &ptr_list, list) { 30 + list_del(&sp->list); 31 + kfree(sp); 32 + } 33 + } 34 + 35 + static int ptr_id(void *ptr) 36 + { 37 + struct shadow_ptr *sp; 38 + static int count; 39 + 40 + list_for_each_entry(sp, &ptr_list, list) { 41 + if (sp->ptr == ptr) 42 + return sp->id; 43 + } 44 + 45 + sp = kmalloc(sizeof(*sp), GFP_ATOMIC); 46 + if (!sp) 47 + return -1; 48 + sp->ptr = ptr; 49 + sp->id = count++; 50 + 51 + list_add(&sp->list, &ptr_list); 52 + 53 + return sp->id; 54 + } 55 + 56 + /* 57 + * Shadow variable wrapper functions that echo the function and arguments 58 + * to the kernel log for testing verification. Don't display raw pointers, 59 + * but use the ptr_id() value instead. 60 + */ 61 + static void *shadow_get(void *obj, unsigned long id) 62 + { 63 + void *ret = klp_shadow_get(obj, id); 64 + 65 + pr_info("klp_%s(obj=PTR%d, id=0x%lx) = PTR%d\n", 66 + __func__, ptr_id(obj), id, ptr_id(ret)); 67 + 68 + return ret; 69 + } 70 + 71 + static void *shadow_alloc(void *obj, unsigned long id, size_t size, 72 + gfp_t gfp_flags, klp_shadow_ctor_t ctor, 73 + void *ctor_data) 74 + { 75 + void *ret = klp_shadow_alloc(obj, id, size, gfp_flags, ctor, 76 + ctor_data); 77 + pr_info("klp_%s(obj=PTR%d, id=0x%lx, size=%zx, gfp_flags=%pGg), ctor=PTR%d, ctor_data=PTR%d = PTR%d\n", 78 + __func__, ptr_id(obj), id, size, &gfp_flags, ptr_id(ctor), 79 + ptr_id(ctor_data), ptr_id(ret)); 80 + return ret; 81 + } 82 + 83 + static void *shadow_get_or_alloc(void *obj, unsigned long id, size_t size, 84 + gfp_t gfp_flags, klp_shadow_ctor_t ctor, 85 + void *ctor_data) 86 + { 87 + void *ret = klp_shadow_get_or_alloc(obj, id, size, gfp_flags, ctor, 88 + ctor_data); 89 + pr_info("klp_%s(obj=PTR%d, id=0x%lx, size=%zx, gfp_flags=%pGg), ctor=PTR%d, ctor_data=PTR%d = PTR%d\n", 90 + __func__, ptr_id(obj), id, size, &gfp_flags, ptr_id(ctor), 91 + ptr_id(ctor_data), ptr_id(ret)); 92 + return ret; 93 + } 94 + 95 + static void shadow_free(void *obj, unsigned long id, klp_shadow_dtor_t dtor) 96 + { 97 + klp_shadow_free(obj, id, dtor); 98 + pr_info("klp_%s(obj=PTR%d, id=0x%lx, dtor=PTR%d)\n", 99 + __func__, ptr_id(obj), id, ptr_id(dtor)); 100 + } 101 + 102 + static void shadow_free_all(unsigned long id, klp_shadow_dtor_t dtor) 103 + { 104 + klp_shadow_free_all(id, dtor); 105 + pr_info("klp_%s(id=0x%lx, dtor=PTR%d)\n", 106 + __func__, id, ptr_id(dtor)); 107 + } 108 + 109 + 110 + /* Shadow variable constructor - remember simple pointer data */ 111 + static int shadow_ctor(void *obj, void *shadow_data, void *ctor_data) 112 + { 113 + int **shadow_int = shadow_data; 114 + *shadow_int = ctor_data; 115 + pr_info("%s: PTR%d -> PTR%d\n", 116 + __func__, ptr_id(shadow_int), ptr_id(ctor_data)); 117 + 118 + return 0; 119 + } 120 + 121 + static void shadow_dtor(void *obj, void *shadow_data) 122 + { 123 + pr_info("%s(obj=PTR%d, shadow_data=PTR%d)\n", 124 + __func__, ptr_id(obj), ptr_id(shadow_data)); 125 + } 126 + 127 + static int test_klp_shadow_vars_init(void) 128 + { 129 + void *obj = THIS_MODULE; 130 + int id = 0x1234; 131 + size_t size = sizeof(int *); 132 + gfp_t gfp_flags = GFP_KERNEL; 133 + 134 + int var1, var2, var3, var4; 135 + int **sv1, **sv2, **sv3, **sv4; 136 + 137 + void *ret; 138 + 139 + ptr_id(NULL); 140 + ptr_id(&var1); 141 + ptr_id(&var2); 142 + ptr_id(&var3); 143 + ptr_id(&var4); 144 + 145 + /* 146 + * With an empty shadow variable hash table, expect not to find 147 + * any matches. 148 + */ 149 + ret = shadow_get(obj, id); 150 + if (!ret) 151 + pr_info(" got expected NULL result\n"); 152 + 153 + /* 154 + * Allocate a few shadow variables with different <obj> and <id>. 155 + */ 156 + sv1 = shadow_alloc(obj, id, size, gfp_flags, shadow_ctor, &var1); 157 + sv2 = shadow_alloc(obj + 1, id, size, gfp_flags, shadow_ctor, &var2); 158 + sv3 = shadow_alloc(obj, id + 1, size, gfp_flags, shadow_ctor, &var3); 159 + 160 + /* 161 + * Verify we can find our new shadow variables and that they point 162 + * to expected data. 163 + */ 164 + ret = shadow_get(obj, id); 165 + if (ret == sv1 && *sv1 == &var1) 166 + pr_info(" got expected PTR%d -> PTR%d result\n", 167 + ptr_id(sv1), ptr_id(*sv1)); 168 + ret = shadow_get(obj + 1, id); 169 + if (ret == sv2 && *sv2 == &var2) 170 + pr_info(" got expected PTR%d -> PTR%d result\n", 171 + ptr_id(sv2), ptr_id(*sv2)); 172 + ret = shadow_get(obj, id + 1); 173 + if (ret == sv3 && *sv3 == &var3) 174 + pr_info(" got expected PTR%d -> PTR%d result\n", 175 + ptr_id(sv3), ptr_id(*sv3)); 176 + 177 + /* 178 + * Allocate or get a few more, this time with the same <obj>, <id>. 179 + * The second invocation should return the same shadow var. 180 + */ 181 + sv4 = shadow_get_or_alloc(obj + 2, id, size, gfp_flags, shadow_ctor, &var4); 182 + ret = shadow_get_or_alloc(obj + 2, id, size, gfp_flags, shadow_ctor, &var4); 183 + if (ret == sv4 && *sv4 == &var4) 184 + pr_info(" got expected PTR%d -> PTR%d result\n", 185 + ptr_id(sv4), ptr_id(*sv4)); 186 + 187 + /* 188 + * Free the <obj=*, id> shadow variables and check that we can no 189 + * longer find them. 190 + */ 191 + shadow_free(obj, id, shadow_dtor); /* sv1 */ 192 + ret = shadow_get(obj, id); 193 + if (!ret) 194 + pr_info(" got expected NULL result\n"); 195 + 196 + shadow_free(obj + 1, id, shadow_dtor); /* sv2 */ 197 + ret = shadow_get(obj + 1, id); 198 + if (!ret) 199 + pr_info(" got expected NULL result\n"); 200 + 201 + shadow_free(obj + 2, id, shadow_dtor); /* sv4 */ 202 + ret = shadow_get(obj + 2, id); 203 + if (!ret) 204 + pr_info(" got expected NULL result\n"); 205 + 206 + /* 207 + * We should still find an <id+1> variable. 208 + */ 209 + ret = shadow_get(obj, id + 1); 210 + if (ret == sv3 && *sv3 == &var3) 211 + pr_info(" got expected PTR%d -> PTR%d result\n", 212 + ptr_id(sv3), ptr_id(*sv3)); 213 + 214 + /* 215 + * Free all the <id+1> variables, too. 216 + */ 217 + shadow_free_all(id + 1, shadow_dtor); /* sv3 */ 218 + ret = shadow_get(obj, id); 219 + if (!ret) 220 + pr_info(" shadow_get() got expected NULL result\n"); 221 + 222 + 223 + free_ptr_list(); 224 + 225 + return 0; 226 + } 227 + 228 + static void test_klp_shadow_vars_exit(void) 229 + { 230 + } 231 + 232 + module_init(test_klp_shadow_vars_init); 233 + module_exit(test_klp_shadow_vars_exit); 234 + MODULE_LICENSE("GPL"); 235 + MODULE_AUTHOR("Joe Lawrence <joe.lawrence@redhat.com>"); 236 + MODULE_DESCRIPTION("Livepatch test: shadow variables");
+1
tools/testing/selftests/Makefile
··· 21 21 TARGETS += kcmp 22 22 TARGETS += kvm 23 23 TARGETS += lib 24 + TARGETS += livepatch 24 25 TARGETS += membarrier 25 26 TARGETS += memfd 26 27 TARGETS += memory-hotplug
+8
tools/testing/selftests/livepatch/Makefile
··· 1 + # SPDX-License-Identifier: GPL-2.0 2 + 3 + TEST_GEN_PROGS := \ 4 + test-livepatch.sh \ 5 + test-callbacks.sh \ 6 + test-shadow-vars.sh 7 + 8 + include ../lib.mk
+43
tools/testing/selftests/livepatch/README
··· 1 + ==================== 2 + Livepatch Self Tests 3 + ==================== 4 + 5 + This is a small set of sanity tests for the kernel livepatching. 6 + 7 + The test suite loads and unloads several test kernel modules to verify 8 + livepatch behavior. Debug information is logged to the kernel's message 9 + buffer and parsed for expected messages. (Note: the tests will clear 10 + the message buffer between individual tests.) 11 + 12 + 13 + Config 14 + ------ 15 + 16 + Set these config options and their prerequisites: 17 + 18 + CONFIG_LIVEPATCH=y 19 + CONFIG_TEST_LIVEPATCH=m 20 + 21 + 22 + Running the tests 23 + ----------------- 24 + 25 + Test kernel modules are built as part of lib/ (make modules) and need to 26 + be installed (make modules_install) as the test scripts will modprobe 27 + them. 28 + 29 + To run the livepatch selftests, from the top of the kernel source tree: 30 + 31 + % make -C tools/testing/selftests TARGETS=livepatch run_tests 32 + 33 + 34 + Adding tests 35 + ------------ 36 + 37 + See the common functions.sh file for the existing collection of utility 38 + functions, most importantly set_dynamic_debug() and check_result(). The 39 + latter function greps the kernel's ring buffer for "livepatch:" and 40 + "test_klp" strings, so tests be sure to include one of those strings for 41 + result comparison. Other utility functions include general module 42 + loading and livepatch loading helpers (waiting for patch transitions, 43 + sysfs entries, etc.)
+1
tools/testing/selftests/livepatch/config
··· 1 + CONFIG_TEST_LIVEPATCH=m
+203
tools/testing/selftests/livepatch/functions.sh
··· 1 + #!/bin/bash 2 + # SPDX-License-Identifier: GPL-2.0 3 + # Copyright (C) 2018 Joe Lawrence <joe.lawrence@redhat.com> 4 + 5 + # Shell functions for the rest of the scripts. 6 + 7 + MAX_RETRIES=600 8 + RETRY_INTERVAL=".1" # seconds 9 + 10 + # log(msg) - write message to kernel log 11 + # msg - insightful words 12 + function log() { 13 + echo "$1" > /dev/kmsg 14 + } 15 + 16 + # die(msg) - game over, man 17 + # msg - dying words 18 + function die() { 19 + log "ERROR: $1" 20 + echo "ERROR: $1" >&2 21 + exit 1 22 + } 23 + 24 + # set_dynamic_debug() - setup kernel dynamic debug 25 + # TODO - push and pop this config? 26 + function set_dynamic_debug() { 27 + cat << EOF > /sys/kernel/debug/dynamic_debug/control 28 + file kernel/livepatch/* +p 29 + func klp_try_switch_task -p 30 + EOF 31 + } 32 + 33 + # loop_until(cmd) - loop a command until it is successful or $MAX_RETRIES, 34 + # sleep $RETRY_INTERVAL between attempts 35 + # cmd - command and its arguments to run 36 + function loop_until() { 37 + local cmd="$*" 38 + local i=0 39 + while true; do 40 + eval "$cmd" && return 0 41 + [[ $((i++)) -eq $MAX_RETRIES ]] && return 1 42 + sleep $RETRY_INTERVAL 43 + done 44 + } 45 + 46 + function is_livepatch_mod() { 47 + local mod="$1" 48 + 49 + if [[ $(modinfo "$mod" | awk '/^livepatch:/{print $NF}') == "Y" ]]; then 50 + return 0 51 + fi 52 + 53 + return 1 54 + } 55 + 56 + function __load_mod() { 57 + local mod="$1"; shift 58 + local args="$*" 59 + 60 + local msg="% modprobe $mod $args" 61 + log "${msg%% }" 62 + ret=$(modprobe "$mod" "$args" 2>&1) 63 + if [[ "$ret" != "" ]]; then 64 + die "$ret" 65 + fi 66 + 67 + # Wait for module in sysfs ... 68 + loop_until '[[ -e "/sys/module/$mod" ]]' || 69 + die "failed to load module $mod" 70 + } 71 + 72 + 73 + # load_mod(modname, params) - load a kernel module 74 + # modname - module name to load 75 + # params - module parameters to pass to modprobe 76 + function load_mod() { 77 + local mod="$1"; shift 78 + local args="$*" 79 + 80 + is_livepatch_mod "$mod" && 81 + die "use load_lp() to load the livepatch module $mod" 82 + 83 + __load_mod "$mod" "$args" 84 + } 85 + 86 + # load_lp_nowait(modname, params) - load a kernel module with a livepatch 87 + # but do not wait on until the transition finishes 88 + # modname - module name to load 89 + # params - module parameters to pass to modprobe 90 + function load_lp_nowait() { 91 + local mod="$1"; shift 92 + local args="$*" 93 + 94 + is_livepatch_mod "$mod" || 95 + die "module $mod is not a livepatch" 96 + 97 + __load_mod "$mod" "$args" 98 + 99 + # Wait for livepatch in sysfs ... 100 + loop_until '[[ -e "/sys/kernel/livepatch/$mod" ]]' || 101 + die "failed to load module $mod (sysfs)" 102 + } 103 + 104 + # load_lp(modname, params) - load a kernel module with a livepatch 105 + # modname - module name to load 106 + # params - module parameters to pass to modprobe 107 + function load_lp() { 108 + local mod="$1"; shift 109 + local args="$*" 110 + 111 + load_lp_nowait "$mod" "$args" 112 + 113 + # Wait until the transition finishes ... 114 + loop_until 'grep -q '^0$' /sys/kernel/livepatch/$mod/transition' || 115 + die "failed to complete transition" 116 + } 117 + 118 + # load_failing_mod(modname, params) - load a kernel module, expect to fail 119 + # modname - module name to load 120 + # params - module parameters to pass to modprobe 121 + function load_failing_mod() { 122 + local mod="$1"; shift 123 + local args="$*" 124 + 125 + local msg="% modprobe $mod $args" 126 + log "${msg%% }" 127 + ret=$(modprobe "$mod" "$args" 2>&1) 128 + if [[ "$ret" == "" ]]; then 129 + die "$mod unexpectedly loaded" 130 + fi 131 + log "$ret" 132 + } 133 + 134 + # unload_mod(modname) - unload a kernel module 135 + # modname - module name to unload 136 + function unload_mod() { 137 + local mod="$1" 138 + 139 + # Wait for module reference count to clear ... 140 + loop_until '[[ $(cat "/sys/module/$mod/refcnt") == "0" ]]' || 141 + die "failed to unload module $mod (refcnt)" 142 + 143 + log "% rmmod $mod" 144 + ret=$(rmmod "$mod" 2>&1) 145 + if [[ "$ret" != "" ]]; then 146 + die "$ret" 147 + fi 148 + 149 + # Wait for module in sysfs ... 150 + loop_until '[[ ! -e "/sys/module/$mod" ]]' || 151 + die "failed to unload module $mod (/sys/module)" 152 + } 153 + 154 + # unload_lp(modname) - unload a kernel module with a livepatch 155 + # modname - module name to unload 156 + function unload_lp() { 157 + unload_mod "$1" 158 + } 159 + 160 + # disable_lp(modname) - disable a livepatch 161 + # modname - module name to unload 162 + function disable_lp() { 163 + local mod="$1" 164 + 165 + log "% echo 0 > /sys/kernel/livepatch/$mod/enabled" 166 + echo 0 > /sys/kernel/livepatch/"$mod"/enabled 167 + 168 + # Wait until the transition finishes and the livepatch gets 169 + # removed from sysfs... 170 + loop_until '[[ ! -e "/sys/kernel/livepatch/$mod" ]]' || 171 + die "failed to disable livepatch $mod" 172 + } 173 + 174 + # set_pre_patch_ret(modname, pre_patch_ret) 175 + # modname - module name to set 176 + # pre_patch_ret - new pre_patch_ret value 177 + function set_pre_patch_ret { 178 + local mod="$1"; shift 179 + local ret="$1" 180 + 181 + log "% echo $ret > /sys/module/$mod/parameters/pre_patch_ret" 182 + echo "$ret" > /sys/module/"$mod"/parameters/pre_patch_ret 183 + 184 + # Wait for sysfs value to hold ... 185 + loop_until '[[ $(cat "/sys/module/$mod/parameters/pre_patch_ret") == "$ret" ]]' || 186 + die "failed to set pre_patch_ret parameter for $mod module" 187 + } 188 + 189 + # check_result() - verify dmesg output 190 + # TODO - better filter, out of order msgs, etc? 191 + function check_result { 192 + local expect="$*" 193 + local result 194 + 195 + result=$(dmesg | grep -v 'tainting' | grep -e 'livepatch:' -e 'test_klp' | sed 's/^\[[ 0-9.]*\] //') 196 + 197 + if [[ "$expect" == "$result" ]] ; then 198 + echo "ok" 199 + else 200 + echo -e "not ok\n\n$(diff -upr --label expected --label result <(echo "$expect") <(echo "$result"))\n" 201 + die "livepatch kselftest(s) failed" 202 + fi 203 + }
+587
tools/testing/selftests/livepatch/test-callbacks.sh
··· 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
+168
tools/testing/selftests/livepatch/test-livepatch.sh
··· 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_livepatch 8 + MOD_REPLACE=test_klp_atomic_replace 9 + 10 + set_dynamic_debug 11 + 12 + 13 + # TEST: basic function patching 14 + # - load a livepatch that modifies the output from /proc/cmdline and 15 + # verify correct behavior 16 + # - unload the livepatch and make sure the patch was removed 17 + 18 + echo -n "TEST: basic function patching ... " 19 + dmesg -C 20 + 21 + load_lp $MOD_LIVEPATCH 22 + 23 + if [[ "$(cat /proc/cmdline)" != "$MOD_LIVEPATCH: this has been live patched" ]] ; then 24 + echo -e "FAIL\n\n" 25 + die "livepatch kselftest(s) failed" 26 + fi 27 + 28 + disable_lp $MOD_LIVEPATCH 29 + unload_lp $MOD_LIVEPATCH 30 + 31 + if [[ "$(cat /proc/cmdline)" == "$MOD_LIVEPATCH: this has been live patched" ]] ; then 32 + echo -e "FAIL\n\n" 33 + die "livepatch kselftest(s) failed" 34 + fi 35 + 36 + check_result "% modprobe $MOD_LIVEPATCH 37 + livepatch: enabling patch '$MOD_LIVEPATCH' 38 + livepatch: '$MOD_LIVEPATCH': initializing patching transition 39 + livepatch: '$MOD_LIVEPATCH': starting patching transition 40 + livepatch: '$MOD_LIVEPATCH': completing patching transition 41 + livepatch: '$MOD_LIVEPATCH': patching complete 42 + % echo 0 > /sys/kernel/livepatch/$MOD_LIVEPATCH/enabled 43 + livepatch: '$MOD_LIVEPATCH': initializing unpatching transition 44 + livepatch: '$MOD_LIVEPATCH': starting unpatching transition 45 + livepatch: '$MOD_LIVEPATCH': completing unpatching transition 46 + livepatch: '$MOD_LIVEPATCH': unpatching complete 47 + % rmmod $MOD_LIVEPATCH" 48 + 49 + 50 + # TEST: multiple livepatches 51 + # - load a livepatch that modifies the output from /proc/cmdline and 52 + # verify correct behavior 53 + # - load another livepatch and verify that both livepatches are active 54 + # - unload the second livepatch and verify that the first is still active 55 + # - unload the first livepatch and verify none are active 56 + 57 + echo -n "TEST: multiple livepatches ... " 58 + dmesg -C 59 + 60 + load_lp $MOD_LIVEPATCH 61 + 62 + grep 'live patched' /proc/cmdline > /dev/kmsg 63 + grep 'live patched' /proc/meminfo > /dev/kmsg 64 + 65 + load_lp $MOD_REPLACE replace=0 66 + 67 + grep 'live patched' /proc/cmdline > /dev/kmsg 68 + grep 'live patched' /proc/meminfo > /dev/kmsg 69 + 70 + disable_lp $MOD_REPLACE 71 + unload_lp $MOD_REPLACE 72 + 73 + grep 'live patched' /proc/cmdline > /dev/kmsg 74 + grep 'live patched' /proc/meminfo > /dev/kmsg 75 + 76 + disable_lp $MOD_LIVEPATCH 77 + unload_lp $MOD_LIVEPATCH 78 + 79 + grep 'live patched' /proc/cmdline > /dev/kmsg 80 + grep 'live patched' /proc/meminfo > /dev/kmsg 81 + 82 + check_result "% modprobe $MOD_LIVEPATCH 83 + livepatch: enabling patch '$MOD_LIVEPATCH' 84 + livepatch: '$MOD_LIVEPATCH': initializing patching transition 85 + livepatch: '$MOD_LIVEPATCH': starting patching transition 86 + livepatch: '$MOD_LIVEPATCH': completing patching transition 87 + livepatch: '$MOD_LIVEPATCH': patching complete 88 + $MOD_LIVEPATCH: this has been live patched 89 + % modprobe $MOD_REPLACE replace=0 90 + livepatch: enabling patch '$MOD_REPLACE' 91 + livepatch: '$MOD_REPLACE': initializing patching transition 92 + livepatch: '$MOD_REPLACE': starting patching transition 93 + livepatch: '$MOD_REPLACE': completing patching transition 94 + livepatch: '$MOD_REPLACE': patching complete 95 + $MOD_LIVEPATCH: this has been live patched 96 + $MOD_REPLACE: this has been live patched 97 + % echo 0 > /sys/kernel/livepatch/$MOD_REPLACE/enabled 98 + livepatch: '$MOD_REPLACE': initializing unpatching transition 99 + livepatch: '$MOD_REPLACE': starting unpatching transition 100 + livepatch: '$MOD_REPLACE': completing unpatching transition 101 + livepatch: '$MOD_REPLACE': unpatching complete 102 + % rmmod $MOD_REPLACE 103 + $MOD_LIVEPATCH: this has been live patched 104 + % echo 0 > /sys/kernel/livepatch/$MOD_LIVEPATCH/enabled 105 + livepatch: '$MOD_LIVEPATCH': initializing unpatching transition 106 + livepatch: '$MOD_LIVEPATCH': starting unpatching transition 107 + livepatch: '$MOD_LIVEPATCH': completing unpatching transition 108 + livepatch: '$MOD_LIVEPATCH': unpatching complete 109 + % rmmod $MOD_LIVEPATCH" 110 + 111 + 112 + # TEST: atomic replace livepatch 113 + # - load a livepatch that modifies the output from /proc/cmdline and 114 + # verify correct behavior 115 + # - load an atomic replace livepatch and verify that only the second is active 116 + # - remove the first livepatch and verify that the atomic replace livepatch 117 + # is still active 118 + # - remove the atomic replace livepatch and verify that none are active 119 + 120 + echo -n "TEST: atomic replace livepatch ... " 121 + dmesg -C 122 + 123 + load_lp $MOD_LIVEPATCH 124 + 125 + grep 'live patched' /proc/cmdline > /dev/kmsg 126 + grep 'live patched' /proc/meminfo > /dev/kmsg 127 + 128 + load_lp $MOD_REPLACE replace=1 129 + 130 + grep 'live patched' /proc/cmdline > /dev/kmsg 131 + grep 'live patched' /proc/meminfo > /dev/kmsg 132 + 133 + unload_lp $MOD_LIVEPATCH 134 + 135 + grep 'live patched' /proc/cmdline > /dev/kmsg 136 + grep 'live patched' /proc/meminfo > /dev/kmsg 137 + 138 + disable_lp $MOD_REPLACE 139 + unload_lp $MOD_REPLACE 140 + 141 + grep 'live patched' /proc/cmdline > /dev/kmsg 142 + grep 'live patched' /proc/meminfo > /dev/kmsg 143 + 144 + check_result "% modprobe $MOD_LIVEPATCH 145 + livepatch: enabling patch '$MOD_LIVEPATCH' 146 + livepatch: '$MOD_LIVEPATCH': initializing patching transition 147 + livepatch: '$MOD_LIVEPATCH': starting patching transition 148 + livepatch: '$MOD_LIVEPATCH': completing patching transition 149 + livepatch: '$MOD_LIVEPATCH': patching complete 150 + $MOD_LIVEPATCH: this has been live patched 151 + % modprobe $MOD_REPLACE replace=1 152 + livepatch: enabling patch '$MOD_REPLACE' 153 + livepatch: '$MOD_REPLACE': initializing patching transition 154 + livepatch: '$MOD_REPLACE': starting patching transition 155 + livepatch: '$MOD_REPLACE': completing patching transition 156 + livepatch: '$MOD_REPLACE': patching complete 157 + $MOD_REPLACE: this has been live patched 158 + % rmmod $MOD_LIVEPATCH 159 + $MOD_REPLACE: this has been live patched 160 + % echo 0 > /sys/kernel/livepatch/$MOD_REPLACE/enabled 161 + livepatch: '$MOD_REPLACE': initializing unpatching transition 162 + livepatch: '$MOD_REPLACE': starting unpatching transition 163 + livepatch: '$MOD_REPLACE': completing unpatching transition 164 + livepatch: '$MOD_REPLACE': unpatching complete 165 + % rmmod $MOD_REPLACE" 166 + 167 + 168 + exit 0
+60
tools/testing/selftests/livepatch/test-shadow-vars.sh
··· 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_TEST=test_klp_shadow_vars 8 + 9 + set_dynamic_debug 10 + 11 + 12 + # TEST: basic shadow variable API 13 + # - load a module that exercises the shadow variable API 14 + 15 + echo -n "TEST: basic shadow variable API ... " 16 + dmesg -C 17 + 18 + load_mod $MOD_TEST 19 + unload_mod $MOD_TEST 20 + 21 + check_result "% modprobe $MOD_TEST 22 + $MOD_TEST: klp_shadow_get(obj=PTR5, id=0x1234) = PTR0 23 + $MOD_TEST: got expected NULL result 24 + $MOD_TEST: shadow_ctor: PTR6 -> PTR1 25 + $MOD_TEST: klp_shadow_alloc(obj=PTR5, id=0x1234, size=8, gfp_flags=GFP_KERNEL), ctor=PTR7, ctor_data=PTR1 = PTR6 26 + $MOD_TEST: shadow_ctor: PTR8 -> PTR2 27 + $MOD_TEST: klp_shadow_alloc(obj=PTR9, id=0x1234, size=8, gfp_flags=GFP_KERNEL), ctor=PTR7, ctor_data=PTR2 = PTR8 28 + $MOD_TEST: shadow_ctor: PTR10 -> PTR3 29 + $MOD_TEST: klp_shadow_alloc(obj=PTR5, id=0x1235, size=8, gfp_flags=GFP_KERNEL), ctor=PTR7, ctor_data=PTR3 = PTR10 30 + $MOD_TEST: klp_shadow_get(obj=PTR5, id=0x1234) = PTR6 31 + $MOD_TEST: got expected PTR6 -> PTR1 result 32 + $MOD_TEST: klp_shadow_get(obj=PTR9, id=0x1234) = PTR8 33 + $MOD_TEST: got expected PTR8 -> PTR2 result 34 + $MOD_TEST: klp_shadow_get(obj=PTR5, id=0x1235) = PTR10 35 + $MOD_TEST: got expected PTR10 -> PTR3 result 36 + $MOD_TEST: shadow_ctor: PTR11 -> PTR4 37 + $MOD_TEST: klp_shadow_get_or_alloc(obj=PTR12, id=0x1234, size=8, gfp_flags=GFP_KERNEL), ctor=PTR7, ctor_data=PTR4 = PTR11 38 + $MOD_TEST: klp_shadow_get_or_alloc(obj=PTR12, id=0x1234, size=8, gfp_flags=GFP_KERNEL), ctor=PTR7, ctor_data=PTR4 = PTR11 39 + $MOD_TEST: got expected PTR11 -> PTR4 result 40 + $MOD_TEST: shadow_dtor(obj=PTR5, shadow_data=PTR6) 41 + $MOD_TEST: klp_shadow_free(obj=PTR5, id=0x1234, dtor=PTR13) 42 + $MOD_TEST: klp_shadow_get(obj=PTR5, id=0x1234) = PTR0 43 + $MOD_TEST: got expected NULL result 44 + $MOD_TEST: shadow_dtor(obj=PTR9, shadow_data=PTR8) 45 + $MOD_TEST: klp_shadow_free(obj=PTR9, id=0x1234, dtor=PTR13) 46 + $MOD_TEST: klp_shadow_get(obj=PTR9, id=0x1234) = PTR0 47 + $MOD_TEST: got expected NULL result 48 + $MOD_TEST: shadow_dtor(obj=PTR12, shadow_data=PTR11) 49 + $MOD_TEST: klp_shadow_free(obj=PTR12, id=0x1234, dtor=PTR13) 50 + $MOD_TEST: klp_shadow_get(obj=PTR12, id=0x1234) = PTR0 51 + $MOD_TEST: got expected NULL result 52 + $MOD_TEST: klp_shadow_get(obj=PTR5, id=0x1235) = PTR10 53 + $MOD_TEST: got expected PTR10 -> PTR3 result 54 + $MOD_TEST: shadow_dtor(obj=PTR5, shadow_data=PTR10) 55 + $MOD_TEST: klp_shadow_free_all(id=0x1235, dtor=PTR13) 56 + $MOD_TEST: klp_shadow_get(obj=PTR5, id=0x1234) = PTR0 57 + $MOD_TEST: shadow_get() got expected NULL result 58 + % rmmod test_klp_shadow_vars" 59 + 60 + exit 0