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