aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/livepatch/callbacks.txt489
-rw-r--r--MAINTAINERS1
-rw-r--r--lib/Kconfig.debug22
-rw-r--r--lib/Makefile2
-rw-r--r--lib/livepatch/Makefile15
-rw-r--r--lib/livepatch/test_klp_atomic_replace.c57
-rw-r--r--lib/livepatch/test_klp_callbacks_busy.c43
-rw-r--r--lib/livepatch/test_klp_callbacks_demo.c121
-rw-r--r--lib/livepatch/test_klp_callbacks_demo2.c93
-rw-r--r--lib/livepatch/test_klp_callbacks_mod.c24
-rw-r--r--lib/livepatch/test_klp_livepatch.c51
-rw-r--r--lib/livepatch/test_klp_shadow_vars.c236
-rw-r--r--tools/testing/selftests/Makefile1
-rw-r--r--tools/testing/selftests/livepatch/Makefile8
-rw-r--r--tools/testing/selftests/livepatch/README43
-rw-r--r--tools/testing/selftests/livepatch/config1
-rw-r--r--tools/testing/selftests/livepatch/functions.sh203
-rwxr-xr-xtools/testing/selftests/livepatch/test-callbacks.sh587
-rwxr-xr-xtools/testing/selftests/livepatch/test-livepatch.sh168
-rwxr-xr-xtools/testing/selftests/livepatch/test-shadow-vars.sh60
20 files changed, 1740 insertions, 485 deletions
diff --git a/Documentation/livepatch/callbacks.txt b/Documentation/livepatch/callbacks.txt
index c9776f48e458..182e31d4abce 100644
--- a/Documentation/livepatch/callbacks.txt
+++ b/Documentation/livepatch/callbacks.txt
@@ -118,488 +118,9 @@ similar change to their hw_features value. (Client functions of the
118value may need to be updated accordingly.) 118value may need to be updated accordingly.)
119 119
120 120
121Test cases 121Other Examples
122========== 122==============
123
124What follows is not an exhaustive test suite of every possible livepatch
125pre/post-(un)patch combination, but a selection that demonstrates a few
126important concepts. Each test case uses the kernel modules located in
127the samples/livepatch/ and assumes that no livepatches are loaded at the
128beginning of the test.
129
130
131Test 1
132------
133
134Test a combination of loading a kernel module and a livepatch that
135patches a function in the first module. (Un)load the target module
136before the livepatch module:
137
138- load target module
139- load livepatch
140- disable livepatch
141- unload target module
142- unload livepatch
143
144First load a target module:
145
146 % insmod samples/livepatch/livepatch-callbacks-mod.ko
147 [ 34.475708] livepatch_callbacks_mod: livepatch_callbacks_mod_init
148
149On livepatch enable, before the livepatch transition starts, pre-patch
150callbacks are executed for vmlinux and livepatch_callbacks_mod (those
151klp_objects currently loaded). After klp_objects are patched according
152to the klp_patch, their post-patch callbacks run and the transition
153completes:
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
166Similarly, on livepatch disable, pre-patch callbacks run before the
167unpatching transition starts. klp_objects are reverted, post-patch
168callbacks 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
185Test 2
186------
187
188This test is similar to the previous test, but (un)load the livepatch
189module before the target kernel module. This tests the livepatch core's
190module_coming handler:
191
192- load livepatch
193- load target module
194- disable livepatch
195- unload livepatch
196- unload target module
197
198
199On livepatch enable, only pre/post-patch callbacks are executed for
200currently 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
211When a targeted module is subsequently loaded, only its pre/post-patch
212callbacks 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
220On livepatch disable, all currently loaded klp_objects' (vmlinux and
221livepatch_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
238Test 3
239------
240
241Test loading the livepatch after a targeted kernel module, then unload
242the kernel module before disabling the livepatch. This tests the
243livepatch core's module_going handler:
244
245- load target module
246- load livepatch
247- unload target module
248- disable livepatch
249- unload livepatch
250
251First 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
267When a target module is unloaded, the livepatch is only reverted from
268that klp_object (livepatch_callbacks_mod). As such, only its pre and
269post-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
277When the livepatch is disabled, pre and post-unpatch callbacks are run
278for 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
291Test 4
292------
293
294This test is similar to the previous test, however the livepatch is
295loaded first. This tests the livepatch core's module_coming and
296module_going handlers:
297
298- load livepatch
299- load target module
300- unload target module
301- disable livepatch
302- unload livepatch
303
304First 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
315When a targeted kernel module is subsequently loaded, only its
316pre/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
324When the target module is unloaded, the livepatch is only reverted from
325the livepatch_callbacks_mod klp_object. As such, only pre and
326post-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
345Test 5
346------
347
348A simple test of loading a livepatch without one of its patch target
349klp_objects ever loaded (livepatch_callbacks_mod):
350
351- load livepatch
352- disable livepatch
353- unload livepatch
354
355Load 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
366As 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 123
376 % rmmod samples/livepatch/livepatch-callbacks-demo.ko 124Sample livepatch modules demonstrating the callback API can be found in
377 125samples/livepatch/ directory. These samples were modified for use in
378 126kselftests and can be found in the lib/livepatch directory.
379Test 6
380------
381
382Test a scenario where a vmlinux pre-patch callback returns a non-zero
383status (ie, failure):
384
385- load target module
386- load livepatch -ENODEV
387- unload target module
388
389First load a target module:
390
391 % insmod samples/livepatch/livepatch-callbacks-mod.ko
392 [ 80.740520] livepatch_callbacks_mod: livepatch_callbacks_mod_init
393
394Load the livepatch module, setting its 'pre_patch_ret' value to -19
395(-ENODEV). When its vmlinux pre-patch callback executed, this status
396code will propagate back to the module-loading subsystem. The result is
397that 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
414Test 7
415------
416
417Similar to the previous test, setup a livepatch such that its vmlinux
418pre-patch callback returns success. However, when a targeted kernel
419module 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
427Load 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
438Set a trap so subsequent pre-patch callbacks to this livepatch will
439return -ENODEV:
440
441 % echo -19 > /sys/module/livepatch_callbacks_demo/parameters/pre_patch_ret
442
443The livepatch pre-patch callback for subsequently loaded target modules
444will return failure, so the module loader refuses to load the kernel
445module. Notice that no post-patch or pre/post-unpatch callbacks are
446executed 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
455However, 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
468Test 8
469------
470
471Test loading multiple targeted kernel modules. This test-case is
472mainly 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
483Load a target "busy" kernel module which kicks off a worker function
484that 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
491Proceed with loading the livepatch and another ordinary target module,
492notice that the post-patch callbacks are executed and the transition
493completes 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
533Test 9
534------
535
536A similar test as the previous one, but force the "busy" kernel module
537to do longer work.
538
539The livepatching core will refuse to patch a task that is currently
540executing a to-be-patched function -- the consistency model stalls the
541current patch transition until this safety-check is met. Test a
542scenario where one of a livepatch's target klp_objects sits on such a
543function for a long time. Meanwhile, load and unload other target
544kernel 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
555Load the "busy" kernel module, this time make it do 30 seconds worth of
556work:
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
562Meanwhile, the livepatch is loaded. Notice that the patch transition
563does not complete as the targeted "busy" module is sitting on a
564to-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
573Load a second target module (this one is an ordinary idle kernel
574module). Note that *no* post-patch callbacks will be executed while the
575livepatch 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
582Request an unload of the simple kernel module. The patch is still
583transitioning, 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
590Finally the livepatch is disabled. Since none of the patch's
591klp_object's post-patch callbacks executed, the remaining klp_object's
592pre-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
diff --git a/MAINTAINERS b/MAINTAINERS
index 39e75bbefc3d..b1c5cf166703 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8832,6 +8832,7 @@ F: arch/x86/kernel/livepatch.c
8832F: Documentation/livepatch/ 8832F: Documentation/livepatch/
8833F: Documentation/ABI/testing/sysfs-kernel-livepatch 8833F: Documentation/ABI/testing/sysfs-kernel-livepatch
8834F: samples/livepatch/ 8834F: samples/livepatch/
8835F: tools/testing/selftests/livepatch/
8835L: live-patching@vger.kernel.org 8836L: live-patching@vger.kernel.org
8836T: git git://git.kernel.org/pub/scm/linux/kernel/git/jikos/livepatching.git 8837T: git git://git.kernel.org/pub/scm/linux/kernel/git/jikos/livepatching.git
8837 8838
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index d4df5b24d75e..0298eb8eaa4e 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -1991,6 +1991,27 @@ config TEST_MEMCAT_P
1991 1991
1992 If unsure, say N. 1992 If unsure, say N.
1993 1993
1994config 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
1994config TEST_OBJAGG 2015config TEST_OBJAGG
1995 tristate "Perform selftest on object aggreration manager" 2016 tristate "Perform selftest on object aggreration manager"
1996 default n 2017 default n
@@ -1999,7 +2020,6 @@ config TEST_OBJAGG
1999 Enable this option to test object aggregation manager on boot 2020 Enable this option to test object aggregation manager on boot
2000 (or module load). 2021 (or module load).
2001 2022
2002 If unsure, say N.
2003 2023
2004endif # RUNTIME_TESTING_MENU 2024endif # RUNTIME_TESTING_MENU
2005 2025
diff --git a/lib/Makefile b/lib/Makefile
index e1b59da71418..a1cfa1975ca3 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -77,6 +77,8 @@ obj-$(CONFIG_TEST_DEBUG_VIRTUAL) += test_debug_virtual.o
77obj-$(CONFIG_TEST_MEMCAT_P) += test_memcat_p.o 77obj-$(CONFIG_TEST_MEMCAT_P) += test_memcat_p.o
78obj-$(CONFIG_TEST_OBJAGG) += test_objagg.o 78obj-$(CONFIG_TEST_OBJAGG) += test_objagg.o
79 79
80obj-$(CONFIG_TEST_LIVEPATCH) += livepatch/
81
80ifeq ($(CONFIG_DEBUG_KOBJECT),y) 82ifeq ($(CONFIG_DEBUG_KOBJECT),y)
81CFLAGS_kobject.o += -DDEBUG 83CFLAGS_kobject.o += -DDEBUG
82CFLAGS_kobject_uevent.o += -DDEBUG 84CFLAGS_kobject_uevent.o += -DDEBUG
diff --git a/lib/livepatch/Makefile b/lib/livepatch/Makefile
new file mode 100644
index 000000000000..26900ddaef82
--- /dev/null
+++ b/lib/livepatch/Makefile
@@ -0,0 +1,15 @@
1# SPDX-License-Identifier: GPL-2.0
2#
3# Makefile for livepatch test code.
4
5obj-$(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
14CFLAGS_test_klp_callbacks_busy.o += $(CC_FLAGS_FTRACE)
15CFLAGS_test_klp_callbacks_mod.o += $(CC_FLAGS_FTRACE)
diff --git a/lib/livepatch/test_klp_atomic_replace.c b/lib/livepatch/test_klp_atomic_replace.c
new file mode 100644
index 000000000000..5af7093ca00c
--- /dev/null
+++ b/lib/livepatch/test_klp_atomic_replace.c
@@ -0,0 +1,57 @@
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
10static int replace;
11module_param(replace, int, 0644);
12MODULE_PARM_DESC(replace, "replace (default=0)");
13
14#include <linux/seq_file.h>
15static 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
22static struct klp_func funcs[] = {
23 {
24 .old_name = "meminfo_proc_show",
25 .new_func = livepatch_meminfo_proc_show,
26 }, {}
27};
28
29static struct klp_object objs[] = {
30 {
31 /* name being NULL means vmlinux */
32 .funcs = funcs,
33 }, {}
34};
35
36static struct klp_patch patch = {
37 .mod = THIS_MODULE,
38 .objs = objs,
39 /* set .replace in the init function below for demo purposes */
40};
41
42static int test_klp_atomic_replace_init(void)
43{
44 patch.replace = replace;
45 return klp_enable_patch(&patch);
46}
47
48static void test_klp_atomic_replace_exit(void)
49{
50}
51
52module_init(test_klp_atomic_replace_init);
53module_exit(test_klp_atomic_replace_exit);
54MODULE_LICENSE("GPL");
55MODULE_INFO(livepatch, "Y");
56MODULE_AUTHOR("Joe Lawrence <joe.lawrence@redhat.com>");
57MODULE_DESCRIPTION("Livepatch test: atomic replace");
diff --git a/lib/livepatch/test_klp_callbacks_busy.c b/lib/livepatch/test_klp_callbacks_busy.c
new file mode 100644
index 000000000000..40beddf8a0e2
--- /dev/null
+++ b/lib/livepatch/test_klp_callbacks_busy.c
@@ -0,0 +1,43 @@
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
11static int sleep_secs;
12module_param(sleep_secs, int, 0644);
13MODULE_PARM_DESC(sleep_secs, "sleep_secs (default=0)");
14
15static void busymod_work_func(struct work_struct *work);
16static DECLARE_DELAYED_WORK(work, busymod_work_func);
17
18static 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
25static 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
33static void test_klp_callbacks_busy_exit(void)
34{
35 cancel_delayed_work_sync(&work);
36 pr_info("%s\n", __func__);
37}
38
39module_init(test_klp_callbacks_busy_init);
40module_exit(test_klp_callbacks_busy_exit);
41MODULE_LICENSE("GPL");
42MODULE_AUTHOR("Joe Lawrence <joe.lawrence@redhat.com>");
43MODULE_DESCRIPTION("Livepatch test: busy target module");
diff --git a/lib/livepatch/test_klp_callbacks_demo.c b/lib/livepatch/test_klp_callbacks_demo.c
new file mode 100644
index 000000000000..3fd8fe1cd1cc
--- /dev/null
+++ b/lib/livepatch/test_klp_callbacks_demo.c
@@ -0,0 +1,121 @@
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
10static int pre_patch_ret;
11module_param(pre_patch_ret, int, 0644);
12MODULE_PARM_DESC(pre_patch_ret, "pre_patch_ret (default=0)");
13
14static 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
21static 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) */
31static 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) */
38static void post_patch_callback(struct klp_object *obj)
39{
40 callback_info(__func__, obj);
41}
42
43/* Executed on object unpatching (ie, patch disablement) */
44static void pre_unpatch_callback(struct klp_object *obj)
45{
46 callback_info(__func__, obj);
47}
48
49/* Executed on object unpatching (ie, patch disablement) */
50static void post_unpatch_callback(struct klp_object *obj)
51{
52 callback_info(__func__, obj);
53}
54
55static void patched_work_func(struct work_struct *work)
56{
57 pr_info("%s\n", __func__);
58}
59
60static struct klp_func no_funcs[] = {
61 {}
62};
63
64static struct klp_func busymod_funcs[] = {
65 {
66 .old_name = "busymod_work_func",
67 .new_func = patched_work_func,
68 }, {}
69};
70
71static 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
102static struct klp_patch patch = {
103 .mod = THIS_MODULE,
104 .objs = objs,
105};
106
107static int test_klp_callbacks_demo_init(void)
108{
109 return klp_enable_patch(&patch);
110}
111
112static void test_klp_callbacks_demo_exit(void)
113{
114}
115
116module_init(test_klp_callbacks_demo_init);
117module_exit(test_klp_callbacks_demo_exit);
118MODULE_LICENSE("GPL");
119MODULE_INFO(livepatch, "Y");
120MODULE_AUTHOR("Joe Lawrence <joe.lawrence@redhat.com>");
121MODULE_DESCRIPTION("Livepatch test: livepatch demo");
diff --git a/lib/livepatch/test_klp_callbacks_demo2.c b/lib/livepatch/test_klp_callbacks_demo2.c
new file mode 100644
index 000000000000..5417573e80af
--- /dev/null
+++ b/lib/livepatch/test_klp_callbacks_demo2.c
@@ -0,0 +1,93 @@
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
10static int replace;
11module_param(replace, int, 0644);
12MODULE_PARM_DESC(replace, "replace (default=0)");
13
14static 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
21static 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) */
31static 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) */
38static void post_patch_callback(struct klp_object *obj)
39{
40 callback_info(__func__, obj);
41}
42
43/* Executed on object unpatching (ie, patch disablement) */
44static void pre_unpatch_callback(struct klp_object *obj)
45{
46 callback_info(__func__, obj);
47}
48
49/* Executed on object unpatching (ie, patch disablement) */
50static void post_unpatch_callback(struct klp_object *obj)
51{
52 callback_info(__func__, obj);
53}
54
55static struct klp_func no_funcs[] = {
56 { }
57};
58
59static 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
72static struct klp_patch patch = {
73 .mod = THIS_MODULE,
74 .objs = objs,
75 /* set .replace in the init function below for demo purposes */
76};
77
78static int test_klp_callbacks_demo2_init(void)
79{
80 patch.replace = replace;
81 return klp_enable_patch(&patch);
82}
83
84static void test_klp_callbacks_demo2_exit(void)
85{
86}
87
88module_init(test_klp_callbacks_demo2_init);
89module_exit(test_klp_callbacks_demo2_exit);
90MODULE_LICENSE("GPL");
91MODULE_INFO(livepatch, "Y");
92MODULE_AUTHOR("Joe Lawrence <joe.lawrence@redhat.com>");
93MODULE_DESCRIPTION("Livepatch test: livepatch demo2");
diff --git a/lib/livepatch/test_klp_callbacks_mod.c b/lib/livepatch/test_klp_callbacks_mod.c
new file mode 100644
index 000000000000..8fbe645b1c2c
--- /dev/null
+++ b/lib/livepatch/test_klp_callbacks_mod.c
@@ -0,0 +1,24 @@
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
9static int test_klp_callbacks_mod_init(void)
10{
11 pr_info("%s\n", __func__);
12 return 0;
13}
14
15static void test_klp_callbacks_mod_exit(void)
16{
17 pr_info("%s\n", __func__);
18}
19
20module_init(test_klp_callbacks_mod_init);
21module_exit(test_klp_callbacks_mod_exit);
22MODULE_LICENSE("GPL");
23MODULE_AUTHOR("Joe Lawrence <joe.lawrence@redhat.com>");
24MODULE_DESCRIPTION("Livepatch test: target module");
diff --git a/lib/livepatch/test_klp_livepatch.c b/lib/livepatch/test_klp_livepatch.c
new file mode 100644
index 000000000000..aff08199de71
--- /dev/null
+++ b/lib/livepatch/test_klp_livepatch.c
@@ -0,0 +1,51 @@
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>
11static 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
18static struct klp_func funcs[] = {
19 {
20 .old_name = "cmdline_proc_show",
21 .new_func = livepatch_cmdline_proc_show,
22 }, { }
23};
24
25static struct klp_object objs[] = {
26 {
27 /* name being NULL means vmlinux */
28 .funcs = funcs,
29 }, { }
30};
31
32static struct klp_patch patch = {
33 .mod = THIS_MODULE,
34 .objs = objs,
35};
36
37static int test_klp_livepatch_init(void)
38{
39 return klp_enable_patch(&patch);
40}
41
42static void test_klp_livepatch_exit(void)
43{
44}
45
46module_init(test_klp_livepatch_init);
47module_exit(test_klp_livepatch_exit);
48MODULE_LICENSE("GPL");
49MODULE_INFO(livepatch, "Y");
50MODULE_AUTHOR("Seth Jennings <sjenning@redhat.com>");
51MODULE_DESCRIPTION("Livepatch test: livepatch module");
diff --git a/lib/livepatch/test_klp_shadow_vars.c b/lib/livepatch/test_klp_shadow_vars.c
new file mode 100644
index 000000000000..02f892f941dc
--- /dev/null
+++ b/lib/livepatch/test_klp_shadow_vars.c
@@ -0,0 +1,236 @@
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 */
18static LIST_HEAD(ptr_list);
19struct shadow_ptr {
20 void *ptr;
21 int id;
22 struct list_head list;
23};
24
25static 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
35static 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 */
61static 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
71static 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
83static 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
95static 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
102static 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 */
111static 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
121static 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
127static 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
228static void test_klp_shadow_vars_exit(void)
229{
230}
231
232module_init(test_klp_shadow_vars_init);
233module_exit(test_klp_shadow_vars_exit);
234MODULE_LICENSE("GPL");
235MODULE_AUTHOR("Joe Lawrence <joe.lawrence@redhat.com>");
236MODULE_DESCRIPTION("Livepatch test: shadow variables");
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
index 1a2bd15c5b6e..a8ba662da827 100644
--- a/tools/testing/selftests/Makefile
+++ b/tools/testing/selftests/Makefile
@@ -21,6 +21,7 @@ TARGETS += ir
21TARGETS += kcmp 21TARGETS += kcmp
22TARGETS += kvm 22TARGETS += kvm
23TARGETS += lib 23TARGETS += lib
24TARGETS += livepatch
24TARGETS += membarrier 25TARGETS += membarrier
25TARGETS += memfd 26TARGETS += memfd
26TARGETS += memory-hotplug 27TARGETS += memory-hotplug
diff --git a/tools/testing/selftests/livepatch/Makefile b/tools/testing/selftests/livepatch/Makefile
new file mode 100644
index 000000000000..af4aee79bebb
--- /dev/null
+++ b/tools/testing/selftests/livepatch/Makefile
@@ -0,0 +1,8 @@
1# SPDX-License-Identifier: GPL-2.0
2
3TEST_GEN_PROGS := \
4 test-livepatch.sh \
5 test-callbacks.sh \
6 test-shadow-vars.sh
7
8include ../lib.mk
diff --git a/tools/testing/selftests/livepatch/README b/tools/testing/selftests/livepatch/README
new file mode 100644
index 000000000000..b73cd0e2dd51
--- /dev/null
+++ b/tools/testing/selftests/livepatch/README
@@ -0,0 +1,43 @@
1====================
2Livepatch Self Tests
3====================
4
5This is a small set of sanity tests for the kernel livepatching.
6
7The test suite loads and unloads several test kernel modules to verify
8livepatch behavior. Debug information is logged to the kernel's message
9buffer and parsed for expected messages. (Note: the tests will clear
10the message buffer between individual tests.)
11
12
13Config
14------
15
16Set these config options and their prerequisites:
17
18CONFIG_LIVEPATCH=y
19CONFIG_TEST_LIVEPATCH=m
20
21
22Running the tests
23-----------------
24
25Test kernel modules are built as part of lib/ (make modules) and need to
26be installed (make modules_install) as the test scripts will modprobe
27them.
28
29To 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
34Adding tests
35------------
36
37See the common functions.sh file for the existing collection of utility
38functions, most importantly set_dynamic_debug() and check_result(). The
39latter 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
41result comparison. Other utility functions include general module
42loading and livepatch loading helpers (waiting for patch transitions,
43sysfs entries, etc.)
diff --git a/tools/testing/selftests/livepatch/config b/tools/testing/selftests/livepatch/config
new file mode 100644
index 000000000000..0dd7700464a8
--- /dev/null
+++ b/tools/testing/selftests/livepatch/config
@@ -0,0 +1 @@
CONFIG_TEST_LIVEPATCH=m
diff --git a/tools/testing/selftests/livepatch/functions.sh b/tools/testing/selftests/livepatch/functions.sh
new file mode 100644
index 000000000000..c7b9fb45d7c9
--- /dev/null
+++ b/tools/testing/selftests/livepatch/functions.sh
@@ -0,0 +1,203 @@
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
7MAX_RETRIES=600
8RETRY_INTERVAL=".1" # seconds
9
10# log(msg) - write message to kernel log
11# msg - insightful words
12function log() {
13 echo "$1" > /dev/kmsg
14}
15
16# die(msg) - game over, man
17# msg - dying words
18function 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?
26function set_dynamic_debug() {
27 cat << EOF > /sys/kernel/debug/dynamic_debug/control
28file kernel/livepatch/* +p
29func klp_try_switch_task -p
30EOF
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
36function 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
46function 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
56function __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
76function 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
90function 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
107function 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
121function 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
136function 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
156function unload_lp() {
157 unload_mod "$1"
158}
159
160# disable_lp(modname) - disable a livepatch
161# modname - module name to unload
162function 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
177function 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?
191function 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}
diff --git a/tools/testing/selftests/livepatch/test-callbacks.sh b/tools/testing/selftests/livepatch/test-callbacks.sh
new file mode 100755
index 000000000000..e97a9dcb73c7
--- /dev/null
+++ b/tools/testing/selftests/livepatch/test-callbacks.sh
@@ -0,0 +1,587 @@
1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3# Copyright (C) 2018 Joe Lawrence <joe.lawrence@redhat.com>
4
5. $(dirname $0)/functions.sh
6
7MOD_LIVEPATCH=test_klp_callbacks_demo
8MOD_LIVEPATCH2=test_klp_callbacks_demo2
9MOD_TARGET=test_klp_callbacks_mod
10MOD_TARGET_BUSY=test_klp_callbacks_busy
11
12set_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
31echo -n "TEST: target module before livepatch ... "
32dmesg -C
33
34load_mod $MOD_TARGET
35load_lp $MOD_LIVEPATCH
36disable_lp $MOD_LIVEPATCH
37unload_lp $MOD_LIVEPATCH
38unload_mod $MOD_TARGET
39
40check_result "% modprobe $MOD_TARGET
41$MOD_TARGET: ${MOD_TARGET}_init
42% modprobe $MOD_LIVEPATCH
43livepatch: enabling patch '$MOD_LIVEPATCH'
44livepatch: '$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
47livepatch: '$MOD_LIVEPATCH': starting patching transition
48livepatch: '$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
51livepatch: '$MOD_LIVEPATCH': patching complete
52% echo 0 > /sys/kernel/livepatch/$MOD_LIVEPATCH/enabled
53livepatch: '$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
56livepatch: '$MOD_LIVEPATCH': starting unpatching transition
57livepatch: '$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
60livepatch: '$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
81echo -n "TEST: module_coming notifier ... "
82dmesg -C
83
84load_lp $MOD_LIVEPATCH
85load_mod $MOD_TARGET
86disable_lp $MOD_LIVEPATCH
87unload_lp $MOD_LIVEPATCH
88unload_mod $MOD_TARGET
89
90check_result "% modprobe $MOD_LIVEPATCH
91livepatch: enabling patch '$MOD_LIVEPATCH'
92livepatch: '$MOD_LIVEPATCH': initializing patching transition
93$MOD_LIVEPATCH: pre_patch_callback: vmlinux
94livepatch: '$MOD_LIVEPATCH': starting patching transition
95livepatch: '$MOD_LIVEPATCH': completing patching transition
96$MOD_LIVEPATCH: post_patch_callback: vmlinux
97livepatch: '$MOD_LIVEPATCH': patching complete
98% modprobe $MOD_TARGET
99livepatch: 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
104livepatch: '$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
107livepatch: '$MOD_LIVEPATCH': starting unpatching transition
108livepatch: '$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
111livepatch: '$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
132echo -n "TEST: module_going notifier ... "
133dmesg -C
134
135load_mod $MOD_TARGET
136load_lp $MOD_LIVEPATCH
137unload_mod $MOD_TARGET
138disable_lp $MOD_LIVEPATCH
139unload_lp $MOD_LIVEPATCH
140
141check_result "% modprobe $MOD_TARGET
142$MOD_TARGET: ${MOD_TARGET}_init
143% modprobe $MOD_LIVEPATCH
144livepatch: enabling patch '$MOD_LIVEPATCH'
145livepatch: '$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
148livepatch: '$MOD_LIVEPATCH': starting patching transition
149livepatch: '$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
152livepatch: '$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
156livepatch: 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
159livepatch: '$MOD_LIVEPATCH': initializing unpatching transition
160$MOD_LIVEPATCH: pre_unpatch_callback: vmlinux
161livepatch: '$MOD_LIVEPATCH': starting unpatching transition
162livepatch: '$MOD_LIVEPATCH': completing unpatching transition
163$MOD_LIVEPATCH: post_unpatch_callback: vmlinux
164livepatch: '$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
183echo -n "TEST: module_coming and module_going notifiers ... "
184dmesg -C
185
186load_lp $MOD_LIVEPATCH
187load_mod $MOD_TARGET
188unload_mod $MOD_TARGET
189disable_lp $MOD_LIVEPATCH
190unload_lp $MOD_LIVEPATCH
191
192check_result "% modprobe $MOD_LIVEPATCH
193livepatch: enabling patch '$MOD_LIVEPATCH'
194livepatch: '$MOD_LIVEPATCH': initializing patching transition
195$MOD_LIVEPATCH: pre_patch_callback: vmlinux
196livepatch: '$MOD_LIVEPATCH': starting patching transition
197livepatch: '$MOD_LIVEPATCH': completing patching transition
198$MOD_LIVEPATCH: post_patch_callback: vmlinux
199livepatch: '$MOD_LIVEPATCH': patching complete
200% modprobe $MOD_TARGET
201livepatch: 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
208livepatch: 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
211livepatch: '$MOD_LIVEPATCH': initializing unpatching transition
212$MOD_LIVEPATCH: pre_unpatch_callback: vmlinux
213livepatch: '$MOD_LIVEPATCH': starting unpatching transition
214livepatch: '$MOD_LIVEPATCH': completing unpatching transition
215$MOD_LIVEPATCH: post_unpatch_callback: vmlinux
216livepatch: '$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
230echo -n "TEST: target module not present ... "
231dmesg -C
232
233load_lp $MOD_LIVEPATCH
234disable_lp $MOD_LIVEPATCH
235unload_lp $MOD_LIVEPATCH
236
237check_result "% modprobe $MOD_LIVEPATCH
238livepatch: enabling patch '$MOD_LIVEPATCH'
239livepatch: '$MOD_LIVEPATCH': initializing patching transition
240$MOD_LIVEPATCH: pre_patch_callback: vmlinux
241livepatch: '$MOD_LIVEPATCH': starting patching transition
242livepatch: '$MOD_LIVEPATCH': completing patching transition
243$MOD_LIVEPATCH: post_patch_callback: vmlinux
244livepatch: '$MOD_LIVEPATCH': patching complete
245% echo 0 > /sys/kernel/livepatch/$MOD_LIVEPATCH/enabled
246livepatch: '$MOD_LIVEPATCH': initializing unpatching transition
247$MOD_LIVEPATCH: pre_unpatch_callback: vmlinux
248livepatch: '$MOD_LIVEPATCH': starting unpatching transition
249livepatch: '$MOD_LIVEPATCH': completing unpatching transition
250$MOD_LIVEPATCH: post_unpatch_callback: vmlinux
251livepatch: '$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
268echo -n "TEST: pre-patch callback -ENODEV ... "
269dmesg -C
270
271load_mod $MOD_TARGET
272load_failing_mod $MOD_LIVEPATCH pre_patch_ret=-19
273unload_mod $MOD_TARGET
274
275check_result "% modprobe $MOD_TARGET
276$MOD_TARGET: ${MOD_TARGET}_init
277% modprobe $MOD_LIVEPATCH pre_patch_ret=-19
278livepatch: enabling patch '$MOD_LIVEPATCH'
279livepatch: '$MOD_LIVEPATCH': initializing patching transition
280test_klp_callbacks_demo: pre_patch_callback: vmlinux
281livepatch: pre-patch callback failed for object 'vmlinux'
282livepatch: failed to enable patch '$MOD_LIVEPATCH'
283livepatch: '$MOD_LIVEPATCH': canceling patching transition, going to unpatch
284livepatch: '$MOD_LIVEPATCH': completing unpatching transition
285livepatch: '$MOD_LIVEPATCH': unpatching complete
286modprobe: 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
310echo -n "TEST: module_coming + pre-patch callback -ENODEV ... "
311dmesg -C
312
313load_lp $MOD_LIVEPATCH
314set_pre_patch_ret $MOD_LIVEPATCH -19
315load_failing_mod $MOD_TARGET
316disable_lp $MOD_LIVEPATCH
317unload_lp $MOD_LIVEPATCH
318
319check_result "% modprobe $MOD_LIVEPATCH
320livepatch: enabling patch '$MOD_LIVEPATCH'
321livepatch: '$MOD_LIVEPATCH': initializing patching transition
322$MOD_LIVEPATCH: pre_patch_callback: vmlinux
323livepatch: '$MOD_LIVEPATCH': starting patching transition
324livepatch: '$MOD_LIVEPATCH': completing patching transition
325$MOD_LIVEPATCH: post_patch_callback: vmlinux
326livepatch: '$MOD_LIVEPATCH': patching complete
327% echo -19 > /sys/module/$MOD_LIVEPATCH/parameters/pre_patch_ret
328% modprobe $MOD_TARGET
329livepatch: 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
331livepatch: pre-patch callback failed for object '$MOD_TARGET'
332livepatch: patch '$MOD_LIVEPATCH' failed for module '$MOD_TARGET', refusing to load module '$MOD_TARGET'
333modprobe: ERROR: could not insert '$MOD_TARGET': No such device
334% echo 0 > /sys/kernel/livepatch/$MOD_LIVEPATCH/enabled
335livepatch: '$MOD_LIVEPATCH': initializing unpatching transition
336$MOD_LIVEPATCH: pre_unpatch_callback: vmlinux
337livepatch: '$MOD_LIVEPATCH': starting unpatching transition
338livepatch: '$MOD_LIVEPATCH': completing unpatching transition
339$MOD_LIVEPATCH: post_unpatch_callback: vmlinux
340livepatch: '$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
356echo -n "TEST: multiple target modules ... "
357dmesg -C
358
359load_mod $MOD_TARGET_BUSY sleep_secs=0
360# give $MOD_TARGET_BUSY::busymod_work_func() a chance to run
361sleep 5
362load_lp $MOD_LIVEPATCH
363load_mod $MOD_TARGET
364unload_mod $MOD_TARGET
365disable_lp $MOD_LIVEPATCH
366unload_lp $MOD_LIVEPATCH
367unload_mod $MOD_TARGET_BUSY
368
369check_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
374livepatch: enabling patch '$MOD_LIVEPATCH'
375livepatch: '$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
378livepatch: '$MOD_LIVEPATCH': starting patching transition
379livepatch: '$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
382livepatch: '$MOD_LIVEPATCH': patching complete
383% modprobe $MOD_TARGET
384livepatch: 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
391livepatch: 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
394livepatch: '$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
397livepatch: '$MOD_LIVEPATCH': starting unpatching transition
398livepatch: '$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
401livepatch: '$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
438echo -n "TEST: busy target module ... "
439dmesg -C
440
441load_mod $MOD_TARGET_BUSY sleep_secs=10
442load_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()
445sleep 5
446load_mod $MOD_TARGET
447unload_mod $MOD_TARGET
448disable_lp $MOD_LIVEPATCH
449unload_lp $MOD_LIVEPATCH
450unload_mod $MOD_TARGET_BUSY
451
452check_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
456livepatch: enabling patch '$MOD_LIVEPATCH'
457livepatch: '$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
460livepatch: '$MOD_LIVEPATCH': starting patching transition
461% modprobe $MOD_TARGET
462livepatch: 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
467livepatch: 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
470livepatch: '$MOD_LIVEPATCH': reversing transition from patching to unpatching
471livepatch: '$MOD_LIVEPATCH': starting unpatching transition
472livepatch: '$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
475livepatch: '$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
491echo -n "TEST: multiple livepatches ... "
492dmesg -C
493
494load_lp $MOD_LIVEPATCH
495load_lp $MOD_LIVEPATCH2
496disable_lp $MOD_LIVEPATCH2
497disable_lp $MOD_LIVEPATCH
498unload_lp $MOD_LIVEPATCH2
499unload_lp $MOD_LIVEPATCH
500
501check_result "% modprobe $MOD_LIVEPATCH
502livepatch: enabling patch '$MOD_LIVEPATCH'
503livepatch: '$MOD_LIVEPATCH': initializing patching transition
504$MOD_LIVEPATCH: pre_patch_callback: vmlinux
505livepatch: '$MOD_LIVEPATCH': starting patching transition
506livepatch: '$MOD_LIVEPATCH': completing patching transition
507$MOD_LIVEPATCH: post_patch_callback: vmlinux
508livepatch: '$MOD_LIVEPATCH': patching complete
509% modprobe $MOD_LIVEPATCH2
510livepatch: enabling patch '$MOD_LIVEPATCH2'
511livepatch: '$MOD_LIVEPATCH2': initializing patching transition
512$MOD_LIVEPATCH2: pre_patch_callback: vmlinux
513livepatch: '$MOD_LIVEPATCH2': starting patching transition
514livepatch: '$MOD_LIVEPATCH2': completing patching transition
515$MOD_LIVEPATCH2: post_patch_callback: vmlinux
516livepatch: '$MOD_LIVEPATCH2': patching complete
517% echo 0 > /sys/kernel/livepatch/$MOD_LIVEPATCH2/enabled
518livepatch: '$MOD_LIVEPATCH2': initializing unpatching transition
519$MOD_LIVEPATCH2: pre_unpatch_callback: vmlinux
520livepatch: '$MOD_LIVEPATCH2': starting unpatching transition
521livepatch: '$MOD_LIVEPATCH2': completing unpatching transition
522$MOD_LIVEPATCH2: post_unpatch_callback: vmlinux
523livepatch: '$MOD_LIVEPATCH2': unpatching complete
524% echo 0 > /sys/kernel/livepatch/$MOD_LIVEPATCH/enabled
525livepatch: '$MOD_LIVEPATCH': initializing unpatching transition
526$MOD_LIVEPATCH: pre_unpatch_callback: vmlinux
527livepatch: '$MOD_LIVEPATCH': starting unpatching transition
528livepatch: '$MOD_LIVEPATCH': completing unpatching transition
529$MOD_LIVEPATCH: post_unpatch_callback: vmlinux
530livepatch: '$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
551echo -n "TEST: atomic replace ... "
552dmesg -C
553
554load_lp $MOD_LIVEPATCH
555load_lp $MOD_LIVEPATCH2 replace=1
556disable_lp $MOD_LIVEPATCH2
557unload_lp $MOD_LIVEPATCH2
558unload_lp $MOD_LIVEPATCH
559
560check_result "% modprobe $MOD_LIVEPATCH
561livepatch: enabling patch '$MOD_LIVEPATCH'
562livepatch: '$MOD_LIVEPATCH': initializing patching transition
563$MOD_LIVEPATCH: pre_patch_callback: vmlinux
564livepatch: '$MOD_LIVEPATCH': starting patching transition
565livepatch: '$MOD_LIVEPATCH': completing patching transition
566$MOD_LIVEPATCH: post_patch_callback: vmlinux
567livepatch: '$MOD_LIVEPATCH': patching complete
568% modprobe $MOD_LIVEPATCH2 replace=1
569livepatch: enabling patch '$MOD_LIVEPATCH2'
570livepatch: '$MOD_LIVEPATCH2': initializing patching transition
571$MOD_LIVEPATCH2: pre_patch_callback: vmlinux
572livepatch: '$MOD_LIVEPATCH2': starting patching transition
573livepatch: '$MOD_LIVEPATCH2': completing patching transition
574$MOD_LIVEPATCH2: post_patch_callback: vmlinux
575livepatch: '$MOD_LIVEPATCH2': patching complete
576% echo 0 > /sys/kernel/livepatch/$MOD_LIVEPATCH2/enabled
577livepatch: '$MOD_LIVEPATCH2': initializing unpatching transition
578$MOD_LIVEPATCH2: pre_unpatch_callback: vmlinux
579livepatch: '$MOD_LIVEPATCH2': starting unpatching transition
580livepatch: '$MOD_LIVEPATCH2': completing unpatching transition
581$MOD_LIVEPATCH2: post_unpatch_callback: vmlinux
582livepatch: '$MOD_LIVEPATCH2': unpatching complete
583% rmmod $MOD_LIVEPATCH2
584% rmmod $MOD_LIVEPATCH"
585
586
587exit 0
diff --git a/tools/testing/selftests/livepatch/test-livepatch.sh b/tools/testing/selftests/livepatch/test-livepatch.sh
new file mode 100755
index 000000000000..f05268aea859
--- /dev/null
+++ b/tools/testing/selftests/livepatch/test-livepatch.sh
@@ -0,0 +1,168 @@
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
7MOD_LIVEPATCH=test_klp_livepatch
8MOD_REPLACE=test_klp_atomic_replace
9
10set_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
18echo -n "TEST: basic function patching ... "
19dmesg -C
20
21load_lp $MOD_LIVEPATCH
22
23if [[ "$(cat /proc/cmdline)" != "$MOD_LIVEPATCH: this has been live patched" ]] ; then
24 echo -e "FAIL\n\n"
25 die "livepatch kselftest(s) failed"
26fi
27
28disable_lp $MOD_LIVEPATCH
29unload_lp $MOD_LIVEPATCH
30
31if [[ "$(cat /proc/cmdline)" == "$MOD_LIVEPATCH: this has been live patched" ]] ; then
32 echo -e "FAIL\n\n"
33 die "livepatch kselftest(s) failed"
34fi
35
36check_result "% modprobe $MOD_LIVEPATCH
37livepatch: enabling patch '$MOD_LIVEPATCH'
38livepatch: '$MOD_LIVEPATCH': initializing patching transition
39livepatch: '$MOD_LIVEPATCH': starting patching transition
40livepatch: '$MOD_LIVEPATCH': completing patching transition
41livepatch: '$MOD_LIVEPATCH': patching complete
42% echo 0 > /sys/kernel/livepatch/$MOD_LIVEPATCH/enabled
43livepatch: '$MOD_LIVEPATCH': initializing unpatching transition
44livepatch: '$MOD_LIVEPATCH': starting unpatching transition
45livepatch: '$MOD_LIVEPATCH': completing unpatching transition
46livepatch: '$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
57echo -n "TEST: multiple livepatches ... "
58dmesg -C
59
60load_lp $MOD_LIVEPATCH
61
62grep 'live patched' /proc/cmdline > /dev/kmsg
63grep 'live patched' /proc/meminfo > /dev/kmsg
64
65load_lp $MOD_REPLACE replace=0
66
67grep 'live patched' /proc/cmdline > /dev/kmsg
68grep 'live patched' /proc/meminfo > /dev/kmsg
69
70disable_lp $MOD_REPLACE
71unload_lp $MOD_REPLACE
72
73grep 'live patched' /proc/cmdline > /dev/kmsg
74grep 'live patched' /proc/meminfo > /dev/kmsg
75
76disable_lp $MOD_LIVEPATCH
77unload_lp $MOD_LIVEPATCH
78
79grep 'live patched' /proc/cmdline > /dev/kmsg
80grep 'live patched' /proc/meminfo > /dev/kmsg
81
82check_result "% modprobe $MOD_LIVEPATCH
83livepatch: enabling patch '$MOD_LIVEPATCH'
84livepatch: '$MOD_LIVEPATCH': initializing patching transition
85livepatch: '$MOD_LIVEPATCH': starting patching transition
86livepatch: '$MOD_LIVEPATCH': completing patching transition
87livepatch: '$MOD_LIVEPATCH': patching complete
88$MOD_LIVEPATCH: this has been live patched
89% modprobe $MOD_REPLACE replace=0
90livepatch: enabling patch '$MOD_REPLACE'
91livepatch: '$MOD_REPLACE': initializing patching transition
92livepatch: '$MOD_REPLACE': starting patching transition
93livepatch: '$MOD_REPLACE': completing patching transition
94livepatch: '$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
98livepatch: '$MOD_REPLACE': initializing unpatching transition
99livepatch: '$MOD_REPLACE': starting unpatching transition
100livepatch: '$MOD_REPLACE': completing unpatching transition
101livepatch: '$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
105livepatch: '$MOD_LIVEPATCH': initializing unpatching transition
106livepatch: '$MOD_LIVEPATCH': starting unpatching transition
107livepatch: '$MOD_LIVEPATCH': completing unpatching transition
108livepatch: '$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
120echo -n "TEST: atomic replace livepatch ... "
121dmesg -C
122
123load_lp $MOD_LIVEPATCH
124
125grep 'live patched' /proc/cmdline > /dev/kmsg
126grep 'live patched' /proc/meminfo > /dev/kmsg
127
128load_lp $MOD_REPLACE replace=1
129
130grep 'live patched' /proc/cmdline > /dev/kmsg
131grep 'live patched' /proc/meminfo > /dev/kmsg
132
133unload_lp $MOD_LIVEPATCH
134
135grep 'live patched' /proc/cmdline > /dev/kmsg
136grep 'live patched' /proc/meminfo > /dev/kmsg
137
138disable_lp $MOD_REPLACE
139unload_lp $MOD_REPLACE
140
141grep 'live patched' /proc/cmdline > /dev/kmsg
142grep 'live patched' /proc/meminfo > /dev/kmsg
143
144check_result "% modprobe $MOD_LIVEPATCH
145livepatch: enabling patch '$MOD_LIVEPATCH'
146livepatch: '$MOD_LIVEPATCH': initializing patching transition
147livepatch: '$MOD_LIVEPATCH': starting patching transition
148livepatch: '$MOD_LIVEPATCH': completing patching transition
149livepatch: '$MOD_LIVEPATCH': patching complete
150$MOD_LIVEPATCH: this has been live patched
151% modprobe $MOD_REPLACE replace=1
152livepatch: enabling patch '$MOD_REPLACE'
153livepatch: '$MOD_REPLACE': initializing patching transition
154livepatch: '$MOD_REPLACE': starting patching transition
155livepatch: '$MOD_REPLACE': completing patching transition
156livepatch: '$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
161livepatch: '$MOD_REPLACE': initializing unpatching transition
162livepatch: '$MOD_REPLACE': starting unpatching transition
163livepatch: '$MOD_REPLACE': completing unpatching transition
164livepatch: '$MOD_REPLACE': unpatching complete
165% rmmod $MOD_REPLACE"
166
167
168exit 0
diff --git a/tools/testing/selftests/livepatch/test-shadow-vars.sh b/tools/testing/selftests/livepatch/test-shadow-vars.sh
new file mode 100755
index 000000000000..04a37831e204
--- /dev/null
+++ b/tools/testing/selftests/livepatch/test-shadow-vars.sh
@@ -0,0 +1,60 @@
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
7MOD_TEST=test_klp_shadow_vars
8
9set_dynamic_debug
10
11
12# TEST: basic shadow variable API
13# - load a module that exercises the shadow variable API
14
15echo -n "TEST: basic shadow variable API ... "
16dmesg -C
17
18load_mod $MOD_TEST
19unload_mod $MOD_TEST
20
21check_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
60exit 0