^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (C) 2017 Joe Lawrence <joe.lawrence@redhat.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * livepatch-shadow-mod.c - Shadow variables, buggy module demo
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * Purpose
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * -------
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * As a demonstration of livepatch shadow variable API, this module
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * introduces memory leak behavior that livepatch modules
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * livepatch-shadow-fix1.ko and livepatch-shadow-fix2.ko correct and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * enhance.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * WARNING - even though the livepatch-shadow-fix modules patch the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * memory leak, please load these modules at your own risk -- some
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * amount of memory may leaked before the bug is patched.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) * Usage
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) * -----
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) * Step 1 - Load the buggy demonstration module:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) * insmod samples/livepatch/livepatch-shadow-mod.ko
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) * Watch dmesg output for a few moments to see new dummy being allocated
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) * and a periodic cleanup check. (Note: a small amount of memory is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) * being leaked.)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) * Step 2 - Load livepatch fix1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) * insmod samples/livepatch/livepatch-shadow-fix1.ko
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) * Continue watching dmesg and note that now livepatch_fix1_dummy_free()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) * and livepatch_fix1_dummy_alloc() are logging messages about leaked
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) * memory and eventually leaks prevented.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) * Step 3 - Load livepatch fix2 (on top of fix1):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) * insmod samples/livepatch/livepatch-shadow-fix2.ko
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) * This module extends functionality through shadow variables, as a new
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) * "check" counter is added to the dummy structure. Periodic dmesg
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) * messages will log these as dummies are cleaned up.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) * Step 4 - Cleanup
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) * Unwind the demonstration by disabling the livepatch fix modules, then
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) * removing them and the demo module:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) * echo 0 > /sys/kernel/livepatch/livepatch_shadow_fix2/enabled
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) * echo 0 > /sys/kernel/livepatch/livepatch_shadow_fix1/enabled
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) * rmmod livepatch-shadow-fix2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) * rmmod livepatch-shadow-fix1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) * rmmod livepatch-shadow-mod
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) #include <linux/sched.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) #include <linux/stat.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) #include <linux/workqueue.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) MODULE_AUTHOR("Joe Lawrence <joe.lawrence@redhat.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) MODULE_DESCRIPTION("Buggy module for shadow variable demo");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) /* Allocate new dummies every second */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) #define ALLOC_PERIOD 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) /* Check for expired dummies after a few new ones have been allocated */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) #define CLEANUP_PERIOD (3 * ALLOC_PERIOD)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) /* Dummies expire after a few cleanup instances */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) #define EXPIRE_PERIOD (4 * CLEANUP_PERIOD)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) * Keep a list of all the dummies so we can clean up any residual ones
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) * on module exit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) static LIST_HEAD(dummy_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) static DEFINE_MUTEX(dummy_list_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) struct dummy {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) struct list_head list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) unsigned long jiffies_expire;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) static __used noinline struct dummy *dummy_alloc(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) struct dummy *d;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) int *leak;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) d = kzalloc(sizeof(*d), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) if (!d)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) d->jiffies_expire = jiffies +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) msecs_to_jiffies(1000 * EXPIRE_PERIOD);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) /* Oops, forgot to save leak! */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) leak = kzalloc(sizeof(*leak), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) if (!leak) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) kfree(d);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) pr_info("%s: dummy @ %p, expires @ %lx\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) __func__, d, d->jiffies_expire);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) return d;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) static __used noinline void dummy_free(struct dummy *d)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) pr_info("%s: dummy @ %p, expired = %lx\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) __func__, d, d->jiffies_expire);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) kfree(d);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) static __used noinline bool dummy_check(struct dummy *d,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) unsigned long jiffies)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) return time_after(jiffies, d->jiffies_expire);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) * alloc_work_func: allocates new dummy structures, allocates additional
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) * memory, aptly named "leak", but doesn't keep
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) * permanent record of it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) static void alloc_work_func(struct work_struct *work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) static DECLARE_DELAYED_WORK(alloc_dwork, alloc_work_func);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) static void alloc_work_func(struct work_struct *work)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) struct dummy *d;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) d = dummy_alloc();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) if (!d)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) mutex_lock(&dummy_list_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) list_add(&d->list, &dummy_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) mutex_unlock(&dummy_list_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) schedule_delayed_work(&alloc_dwork,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) msecs_to_jiffies(1000 * ALLOC_PERIOD));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) * cleanup_work_func: frees dummy structures. Without knownledge of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) * "leak", it leaks the additional memory that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) * alloc_work_func created.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) static void cleanup_work_func(struct work_struct *work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) static DECLARE_DELAYED_WORK(cleanup_dwork, cleanup_work_func);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) static void cleanup_work_func(struct work_struct *work)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) struct dummy *d, *tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) unsigned long j;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) j = jiffies;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) pr_info("%s: jiffies = %lx\n", __func__, j);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) mutex_lock(&dummy_list_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) list_for_each_entry_safe(d, tmp, &dummy_list, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) /* Kick out and free any expired dummies */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) if (dummy_check(d, j)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) list_del(&d->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) dummy_free(d);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) mutex_unlock(&dummy_list_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) schedule_delayed_work(&cleanup_dwork,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) msecs_to_jiffies(1000 * CLEANUP_PERIOD));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) static int livepatch_shadow_mod_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) schedule_delayed_work(&alloc_dwork,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) msecs_to_jiffies(1000 * ALLOC_PERIOD));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) schedule_delayed_work(&cleanup_dwork,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) msecs_to_jiffies(1000 * CLEANUP_PERIOD));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) static void livepatch_shadow_mod_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) struct dummy *d, *tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) /* Wait for any dummies at work */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) cancel_delayed_work_sync(&alloc_dwork);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) cancel_delayed_work_sync(&cleanup_dwork);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) /* Cleanup residual dummies */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) list_for_each_entry_safe(d, tmp, &dummy_list, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) list_del(&d->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) dummy_free(d);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) module_init(livepatch_shadow_mod_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) module_exit(livepatch_shadow_mod_exit);