at v4.20 156 lines 3.8 kB view raw
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 48struct dummy { 49 struct list_head list; 50 unsigned long jiffies_expire; 51}; 52 53bool 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 71static 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 81void 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 107static 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 118static struct klp_object objs[] = { 119 { 120 .name = "livepatch_shadow_mod", 121 .funcs = funcs, 122 }, { } 123}; 124 125static struct klp_patch patch = { 126 .mod = THIS_MODULE, 127 .objs = objs, 128}; 129 130static 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 145static 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 153module_init(livepatch_shadow_fix2_init); 154module_exit(livepatch_shadow_fix2_exit); 155MODULE_LICENSE("GPL"); 156MODULE_INFO(livepatch, "Y");