Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/samples/livepatch/livepatch-callbacks-demo.c
26278 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
* Copyright (C) 2017 Joe Lawrence <[email protected]>
4
*/
5
6
/*
7
* livepatch-callbacks-demo.c - (un)patching callbacks livepatch demo
8
*
9
*
10
* Purpose
11
* -------
12
*
13
* Demonstration of registering livepatch (un)patching callbacks.
14
*
15
*
16
* Usage
17
* -----
18
*
19
* Step 1 - load the simple module
20
*
21
* insmod samples/livepatch/livepatch-callbacks-mod.ko
22
*
23
*
24
* Step 2 - load the demonstration livepatch (with callbacks)
25
*
26
* insmod samples/livepatch/livepatch-callbacks-demo.ko
27
*
28
*
29
* Step 3 - cleanup
30
*
31
* echo 0 > /sys/kernel/livepatch/livepatch_callbacks_demo/enabled
32
* rmmod livepatch_callbacks_demo
33
* rmmod livepatch_callbacks_mod
34
*
35
* Watch dmesg output to see livepatch enablement, callback execution
36
* and patching operations for both vmlinux and module targets.
37
*
38
* NOTE: swap the insmod order of livepatch-callbacks-mod.ko and
39
* livepatch-callbacks-demo.ko to observe what happens when a
40
* target module is loaded after a livepatch with callbacks.
41
*
42
* NOTE: 'pre_patch_ret' is a module parameter that sets the pre-patch
43
* callback return status. Try setting up a non-zero status
44
* such as -19 (-ENODEV):
45
*
46
* # Load demo livepatch, vmlinux is patched
47
* insmod samples/livepatch/livepatch-callbacks-demo.ko
48
*
49
* # Setup next pre-patch callback to return -ENODEV
50
* echo -19 > /sys/module/livepatch_callbacks_demo/parameters/pre_patch_ret
51
*
52
* # Module loader refuses to load the target module
53
* insmod samples/livepatch/livepatch-callbacks-mod.ko
54
* insmod: ERROR: could not insert module samples/livepatch/livepatch-callbacks-mod.ko: No such device
55
*
56
* NOTE: There is a second target module,
57
* livepatch-callbacks-busymod.ko, available for experimenting
58
* with livepatch (un)patch callbacks. This module contains
59
* a 'sleep_secs' parameter that parks the module on one of the
60
* functions that the livepatch demo module wants to patch.
61
* Modifying this value and tweaking the order of module loads can
62
* effectively demonstrate stalled patch transitions:
63
*
64
* # Load a target module, let it park on 'busymod_work_func' for
65
* # thirty seconds
66
* insmod samples/livepatch/livepatch-callbacks-busymod.ko sleep_secs=30
67
*
68
* # Meanwhile load the livepatch
69
* insmod samples/livepatch/livepatch-callbacks-demo.ko
70
*
71
* # ... then load and unload another target module while the
72
* # transition is in progress
73
* insmod samples/livepatch/livepatch-callbacks-mod.ko
74
* rmmod samples/livepatch/livepatch-callbacks-mod.ko
75
*
76
* # Finally cleanup
77
* echo 0 > /sys/kernel/livepatch/livepatch_callbacks_demo/enabled
78
* rmmod samples/livepatch/livepatch-callbacks-demo.ko
79
*/
80
81
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
82
83
#include <linux/module.h>
84
#include <linux/kernel.h>
85
#include <linux/livepatch.h>
86
87
static int pre_patch_ret;
88
module_param(pre_patch_ret, int, 0644);
89
MODULE_PARM_DESC(pre_patch_ret, "pre_patch_ret (default=0)");
90
91
static 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
98
static 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
else
104
pr_info("%s: vmlinux\n", callback);
105
}
106
107
/* Executed on object patching (ie, patch enablement) */
108
static 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) */
115
static void post_patch_callback(struct klp_object *obj)
116
{
117
callback_info(__func__, obj);
118
}
119
120
/* Executed on object unpatching (ie, patch disablement) */
121
static void pre_unpatch_callback(struct klp_object *obj)
122
{
123
callback_info(__func__, obj);
124
}
125
126
/* Executed on object unpatching (ie, patch disablement) */
127
static void post_unpatch_callback(struct klp_object *obj)
128
{
129
callback_info(__func__, obj);
130
}
131
132
static void patched_work_func(struct work_struct *work)
133
{
134
pr_info("%s\n", __func__);
135
}
136
137
static struct klp_func no_funcs[] = {
138
{ }
139
};
140
141
static struct klp_func busymod_funcs[] = {
142
{
143
.old_name = "busymod_work_func",
144
.new_func = patched_work_func,
145
}, { }
146
};
147
148
static 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
179
static struct klp_patch patch = {
180
.mod = THIS_MODULE,
181
.objs = objs,
182
};
183
184
static int livepatch_callbacks_demo_init(void)
185
{
186
return klp_enable_patch(&patch);
187
}
188
189
static void livepatch_callbacks_demo_exit(void)
190
{
191
}
192
193
module_init(livepatch_callbacks_demo_init);
194
module_exit(livepatch_callbacks_demo_exit);
195
MODULE_DESCRIPTION("Live patching demo for (un)patching callbacks");
196
MODULE_LICENSE("GPL");
197
MODULE_INFO(livepatch, "Y");
198
199