brintos

brintos / linux-shallow public Read only

0
0
Text · 5.5 KiB · 11c3f43 Raw
197 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Copyright (C) 2017 Joe Lawrence <joe.lawrence@redhat.com>4 */5 6/*7 * livepatch-callbacks-demo.c - (un)patching callbacks livepatch demo8 *9 *10 * Purpose11 * -------12 *13 * Demonstration of registering livepatch (un)patching callbacks.14 *15 *16 * Usage17 * -----18 *19 * Step 1 - load the simple module20 *21 *   insmod samples/livepatch/livepatch-callbacks-mod.ko22 *23 *24 * Step 2 - load the demonstration livepatch (with callbacks)25 *26 *   insmod samples/livepatch/livepatch-callbacks-demo.ko27 *28 *29 * Step 3 - cleanup30 *31 *   echo 0 > /sys/kernel/livepatch/livepatch_callbacks_demo/enabled32 *   rmmod livepatch_callbacks_demo33 *   rmmod livepatch_callbacks_mod34 *35 * Watch dmesg output to see livepatch enablement, callback execution36 * and patching operations for both vmlinux and module targets.37 *38 * NOTE: swap the insmod order of livepatch-callbacks-mod.ko and39 *       livepatch-callbacks-demo.ko to observe what happens when a40 *       target module is loaded after a livepatch with callbacks.41 *42 * NOTE: 'pre_patch_ret' is a module parameter that sets the pre-patch43 *       callback return status.  Try setting up a non-zero status44 *       such as -19 (-ENODEV):45 *46 *       # Load demo livepatch, vmlinux is patched47 *       insmod samples/livepatch/livepatch-callbacks-demo.ko48 *49 *       # Setup next pre-patch callback to return -ENODEV50 *       echo -19 > /sys/module/livepatch_callbacks_demo/parameters/pre_patch_ret51 *52 *       # Module loader refuses to load the target module53 *       insmod samples/livepatch/livepatch-callbacks-mod.ko54 *       insmod: ERROR: could not insert module samples/livepatch/livepatch-callbacks-mod.ko: No such device55 *56 * NOTE: There is a second target module,57 *       livepatch-callbacks-busymod.ko, available for experimenting58 *       with livepatch (un)patch callbacks.  This module contains59 *       a 'sleep_secs' parameter that parks the module on one of the60 *       functions that the livepatch demo module wants to patch.61 *       Modifying this value and tweaking the order of module loads can62 *       effectively demonstrate stalled patch transitions:63 *64 *       # Load a target module, let it park on 'busymod_work_func' for65 *       # thirty seconds66 *       insmod samples/livepatch/livepatch-callbacks-busymod.ko sleep_secs=3067 *68 *       # Meanwhile load the livepatch69 *       insmod samples/livepatch/livepatch-callbacks-demo.ko70 *71 *       # ... then load and unload another target module while the72 *       # transition is in progress73 *       insmod samples/livepatch/livepatch-callbacks-mod.ko74 *       rmmod samples/livepatch/livepatch-callbacks-mod.ko75 *76 *       # Finally cleanup77 *       echo 0 > /sys/kernel/livepatch/livepatch_callbacks_demo/enabled78 *       rmmod samples/livepatch/livepatch-callbacks-demo.ko79 */80 81#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt82 83#include <linux/module.h>84#include <linux/kernel.h>85#include <linux/livepatch.h>86 87static int pre_patch_ret;88module_param(pre_patch_ret, int, 0644);89MODULE_PARM_DESC(pre_patch_ret, "pre_patch_ret (default=0)");90 91static const char *const module_state[] = {92	[MODULE_STATE_LIVE]	= "[MODULE_STATE_LIVE] Normal state",93	[MODULE_STATE_COMING]	= "[MODULE_STATE_COMING] Full formed, running module_init",94	[MODULE_STATE_GOING]	= "[MODULE_STATE_GOING] Going away",95	[MODULE_STATE_UNFORMED]	= "[MODULE_STATE_UNFORMED] Still setting it up",96};97 98static void callback_info(const char *callback, struct klp_object *obj)99{100	if (obj->mod)101		pr_info("%s: %s -> %s\n", callback, obj->mod->name,102			module_state[obj->mod->state]);103	else104		pr_info("%s: vmlinux\n", callback);105}106 107/* Executed on object patching (ie, patch enablement) */108static int pre_patch_callback(struct klp_object *obj)109{110	callback_info(__func__, obj);111	return pre_patch_ret;112}113 114/* Executed on object unpatching (ie, patch disablement) */115static void post_patch_callback(struct klp_object *obj)116{117	callback_info(__func__, obj);118}119 120/* Executed on object unpatching (ie, patch disablement) */121static void pre_unpatch_callback(struct klp_object *obj)122{123	callback_info(__func__, obj);124}125 126/* Executed on object unpatching (ie, patch disablement) */127static void post_unpatch_callback(struct klp_object *obj)128{129	callback_info(__func__, obj);130}131 132static void patched_work_func(struct work_struct *work)133{134	pr_info("%s\n", __func__);135}136 137static struct klp_func no_funcs[] = {138	{ }139};140 141static struct klp_func busymod_funcs[] = {142	{143		.old_name = "busymod_work_func",144		.new_func = patched_work_func,145	}, { }146};147 148static struct klp_object objs[] = {149	{150		.name = NULL,	/* vmlinux */151		.funcs = no_funcs,152		.callbacks = {153			.pre_patch = pre_patch_callback,154			.post_patch = post_patch_callback,155			.pre_unpatch = pre_unpatch_callback,156			.post_unpatch = post_unpatch_callback,157		},158	},	{159		.name = "livepatch_callbacks_mod",160		.funcs = no_funcs,161		.callbacks = {162			.pre_patch = pre_patch_callback,163			.post_patch = post_patch_callback,164			.pre_unpatch = pre_unpatch_callback,165			.post_unpatch = post_unpatch_callback,166		},167	},	{168		.name = "livepatch_callbacks_busymod",169		.funcs = busymod_funcs,170		.callbacks = {171			.pre_patch = pre_patch_callback,172			.post_patch = post_patch_callback,173			.pre_unpatch = pre_unpatch_callback,174			.post_unpatch = post_unpatch_callback,175		},176	}, { }177};178 179static struct klp_patch patch = {180	.mod = THIS_MODULE,181	.objs = objs,182};183 184static int livepatch_callbacks_demo_init(void)185{186	return klp_enable_patch(&patch);187}188 189static void livepatch_callbacks_demo_exit(void)190{191}192 193module_init(livepatch_callbacks_demo_init);194module_exit(livepatch_callbacks_demo_exit);195MODULE_LICENSE("GPL");196MODULE_INFO(livepatch, "Y");197