linux/samples/livepatch/livepatch-shadow-fix1.c
<<
>>
Prefs
   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-fix1.c - Shadow variables, livepatch demo
  20 *
  21 * Purpose
  22 * -------
  23 *
  24 * Fixes the memory leak introduced in livepatch-shadow-mod through the
  25 * use of a shadow variable.  This fix demonstrates the "extending" of
  26 * short-lived data structures by patching its allocation and release
  27 * functions.
  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
  47/* Allocate new dummies every second */
  48#define ALLOC_PERIOD    1
  49/* Check for expired dummies after a few new ones have been allocated */
  50#define CLEANUP_PERIOD  (3 * ALLOC_PERIOD)
  51/* Dummies expire after a few cleanup instances */
  52#define EXPIRE_PERIOD   (4 * CLEANUP_PERIOD)
  53
  54struct dummy {
  55        struct list_head list;
  56        unsigned long jiffies_expire;
  57};
  58
  59/*
  60 * The constructor makes more sense together with klp_shadow_get_or_alloc().
  61 * In this example, it would be safe to assign the pointer also to the shadow
  62 * variable returned by klp_shadow_alloc().  But we wanted to show the more
  63 * complicated use of the API.
  64 */
  65static int shadow_leak_ctor(void *obj, void *shadow_data, void *ctor_data)
  66{
  67        void **shadow_leak = shadow_data;
  68        void *leak = ctor_data;
  69
  70        *shadow_leak = leak;
  71        return 0;
  72}
  73
  74struct dummy *livepatch_fix1_dummy_alloc(void)
  75{
  76        struct dummy *d;
  77        void *leak;
  78
  79        d = kzalloc(sizeof(*d), GFP_KERNEL);
  80        if (!d)
  81                return NULL;
  82
  83        d->jiffies_expire = jiffies +
  84                msecs_to_jiffies(1000 * EXPIRE_PERIOD);
  85
  86        /*
  87         * Patch: save the extra memory location into a SV_LEAK shadow
  88         * variable.  A patched dummy_free routine can later fetch this
  89         * pointer to handle resource release.
  90         */
  91        leak = kzalloc(sizeof(int), GFP_KERNEL);
  92        if (!leak) {
  93                kfree(d);
  94                return NULL;
  95        }
  96
  97        klp_shadow_alloc(d, SV_LEAK, sizeof(leak), GFP_KERNEL,
  98                         shadow_leak_ctor, leak);
  99
 100        pr_info("%s: dummy @ %p, expires @ %lx\n",
 101                __func__, d, d->jiffies_expire);
 102
 103        return d;
 104}
 105
 106static void livepatch_fix1_dummy_leak_dtor(void *obj, void *shadow_data)
 107{
 108        void *d = obj;
 109        void **shadow_leak = shadow_data;
 110
 111        kfree(*shadow_leak);
 112        pr_info("%s: dummy @ %p, prevented leak @ %p\n",
 113                         __func__, d, *shadow_leak);
 114}
 115
 116void livepatch_fix1_dummy_free(struct dummy *d)
 117{
 118        void **shadow_leak;
 119
 120        /*
 121         * Patch: fetch the saved SV_LEAK shadow variable, detach and
 122         * free it.  Note: handle cases where this shadow variable does
 123         * not exist (ie, dummy structures allocated before this livepatch
 124         * was loaded.)
 125         */
 126        shadow_leak = klp_shadow_get(d, SV_LEAK);
 127        if (shadow_leak)
 128                klp_shadow_free(d, SV_LEAK, livepatch_fix1_dummy_leak_dtor);
 129        else
 130                pr_info("%s: dummy @ %p leaked!\n", __func__, d);
 131
 132        kfree(d);
 133}
 134
 135static struct klp_func funcs[] = {
 136        {
 137                .old_name = "dummy_alloc",
 138                .new_func = livepatch_fix1_dummy_alloc,
 139        },
 140        {
 141                .old_name = "dummy_free",
 142                .new_func = livepatch_fix1_dummy_free,
 143        }, { }
 144};
 145
 146static struct klp_object objs[] = {
 147        {
 148                .name = "livepatch_shadow_mod",
 149                .funcs = funcs,
 150        }, { }
 151};
 152
 153static struct klp_patch patch = {
 154        .mod = THIS_MODULE,
 155        .objs = objs,
 156};
 157
 158static int livepatch_shadow_fix1_init(void)
 159{
 160        int ret;
 161
 162        ret = klp_register_patch(&patch);
 163        if (ret)
 164                return ret;
 165        ret = klp_enable_patch(&patch);
 166        if (ret) {
 167                WARN_ON(klp_unregister_patch(&patch));
 168                return ret;
 169        }
 170        return 0;
 171}
 172
 173static void livepatch_shadow_fix1_exit(void)
 174{
 175        /* Cleanup any existing SV_LEAK shadow variables */
 176        klp_shadow_free_all(SV_LEAK, livepatch_fix1_dummy_leak_dtor);
 177
 178        WARN_ON(klp_unregister_patch(&patch));
 179}
 180
 181module_init(livepatch_shadow_fix1_init);
 182module_exit(livepatch_shadow_fix1_exit);
 183MODULE_LICENSE("GPL");
 184MODULE_INFO(livepatch, "Y");
 185