1 /* 2 * Copyright (C) 2017 Joe Lawrence <joe.lawrence@redhat.com> 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation; either version 2 7 * of the License, or (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 /* 19 * livepatch-shadow-fix2.c - Shadow variables, livepatch demo 20 * 21 * Purpose 22 * ------- 23 * 24 * Adds functionality to livepatch-shadow-mod's in-flight data 25 * structures through a shadow variable. The livepatch patches a 26 * routine that periodically inspects data structures, incrementing a 27 * per-data-structure counter, creating the counter if needed. 28 * 29 * 30 * Usage 31 * ----- 32 * 33 * This module is not intended to be standalone. See the "Usage" 34 * section of livepatch-shadow-mod.c. 35 */ 36 37 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 38 39 #include <linux/module.h> 40 #include <linux/kernel.h> 41 #include <linux/livepatch.h> 42 #include <linux/slab.h> 43 44 /* Shadow variable enums */ 45 #define SV_LEAK 1 46 #define SV_COUNTER 2 47 48 struct dummy { 49 struct list_head list; 50 unsigned long jiffies_expire; 51 }; 52 53 bool livepatch_fix2_dummy_check(struct dummy *d, unsigned long jiffies) 54 { 55 int *shadow_count; 56 57 /* 58 * Patch: handle in-flight dummy structures, if they do not 59 * already have a SV_COUNTER shadow variable, then attach a 60 * new one. 61 */ 62 shadow_count = klp_shadow_get_or_alloc(d, SV_COUNTER, 63 sizeof(*shadow_count), GFP_NOWAIT, 64 NULL, NULL); 65 if (shadow_count) 66 *shadow_count += 1; 67 68 return time_after(jiffies, d->jiffies_expire); 69 } 70 71 static void livepatch_fix2_dummy_leak_dtor(void *obj, void *shadow_data) 72 { 73 void *d = obj; 74 void **shadow_leak = shadow_data; 75 76 kfree(*shadow_leak); 77 pr_info("%s: dummy @ %p, prevented leak @ %p\n", 78 __func__, d, *shadow_leak); 79 } 80 81 void livepatch_fix2_dummy_free(struct dummy *d) 82 { 83 void **shadow_leak; 84 int *shadow_count; 85 86 /* Patch: copy the memory leak patch from the fix1 module. */ 87 shadow_leak = klp_shadow_get(d, SV_LEAK); 88 if (shadow_leak) 89 klp_shadow_free(d, SV_LEAK, livepatch_fix2_dummy_leak_dtor); 90 else 91 pr_info("%s: dummy @ %p leaked!\n", __func__, d); 92 93 /* 94 * Patch: fetch the SV_COUNTER shadow variable and display 95 * the final count. Detach the shadow variable. 96 */ 97 shadow_count = klp_shadow_get(d, SV_COUNTER); 98 if (shadow_count) { 99 pr_info("%s: dummy @ %p, check counter = %d\n", 100 __func__, d, *shadow_count); 101 klp_shadow_free(d, SV_COUNTER, NULL); 102 } 103 104 kfree(d); 105 } 106 107 static struct klp_func funcs[] = { 108 { 109 .old_name = "dummy_check", 110 .new_func = livepatch_fix2_dummy_check, 111 }, 112 { 113 .old_name = "dummy_free", 114 .new_func = livepatch_fix2_dummy_free, 115 }, { } 116 }; 117 118 static struct klp_object objs[] = { 119 { 120 .name = "livepatch_shadow_mod", 121 .funcs = funcs, 122 }, { } 123 }; 124 125 static struct klp_patch patch = { 126 .mod = THIS_MODULE, 127 .objs = objs, 128 }; 129 130 static int livepatch_shadow_fix2_init(void) 131 { 132 int ret; 133 134 ret = klp_register_patch(&patch); 135 if (ret) 136 return ret; 137 ret = klp_enable_patch(&patch); 138 if (ret) { 139 WARN_ON(klp_unregister_patch(&patch)); 140 return ret; 141 } 142 return 0; 143 } 144 145 static void livepatch_shadow_fix2_exit(void) 146 { 147 /* Cleanup any existing SV_COUNTER shadow variables */ 148 klp_shadow_free_all(SV_COUNTER, NULL); 149 150 WARN_ON(klp_unregister_patch(&patch)); 151 } 152 153 module_init(livepatch_shadow_fix2_init); 154 module_exit(livepatch_shadow_fix2_exit); 155 MODULE_LICENSE("GPL"); 156 MODULE_INFO(livepatch, "Y"); 157