aboutsummaryrefslogtreecommitdiffstats
path: root/samples/livepatch
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/livepatch
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/livepatch')
-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
4 files changed, 568 insertions, 0 deletions
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