Skip to content

Commit a2818ee

Browse files
joe-lawrenceJiri Kosina
authored andcommitted
selftests/livepatch: introduce tests
Add a few livepatch modules and simple target modules that the included regression suite can run tests against: - basic livepatching (multiple patches, atomic replace) - pre/post (un)patch callbacks - shadow variable API Signed-off-by: Joe Lawrence <[email protected]> Signed-off-by: Petr Mladek <[email protected]> Tested-by: Miroslav Benes <[email protected]> Tested-by: Alice Ferrazzi <[email protected]> Acked-by: Joe Lawrence <[email protected]> Acked-by: Josh Poimboeuf <[email protected]> Signed-off-by: Jiri Kosina <[email protected]>
1 parent d67a537 commit a2818ee

20 files changed

+1740
-485
lines changed

Documentation/livepatch/callbacks.txt

Lines changed: 5 additions & 484 deletions
Large diffs are not rendered by default.

MAINTAINERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8832,6 +8832,7 @@ F: arch/x86/kernel/livepatch.c
88328832
F: Documentation/livepatch/
88338833
F: Documentation/ABI/testing/sysfs-kernel-livepatch
88348834
F: samples/livepatch/
8835+
F: tools/testing/selftests/livepatch/
88358836
88368837
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jikos/livepatching.git
88378838

lib/Kconfig.debug

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1991,6 +1991,27 @@ config TEST_MEMCAT_P
19911991

19921992
If unsure, say N.
19931993

1994+
config TEST_LIVEPATCH
1995+
tristate "Test livepatching"
1996+
default n
1997+
depends on LIVEPATCH
1998+
depends on m
1999+
help
2000+
Test kernel livepatching features for correctness. The tests will
2001+
load test modules that will be livepatched in various scenarios.
2002+
2003+
To run all the livepatching tests:
2004+
2005+
make -C tools/testing/selftests TARGETS=livepatch run_tests
2006+
2007+
Alternatively, individual tests may be invoked:
2008+
2009+
tools/testing/selftests/livepatch/test-callbacks.sh
2010+
tools/testing/selftests/livepatch/test-livepatch.sh
2011+
tools/testing/selftests/livepatch/test-shadow-vars.sh
2012+
2013+
If unsure, say N.
2014+
19942015
config TEST_OBJAGG
19952016
tristate "Perform selftest on object aggreration manager"
19962017
default n
@@ -1999,7 +2020,6 @@ config TEST_OBJAGG
19992020
Enable this option to test object aggregation manager on boot
20002021
(or module load).
20012022

2002-
If unsure, say N.
20032023

20042024
endif # RUNTIME_TESTING_MENU
20052025

lib/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ obj-$(CONFIG_TEST_DEBUG_VIRTUAL) += test_debug_virtual.o
7777
obj-$(CONFIG_TEST_MEMCAT_P) += test_memcat_p.o
7878
obj-$(CONFIG_TEST_OBJAGG) += test_objagg.o
7979

80+
obj-$(CONFIG_TEST_LIVEPATCH) += livepatch/
81+
8082
ifeq ($(CONFIG_DEBUG_KOBJECT),y)
8183
CFLAGS_kobject.o += -DDEBUG
8284
CFLAGS_kobject_uevent.o += -DDEBUG

