summaryrefslogtreecommitdiffstats
path: root/samples
diff options
context:
space:
mode:
authorJoe Lawrence <joe.lawrence@redhat.com>2017-08-31 16:37:41 -0400
committerJiri Kosina <jkosina@suse.cz>2017-09-14 17:06:12 -0400
commit439e7271dc2b63de379e37971dc2f64d71e24f8a (patch)
treec3dd63d08e743a63936c24949b456d4522003022 /samples
parentdcba71086e0d1abf4f00cd381530b11d0db7fa1d (diff)
livepatch: introduce shadow variable API
Add exported API for livepatch modules: klp_shadow_get() klp_shadow_alloc() klp_shadow_get_or_alloc() klp_shadow_free() klp_shadow_free_all() that implement "shadow" variables, which allow callers to associate new shadow fields to existing data structures. This is intended to be used by livepatch modules seeking to emulate additions to data structure definitions. See Documentation/livepatch/shadow-vars.txt for a summary of the new shadow variable API, including a few common use cases. See samples/livepatch/livepatch-shadow-* for example modules that demonstrate shadow variables. [jkosina@suse.cz: fix __klp_shadow_get_or_alloc() comment as spotted by Josh] Signed-off-by: Joe Lawrence <joe.lawrence@redhat.com> Acked-by: Josh Poimboeuf <jpoimboe@redhat.com> Acked-by: Miroslav Benes <mbenes@suse.cz> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'samples')
-rw-r--r--samples/Kconfig5
-rw-r--r--samples/livepatch/Makefile3
-rw-r--r--samples/livepatch/livepatch-shadow-fix1.c173
-rw-r--r--samples/livepatch/livepatch-shadow-fix2.c168
-rw-r--r--samples/livepatch/livepatch-shadow-mod.c224
5 files changed, 570 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
73config SAMPLE_LIVEPATCH 73config 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
80config SAMPLE_CONFIGFS 79config 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..539e81d433cd 100644
--- a/samples/livepatch/Makefile
+++ b/samples/livepatch/Makefile
@@ -1 +1,4 @@
1obj-$(CONFIG_SAMPLE_LIVEPATCH) += livepatch-sample.o 1obj-$(CONFIG_SAMPLE_LIVEPATCH) += livepatch-sample.o
2obj-$(CONFIG_SAMPLE_LIVEPATCH) += livepatch-shadow-mod.o
3obj-$(CONFIG_SAMPLE_LIVEPATCH) += livepatch-shadow-fix1.o
4obj-$(CONFIG_SAMPLE_LIVEPATCH) += livepatch-shadow-fix2.o
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
54struct dummy {
55 struct list_head list;
56 unsigned long jiffies_expire;
57};
58
59struct 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
85void 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
109static 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
120static struct klp_object objs[] = {
121 {
122 .name = "livepatch_shadow_mod",
123 .funcs = funcs,
124 }, { }
125};
126
127static struct klp_patch patch = {
128 .mod = THIS_MODULE,
129 .objs = objs,
130};
131
132static 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
162static 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
170module_init(livepatch_shadow_fix1_init);
171module_exit(livepatch_shadow_fix1_exit);
172MODULE_LICENSE("GPL");
173MODULE_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
48struct dummy {
49 struct list_head list;
50 unsigned long jiffies_expire;
51};
52
53bool 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
73void 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
104static 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
115static struct klp_object objs[] = {
116 {
117 .name = "livepatch_shadow_mod",
118 .funcs = funcs,
119 }, { }
120};
121
122static struct klp_patch patch = {
123 .mod = THIS_MODULE,
124 .objs = objs,
125};
126
127static 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
157static 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
165module_init(livepatch_shadow_fix2_init);
166module_exit(livepatch_shadow_fix2_exit);
167MODULE_LICENSE("GPL");
168MODULE_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
84MODULE_LICENSE("GPL");
85MODULE_AUTHOR("Joe Lawrence <joe.lawrence@redhat.com>");
86MODULE_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 */
99LIST_HEAD(dummy_list);
100DEFINE_MUTEX(dummy_list_mutex);
101
102struct dummy {
103 struct list_head list;
104 unsigned long jiffies_expire;
105};
106
107noinline 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
128noinline 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
136noinline 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
147static void alloc_work_func(struct work_struct *work);
148static DECLARE_DELAYED_WORK(alloc_dwork, alloc_work_func);
149
150static 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
172static void cleanup_work_func(struct work_struct *work);
173static DECLARE_DELAYED_WORK(cleanup_dwork, cleanup_work_func);
174
175static 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
198static 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
208static 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
223module_init(livepatch_shadow_mod_init);
224module_exit(livepatch_shadow_mod_exit);