xref: /linux/samples/livepatch/livepatch-shadow-fix1.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
11ccea77eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2439e7271SJoe Lawrence /*
3439e7271SJoe Lawrence  * Copyright (C) 2017 Joe Lawrence <joe.lawrence@redhat.com>
4439e7271SJoe Lawrence  */
5439e7271SJoe Lawrence 
6439e7271SJoe Lawrence /*
7439e7271SJoe Lawrence  * livepatch-shadow-fix1.c - Shadow variables, livepatch demo
8439e7271SJoe Lawrence  *
9439e7271SJoe Lawrence  * Purpose
10439e7271SJoe Lawrence  * -------
11439e7271SJoe Lawrence  *
12439e7271SJoe Lawrence  * Fixes the memory leak introduced in livepatch-shadow-mod through the
13439e7271SJoe Lawrence  * use of a shadow variable.  This fix demonstrates the "extending" of
14439e7271SJoe Lawrence  * short-lived data structures by patching its allocation and release
15439e7271SJoe Lawrence  * functions.
16439e7271SJoe Lawrence  *
17439e7271SJoe Lawrence  *
18439e7271SJoe Lawrence  * Usage
19439e7271SJoe Lawrence  * -----
20439e7271SJoe Lawrence  *
21439e7271SJoe Lawrence  * This module is not intended to be standalone.  See the "Usage"
22439e7271SJoe Lawrence  * section of livepatch-shadow-mod.c.
23439e7271SJoe Lawrence  */
24439e7271SJoe Lawrence 
25439e7271SJoe Lawrence #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
26439e7271SJoe Lawrence 
27439e7271SJoe Lawrence #include <linux/module.h>
28439e7271SJoe Lawrence #include <linux/kernel.h>
29439e7271SJoe Lawrence #include <linux/livepatch.h>
30439e7271SJoe Lawrence #include <linux/slab.h>
31439e7271SJoe Lawrence 
32439e7271SJoe Lawrence /* Shadow variable enums */
33439e7271SJoe Lawrence #define SV_LEAK		1
34439e7271SJoe Lawrence 
35439e7271SJoe Lawrence /* Allocate new dummies every second */
36439e7271SJoe Lawrence #define ALLOC_PERIOD	1
37439e7271SJoe Lawrence /* Check for expired dummies after a few new ones have been allocated */
38439e7271SJoe Lawrence #define CLEANUP_PERIOD	(3 * ALLOC_PERIOD)
39439e7271SJoe Lawrence /* Dummies expire after a few cleanup instances */
40439e7271SJoe Lawrence #define EXPIRE_PERIOD	(4 * CLEANUP_PERIOD)
41439e7271SJoe Lawrence 
42439e7271SJoe Lawrence struct dummy {
43439e7271SJoe Lawrence 	struct list_head list;
44439e7271SJoe Lawrence 	unsigned long jiffies_expire;
45439e7271SJoe Lawrence };
46439e7271SJoe Lawrence 
47e91c2518SPetr Mladek /*
48e91c2518SPetr Mladek  * The constructor makes more sense together with klp_shadow_get_or_alloc().
49e91c2518SPetr Mladek  * In this example, it would be safe to assign the pointer also to the shadow
50e91c2518SPetr Mladek  * variable returned by klp_shadow_alloc().  But we wanted to show the more
51e91c2518SPetr Mladek  * complicated use of the API.
52e91c2518SPetr Mladek  */
shadow_leak_ctor(void * obj,void * shadow_data,void * ctor_data)53e91c2518SPetr Mladek static int shadow_leak_ctor(void *obj, void *shadow_data, void *ctor_data)
54e91c2518SPetr Mladek {
558f6b8866SPetr Mladek 	int **shadow_leak = shadow_data;
56be6da984SPetr Mladek 	int **leak = ctor_data;
57e91c2518SPetr Mladek 
58be6da984SPetr Mladek 	if (!ctor_data)
59be6da984SPetr Mladek 		return -EINVAL;
60be6da984SPetr Mladek 
61be6da984SPetr Mladek 	*shadow_leak = *leak;
62e91c2518SPetr Mladek 	return 0;
63e91c2518SPetr Mladek }
64e91c2518SPetr Mladek 
livepatch_fix1_dummy_alloc(void)65b73d5dc7SNicholas Mc Guire static struct dummy *livepatch_fix1_dummy_alloc(void)
66439e7271SJoe Lawrence {
67439e7271SJoe Lawrence 	struct dummy *d;
688f6b8866SPetr Mladek 	int *leak;
69f46e49a9SPetr Mladek 	int **shadow_leak;
70439e7271SJoe Lawrence 
71439e7271SJoe Lawrence 	d = kzalloc(sizeof(*d), GFP_KERNEL);
72439e7271SJoe Lawrence 	if (!d)
73439e7271SJoe Lawrence 		return NULL;
74439e7271SJoe Lawrence 
75439e7271SJoe Lawrence 	d->jiffies_expire = jiffies +
76439e7271SJoe Lawrence 		msecs_to_jiffies(1000 * EXPIRE_PERIOD);
77439e7271SJoe Lawrence 
78439e7271SJoe Lawrence 	/*
79439e7271SJoe Lawrence 	 * Patch: save the extra memory location into a SV_LEAK shadow
80439e7271SJoe Lawrence 	 * variable.  A patched dummy_free routine can later fetch this
81439e7271SJoe Lawrence 	 * pointer to handle resource release.
82439e7271SJoe Lawrence 	 */
838f6b8866SPetr Mladek 	leak = kzalloc(sizeof(*leak), GFP_KERNEL);
84f46e49a9SPetr Mladek 	if (!leak)
85f46e49a9SPetr Mladek 		goto err_leak;
865f30b2e8SNicholas Mc Guire 
87f46e49a9SPetr Mladek 	shadow_leak = klp_shadow_alloc(d, SV_LEAK, sizeof(leak), GFP_KERNEL,
88be6da984SPetr Mladek 				       shadow_leak_ctor, &leak);
89f46e49a9SPetr Mladek 	if (!shadow_leak) {
90f46e49a9SPetr Mladek 		pr_err("%s: failed to allocate shadow variable for the leaking pointer: dummy @ %p, leak @ %p\n",
91f46e49a9SPetr Mladek 		       __func__, d, leak);
92f46e49a9SPetr Mladek 		goto err_shadow;
93f46e49a9SPetr Mladek 	}
94439e7271SJoe Lawrence 
95439e7271SJoe Lawrence 	pr_info("%s: dummy @ %p, expires @ %lx\n",
96439e7271SJoe Lawrence 		__func__, d, d->jiffies_expire);
97439e7271SJoe Lawrence 
98439e7271SJoe Lawrence 	return d;
99f46e49a9SPetr Mladek 
100f46e49a9SPetr Mladek err_shadow:
101f46e49a9SPetr Mladek 	kfree(leak);
102f46e49a9SPetr Mladek err_leak:
103f46e49a9SPetr Mladek 	kfree(d);
104f46e49a9SPetr Mladek 	return NULL;
105439e7271SJoe Lawrence }
106439e7271SJoe Lawrence 
livepatch_fix1_dummy_leak_dtor(void * obj,void * shadow_data)1073b2c77d0SPetr Mladek static void livepatch_fix1_dummy_leak_dtor(void *obj, void *shadow_data)
1083b2c77d0SPetr Mladek {
1093b2c77d0SPetr Mladek 	void *d = obj;
1108f6b8866SPetr Mladek 	int **shadow_leak = shadow_data;
1113b2c77d0SPetr Mladek 
1123b2c77d0SPetr Mladek 	pr_info("%s: dummy @ %p, prevented leak @ %p\n",
1133b2c77d0SPetr Mladek 			 __func__, d, *shadow_leak);
114*5e6ded2eSTom Rix 	kfree(*shadow_leak);
1153b2c77d0SPetr Mladek }
1163b2c77d0SPetr Mladek 
livepatch_fix1_dummy_free(struct dummy * d)117b73d5dc7SNicholas Mc Guire static void livepatch_fix1_dummy_free(struct dummy *d)
118439e7271SJoe Lawrence {
1198f6b8866SPetr Mladek 	int **shadow_leak;
120439e7271SJoe Lawrence 
121439e7271SJoe Lawrence 	/*
122439e7271SJoe Lawrence 	 * Patch: fetch the saved SV_LEAK shadow variable, detach and
123439e7271SJoe Lawrence 	 * free it.  Note: handle cases where this shadow variable does
124439e7271SJoe Lawrence 	 * not exist (ie, dummy structures allocated before this livepatch
125439e7271SJoe Lawrence 	 * was loaded.)
126439e7271SJoe Lawrence 	 */
127439e7271SJoe Lawrence 	shadow_leak = klp_shadow_get(d, SV_LEAK);
1283b2c77d0SPetr Mladek 	if (shadow_leak)
1293b2c77d0SPetr Mladek 		klp_shadow_free(d, SV_LEAK, livepatch_fix1_dummy_leak_dtor);
1303b2c77d0SPetr Mladek 	else
131439e7271SJoe Lawrence 		pr_info("%s: dummy @ %p leaked!\n", __func__, d);
132439e7271SJoe Lawrence 
133439e7271SJoe Lawrence 	kfree(d);
134439e7271SJoe Lawrence }
135439e7271SJoe Lawrence 
136439e7271SJoe Lawrence static struct klp_func funcs[] = {
137439e7271SJoe Lawrence 	{
138439e7271SJoe Lawrence 		.old_name = "dummy_alloc",
139439e7271SJoe Lawrence 		.new_func = livepatch_fix1_dummy_alloc,
140439e7271SJoe Lawrence 	},
141439e7271SJoe Lawrence 	{
142439e7271SJoe Lawrence 		.old_name = "dummy_free",
143439e7271SJoe Lawrence 		.new_func = livepatch_fix1_dummy_free,
144439e7271SJoe Lawrence 	}, { }
145439e7271SJoe Lawrence };
146439e7271SJoe Lawrence 
147439e7271SJoe Lawrence static struct klp_object objs[] = {
148439e7271SJoe Lawrence 	{
149439e7271SJoe Lawrence 		.name = "livepatch_shadow_mod",
150439e7271SJoe Lawrence 		.funcs = funcs,
151439e7271SJoe Lawrence 	}, { }
152439e7271SJoe Lawrence };
153439e7271SJoe Lawrence 
154439e7271SJoe Lawrence static struct klp_patch patch = {
155439e7271SJoe Lawrence 	.mod = THIS_MODULE,
156439e7271SJoe Lawrence 	.objs = objs,
157439e7271SJoe Lawrence };
158439e7271SJoe Lawrence 
livepatch_shadow_fix1_init(void)159439e7271SJoe Lawrence static int livepatch_shadow_fix1_init(void)
160439e7271SJoe Lawrence {
161958ef1e3SPetr Mladek 	return klp_enable_patch(&patch);
162439e7271SJoe Lawrence }
163439e7271SJoe Lawrence 
livepatch_shadow_fix1_exit(void)164439e7271SJoe Lawrence static void livepatch_shadow_fix1_exit(void)
165439e7271SJoe Lawrence {
166439e7271SJoe Lawrence 	/* Cleanup any existing SV_LEAK shadow variables */
1673b2c77d0SPetr Mladek 	klp_shadow_free_all(SV_LEAK, livepatch_fix1_dummy_leak_dtor);
168439e7271SJoe Lawrence }
169439e7271SJoe Lawrence 
170439e7271SJoe Lawrence module_init(livepatch_shadow_fix1_init);
171439e7271SJoe Lawrence module_exit(livepatch_shadow_fix1_exit);
172439e7271SJoe Lawrence MODULE_LICENSE("GPL");
173439e7271SJoe Lawrence MODULE_INFO(livepatch, "Y");
174