diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-11-15 13:21:58 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-11-15 13:21:58 -0500 |
commit | 0ef76878cfcf4d6b64972b283021f576a95d9216 (patch) | |
tree | 387f5bf5bff34738550686c0306e97528dc69711 /samples | |
parent | 9682b3dea22190a6fd449d157e3175b0e748684d (diff) | |
parent | fc41efc1843009ebcdb4850b21f1c371ad203f4e (diff) |
Merge branch 'for-linus' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/jikos/livepatching
Pull livepatching updates from Jiri Kosina:
- shadow variables support, allowing livepatches to associate new
"shadow" fields to existing data structures, from Joe Lawrence
- pre/post patch callbacks API, allowing livepatch writers to register
callbacks to be called before and after patch application, from Joe
Lawrence
* 'for-linus' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/jikos/livepatching:
livepatch: __klp_disable_patch() should never be called for disabled patches
livepatch: Correctly call klp_post_unpatch_callback() in error paths
livepatch: add transition notices
livepatch: move transition "complete" notice into klp_complete_transition()
livepatch: add (un)patch callbacks
livepatch: Small shadow variable documentation fixes
livepatch: __klp_shadow_get_or_alloc() is local to shadow.c
livepatch: introduce shadow variable API
Diffstat (limited to 'samples')
-rw-r--r-- | samples/Kconfig | 5 | ||||
-rw-r--r-- | samples/livepatch/Makefile | 6 | ||||
-rw-r--r-- | samples/livepatch/livepatch-callbacks-busymod.c | 72 | ||||
-rw-r--r-- | samples/livepatch/livepatch-callbacks-demo.c | 234 | ||||
-rw-r--r-- | samples/livepatch/livepatch-callbacks-mod.c | 53 | ||||
-rw-r--r-- | samples/livepatch/livepatch-shadow-fix1.c | 173 | ||||
-rw-r--r-- | samples/livepatch/livepatch-shadow-fix2.c | 168 | ||||
-rw-r--r-- | samples/livepatch/livepatch-shadow-mod.c | 224 |
8 files changed, 932 insertions, 3 deletions
diff --git a/samples/Kconfig b/samples/Kconfig index 9cb63188d3ef..c332a3b9de05 100644 --- a/samples/Kconfig +++ b/samples/Kconfig | |||
@@ -71,11 +71,10 @@ config SAMPLE_RPMSG_CLIENT | |||
71 | the rpmsg bus. | 71 | the rpmsg bus. |
72 | 72 | ||
73 | config SAMPLE_LIVEPATCH | 73 | config SAMPLE_LIVEPATCH |
74 | tristate "Build live patching sample -- loadable modules only" | 74 | tristate "Build live patching samples -- loadable modules only" |
75 | depends on LIVEPATCH && m | 75 | depends on LIVEPATCH && m |
76 | help | 76 | help |
77 | Builds a sample live patch that replaces the procfs handler | 77 | Build sample live patch demonstrations. |
78 | for /proc/cmdline to print "this has been live patched". | ||
79 | 78 | ||
80 | config SAMPLE_CONFIGFS | 79 | config SAMPLE_CONFIGFS |
81 | tristate "Build configfs patching sample -- loadable modules only" | 80 | tristate "Build configfs patching sample -- loadable modules only" |
diff --git a/samples/livepatch/Makefile b/samples/livepatch/Makefile index 10319d7ea0b1..2472ce39a18d 100644 --- a/samples/livepatch/Makefile +++ b/samples/livepatch/Makefile | |||
@@ -1 +1,7 @@ | |||
1 | obj-$(CONFIG_SAMPLE_LIVEPATCH) += livepatch-sample.o | 1 | obj-$(CONFIG_SAMPLE_LIVEPATCH) += livepatch-sample.o |
2 | obj-$(CONFIG_SAMPLE_LIVEPATCH) += livepatch-shadow-mod.o | ||
3 | obj-$(CONFIG_SAMPLE_LIVEPATCH) += livepatch-shadow-fix1.o | ||
4 | obj-$(CONFIG_SAMPLE_LIVEPATCH) += livepatch-shadow-fix2.o | ||
5 | obj-$(CONFIG_SAMPLE_LIVEPATCH) += livepatch-callbacks-demo.o | ||
6 | obj-$(CONFIG_SAMPLE_LIVEPATCH) += livepatch-callbacks-mod.o | ||
7 | obj-$(CONFIG_SAMPLE_LIVEPATCH) += livepatch-callbacks-busymod.o | ||
diff --git a/samples/livepatch/livepatch-callbacks-busymod.c b/samples/livepatch/livepatch-callbacks-busymod.c new file mode 100644 index 000000000000..80d06e103f1b --- /dev/null +++ b/samples/livepatch/livepatch-callbacks-busymod.c | |||
@@ -0,0 +1,72 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2017 Joe Lawrence <joe.lawrence@redhat.com> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation; either version 2 | ||
7 | * of the License, or (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | /* | ||
19 | * livepatch-callbacks-busymod.c - (un)patching callbacks demo support module | ||
20 | * | ||
21 | * | ||
22 | * Purpose | ||
23 | * ------- | ||
24 | * | ||
25 | * Simple module to demonstrate livepatch (un)patching callbacks. | ||
26 | * | ||
27 | * | ||
28 | * Usage | ||
29 | * ----- | ||
30 | * | ||
31 | * This module is not intended to be standalone. See the "Usage" | ||
32 | * section of livepatch-callbacks-mod.c. | ||
33 | */ | ||
34 | |||
35 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
36 | |||
37 | #include <linux/module.h> | ||
38 | #include <linux/kernel.h> | ||
39 | #include <linux/workqueue.h> | ||
40 | #include <linux/delay.h> | ||
41 | |||
42 | static int sleep_secs; | ||
43 | module_param(sleep_secs, int, 0644); | ||
44 | MODULE_PARM_DESC(sleep_secs, "sleep_secs (default=0)"); | ||
45 | |||
46 | static void busymod_work_func(struct work_struct *work); | ||
47 | static DECLARE_DELAYED_WORK(work, busymod_work_func); | ||
48 | |||
49 | static void busymod_work_func(struct work_struct *work) | ||
50 | { | ||
51 | pr_info("%s, sleeping %d seconds ...\n", __func__, sleep_secs); | ||
52 | msleep(sleep_secs * 1000); | ||
53 | pr_info("%s exit\n", __func__); | ||
54 | } | ||
55 | |||
56 | static int livepatch_callbacks_mod_init(void) | ||
57 | { | ||
58 | pr_info("%s\n", __func__); | ||
59 | schedule_delayed_work(&work, | ||
60 | msecs_to_jiffies(1000 * 0)); | ||
61 | return 0; | ||
62 | } | ||
63 | |||
64 | static void livepatch_callbacks_mod_exit(void) | ||
65 | { | ||
66 | cancel_delayed_work_sync(&work); | ||
67 | pr_info("%s\n", __func__); | ||
68 | } | ||
69 | |||
70 | module_init(livepatch_callbacks_mod_init); | ||
71 | module_exit(livepatch_callbacks_mod_exit); | ||
72 | MODULE_LICENSE("GPL"); | ||
diff --git a/samples/livepatch/livepatch-callbacks-demo.c b/samples/livepatch/livepatch-callbacks-demo.c new file mode 100644 index 000000000000..3d115bd68442 --- /dev/null +++ b/samples/livepatch/livepatch-callbacks-demo.c | |||
@@ -0,0 +1,234 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2017 Joe Lawrence <joe.lawrence@redhat.com> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation; either version 2 | ||
7 | * of the License, or (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | /* | ||
19 | * livepatch-callbacks-demo.c - (un)patching callbacks livepatch demo | ||
20 | * | ||
21 | * | ||
22 | * Purpose | ||
23 | * ------- | ||
24 | * | ||
25 | * Demonstration of registering livepatch (un)patching callbacks. | ||
26 | * | ||
27 | * | ||
28 | * Usage | ||
29 | * ----- | ||
30 | * | ||
31 | * Step 1 - load the simple module | ||
32 | * | ||
33 | * insmod samples/livepatch/livepatch-callbacks-mod.ko | ||
34 | * | ||
35 | * | ||
36 | * Step 2 - load the demonstration livepatch (with callbacks) | ||
37 | * | ||
38 | * insmod samples/livepatch/livepatch-callbacks-demo.ko | ||
39 | * | ||
40 | * | ||
41 | * Step 3 - cleanup | ||
42 | * | ||
43 | * echo 0 > /sys/kernel/livepatch/livepatch_callbacks_demo/enabled | ||
44 | * rmmod livepatch_callbacks_demo | ||
45 | * rmmod livepatch_callbacks_mod | ||
46 | * | ||
47 | * Watch dmesg output to see livepatch enablement, callback execution | ||
48 | * and patching operations for both vmlinux and module targets. | ||
49 | * | ||
50 | * NOTE: swap the insmod order of livepatch-callbacks-mod.ko and | ||
51 | * livepatch-callbacks-demo.ko to observe what happens when a | ||
52 | * target module is loaded after a livepatch with callbacks. | ||
53 | * | ||
54 | * NOTE: 'pre_patch_ret' is a module parameter that sets the pre-patch | ||
55 | * callback return status. Try setting up a non-zero status | ||
56 | * such as -19 (-ENODEV): | ||
57 | * | ||
58 | * # Load demo livepatch, vmlinux is patched | ||
59 | * insmod samples/livepatch/livepatch-callbacks-demo.ko | ||
60 | * | ||
61 | * # Setup next pre-patch callback to return -ENODEV | ||
62 | * echo -19 > /sys/module/livepatch_callbacks_demo/parameters/pre_patch_ret | ||
63 | * | ||
64 | * # Module loader refuses to load the target module | ||
65 | * insmod samples/livepatch/livepatch-callbacks-mod.ko | ||
66 | * insmod: ERROR: could not insert module samples/livepatch/livepatch-callbacks-mod.ko: No such device | ||
67 | * | ||
68 | * NOTE: There is a second target module, | ||
69 | * livepatch-callbacks-busymod.ko, available for experimenting | ||
70 | * with livepatch (un)patch callbacks. This module contains | ||
71 | * a 'sleep_secs' parameter that parks the module on one of the | ||
72 | * functions that the livepatch demo module wants to patch. | ||
73 | * Modifying this value and tweaking the order of module loads can | ||
74 | * effectively demonstrate stalled patch transitions: | ||
75 | * | ||
76 | * # Load a target module, let it park on 'busymod_work_func' for | ||
77 | * # thirty seconds | ||
78 | * insmod samples/livepatch/livepatch-callbacks-busymod.ko sleep_secs=30 | ||
79 | * | ||
80 | * # Meanwhile load the livepatch | ||
81 | * insmod samples/livepatch/livepatch-callbacks-demo.ko | ||
82 | * | ||
83 | * # ... then load and unload another target module while the | ||
84 | * # transition is in progress | ||
85 | * insmod samples/livepatch/livepatch-callbacks-mod.ko | ||
86 | * rmmod samples/livepatch/livepatch-callbacks-mod.ko | ||
87 | * | ||
88 | * # Finally cleanup | ||
89 | * echo 0 > /sys/kernel/livepatch/livepatch_callbacks_demo/enabled | ||
90 | * rmmod samples/livepatch/livepatch-callbacks-demo.ko | ||
91 | */ | ||
92 | |||
93 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
94 | |||
95 | #include <linux/module.h> | ||
96 | #include <linux/kernel.h> | ||
97 | #include <linux/livepatch.h> | ||
98 | |||
99 | static int pre_patch_ret; | ||
100 | module_param(pre_patch_ret, int, 0644); | ||
101 | MODULE_PARM_DESC(pre_patch_ret, "pre_patch_ret (default=0)"); | ||
102 | |||
103 | static const char *const module_state[] = { | ||
104 | [MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state", | ||
105 | [MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init", | ||
106 | [MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away", | ||
107 | [MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up", | ||
108 | }; | ||
109 | |||
110 | static void callback_info(const char *callback, struct klp_object *obj) | ||
111 | { | ||
112 | if (obj->mod) | ||
113 | pr_info("%s: %s -> %s\n", callback, obj->mod->name, | ||
114 | module_state[obj->mod->state]); | ||
115 | else | ||
116 | pr_info("%s: vmlinux\n", callback); | ||
117 | } | ||
118 | |||
119 | /* Executed on object patching (ie, patch enablement) */ | ||
120 | static int pre_patch_callback(struct klp_object *obj) | ||
121 | { | ||
122 | callback_info(__func__, obj); | ||
123 | return pre_patch_ret; | ||
124 | } | ||
125 | |||
126 | /* Executed on object unpatching (ie, patch disablement) */ | ||
127 | static void post_patch_callback(struct klp_object *obj) | ||
128 | { | ||
129 | callback_info(__func__, obj); | ||
130 | } | ||
131 | |||
132 | /* Executed on object unpatching (ie, patch disablement) */ | ||
133 | static void pre_unpatch_callback(struct klp_object *obj) | ||
134 | { | ||
135 | callback_info(__func__, obj); | ||
136 | } | ||
137 | |||
138 | /* Executed on object unpatching (ie, patch disablement) */ | ||
139 | static void post_unpatch_callback(struct klp_object *obj) | ||
140 | { | ||
141 | callback_info(__func__, obj); | ||
142 | } | ||
143 | |||
144 | static void patched_work_func(struct work_struct *work) | ||
145 | { | ||
146 | pr_info("%s\n", __func__); | ||
147 | } | ||
148 | |||
149 | static struct klp_func no_funcs[] = { | ||
150 | { } | ||
151 | }; | ||
152 | |||
153 | static struct klp_func busymod_funcs[] = { | ||
154 | { | ||
155 | .old_name = "busymod_work_func", | ||
156 | .new_func = patched_work_func, | ||
157 | }, { } | ||
158 | }; | ||
159 | |||
160 | static struct klp_object objs[] = { | ||
161 | { | ||
162 | .name = NULL, /* vmlinux */ | ||
163 | .funcs = no_funcs, | ||
164 | .callbacks = { | ||
165 | .pre_patch = pre_patch_callback, | ||
166 | .post_patch = post_patch_callback, | ||
167 | .pre_unpatch = pre_unpatch_callback, | ||
168 | .post_unpatch = post_unpatch_callback, | ||
169 | }, | ||
170 | }, { | ||
171 | .name = "livepatch_callbacks_mod", | ||
172 | .funcs = no_funcs, | ||
173 | .callbacks = { | ||
174 | .pre_patch = pre_patch_callback, | ||
175 | .post_patch = post_patch_callback, | ||
176 | .pre_unpatch = pre_unpatch_callback, | ||
177 | .post_unpatch = post_unpatch_callback, | ||
178 | }, | ||
179 | }, { | ||
180 | .name = "livepatch_callbacks_busymod", | ||
181 | .funcs = busymod_funcs, | ||
182 | .callbacks = { | ||
183 | .pre_patch = pre_patch_callback, | ||
184 | .post_patch = post_patch_callback, | ||
185 | .pre_unpatch = pre_unpatch_callback, | ||
186 | .post_unpatch = post_unpatch_callback, | ||
187 | }, | ||
188 | }, { } | ||
189 | }; | ||
190 | |||
191 | static struct klp_patch patch = { | ||
192 | .mod = THIS_MODULE, | ||
193 | .objs = objs, | ||
194 | }; | ||
195 | |||
196 | static int livepatch_callbacks_demo_init(void) | ||
197 | { | ||
198 | int ret; | ||
199 | |||
200 | if (!klp_have_reliable_stack() && !patch.immediate) { | ||
201 | /* | ||
202 | * WARNING: Be very careful when using 'patch.immediate' in | ||
203 | * your patches. It's ok to use it for simple patches like | ||
204 | * this, but for more complex patches which change function | ||
205 | * semantics, locking semantics, or data structures, it may not | ||
206 | * be safe. Use of this option will also prevent removal of | ||
207 | * the patch. | ||
208 | * | ||
209 | * See Documentation/livepatch/livepatch.txt for more details. | ||
210 | */ | ||
211 | patch.immediate = true; | ||
212 | pr_notice("The consistency model isn't supported for your architecture. Bypassing safety mechanisms and applying the patch immediately.\n"); | ||
213 | } | ||
214 | |||
215 | ret = klp_register_patch(&patch); | ||
216 | if (ret) | ||
217 | return ret; | ||
218 | ret = klp_enable_patch(&patch); | ||
219 | if (ret) { | ||
220 | WARN_ON(klp_unregister_patch(&patch)); | ||
221 | return ret; | ||
222 | } | ||
223 | return 0; | ||
224 | } | ||
225 | |||
226 | static void livepatch_callbacks_demo_exit(void) | ||
227 | { | ||
228 | WARN_ON(klp_unregister_patch(&patch)); | ||
229 | } | ||
230 | |||
231 | module_init(livepatch_callbacks_demo_init); | ||
232 | module_exit(livepatch_callbacks_demo_exit); | ||
233 | MODULE_LICENSE("GPL"); | ||
234 | MODULE_INFO(livepatch, "Y"); | ||
diff --git a/samples/livepatch/livepatch-callbacks-mod.c b/samples/livepatch/livepatch-callbacks-mod.c new file mode 100644 index 000000000000..e610ce29ba44 --- /dev/null +++ b/samples/livepatch/livepatch-callbacks-mod.c | |||
@@ -0,0 +1,53 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2017 Joe Lawrence <joe.lawrence@redhat.com> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation; either version 2 | ||
7 | * of the License, or (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | /* | ||
19 | * livepatch-callbacks-mod.c - (un)patching callbacks demo support module | ||
20 | * | ||
21 | * | ||
22 | * Purpose | ||
23 | * ------- | ||
24 | * | ||
25 | * Simple module to demonstrate livepatch (un)patching callbacks. | ||
26 | * | ||
27 | * | ||
28 | * Usage | ||
29 | * ----- | ||
30 | * | ||
31 | * This module is not intended to be standalone. See the "Usage" | ||
32 | * section of livepatch-callbacks-demo.c. | ||
33 | */ | ||
34 | |||
35 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
36 | |||
37 | #include <linux/module.h> | ||
38 | #include <linux/kernel.h> | ||
39 | |||
40 | static int livepatch_callbacks_mod_init(void) | ||
41 | { | ||
42 | pr_info("%s\n", __func__); | ||
43 | return 0; | ||
44 | } | ||
45 | |||
46 | static void livepatch_callbacks_mod_exit(void) | ||
47 | { | ||
48 | pr_info("%s\n", __func__); | ||
49 | } | ||
50 | |||
51 | module_init(livepatch_callbacks_mod_init); | ||
52 | module_exit(livepatch_callbacks_mod_exit); | ||
53 | MODULE_LICENSE("GPL"); | ||
diff --git a/samples/livepatch/livepatch-shadow-fix1.c b/samples/livepatch/livepatch-shadow-fix1.c new file mode 100644 index 000000000000..fbe0a1f3d99b --- /dev/null +++ b/samples/livepatch/livepatch-shadow-fix1.c | |||
@@ -0,0 +1,173 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2017 Joe Lawrence <joe.lawrence@redhat.com> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation; either version 2 | ||
7 | * of the License, or (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | /* | ||
19 | * livepatch-shadow-fix1.c - Shadow variables, livepatch demo | ||
20 | * | ||
21 | * Purpose | ||
22 | * ------- | ||
23 | * | ||
24 | * Fixes the memory leak introduced in livepatch-shadow-mod through the | ||
25 | * use of a shadow variable. This fix demonstrates the "extending" of | ||
26 | * short-lived data structures by patching its allocation and release | ||
27 | * functions. | ||
28 | * | ||
29 | * | ||
30 | * Usage | ||
31 | * ----- | ||
32 | * | ||
33 | * This module is not intended to be standalone. See the "Usage" | ||
34 | * section of livepatch-shadow-mod.c. | ||
35 | */ | ||
36 | |||
37 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
38 | |||
39 | #include <linux/module.h> | ||
40 | #include <linux/kernel.h> | ||
41 | #include <linux/livepatch.h> | ||
42 | #include <linux/slab.h> | ||
43 | |||
44 | /* Shadow variable enums */ | ||
45 | #define SV_LEAK 1 | ||
46 | |||
47 | /* Allocate new dummies every second */ | ||
48 | #define ALLOC_PERIOD 1 | ||
49 | /* Check for expired dummies after a few new ones have been allocated */ | ||
50 | #define CLEANUP_PERIOD (3 * ALLOC_PERIOD) | ||
51 | /* Dummies expire after a few cleanup instances */ | ||
52 | #define EXPIRE_PERIOD (4 * CLEANUP_PERIOD) | ||
53 | |||
54 | struct dummy { | ||
55 | struct list_head list; | ||
56 | unsigned long jiffies_expire; | ||
57 | }; | ||
58 | |||
59 | struct dummy *livepatch_fix1_dummy_alloc(void) | ||
60 | { | ||
61 | struct dummy *d; | ||
62 | void *leak; | ||
63 | |||
64 | d = kzalloc(sizeof(*d), GFP_KERNEL); | ||
65 | if (!d) | ||
66 | return NULL; | ||
67 | |||
68 | d->jiffies_expire = jiffies + | ||
69 | msecs_to_jiffies(1000 * EXPIRE_PERIOD); | ||
70 | |||
71 | /* | ||
72 | * Patch: save the extra memory location into a SV_LEAK shadow | ||
73 | * variable. A patched dummy_free routine can later fetch this | ||
74 | * pointer to handle resource release. | ||
75 | */ | ||
76 | leak = kzalloc(sizeof(int), GFP_KERNEL); | ||
77 | klp_shadow_alloc(d, SV_LEAK, &leak, sizeof(leak), GFP_KERNEL); | ||
78 | |||
79 | pr_info("%s: dummy @ %p, expires @ %lx\n", | ||
80 | __func__, d, d->jiffies_expire); | ||
81 | |||
82 | return d; | ||
83 | } | ||
84 | |||
85 | void livepatch_fix1_dummy_free(struct dummy *d) | ||
86 | { | ||
87 | void **shadow_leak, *leak; | ||
88 | |||
89 | /* | ||
90 | * Patch: fetch the saved SV_LEAK shadow variable, detach and | ||
91 | * free it. Note: handle cases where this shadow variable does | ||
92 | * not exist (ie, dummy structures allocated before this livepatch | ||
93 | * was loaded.) | ||
94 | */ | ||
95 | shadow_leak = klp_shadow_get(d, SV_LEAK); | ||
96 | if (shadow_leak) { | ||
97 | leak = *shadow_leak; | ||
98 | klp_shadow_free(d, SV_LEAK); | ||
99 | kfree(leak); | ||
100 | pr_info("%s: dummy @ %p, prevented leak @ %p\n", | ||
101 | __func__, d, leak); | ||
102 | } else { | ||
103 | pr_info("%s: dummy @ %p leaked!\n", __func__, d); | ||
104 | } | ||
105 | |||
106 | kfree(d); | ||
107 | } | ||
108 | |||
109 | static struct klp_func funcs[] = { | ||
110 | { | ||
111 | .old_name = "dummy_alloc", | ||
112 | .new_func = livepatch_fix1_dummy_alloc, | ||
113 | }, | ||
114 | { | ||
115 | .old_name = "dummy_free", | ||
116 | .new_func = livepatch_fix1_dummy_free, | ||
117 | }, { } | ||
118 | }; | ||
119 | |||
120 | static struct klp_object objs[] = { | ||
121 | { | ||
122 | .name = "livepatch_shadow_mod", | ||
123 | .funcs = funcs, | ||
124 | }, { } | ||
125 | }; | ||
126 | |||
127 | static struct klp_patch patch = { | ||
128 | .mod = THIS_MODULE, | ||
129 | .objs = objs, | ||
130 | }; | ||
131 | |||
132 | static int livepatch_shadow_fix1_init(void) | ||
133 | { | ||
134 | int ret; | ||
135 | |||
136 | if (!klp_have_reliable_stack() && !patch.immediate) { | ||
137 | /* | ||
138 | * WARNING: Be very careful when using 'patch.immediate' in | ||
139 | * your patches. It's ok to use it for simple patches like | ||
140 | * this, but for more complex patches which change function | ||
141 | * semantics, locking semantics, or data structures, it may not | ||
142 | * be safe. Use of this option will also prevent removal of | ||
143 | * the patch. | ||
144 | * | ||
145 | * See Documentation/livepatch/livepatch.txt for more details. | ||
146 | */ | ||
147 | patch.immediate = true; | ||
148 | pr_notice("The consistency model isn't supported for your architecture. Bypassing safety mechanisms and applying the patch immediately.\n"); | ||
149 | } | ||
150 | |||
151 | ret = klp_register_patch(&patch); | ||
152 | if (ret) | ||
153 | return ret; | ||
154 | ret = klp_enable_patch(&patch); | ||
155 | if (ret) { | ||
156 | WARN_ON(klp_unregister_patch(&patch)); | ||
157 | return ret; | ||
158 | } | ||
159 | return 0; | ||
160 | } | ||
161 | |||
162 | static void livepatch_shadow_fix1_exit(void) | ||
163 | { | ||
164 | /* Cleanup any existing SV_LEAK shadow variables */ | ||
165 | klp_shadow_free_all(SV_LEAK); | ||
166 | |||
167 | WARN_ON(klp_unregister_patch(&patch)); | ||
168 | } | ||
169 | |||
170 | module_init(livepatch_shadow_fix1_init); | ||
171 | module_exit(livepatch_shadow_fix1_exit); | ||
172 | MODULE_LICENSE("GPL"); | ||
173 | MODULE_INFO(livepatch, "Y"); | ||
diff --git a/samples/livepatch/livepatch-shadow-fix2.c b/samples/livepatch/livepatch-shadow-fix2.c new file mode 100644 index 000000000000..53c1794bdc5f --- /dev/null +++ b/samples/livepatch/livepatch-shadow-fix2.c | |||
@@ -0,0 +1,168 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2017 Joe Lawrence <joe.lawrence@redhat.com> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation; either version 2 | ||
7 | * of the License, or (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | /* | ||
19 | * livepatch-shadow-fix2.c - Shadow variables, livepatch demo | ||
20 | * | ||
21 | * Purpose | ||
22 | * ------- | ||
23 | * | ||
24 | * Adds functionality to livepatch-shadow-mod's in-flight data | ||
25 | * structures through a shadow variable. The livepatch patches a | ||
26 | * routine that periodically inspects data structures, incrementing a | ||
27 | * per-data-structure counter, creating the counter if needed. | ||
28 | * | ||
29 | * | ||
30 | * Usage | ||
31 | * ----- | ||
32 | * | ||
33 | * This module is not intended to be standalone. See the "Usage" | ||
34 | * section of livepatch-shadow-mod.c. | ||
35 | */ | ||
36 | |||
37 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
38 | |||
39 | #include <linux/module.h> | ||
40 | #include <linux/kernel.h> | ||
41 | #include <linux/livepatch.h> | ||
42 | #include <linux/slab.h> | ||
43 | |||
44 | /* Shadow variable enums */ | ||
45 | #define SV_LEAK 1 | ||
46 | #define SV_COUNTER 2 | ||
47 | |||
48 | struct dummy { | ||
49 | struct list_head list; | ||
50 | unsigned long jiffies_expire; | ||
51 | }; | ||
52 | |||
53 | bool livepatch_fix2_dummy_check(struct dummy *d, unsigned long jiffies) | ||
54 | { | ||
55 | int *shadow_count; | ||
56 | int count; | ||
57 | |||
58 | /* | ||
59 | * Patch: handle in-flight dummy structures, if they do not | ||
60 | * already have a SV_COUNTER shadow variable, then attach a | ||
61 | * new one. | ||
62 | */ | ||
63 | count = 0; | ||
64 | shadow_count = klp_shadow_get_or_alloc(d, SV_COUNTER, | ||
65 | &count, sizeof(count), | ||
66 | GFP_NOWAIT); | ||
67 | if (shadow_count) | ||
68 | *shadow_count += 1; | ||
69 | |||
70 | return time_after(jiffies, d->jiffies_expire); | ||
71 | } | ||
72 | |||
73 | void livepatch_fix2_dummy_free(struct dummy *d) | ||
74 | { | ||
75 | void **shadow_leak, *leak; | ||
76 | int *shadow_count; | ||
77 | |||
78 | /* Patch: copy the memory leak patch from the fix1 module. */ | ||
79 | shadow_leak = klp_shadow_get(d, SV_LEAK); | ||
80 | if (shadow_leak) { | ||
81 | leak = *shadow_leak; | ||
82 | klp_shadow_free(d, SV_LEAK); | ||
83 | kfree(leak); | ||
84 | pr_info("%s: dummy @ %p, prevented leak @ %p\n", | ||
85 | __func__, d, leak); | ||
86 | } else { | ||
87 | pr_info("%s: dummy @ %p leaked!\n", __func__, d); | ||
88 | } | ||
89 | |||
90 | /* | ||
91 | * Patch: fetch the SV_COUNTER shadow variable and display | ||
92 | * the final count. Detach the shadow variable. | ||
93 | */ | ||
94 | shadow_count = klp_shadow_get(d, SV_COUNTER); | ||
95 | if (shadow_count) { | ||
96 | pr_info("%s: dummy @ %p, check counter = %d\n", | ||
97 | __func__, d, *shadow_count); | ||
98 | klp_shadow_free(d, SV_COUNTER); | ||
99 | } | ||
100 | |||
101 | kfree(d); | ||
102 | } | ||
103 | |||
104 | static struct klp_func funcs[] = { | ||
105 | { | ||
106 | .old_name = "dummy_check", | ||
107 | .new_func = livepatch_fix2_dummy_check, | ||
108 | }, | ||
109 | { | ||
110 | .old_name = "dummy_free", | ||
111 | .new_func = livepatch_fix2_dummy_free, | ||
112 | }, { } | ||
113 | }; | ||
114 | |||
115 | static struct klp_object objs[] = { | ||
116 | { | ||
117 | .name = "livepatch_shadow_mod", | ||
118 | .funcs = funcs, | ||
119 | }, { } | ||
120 | }; | ||
121 | |||
122 | static struct klp_patch patch = { | ||
123 | .mod = THIS_MODULE, | ||
124 | .objs = objs, | ||
125 | }; | ||
126 | |||
127 | static int livepatch_shadow_fix2_init(void) | ||
128 | { | ||
129 | int ret; | ||
130 | |||
131 | if (!klp_have_reliable_stack() && !patch.immediate) { | ||
132 | /* | ||
133 | * WARNING: Be very careful when using 'patch.immediate' in | ||
134 | * your patches. It's ok to use it for simple patches like | ||
135 | * this, but for more complex patches which change function | ||
136 | * semantics, locking semantics, or data structures, it may not | ||
137 | * be safe. Use of this option will also prevent removal of | ||
138 | * the patch. | ||
139 | * | ||
140 | * See Documentation/livepatch/livepatch.txt for more details. | ||
141 | */ | ||
142 | patch.immediate = true; | ||
143 | pr_notice("The consistency model isn't supported for your architecture. Bypassing safety mechanisms and applying the patch immediately.\n"); | ||
144 | } | ||
145 | |||
146 | ret = klp_register_patch(&patch); | ||
147 | if (ret) | ||
148 | return ret; | ||
149 | ret = klp_enable_patch(&patch); | ||
150 | if (ret) { | ||
151 | WARN_ON(klp_unregister_patch(&patch)); | ||
152 | return ret; | ||
153 | } | ||
154 | return 0; | ||
155 | } | ||
156 | |||
157 | static void livepatch_shadow_fix2_exit(void) | ||
158 | { | ||
159 | /* Cleanup any existing SV_COUNTER shadow variables */ | ||
160 | klp_shadow_free_all(SV_COUNTER); | ||
161 | |||
162 | WARN_ON(klp_unregister_patch(&patch)); | ||
163 | } | ||
164 | |||
165 | module_init(livepatch_shadow_fix2_init); | ||
166 | module_exit(livepatch_shadow_fix2_exit); | ||
167 | MODULE_LICENSE("GPL"); | ||
168 | MODULE_INFO(livepatch, "Y"); | ||
diff --git a/samples/livepatch/livepatch-shadow-mod.c b/samples/livepatch/livepatch-shadow-mod.c new file mode 100644 index 000000000000..4c54b250332d --- /dev/null +++ b/samples/livepatch/livepatch-shadow-mod.c | |||
@@ -0,0 +1,224 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2017 Joe Lawrence <joe.lawrence@redhat.com> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation; either version 2 | ||
7 | * of the License, or (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | /* | ||
19 | * livepatch-shadow-mod.c - Shadow variables, buggy module demo | ||
20 | * | ||
21 | * Purpose | ||
22 | * ------- | ||
23 | * | ||
24 | * As a demonstration of livepatch shadow variable API, this module | ||
25 | * introduces memory leak behavior that livepatch modules | ||
26 | * livepatch-shadow-fix1.ko and livepatch-shadow-fix2.ko correct and | ||
27 | * enhance. | ||
28 | * | ||
29 | * WARNING - even though the livepatch-shadow-fix modules patch the | ||
30 | * memory leak, please load these modules at your own risk -- some | ||
31 | * amount of memory may leaked before the bug is patched. | ||
32 | * | ||
33 | * | ||
34 | * Usage | ||
35 | * ----- | ||
36 | * | ||
37 | * Step 1 - Load the buggy demonstration module: | ||
38 | * | ||
39 | * insmod samples/livepatch/livepatch-shadow-mod.ko | ||
40 | * | ||
41 | * Watch dmesg output for a few moments to see new dummy being allocated | ||
42 | * and a periodic cleanup check. (Note: a small amount of memory is | ||
43 | * being leaked.) | ||
44 | * | ||
45 | * | ||
46 | * Step 2 - Load livepatch fix1: | ||
47 | * | ||
48 | * insmod samples/livepatch/livepatch-shadow-fix1.ko | ||
49 | * | ||
50 | * Continue watching dmesg and note that now livepatch_fix1_dummy_free() | ||
51 | * and livepatch_fix1_dummy_alloc() are logging messages about leaked | ||
52 | * memory and eventually leaks prevented. | ||
53 | * | ||
54 | * | ||
55 | * Step 3 - Load livepatch fix2 (on top of fix1): | ||
56 | * | ||
57 | * insmod samples/livepatch/livepatch-shadow-fix2.ko | ||
58 | * | ||
59 | * This module extends functionality through shadow variables, as a new | ||
60 | * "check" counter is added to the dummy structure. Periodic dmesg | ||
61 | * messages will log these as dummies are cleaned up. | ||
62 | * | ||
63 | * | ||
64 | * Step 4 - Cleanup | ||
65 | * | ||
66 | * Unwind the demonstration by disabling the livepatch fix modules, then | ||
67 | * removing them and the demo module: | ||
68 | * | ||
69 | * echo 0 > /sys/kernel/livepatch/livepatch_shadow_fix2/enabled | ||
70 | * echo 0 > /sys/kernel/livepatch/livepatch_shadow_fix1/enabled | ||
71 | * rmmod livepatch-shadow-fix2 | ||
72 | * rmmod livepatch-shadow-fix1 | ||
73 | * rmmod livepatch-shadow-mod | ||
74 | */ | ||
75 | |||
76 | |||
77 | #include <linux/kernel.h> | ||
78 | #include <linux/module.h> | ||
79 | #include <linux/sched.h> | ||
80 | #include <linux/slab.h> | ||
81 | #include <linux/stat.h> | ||
82 | #include <linux/workqueue.h> | ||
83 | |||
84 | MODULE_LICENSE("GPL"); | ||
85 | MODULE_AUTHOR("Joe Lawrence <joe.lawrence@redhat.com>"); | ||
86 | MODULE_DESCRIPTION("Buggy module for shadow variable demo"); | ||
87 | |||
88 | /* Allocate new dummies every second */ | ||
89 | #define ALLOC_PERIOD 1 | ||
90 | /* Check for expired dummies after a few new ones have been allocated */ | ||
91 | #define CLEANUP_PERIOD (3 * ALLOC_PERIOD) | ||
92 | /* Dummies expire after a few cleanup instances */ | ||
93 | #define EXPIRE_PERIOD (4 * CLEANUP_PERIOD) | ||
94 | |||
95 | /* | ||
96 | * Keep a list of all the dummies so we can clean up any residual ones | ||
97 | * on module exit | ||
98 | */ | ||
99 | LIST_HEAD(dummy_list); | ||
100 | DEFINE_MUTEX(dummy_list_mutex); | ||
101 | |||
102 | struct dummy { | ||
103 | struct list_head list; | ||
104 | unsigned long jiffies_expire; | ||
105 | }; | ||
106 | |||
107 | noinline struct dummy *dummy_alloc(void) | ||
108 | { | ||
109 | struct dummy *d; | ||
110 | void *leak; | ||
111 | |||
112 | d = kzalloc(sizeof(*d), GFP_KERNEL); | ||
113 | if (!d) | ||
114 | return NULL; | ||
115 | |||
116 | d->jiffies_expire = jiffies + | ||
117 | msecs_to_jiffies(1000 * EXPIRE_PERIOD); | ||
118 | |||
119 | /* Oops, forgot to save leak! */ | ||
120 | leak = kzalloc(sizeof(int), GFP_KERNEL); | ||
121 | |||
122 | pr_info("%s: dummy @ %p, expires @ %lx\n", | ||
123 | __func__, d, d->jiffies_expire); | ||
124 | |||
125 | return d; | ||
126 | } | ||
127 | |||
128 | noinline void dummy_free(struct dummy *d) | ||
129 | { | ||
130 | pr_info("%s: dummy @ %p, expired = %lx\n", | ||
131 | __func__, d, d->jiffies_expire); | ||
132 | |||
133 | kfree(d); | ||
134 | } | ||
135 | |||
136 | noinline bool dummy_check(struct dummy *d, unsigned long jiffies) | ||
137 | { | ||
138 | return time_after(jiffies, d->jiffies_expire); | ||
139 | } | ||
140 | |||
141 | /* | ||
142 | * alloc_work_func: allocates new dummy structures, allocates additional | ||
143 | * memory, aptly named "leak", but doesn't keep | ||
144 | * permanent record of it. | ||
145 | */ | ||
146 | |||
147 | static void alloc_work_func(struct work_struct *work); | ||
148 | static DECLARE_DELAYED_WORK(alloc_dwork, alloc_work_func); | ||
149 | |||
150 | static void alloc_work_func(struct work_struct *work) | ||
151 | { | ||
152 | struct dummy *d; | ||
153 | |||
154 | d = dummy_alloc(); | ||
155 | if (!d) | ||
156 | return; | ||
157 | |||
158 | mutex_lock(&dummy_list_mutex); | ||
159 | list_add(&d->list, &dummy_list); | ||
160 | mutex_unlock(&dummy_list_mutex); | ||
161 | |||
162 | schedule_delayed_work(&alloc_dwork, | ||
163 | msecs_to_jiffies(1000 * ALLOC_PERIOD)); | ||
164 | } | ||
165 | |||
166 | /* | ||
167 | * cleanup_work_func: frees dummy structures. Without knownledge of | ||
168 | * "leak", it leaks the additional memory that | ||
169 | * alloc_work_func created. | ||
170 | */ | ||
171 | |||
172 | static void cleanup_work_func(struct work_struct *work); | ||
173 | static DECLARE_DELAYED_WORK(cleanup_dwork, cleanup_work_func); | ||
174 | |||
175 | static void cleanup_work_func(struct work_struct *work) | ||
176 | { | ||
177 | struct dummy *d, *tmp; | ||
178 | unsigned long j; | ||
179 | |||
180 | j = jiffies; | ||
181 | pr_info("%s: jiffies = %lx\n", __func__, j); | ||
182 | |||
183 | mutex_lock(&dummy_list_mutex); | ||
184 | list_for_each_entry_safe(d, tmp, &dummy_list, list) { | ||
185 | |||
186 | /* Kick out and free any expired dummies */ | ||
187 | if (dummy_check(d, j)) { | ||
188 | list_del(&d->list); | ||
189 | dummy_free(d); | ||
190 | } | ||
191 | } | ||
192 | mutex_unlock(&dummy_list_mutex); | ||
193 | |||
194 | schedule_delayed_work(&cleanup_dwork, | ||
195 | msecs_to_jiffies(1000 * CLEANUP_PERIOD)); | ||
196 | } | ||
197 | |||
198 | static int livepatch_shadow_mod_init(void) | ||
199 | { | ||
200 | schedule_delayed_work(&alloc_dwork, | ||
201 | msecs_to_jiffies(1000 * ALLOC_PERIOD)); | ||
202 | schedule_delayed_work(&cleanup_dwork, | ||
203 | msecs_to_jiffies(1000 * CLEANUP_PERIOD)); | ||
204 | |||
205 | return 0; | ||
206 | } | ||
207 | |||
208 | static void livepatch_shadow_mod_exit(void) | ||
209 | { | ||
210 | struct dummy *d, *tmp; | ||
211 | |||
212 | /* Wait for any dummies at work */ | ||
213 | cancel_delayed_work_sync(&alloc_dwork); | ||
214 | cancel_delayed_work_sync(&cleanup_dwork); | ||
215 | |||
216 | /* Cleanup residual dummies */ | ||
217 | list_for_each_entry_safe(d, tmp, &dummy_list, list) { | ||
218 | list_del(&d->list); | ||
219 | dummy_free(d); | ||
220 | } | ||
221 | } | ||
222 | |||
223 | module_init(livepatch_shadow_mod_init); | ||
224 | module_exit(livepatch_shadow_mod_exit); | ||