1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (C) 2017 Joe Lawrence <joe.lawrence@redhat.com>
4*4882a593Smuzhiyun */
5*4882a593Smuzhiyun
6*4882a593Smuzhiyun /*
7*4882a593Smuzhiyun * livepatch-shadow-fix1.c - Shadow variables, livepatch demo
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun * Purpose
10*4882a593Smuzhiyun * -------
11*4882a593Smuzhiyun *
12*4882a593Smuzhiyun * Fixes the memory leak introduced in livepatch-shadow-mod through the
13*4882a593Smuzhiyun * use of a shadow variable. This fix demonstrates the "extending" of
14*4882a593Smuzhiyun * short-lived data structures by patching its allocation and release
15*4882a593Smuzhiyun * functions.
16*4882a593Smuzhiyun *
17*4882a593Smuzhiyun *
18*4882a593Smuzhiyun * Usage
19*4882a593Smuzhiyun * -----
20*4882a593Smuzhiyun *
21*4882a593Smuzhiyun * This module is not intended to be standalone. See the "Usage"
22*4882a593Smuzhiyun * section of livepatch-shadow-mod.c.
23*4882a593Smuzhiyun */
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun #include <linux/module.h>
28*4882a593Smuzhiyun #include <linux/kernel.h>
29*4882a593Smuzhiyun #include <linux/livepatch.h>
30*4882a593Smuzhiyun #include <linux/slab.h>
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun /* Shadow variable enums */
33*4882a593Smuzhiyun #define SV_LEAK 1
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun /* Allocate new dummies every second */
36*4882a593Smuzhiyun #define ALLOC_PERIOD 1
37*4882a593Smuzhiyun /* Check for expired dummies after a few new ones have been allocated */
38*4882a593Smuzhiyun #define CLEANUP_PERIOD (3 * ALLOC_PERIOD)
39*4882a593Smuzhiyun /* Dummies expire after a few cleanup instances */
40*4882a593Smuzhiyun #define EXPIRE_PERIOD (4 * CLEANUP_PERIOD)
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun struct dummy {
43*4882a593Smuzhiyun struct list_head list;
44*4882a593Smuzhiyun unsigned long jiffies_expire;
45*4882a593Smuzhiyun };
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun /*
48*4882a593Smuzhiyun * The constructor makes more sense together with klp_shadow_get_or_alloc().
49*4882a593Smuzhiyun * In this example, it would be safe to assign the pointer also to the shadow
50*4882a593Smuzhiyun * variable returned by klp_shadow_alloc(). But we wanted to show the more
51*4882a593Smuzhiyun * complicated use of the API.
52*4882a593Smuzhiyun */
shadow_leak_ctor(void * obj,void * shadow_data,void * ctor_data)53*4882a593Smuzhiyun static int shadow_leak_ctor(void *obj, void *shadow_data, void *ctor_data)
54*4882a593Smuzhiyun {
55*4882a593Smuzhiyun int **shadow_leak = shadow_data;
56*4882a593Smuzhiyun int **leak = ctor_data;
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun if (!ctor_data)
59*4882a593Smuzhiyun return -EINVAL;
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun *shadow_leak = *leak;
62*4882a593Smuzhiyun return 0;
63*4882a593Smuzhiyun }
64*4882a593Smuzhiyun
livepatch_fix1_dummy_alloc(void)65*4882a593Smuzhiyun static struct dummy *livepatch_fix1_dummy_alloc(void)
66*4882a593Smuzhiyun {
67*4882a593Smuzhiyun struct dummy *d;
68*4882a593Smuzhiyun int *leak;
69*4882a593Smuzhiyun int **shadow_leak;
70*4882a593Smuzhiyun
71*4882a593Smuzhiyun d = kzalloc(sizeof(*d), GFP_KERNEL);
72*4882a593Smuzhiyun if (!d)
73*4882a593Smuzhiyun return NULL;
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun d->jiffies_expire = jiffies +
76*4882a593Smuzhiyun msecs_to_jiffies(1000 * EXPIRE_PERIOD);
77*4882a593Smuzhiyun
78*4882a593Smuzhiyun /*
79*4882a593Smuzhiyun * Patch: save the extra memory location into a SV_LEAK shadow
80*4882a593Smuzhiyun * variable. A patched dummy_free routine can later fetch this
81*4882a593Smuzhiyun * pointer to handle resource release.
82*4882a593Smuzhiyun */
83*4882a593Smuzhiyun leak = kzalloc(sizeof(*leak), GFP_KERNEL);
84*4882a593Smuzhiyun if (!leak)
85*4882a593Smuzhiyun goto err_leak;
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun shadow_leak = klp_shadow_alloc(d, SV_LEAK, sizeof(leak), GFP_KERNEL,
88*4882a593Smuzhiyun shadow_leak_ctor, &leak);
89*4882a593Smuzhiyun if (!shadow_leak) {
90*4882a593Smuzhiyun pr_err("%s: failed to allocate shadow variable for the leaking pointer: dummy @ %p, leak @ %p\n",
91*4882a593Smuzhiyun __func__, d, leak);
92*4882a593Smuzhiyun goto err_shadow;
93*4882a593Smuzhiyun }
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun pr_info("%s: dummy @ %p, expires @ %lx\n",
96*4882a593Smuzhiyun __func__, d, d->jiffies_expire);
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun return d;
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun err_shadow:
101*4882a593Smuzhiyun kfree(leak);
102*4882a593Smuzhiyun err_leak:
103*4882a593Smuzhiyun kfree(d);
104*4882a593Smuzhiyun return NULL;
105*4882a593Smuzhiyun }
106*4882a593Smuzhiyun
livepatch_fix1_dummy_leak_dtor(void * obj,void * shadow_data)107*4882a593Smuzhiyun static void livepatch_fix1_dummy_leak_dtor(void *obj, void *shadow_data)
108*4882a593Smuzhiyun {
109*4882a593Smuzhiyun void *d = obj;
110*4882a593Smuzhiyun int **shadow_leak = shadow_data;
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun kfree(*shadow_leak);
113*4882a593Smuzhiyun pr_info("%s: dummy @ %p, prevented leak @ %p\n",
114*4882a593Smuzhiyun __func__, d, *shadow_leak);
115*4882a593Smuzhiyun }
116*4882a593Smuzhiyun
livepatch_fix1_dummy_free(struct dummy * d)117*4882a593Smuzhiyun static void livepatch_fix1_dummy_free(struct dummy *d)
118*4882a593Smuzhiyun {
119*4882a593Smuzhiyun int **shadow_leak;
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun /*
122*4882a593Smuzhiyun * Patch: fetch the saved SV_LEAK shadow variable, detach and
123*4882a593Smuzhiyun * free it. Note: handle cases where this shadow variable does
124*4882a593Smuzhiyun * not exist (ie, dummy structures allocated before this livepatch
125*4882a593Smuzhiyun * was loaded.)
126*4882a593Smuzhiyun */
127*4882a593Smuzhiyun shadow_leak = klp_shadow_get(d, SV_LEAK);
128*4882a593Smuzhiyun if (shadow_leak)
129*4882a593Smuzhiyun klp_shadow_free(d, SV_LEAK, livepatch_fix1_dummy_leak_dtor);
130*4882a593Smuzhiyun else
131*4882a593Smuzhiyun pr_info("%s: dummy @ %p leaked!\n", __func__, d);
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun kfree(d);
134*4882a593Smuzhiyun }
135*4882a593Smuzhiyun
136*4882a593Smuzhiyun static struct klp_func funcs[] = {
137*4882a593Smuzhiyun {
138*4882a593Smuzhiyun .old_name = "dummy_alloc",
139*4882a593Smuzhiyun .new_func = livepatch_fix1_dummy_alloc,
140*4882a593Smuzhiyun },
141*4882a593Smuzhiyun {
142*4882a593Smuzhiyun .old_name = "dummy_free",
143*4882a593Smuzhiyun .new_func = livepatch_fix1_dummy_free,
144*4882a593Smuzhiyun }, { }
145*4882a593Smuzhiyun };
146*4882a593Smuzhiyun
147*4882a593Smuzhiyun static struct klp_object objs[] = {
148*4882a593Smuzhiyun {
149*4882a593Smuzhiyun .name = "livepatch_shadow_mod",
150*4882a593Smuzhiyun .funcs = funcs,
151*4882a593Smuzhiyun }, { }
152*4882a593Smuzhiyun };
153*4882a593Smuzhiyun
154*4882a593Smuzhiyun static struct klp_patch patch = {
155*4882a593Smuzhiyun .mod = THIS_MODULE,
156*4882a593Smuzhiyun .objs = objs,
157*4882a593Smuzhiyun };
158*4882a593Smuzhiyun
livepatch_shadow_fix1_init(void)159*4882a593Smuzhiyun static int livepatch_shadow_fix1_init(void)
160*4882a593Smuzhiyun {
161*4882a593Smuzhiyun return klp_enable_patch(&patch);
162*4882a593Smuzhiyun }
163*4882a593Smuzhiyun
livepatch_shadow_fix1_exit(void)164*4882a593Smuzhiyun static void livepatch_shadow_fix1_exit(void)
165*4882a593Smuzhiyun {
166*4882a593Smuzhiyun /* Cleanup any existing SV_LEAK shadow variables */
167*4882a593Smuzhiyun klp_shadow_free_all(SV_LEAK, livepatch_fix1_dummy_leak_dtor);
168*4882a593Smuzhiyun }
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun module_init(livepatch_shadow_fix1_init);
171*4882a593Smuzhiyun module_exit(livepatch_shadow_fix1_exit);
172*4882a593Smuzhiyun MODULE_LICENSE("GPL");
173*4882a593Smuzhiyun MODULE_INFO(livepatch, "Y");
174