livepatch-shadow-fix2.c (2990B)
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-fix2.c - Shadow variables, livepatch demo 8 * 9 * Purpose 10 * ------- 11 * 12 * Adds functionality to livepatch-shadow-mod's in-flight data 13 * structures through a shadow variable. The livepatch patches a 14 * routine that periodically inspects data structures, incrementing a 15 * per-data-structure counter, creating the counter if needed. 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#define SV_COUNTER 2 35 36struct dummy { 37 struct list_head list; 38 unsigned long jiffies_expire; 39}; 40 41static bool livepatch_fix2_dummy_check(struct dummy *d, unsigned long jiffies) 42{ 43 int *shadow_count; 44 45 /* 46 * Patch: handle in-flight dummy structures, if they do not 47 * already have a SV_COUNTER shadow variable, then attach a 48 * new one. 49 */ 50 shadow_count = klp_shadow_get_or_alloc(d, SV_COUNTER, 51 sizeof(*shadow_count), GFP_NOWAIT, 52 NULL, NULL); 53 if (shadow_count) 54 *shadow_count += 1; 55 56 return time_after(jiffies, d->jiffies_expire); 57} 58 59static void livepatch_fix2_dummy_leak_dtor(void *obj, void *shadow_data) 60{ 61 void *d = obj; 62 int **shadow_leak = shadow_data; 63 64 pr_info("%s: dummy @ %p, prevented leak @ %p\n", 65 __func__, d, *shadow_leak); 66 kfree(*shadow_leak); 67} 68 69static void livepatch_fix2_dummy_free(struct dummy *d) 70{ 71 int **shadow_leak; 72 int *shadow_count; 73 74 /* Patch: copy the memory leak patch from the fix1 module. */ 75 shadow_leak = klp_shadow_get(d, SV_LEAK); 76 if (shadow_leak) 77 klp_shadow_free(d, SV_LEAK, livepatch_fix2_dummy_leak_dtor); 78 else 79 pr_info("%s: dummy @ %p leaked!\n", __func__, d); 80 81 /* 82 * Patch: fetch the SV_COUNTER shadow variable and display 83 * the final count. Detach the shadow variable. 84 */ 85 shadow_count = klp_shadow_get(d, SV_COUNTER); 86 if (shadow_count) { 87 pr_info("%s: dummy @ %p, check counter = %d\n", 88 __func__, d, *shadow_count); 89 klp_shadow_free(d, SV_COUNTER, NULL); 90 } 91 92 kfree(d); 93} 94 95static struct klp_func funcs[] = { 96 { 97 .old_name = "dummy_check", 98 .new_func = livepatch_fix2_dummy_check, 99 }, 100 { 101 .old_name = "dummy_free", 102 .new_func = livepatch_fix2_dummy_free, 103 }, { } 104}; 105 106static struct klp_object objs[] = { 107 { 108 .name = "livepatch_shadow_mod", 109 .funcs = funcs, 110 }, { } 111}; 112 113static struct klp_patch patch = { 114 .mod = THIS_MODULE, 115 .objs = objs, 116}; 117 118static int livepatch_shadow_fix2_init(void) 119{ 120 return klp_enable_patch(&patch); 121} 122 123static void livepatch_shadow_fix2_exit(void) 124{ 125 /* Cleanup any existing SV_COUNTER shadow variables */ 126 klp_shadow_free_all(SV_COUNTER, NULL); 127} 128 129module_init(livepatch_shadow_fix2_init); 130module_exit(livepatch_shadow_fix2_exit); 131MODULE_LICENSE("GPL"); 132MODULE_INFO(livepatch, "Y");