Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/samples/livepatch/livepatch-shadow-fix2.c
26285 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
* Copyright (C) 2017 Joe Lawrence <[email protected]>
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
36
struct dummy {
37
struct list_head list;
38
unsigned long jiffies_expire;
39
};
40
41
static 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
59
static 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
69
static 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
95
static 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
106
static struct klp_object objs[] = {
107
{
108
.name = "livepatch_shadow_mod",
109
.funcs = funcs,
110
}, { }
111
};
112
113
static struct klp_patch patch = {
114
.mod = THIS_MODULE,
115
.objs = objs,
116
};
117
118
static int livepatch_shadow_fix2_init(void)
119
{
120
return klp_enable_patch(&patch);
121
}
122
123
static 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
129
module_init(livepatch_shadow_fix2_init);
130
module_exit(livepatch_shadow_fix2_exit);
131
MODULE_DESCRIPTION("Live patching demo for shadow variables");
132
MODULE_LICENSE("GPL");
133
MODULE_INFO(livepatch, "Y");
134
135