Path: blob/master/samples/livepatch/livepatch-shadow-fix1.c
26278 views
// SPDX-License-Identifier: GPL-2.0-or-later1/*2* Copyright (C) 2017 Joe Lawrence <[email protected]>3*/45/*6* livepatch-shadow-fix1.c - Shadow variables, livepatch demo7*8* Purpose9* -------10*11* Fixes the memory leak introduced in livepatch-shadow-mod through the12* use of a shadow variable. This fix demonstrates the "extending" of13* short-lived data structures by patching its allocation and release14* functions.15*16*17* Usage18* -----19*20* This module is not intended to be standalone. See the "Usage"21* section of livepatch-shadow-mod.c.22*/2324#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt2526#include <linux/module.h>27#include <linux/kernel.h>28#include <linux/livepatch.h>29#include <linux/slab.h>3031/* Shadow variable enums */32#define SV_LEAK 13334/* Allocate new dummies every second */35#define ALLOC_PERIOD 136/* Check for expired dummies after a few new ones have been allocated */37#define CLEANUP_PERIOD (3 * ALLOC_PERIOD)38/* Dummies expire after a few cleanup instances */39#define EXPIRE_PERIOD (4 * CLEANUP_PERIOD)4041struct dummy {42struct list_head list;43unsigned long jiffies_expire;44};4546/*47* The constructor makes more sense together with klp_shadow_get_or_alloc().48* In this example, it would be safe to assign the pointer also to the shadow49* variable returned by klp_shadow_alloc(). But we wanted to show the more50* complicated use of the API.51*/52static int shadow_leak_ctor(void *obj, void *shadow_data, void *ctor_data)53{54int **shadow_leak = shadow_data;55int **leak = ctor_data;5657if (!ctor_data)58return -EINVAL;5960*shadow_leak = *leak;61return 0;62}6364static struct dummy *livepatch_fix1_dummy_alloc(void)65{66struct dummy *d;67int *leak;68int **shadow_leak;6970d = kzalloc(sizeof(*d), GFP_KERNEL);71if (!d)72return NULL;7374d->jiffies_expire = jiffies + secs_to_jiffies(EXPIRE_PERIOD);7576/*77* Patch: save the extra memory location into a SV_LEAK shadow78* variable. A patched dummy_free routine can later fetch this79* pointer to handle resource release.80*/81leak = kzalloc(sizeof(*leak), GFP_KERNEL);82if (!leak)83goto err_leak;8485shadow_leak = klp_shadow_alloc(d, SV_LEAK, sizeof(leak), GFP_KERNEL,86shadow_leak_ctor, &leak);87if (!shadow_leak) {88pr_err("%s: failed to allocate shadow variable for the leaking pointer: dummy @ %p, leak @ %p\n",89__func__, d, leak);90goto err_shadow;91}9293pr_info("%s: dummy @ %p, expires @ %lx\n",94__func__, d, d->jiffies_expire);9596return d;9798err_shadow:99kfree(leak);100err_leak:101kfree(d);102return NULL;103}104105static void livepatch_fix1_dummy_leak_dtor(void *obj, void *shadow_data)106{107void *d = obj;108int **shadow_leak = shadow_data;109110pr_info("%s: dummy @ %p, prevented leak @ %p\n",111__func__, d, *shadow_leak);112kfree(*shadow_leak);113}114115static void livepatch_fix1_dummy_free(struct dummy *d)116{117int **shadow_leak;118119/*120* Patch: fetch the saved SV_LEAK shadow variable, detach and121* free it. Note: handle cases where this shadow variable does122* not exist (ie, dummy structures allocated before this livepatch123* was loaded.)124*/125shadow_leak = klp_shadow_get(d, SV_LEAK);126if (shadow_leak)127klp_shadow_free(d, SV_LEAK, livepatch_fix1_dummy_leak_dtor);128else129pr_info("%s: dummy @ %p leaked!\n", __func__, d);130131kfree(d);132}133134static struct klp_func funcs[] = {135{136.old_name = "dummy_alloc",137.new_func = livepatch_fix1_dummy_alloc,138},139{140.old_name = "dummy_free",141.new_func = livepatch_fix1_dummy_free,142}, { }143};144145static struct klp_object objs[] = {146{147.name = "livepatch_shadow_mod",148.funcs = funcs,149}, { }150};151152static struct klp_patch patch = {153.mod = THIS_MODULE,154.objs = objs,155};156157static int livepatch_shadow_fix1_init(void)158{159return klp_enable_patch(&patch);160}161162static void livepatch_shadow_fix1_exit(void)163{164/* Cleanup any existing SV_LEAK shadow variables */165klp_shadow_free_all(SV_LEAK, livepatch_fix1_dummy_leak_dtor);166}167168module_init(livepatch_shadow_fix1_init);169module_exit(livepatch_shadow_fix1_exit);170MODULE_DESCRIPTION("Live patching demo for shadow variables");171MODULE_LICENSE("GPL");172MODULE_INFO(livepatch, "Y");173174175