xref: /OK3568_Linux_fs/kernel/samples/livepatch/livepatch-shadow-fix1.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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