linux/samples/livepatch/livepatch-shadow-fix2.c
<<
>>
Prefs
   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        kfree(*shadow_leak);
  65        pr_info("%s: dummy @ %p, prevented leak @ %p\n",
  66                         __func__, d, *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");
 133