~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/samples/livepatch/livepatch-shadow-fix1.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php