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 	ret = klp_register_patch(&patch);
132 	if (ret)
133 		return ret;
134 	ret = klp_enable_patch(&patch);
135 	if (ret) {
136 		WARN_ON(klp_unregister_patch(&patch));
137 		return ret;
138 	}
139 	return 0;
140 }
141 
142 static void livepatch_shadow_fix2_exit(void)
143 {
144 	/* Cleanup any existing SV_COUNTER shadow variables */
145 	klp_shadow_free_all(SV_COUNTER);
146 
147 	WARN_ON(klp_unregister_patch(&patch));
148 }
149 
150 module_init(livepatch_shadow_fix2_init);
151 module_exit(livepatch_shadow_fix2_exit);
152 MODULE_LICENSE("GPL");
153 MODULE_INFO(livepatch, "Y");
154