aboutsummaryrefslogtreecommitdiffstats
path: root/samples/livepatch/livepatch-shadow-fix2.c
diff options
context:
space:
mode:
authorJiri Kosina <jkosina@suse.cz>2017-11-15 04:49:14 -0500
committerJiri Kosina <jkosina@suse.cz>2017-11-15 04:49:14 -0500
commitcb65dc7b89043a66d4459a6a811645d43185b5f0 (patch)
tree7246fb9b5a97405520008e6f6984db9bdd126629 /samples/livepatch/livepatch-shadow-fix2.c
parentef8daf8eeb5b8ab6bc356656163d19f20fb827ed (diff)
parent19205da6a0da701787d42ad754edd1ffb514c956 (diff)
Merge branch 'for-4.15/shadow-variables' into for-linus
Shadow variables 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.
Diffstat (limited to 'samples/livepatch/livepatch-shadow-fix2.c')
-rw-r--r--samples/livepatch/livepatch-shadow-fix2.c168
1 files changed, 168 insertions, 0 deletions
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");