lib/livepatch/Makefile

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# SPDX-License-Identifier: GPL-2.0
2+
#
3+
# Makefile for livepatch test code.
4+
5+
obj-$(CONFIG_TEST_LIVEPATCH) += test_klp_atomic_replace.o \
6+
test_klp_callbacks_demo.o \
7+
test_klp_callbacks_demo2.o \
8+
test_klp_callbacks_busy.o \
9+
test_klp_callbacks_mod.o \
10+
test_klp_livepatch.o \
11+
test_klp_shadow_vars.o
12+
13+
# Target modules to be livepatched require CC_FLAGS_FTRACE
14+
CFLAGS_test_klp_callbacks_busy.o += $(CC_FLAGS_FTRACE)
15+
CFLAGS_test_klp_callbacks_mod.o += $(CC_FLAGS_FTRACE)
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
// Copyright (C) 2018 Joe Lawrence <[email protected]>
3+
4+
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
5+
6+
#include <linux/module.h>
7+
#include <linux/kernel.h>
8+
#include <linux/livepatch.h>
9+
10+
static int replace;
11+
module_param(replace, int, 0644);
12+
MODULE_PARM_DESC(replace, "replace (default=0)");
13+
14+
#include <linux/seq_file.h>
15+
static int livepatch_meminfo_proc_show(struct seq_file *m, void *v)
16+
{
17+
seq_printf(m, "%s: %s\n", THIS_MODULE->name,
18+
"this has been live patched");
19+
return 0;
20+
}
21+
22+
static struct klp_func funcs[] = {
23+
{
24+
.old_name = "meminfo_proc_show",
25+
.new_func = livepatch_meminfo_proc_show,
26+
}, {}
27+
};
28+
29+
static struct klp_object objs[] = {
30+
{
31+
/* name being NULL means vmlinux */
32+
.funcs = funcs,
33+
}, {}
34+
};
35+
36+
static struct klp_patch patch = {
37+
.mod = THIS_MODULE,
38+
.objs = objs,
39+
/* set .replace in the init function below for demo purposes */
40+
};
41+
42+
static int test_klp_atomic_replace_init(void)
43+
{
44+
patch.replace = replace;
45+
return klp_enable_patch(&patch);
46+
}
47+
48+
static void test_klp_atomic_replace_exit(void)
49+
{
50+
}
51+
52+
module_init(test_klp_atomic_replace_init);
53+
module_exit(test_klp_atomic_replace_exit);
54+
MODULE_LICENSE("GPL");
55+
MODULE_INFO(livepatch, "Y");
56+
MODULE_AUTHOR("Joe Lawrence <[email protected]>");
57+
MODULE_DESCRIPTION("Livepatch test: atomic replace");
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
// Copyright (C) 2018 Joe Lawrence <[email protected]>
3+
4+
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
5+
6+
#include <linux/module.h>
7+
#include <linux/kernel.h>
8+
#include <linux/workqueue.h>
9+
#include <linux/delay.h>
10+
11+
static int sleep_secs;
12+
module_param(sleep_secs, int, 0644);
13+
MODULE_PARM_DESC(sleep_secs, "sleep_secs (default=0)");
14+
15+
static void busymod_work_func(struct work_struct *work);
16+
static DECLARE_DELAYED_WORK(work, busymod_work_func);
17+
18+
static void busymod_work_func(struct work_struct *work)
19+
{
20+
pr_info("%s, sleeping %d seconds ...\n", __func__, sleep_secs);
21+
msleep(sleep_secs * 1000);
22+
pr_info("%s exit\n", __func__);
23+
}
24+
25+
static int test_klp_callbacks_busy_init(void)
26+
{
27+
pr_info("%s\n", __func__);
28+
schedule_delayed_work(&work,
29+
msecs_to_jiffies(1000 * 0));
30+
return 0;
31+
}
32+
33+
static void test_klp_callbacks_busy_exit(void)
34+
{
35+
cancel_delayed_work_sync(&work);
36+
pr_info("%s\n", __func__);
37+
}
38+
39+
module_init(test_klp_callbacks_busy_init);
40+
module_exit(test_klp_callbacks_busy_exit);
41+
MODULE_LICENSE("GPL");
42+
MODULE_AUTHOR("Joe Lawrence <[email protected]>");
43+
MODULE_DESCRIPTION("Livepatch test: busy target module");
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
// Copyright (C) 2018 Joe Lawrence <[email protected]>
3+
4+
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
5+
6+
#include <linux/module.h>
7+
#include <linux/kernel.h>
8+
#include <linux/livepatch.h>
9+
10+
static int pre_patch_ret;
11+
module_param(pre_patch_ret, int, 0644);
12+
MODULE_PARM_DESC(pre_patch_ret, "pre_patch_ret (default=0)");
13+
14+
static const char *const module_state[] = {
15+
[MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state",
16+
[MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init",
17+
[MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away",
18+
[MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up",
19+
};
20+
21+
static void callback_info(const char *callback, struct klp_object *obj)
22+
{
23+
if (obj->mod)
24+
pr_info("%s: %s -> %s\n", callback, obj->mod->name,
25+
module_state[obj->mod->state]);
26+
else
27+
pr_info("%s: vmlinux\n", callback);
28+
}
29+
30+
/* Executed on object patching (ie, patch enablement) */
31+
static int pre_patch_callback(struct klp_object *obj)
32+
{
33+
callback_info(__func__, obj);
34+
return pre_patch_ret;
35+
}
36+
37+
/* Executed on object unpatching (ie, patch disablement) */
38+
static void post_patch_callback(struct klp_object *obj)
39+
{
40+
callback_info(__func__, obj);
41+
}
42+
43+
/* Executed on object unpatching (ie, patch disablement) */
44+
static void pre_unpatch_callback(struct klp_object *obj)
45+
{
46+
callback_info(__func__, obj);
47+
}
48+
49+
/* Executed on object unpatching (ie, patch disablement) */
50+
static void post_unpatch_callback(struct klp_object *obj)
51+
{
52+
callback_info(__func__, obj);
53+
}
54+
55+
static void patched_work_func(struct work_struct *work)
56+
{
57+
pr_info("%s\n", __func__);
58+
}
59+
60+
static struct klp_func no_funcs[] = {
61+
{}
62+
};
63+
64+
static struct klp_func busymod_funcs[] = {
65+
{
66+
.old_name = "busymod_work_func",
67+
.new_func = patched_work_func,
68+
}, {}
69+
};
70+
71+
static struct klp_object objs[] = {
72+
{
73+
.name = NULL, /* vmlinux */
74+
.funcs = no_funcs,
75+
.callbacks = {
76+
.pre_patch = pre_patch_callback,
77+
.post_patch = post_patch_callback,
78+
.pre_unpatch = pre_unpatch_callback,
79+
.post_unpatch = post_unpatch_callback,
80+
},
81+
}, {
82+
.name = "test_klp_callbacks_mod",
83+
.funcs = no_funcs,
84+
.callbacks = {
85+
.pre_patch = pre_patch_callback,
86+
.post_patch = post_patch_callback,
87+
.pre_unpatch = pre_unpatch_callback,
88+
.post_unpatch = post_unpatch_callback,
89+
},
90+
}, {
91+
.name = "test_klp_callbacks_busy",
92+
.funcs = busymod_funcs,
93+
.callbacks = {
94+
.pre_patch = pre_patch_callback,
95+
.post_patch = post_patch_callback,
96+
.pre_unpatch = pre_unpatch_callback,
97+
.post_unpatch = post_unpatch_callback,
98+
},
99+
}, { }
100+
};
101+
102+
static struct klp_patch patch = {
103+
.mod = THIS_MODULE,
104+
.objs = objs,
105+
};
106+
107+
static int test_klp_callbacks_demo_init(void)
108+
{
109+
return klp_enable_patch(&patch);
110+
}
111+
112+
static void test_klp_callbacks_demo_exit(void)
113+
{
114+
}
115+
116+
module_init(test_klp_callbacks_demo_init);
117+
module_exit(test_klp_callbacks_demo_exit);
118+
MODULE_LICENSE("GPL");
119+
MODULE_INFO(livepatch, "Y");
120+
MODULE_AUTHOR("Joe Lawrence <[email protected]>");
121+
MODULE_DESCRIPTION("Livepatch test: livepatch demo");
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
// Copyright (C) 2018 Joe Lawrence <[email protected]>
3+
4+
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
5+
6+
#include <linux/module.h>
7+
#include <linux/kernel.h>
8+
#include <linux/livepatch.h>
9+
10+
static int replace;
11+
module_param(replace, int, 0644);
12+
MODULE_PARM_DESC(replace, "replace (default=0)");
13+
14+
static const char *const module_state[] = {
15+
[MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state",
16+
[MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init",
17+
[MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away",
18+
[MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up",
19+
};
20+
21+
static void callback_info(const char *callback, struct klp_object *obj)
22+
{
23+
if (obj->mod)
24+
pr_info("%s: %s -> %s\n", callback, obj->mod->name,
25+
module_state[obj->mod->state]);
26+
else
27+
pr_info("%s: vmlinux\n", callback);
28+
}
29+
30+
/* Executed on object patching (ie, patch enablement) */
31+
static int pre_patch_callback(struct klp_object *obj)
32+
{
33+
callback_info(__func__, obj);
34+
return 0;
35+
}
36+
37+
/* Executed on object unpatching (ie, patch disablement) */
38+
static void post_patch_callback(struct klp_object *obj)
39+
{
40+
callback_info(__func__, obj);
41+
}
42+
43+
/* Executed on object unpatching (ie, patch disablement) */
44+
static void pre_unpatch_callback(struct klp_object *obj)
45+
{
46+
callback_info(__func__, obj);
47+
}
48+
49+
/* Executed on object unpatching (ie, patch disablement) */
50+
static void post_unpatch_callback(struct klp_object *obj)
51+
{
52+
callback_info(__func__, obj);
53+
}
54+
55+
static struct klp_func no_funcs[] = {
56+
{ }
57+
};
58+
59+
static struct klp_object objs[] = {
60+
{
61+
.name = NULL, /* vmlinux */
62+
.funcs = no_funcs,
63+
.callbacks = {
64+
.pre_patch = pre_patch_callback,
65+
.post_patch = post_patch_callback,
66+
.pre_unpatch = pre_unpatch_callback,
67+
.post_unpatch = post_unpatch_callback,
68+
},
69+
}, { }
70+
};
71+
72+
static struct klp_patch patch = {
73+
.mod = THIS_MODULE,
74+
.objs = objs,
75+
/* set .replace in the init function below for demo purposes */
76+
};
77+
78+
static int test_klp_callbacks_demo2_init(void)
79+
{
80+
patch.replace = replace;
81+
return klp_enable_patch(&patch);
82+
}
83+
84+
static void test_klp_callbacks_demo2_exit(void)
85+
{
86+
}
87+
88+
module_init(test_klp_callbacks_demo2_init);
89+
module_exit(test_klp_callbacks_demo2_exit);
90+
MODULE_LICENSE("GPL");
91+
MODULE_INFO(livepatch, "Y");
92+
MODULE_AUTHOR("Joe Lawrence <[email protected]>");
93+
MODULE_DESCRIPTION("Livepatch test: livepatch demo2");

0 commit comments

Comments
 (0)