-
Notifications
You must be signed in to change notification settings - Fork 53.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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]>
- Loading branch information
1 parent
d67a537
commit a2818ee
Showing
20 changed files
with
1,740 additions
and
485 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8832,6 +8832,7 @@ F: arch/x86/kernel/livepatch.c | |
F: Documentation/livepatch/ | ||
F: Documentation/ABI/testing/sysfs-kernel-livepatch | ||
F: samples/livepatch/ | ||
F: tools/testing/selftests/livepatch/ | ||
L: [email protected] | ||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jikos/livepatching.git | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
# SPDX-License-Identifier: GPL-2.0 | ||
# | ||
# Makefile for livepatch test code. | ||
|
||
obj-$(CONFIG_TEST_LIVEPATCH) += test_klp_atomic_replace.o \ | ||
test_klp_callbacks_demo.o \ | ||
test_klp_callbacks_demo2.o \ | ||
test_klp_callbacks_busy.o \ | ||
test_klp_callbacks_mod.o \ | ||
test_klp_livepatch.o \ | ||
test_klp_shadow_vars.o | ||
|
||
# Target modules to be livepatched require CC_FLAGS_FTRACE | ||
CFLAGS_test_klp_callbacks_busy.o += $(CC_FLAGS_FTRACE) | ||
CFLAGS_test_klp_callbacks_mod.o += $(CC_FLAGS_FTRACE) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
// Copyright (C) 2018 Joe Lawrence <[email protected]> | ||
|
||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
|
||
#include <linux/module.h> | ||
#include <linux/kernel.h> | ||
#include <linux/livepatch.h> | ||
|
||
static int replace; | ||
module_param(replace, int, 0644); | ||
MODULE_PARM_DESC(replace, "replace (default=0)"); | ||
|
||
#include <linux/seq_file.h> | ||
static int livepatch_meminfo_proc_show(struct seq_file *m, void *v) | ||
{ | ||
seq_printf(m, "%s: %s\n", THIS_MODULE->name, | ||
"this has been live patched"); | ||
return 0; | ||
} | ||
|
||
static struct klp_func funcs[] = { | ||
{ | ||
.old_name = "meminfo_proc_show", | ||
.new_func = livepatch_meminfo_proc_show, | ||
}, {} | ||
}; | ||
|
||
static struct klp_object objs[] = { | ||
{ | ||
/* name being NULL means vmlinux */ | ||
.funcs = funcs, | ||
}, {} | ||
}; | ||
|
||
static struct klp_patch patch = { | ||
.mod = THIS_MODULE, | ||
.objs = objs, | ||
/* set .replace in the init function below for demo purposes */ | ||
}; | ||
|
||
static int test_klp_atomic_replace_init(void) | ||
{ | ||
patch.replace = replace; | ||
return klp_enable_patch(&patch); | ||
} | ||
|
||
static void test_klp_atomic_replace_exit(void) | ||
{ | ||
} | ||
|
||
module_init(test_klp_atomic_replace_init); | ||
module_exit(test_klp_atomic_replace_exit); | ||
MODULE_LICENSE("GPL"); | ||
MODULE_INFO(livepatch, "Y"); | ||
MODULE_AUTHOR("Joe Lawrence <[email protected]>"); | ||
MODULE_DESCRIPTION("Livepatch test: atomic replace"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
// Copyright (C) 2018 Joe Lawrence <[email protected]> | ||
|
||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
|
||
#include <linux/module.h> | ||
#include <linux/kernel.h> | ||
#include <linux/workqueue.h> | ||
#include <linux/delay.h> | ||
|
||
static int sleep_secs; | ||
module_param(sleep_secs, int, 0644); | ||
MODULE_PARM_DESC(sleep_secs, "sleep_secs (default=0)"); | ||
|
||
static void busymod_work_func(struct work_struct *work); | ||
static DECLARE_DELAYED_WORK(work, busymod_work_func); | ||
|
||
static void busymod_work_func(struct work_struct *work) | ||
{ | ||
pr_info("%s, sleeping %d seconds ...\n", __func__, sleep_secs); | ||
msleep(sleep_secs * 1000); | ||
pr_info("%s exit\n", __func__); | ||
} | ||
|
||
static int test_klp_callbacks_busy_init(void) | ||
{ | ||
pr_info("%s\n", __func__); | ||
schedule_delayed_work(&work, | ||
msecs_to_jiffies(1000 * 0)); | ||
return 0; | ||
} | ||
|
||
static void test_klp_callbacks_busy_exit(void) | ||
{ | ||
cancel_delayed_work_sync(&work); | ||
pr_info("%s\n", __func__); | ||
} | ||
|
||
module_init(test_klp_callbacks_busy_init); | ||
module_exit(test_klp_callbacks_busy_exit); | ||
MODULE_LICENSE("GPL"); | ||
MODULE_AUTHOR("Joe Lawrence <[email protected]>"); | ||
MODULE_DESCRIPTION("Livepatch test: busy target module"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
// Copyright (C) 2018 Joe Lawrence <[email protected]> | ||
|
||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
|
||
#include <linux/module.h> | ||
#include <linux/kernel.h> | ||
#include <linux/livepatch.h> | ||
|
||
static int pre_patch_ret; | ||
module_param(pre_patch_ret, int, 0644); | ||
MODULE_PARM_DESC(pre_patch_ret, "pre_patch_ret (default=0)"); | ||
|
||
static const char *const module_state[] = { | ||
[MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state", | ||
[MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init", | ||
[MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away", | ||
[MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up", | ||
}; | ||
|
||
static void callback_info(const char *callback, struct klp_object *obj) | ||
{ | ||
if (obj->mod) | ||
pr_info("%s: %s -> %s\n", callback, obj->mod->name, | ||
module_state[obj->mod->state]); | ||
else | ||
pr_info("%s: vmlinux\n", callback); | ||
} | ||
|
||
/* Executed on object patching (ie, patch enablement) */ | ||
static int pre_patch_callback(struct klp_object *obj) | ||
{ | ||
callback_info(__func__, obj); | ||
return pre_patch_ret; | ||
} | ||
|
||
/* Executed on object unpatching (ie, patch disablement) */ | ||
static void post_patch_callback(struct klp_object *obj) | ||
{ | ||
callback_info(__func__, obj); | ||
} | ||
|
||
/* Executed on object unpatching (ie, patch disablement) */ | ||
static void pre_unpatch_callback(struct klp_object *obj) | ||
{ | ||
callback_info(__func__, obj); | ||
} | ||
|
||
/* Executed on object unpatching (ie, patch disablement) */ | ||
static void post_unpatch_callback(struct klp_object *obj) | ||
{ | ||
callback_info(__func__, obj); | ||
} | ||
|
||
static void patched_work_func(struct work_struct *work) | ||
{ | ||
pr_info("%s\n", __func__); | ||
} | ||
|
||
static struct klp_func no_funcs[] = { | ||
{} | ||
}; | ||
|
||
static struct klp_func busymod_funcs[] = { | ||
{ | ||
.old_name = "busymod_work_func", | ||
.new_func = patched_work_func, | ||
}, {} | ||
}; | ||
|
||
static struct klp_object objs[] = { | ||
{ | ||
.name = NULL, /* vmlinux */ | ||
.funcs = no_funcs, | ||
.callbacks = { | ||
.pre_patch = pre_patch_callback, | ||
.post_patch = post_patch_callback, | ||
.pre_unpatch = pre_unpatch_callback, | ||
.post_unpatch = post_unpatch_callback, | ||
}, | ||
}, { | ||
.name = "test_klp_callbacks_mod", | ||
.funcs = no_funcs, | ||
.callbacks = { | ||
.pre_patch = pre_patch_callback, | ||
.post_patch = post_patch_callback, | ||
.pre_unpatch = pre_unpatch_callback, | ||
.post_unpatch = post_unpatch_callback, | ||
}, | ||
}, { | ||
.name = "test_klp_callbacks_busy", | ||
.funcs = busymod_funcs, | ||
.callbacks = { | ||
.pre_patch = pre_patch_callback, | ||
.post_patch = post_patch_callback, | ||
.pre_unpatch = pre_unpatch_callback, | ||
.post_unpatch = post_unpatch_callback, | ||
}, | ||
}, { } | ||
}; | ||
|
||
static struct klp_patch patch = { | ||
.mod = THIS_MODULE, | ||
.objs = objs, | ||
}; | ||
|
||
static int test_klp_callbacks_demo_init(void) | ||
{ | ||
return klp_enable_patch(&patch); | ||
} | ||
|
||
static void test_klp_callbacks_demo_exit(void) | ||
{ | ||
} | ||
|
||
module_init(test_klp_callbacks_demo_init); | ||
module_exit(test_klp_callbacks_demo_exit); | ||
MODULE_LICENSE("GPL"); | ||
MODULE_INFO(livepatch, "Y"); | ||
MODULE_AUTHOR("Joe Lawrence <[email protected]>"); | ||
MODULE_DESCRIPTION("Livepatch test: livepatch demo"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
// Copyright (C) 2018 Joe Lawrence <[email protected]> | ||
|
||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
|
||
#include <linux/module.h> | ||
#include <linux/kernel.h> | ||
#include <linux/livepatch.h> | ||
|
||
static int replace; | ||
module_param(replace, int, 0644); | ||
MODULE_PARM_DESC(replace, "replace (default=0)"); | ||
|
||
static const char *const module_state[] = { | ||
[MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state", | ||
[MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init", | ||
[MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away", | ||
[MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up", | ||
}; | ||
|
||
static void callback_info(const char *callback, struct klp_object *obj) | ||
{ | ||
if (obj->mod) | ||
pr_info("%s: %s -> %s\n", callback, obj->mod->name, | ||
module_state[obj->mod->state]); | ||
else | ||
pr_info("%s: vmlinux\n", callback); | ||
} | ||
|
||
/* Executed on object patching (ie, patch enablement) */ | ||
static int pre_patch_callback(struct klp_object *obj) | ||
{ | ||
callback_info(__func__, obj); | ||
return 0; | ||
} | ||
|
||
/* Executed on object unpatching (ie, patch disablement) */ | ||
static void post_patch_callback(struct klp_object *obj) | ||
{ | ||
callback_info(__func__, obj); | ||
} | ||
|
||
/* Executed on object unpatching (ie, patch disablement) */ | ||
static void pre_unpatch_callback(struct klp_object *obj) | ||
{ | ||
callback_info(__func__, obj); | ||
} | ||
|
||
/* Executed on object unpatching (ie, patch disablement) */ | ||
static void post_unpatch_callback(struct klp_object *obj) | ||
{ | ||
callback_info(__func__, obj); | ||
} | ||
|
||
static struct klp_func no_funcs[] = { | ||
{ } | ||
}; | ||
|
||
static struct klp_object objs[] = { | ||
{ | ||
.name = NULL, /* vmlinux */ | ||
.funcs = no_funcs, | ||
.callbacks = { | ||
.pre_patch = pre_patch_callback, | ||
.post_patch = post_patch_callback, | ||
.pre_unpatch = pre_unpatch_callback, | ||
.post_unpatch = post_unpatch_callback, | ||
}, | ||
}, { } | ||
}; | ||
|
||
static struct klp_patch patch = { | ||
.mod = THIS_MODULE, | ||
.objs = objs, | ||
/* set .replace in the init function below for demo purposes */ | ||
}; | ||
|
||
static int test_klp_callbacks_demo2_init(void) | ||
{ | ||
patch.replace = replace; | ||
return klp_enable_patch(&patch); | ||
} | ||
|
||
static void test_klp_callbacks_demo2_exit(void) | ||
{ | ||
} | ||
|
||
module_init(test_klp_callbacks_demo2_init); | ||
module_exit(test_klp_callbacks_demo2_exit); | ||
MODULE_LICENSE("GPL"); | ||
MODULE_INFO(livepatch, "Y"); | ||
MODULE_AUTHOR("Joe Lawrence <[email protected]>"); | ||
MODULE_DESCRIPTION("Livepatch test: livepatch demo2"); |
Oops, something went wrong.