Merge: livepatch: selected fixes for rhel-9.6
MR: https://gitlab.com/redhat/centos-stream/src/kernel/centos-stream-9/-/merge_requests/5428 JIRA: https://issues.redhat.com/browse/RHEL-61781 A collection of small bug fixes and testing updates to the livepatch subsystem as requested by client Conflicts: 6a71770442b5 (selftests: livepatch: Test livepatching a heavily called syscall): - Moved (test_klp-call_getpid.c, test_klp_syscall.c) to /lib/livepatch/ from /tools/testing/selftests/livepatch/ - Edited lib/livepatch/Makefile to compile the new files: (test_klp-call_getpid.c, test_klp_syscall.c 61894818e304 (selftests: livepatch: Test atomic replace against multiple modules): - Changed the module insertion from 'insmod' -> 'modprobe' to not break current testing setup Omitted: 54ee3526796f (selftests: livepatch: Avoid running the tests if kernel-devel is missing): - Would require c4bbe83d27c2 ("livepatch: Move tests from lib/livepatch to selftests/livepatch") which breaks our current testing setup Signed-off-by: Ryan Sullivan <rysulliv@redhat.com> Approved-by: Chris von Recklinghausen <crecklin@redhat.com> Approved-by: Joe Lawrence <joe.lawrence@redhat.com> Approved-by: CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> Merged-by: Rado Vrbovsky <rvrbovsk@redhat.com>
This commit is contained in:
commit
3a7781f68f
|
@ -47,6 +47,14 @@ Description:
|
|||
disabled when the feature is used. See
|
||||
Documentation/livepatch/livepatch.rst for more information.
|
||||
|
||||
What: /sys/kernel/livepatch/<patch>/replace
|
||||
Date: Jun 2024
|
||||
KernelVersion: 6.11.0
|
||||
Contact: live-patching@vger.kernel.org
|
||||
Description:
|
||||
An attribute which indicates whether the patch supports
|
||||
atomic-replace.
|
||||
|
||||
What: /sys/kernel/livepatch/<patch>/<object>
|
||||
Date: Nov 2014
|
||||
KernelVersion: 3.19.0
|
||||
|
|
|
@ -229,6 +229,10 @@ Contributing new tests (details)
|
|||
TEST_PROGS, TEST_GEN_PROGS mean it is the executable tested by
|
||||
default.
|
||||
|
||||
TEST_GEN_MODS_DIR should be used by tests that require modules to be built
|
||||
before the test starts. The variable will contain the name of the directory
|
||||
containing the modules.
|
||||
|
||||
TEST_CUSTOM_PROGS should be used by tests that require custom build
|
||||
rules and prevent common build rule use.
|
||||
|
||||
|
|
|
@ -20,9 +20,9 @@
|
|||
#include <asm/livepatch.h>
|
||||
|
||||
/* task patch states */
|
||||
#define KLP_UNDEFINED -1
|
||||
#define KLP_UNPATCHED 0
|
||||
#define KLP_PATCHED 1
|
||||
#define KLP_TRANSITION_IDLE -1
|
||||
#define KLP_TRANSITION_UNPATCHED 0
|
||||
#define KLP_TRANSITION_PATCHED 1
|
||||
|
||||
/**
|
||||
* struct klp_func - function structure for live patching
|
||||
|
|
|
@ -203,7 +203,7 @@ struct task_struct init_task
|
|||
.trace_recursion = 0,
|
||||
#endif
|
||||
#ifdef CONFIG_LIVEPATCH
|
||||
.patch_state = KLP_UNDEFINED,
|
||||
.patch_state = KLP_TRANSITION_IDLE,
|
||||
#endif
|
||||
#ifdef CONFIG_SECURITY
|
||||
.security = NULL,
|
||||
|
|
|
@ -339,6 +339,7 @@ int klp_apply_section_relocs(struct module *pmod, Elf_Shdr *sechdrs,
|
|||
* /sys/kernel/livepatch/<patch>/enabled
|
||||
* /sys/kernel/livepatch/<patch>/transition
|
||||
* /sys/kernel/livepatch/<patch>/force
|
||||
* /sys/kernel/livepatch/<patch>/replace
|
||||
* /sys/kernel/livepatch/<patch>/<object>
|
||||
* /sys/kernel/livepatch/<patch>/<object>/patched
|
||||
* /sys/kernel/livepatch/<patch>/<object>/<function,sympos>
|
||||
|
@ -394,7 +395,7 @@ static ssize_t enabled_show(struct kobject *kobj,
|
|||
struct klp_patch *patch;
|
||||
|
||||
patch = container_of(kobj, struct klp_patch, kobj);
|
||||
return snprintf(buf, PAGE_SIZE-1, "%d\n", patch->enabled);
|
||||
return sysfs_emit(buf, "%d\n", patch->enabled);
|
||||
}
|
||||
|
||||
static ssize_t transition_show(struct kobject *kobj,
|
||||
|
@ -403,8 +404,7 @@ static ssize_t transition_show(struct kobject *kobj,
|
|||
struct klp_patch *patch;
|
||||
|
||||
patch = container_of(kobj, struct klp_patch, kobj);
|
||||
return snprintf(buf, PAGE_SIZE-1, "%d\n",
|
||||
patch == klp_transition_patch);
|
||||
return sysfs_emit(buf, "%d\n", patch == klp_transition_patch);
|
||||
}
|
||||
|
||||
static ssize_t force_store(struct kobject *kobj, struct kobj_attribute *attr,
|
||||
|
@ -436,13 +436,24 @@ static ssize_t force_store(struct kobject *kobj, struct kobj_attribute *attr,
|
|||
return count;
|
||||
}
|
||||
|
||||
static ssize_t replace_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, char *buf)
|
||||
{
|
||||
struct klp_patch *patch;
|
||||
|
||||
patch = container_of(kobj, struct klp_patch, kobj);
|
||||
return sysfs_emit(buf, "%d\n", patch->replace);
|
||||
}
|
||||
|
||||
static struct kobj_attribute enabled_kobj_attr = __ATTR_RW(enabled);
|
||||
static struct kobj_attribute transition_kobj_attr = __ATTR_RO(transition);
|
||||
static struct kobj_attribute force_kobj_attr = __ATTR_WO(force);
|
||||
static struct kobj_attribute replace_kobj_attr = __ATTR_RO(replace);
|
||||
static struct attribute *klp_patch_attrs[] = {
|
||||
&enabled_kobj_attr.attr,
|
||||
&transition_kobj_attr.attr,
|
||||
&force_kobj_attr.attr,
|
||||
&replace_kobj_attr.attr,
|
||||
NULL
|
||||
};
|
||||
ATTRIBUTE_GROUPS(klp_patch);
|
||||
|
@ -966,7 +977,7 @@ static int __klp_disable_patch(struct klp_patch *patch)
|
|||
if (klp_transition_patch)
|
||||
return -EBUSY;
|
||||
|
||||
klp_init_transition(patch, KLP_UNPATCHED);
|
||||
klp_init_transition(patch, KLP_TRANSITION_UNPATCHED);
|
||||
|
||||
klp_for_each_object(patch, obj)
|
||||
if (obj->patched)
|
||||
|
@ -1001,7 +1012,7 @@ static int __klp_enable_patch(struct klp_patch *patch)
|
|||
|
||||
pr_notice("enabling patch '%s'\n", patch->mod->name);
|
||||
|
||||
klp_init_transition(patch, KLP_PATCHED);
|
||||
klp_init_transition(patch, KLP_TRANSITION_PATCHED);
|
||||
|
||||
/*
|
||||
* Enforce the order of the func->transition writes in
|
||||
|
|
|
@ -95,9 +95,9 @@ static void notrace klp_ftrace_handler(unsigned long ip,
|
|||
|
||||
patch_state = current->patch_state;
|
||||
|
||||
WARN_ON_ONCE(patch_state == KLP_UNDEFINED);
|
||||
WARN_ON_ONCE(patch_state == KLP_TRANSITION_IDLE);
|
||||
|
||||
if (patch_state == KLP_UNPATCHED) {
|
||||
if (patch_state == KLP_TRANSITION_UNPATCHED) {
|
||||
/*
|
||||
* Use the previously patched version of the function.
|
||||
* If no previous patches exist, continue with the
|
||||
|
|
|
@ -24,7 +24,7 @@ static DEFINE_PER_CPU(unsigned long[MAX_STACK_ENTRIES], klp_stack_entries);
|
|||
|
||||
struct klp_patch *klp_transition_patch;
|
||||
|
||||
static int klp_target_state = KLP_UNDEFINED;
|
||||
static int klp_target_state = KLP_TRANSITION_IDLE;
|
||||
|
||||
static unsigned int klp_signals_cnt;
|
||||
|
||||
|
@ -97,16 +97,16 @@ static void klp_complete_transition(void)
|
|||
|
||||
pr_debug("'%s': completing %s transition\n",
|
||||
klp_transition_patch->mod->name,
|
||||
klp_target_state == KLP_PATCHED ? "patching" : "unpatching");
|
||||
klp_target_state == KLP_TRANSITION_PATCHED ? "patching" : "unpatching");
|
||||
|
||||
if (klp_transition_patch->replace && klp_target_state == KLP_PATCHED) {
|
||||
if (klp_transition_patch->replace && klp_target_state == KLP_TRANSITION_PATCHED) {
|
||||
klp_unpatch_replaced_patches(klp_transition_patch);
|
||||
klp_discard_nops(klp_transition_patch);
|
||||
}
|
||||
|
||||
if (klp_target_state == KLP_UNPATCHED) {
|
||||
if (klp_target_state == KLP_TRANSITION_UNPATCHED) {
|
||||
/*
|
||||
* All tasks have transitioned to KLP_UNPATCHED so we can now
|
||||
* All tasks have transitioned to KLP_TRANSITION_UNPATCHED so we can now
|
||||
* remove the new functions from the func_stack.
|
||||
*/
|
||||
klp_unpatch_objects(klp_transition_patch);
|
||||
|
@ -124,36 +124,36 @@ static void klp_complete_transition(void)
|
|||
klp_for_each_func(obj, func)
|
||||
func->transition = false;
|
||||
|
||||
/* Prevent klp_ftrace_handler() from seeing KLP_UNDEFINED state */
|
||||
if (klp_target_state == KLP_PATCHED)
|
||||
/* Prevent klp_ftrace_handler() from seeing KLP_TRANSITION_IDLE state */
|
||||
if (klp_target_state == KLP_TRANSITION_PATCHED)
|
||||
klp_synchronize_transition();
|
||||
|
||||
read_lock(&tasklist_lock);
|
||||
for_each_process_thread(g, task) {
|
||||
WARN_ON_ONCE(test_tsk_thread_flag(task, TIF_PATCH_PENDING));
|
||||
task->patch_state = KLP_UNDEFINED;
|
||||
task->patch_state = KLP_TRANSITION_IDLE;
|
||||
}
|
||||
read_unlock(&tasklist_lock);
|
||||
|
||||
for_each_possible_cpu(cpu) {
|
||||
task = idle_task(cpu);
|
||||
WARN_ON_ONCE(test_tsk_thread_flag(task, TIF_PATCH_PENDING));
|
||||
task->patch_state = KLP_UNDEFINED;
|
||||
task->patch_state = KLP_TRANSITION_IDLE;
|
||||
}
|
||||
|
||||
klp_for_each_object(klp_transition_patch, obj) {
|
||||
if (!klp_is_object_loaded(obj))
|
||||
continue;
|
||||
if (klp_target_state == KLP_PATCHED)
|
||||
if (klp_target_state == KLP_TRANSITION_PATCHED)
|
||||
klp_post_patch_callback(obj);
|
||||
else if (klp_target_state == KLP_UNPATCHED)
|
||||
else if (klp_target_state == KLP_TRANSITION_UNPATCHED)
|
||||
klp_post_unpatch_callback(obj);
|
||||
}
|
||||
|
||||
pr_notice("'%s': %s complete\n", klp_transition_patch->mod->name,
|
||||
klp_target_state == KLP_PATCHED ? "patching" : "unpatching");
|
||||
klp_target_state == KLP_TRANSITION_PATCHED ? "patching" : "unpatching");
|
||||
|
||||
klp_target_state = KLP_UNDEFINED;
|
||||
klp_target_state = KLP_TRANSITION_IDLE;
|
||||
klp_transition_patch = NULL;
|
||||
}
|
||||
|
||||
|
@ -165,13 +165,13 @@ static void klp_complete_transition(void)
|
|||
*/
|
||||
void klp_cancel_transition(void)
|
||||
{
|
||||
if (WARN_ON_ONCE(klp_target_state != KLP_PATCHED))
|
||||
if (WARN_ON_ONCE(klp_target_state != KLP_TRANSITION_PATCHED))
|
||||
return;
|
||||
|
||||
pr_debug("'%s': canceling patching transition, going to unpatch\n",
|
||||
klp_transition_patch->mod->name);
|
||||
|
||||
klp_target_state = KLP_UNPATCHED;
|
||||
klp_target_state = KLP_TRANSITION_UNPATCHED;
|
||||
klp_complete_transition();
|
||||
}
|
||||
|
||||
|
@ -219,7 +219,7 @@ static int klp_check_stack_func(struct klp_func *func, unsigned long *entries,
|
|||
struct klp_ops *ops;
|
||||
int i;
|
||||
|
||||
if (klp_target_state == KLP_UNPATCHED) {
|
||||
if (klp_target_state == KLP_TRANSITION_UNPATCHED) {
|
||||
/*
|
||||
* Check for the to-be-unpatched function
|
||||
* (the func itself).
|
||||
|
@ -456,7 +456,7 @@ void klp_try_complete_transition(void)
|
|||
struct klp_patch *patch;
|
||||
bool complete = true;
|
||||
|
||||
WARN_ON_ONCE(klp_target_state == KLP_UNDEFINED);
|
||||
WARN_ON_ONCE(klp_target_state == KLP_TRANSITION_IDLE);
|
||||
|
||||
/*
|
||||
* Try to switch the tasks to the target patch state by walking their
|
||||
|
@ -533,11 +533,11 @@ void klp_start_transition(void)
|
|||
struct task_struct *g, *task;
|
||||
unsigned int cpu;
|
||||
|
||||
WARN_ON_ONCE(klp_target_state == KLP_UNDEFINED);
|
||||
WARN_ON_ONCE(klp_target_state == KLP_TRANSITION_IDLE);
|
||||
|
||||
pr_notice("'%s': starting %s transition\n",
|
||||
klp_transition_patch->mod->name,
|
||||
klp_target_state == KLP_PATCHED ? "patching" : "unpatching");
|
||||
klp_target_state == KLP_TRANSITION_PATCHED ? "patching" : "unpatching");
|
||||
|
||||
/*
|
||||
* Mark all normal tasks as needing a patch state update. They'll
|
||||
|
@ -579,7 +579,7 @@ void klp_init_transition(struct klp_patch *patch, int state)
|
|||
struct klp_func *func;
|
||||
int initial_state = !state;
|
||||
|
||||
WARN_ON_ONCE(klp_target_state != KLP_UNDEFINED);
|
||||
WARN_ON_ONCE(klp_target_state != KLP_TRANSITION_IDLE);
|
||||
|
||||
klp_transition_patch = patch;
|
||||
|
||||
|
@ -590,7 +590,7 @@ void klp_init_transition(struct klp_patch *patch, int state)
|
|||
klp_target_state = state;
|
||||
|
||||
pr_debug("'%s': initializing %s transition\n", patch->mod->name,
|
||||
klp_target_state == KLP_PATCHED ? "patching" : "unpatching");
|
||||
klp_target_state == KLP_TRANSITION_PATCHED ? "patching" : "unpatching");
|
||||
|
||||
/*
|
||||
* Initialize all tasks to the initial patch state to prepare them for
|
||||
|
@ -598,7 +598,7 @@ void klp_init_transition(struct klp_patch *patch, int state)
|
|||
*/
|
||||
read_lock(&tasklist_lock);
|
||||
for_each_process_thread(g, task) {
|
||||
WARN_ON_ONCE(task->patch_state != KLP_UNDEFINED);
|
||||
WARN_ON_ONCE(task->patch_state != KLP_TRANSITION_IDLE);
|
||||
task->patch_state = initial_state;
|
||||
}
|
||||
read_unlock(&tasklist_lock);
|
||||
|
@ -608,19 +608,19 @@ void klp_init_transition(struct klp_patch *patch, int state)
|
|||
*/
|
||||
for_each_possible_cpu(cpu) {
|
||||
task = idle_task(cpu);
|
||||
WARN_ON_ONCE(task->patch_state != KLP_UNDEFINED);
|
||||
WARN_ON_ONCE(task->patch_state != KLP_TRANSITION_IDLE);
|
||||
task->patch_state = initial_state;
|
||||
}
|
||||
|
||||
/*
|
||||
* Enforce the order of the task->patch_state initializations and the
|
||||
* func->transition updates to ensure that klp_ftrace_handler() doesn't
|
||||
* see a func in transition with a task->patch_state of KLP_UNDEFINED.
|
||||
* see a func in transition with a task->patch_state of KLP_TRANSITION_IDLE.
|
||||
*
|
||||
* Also enforce the order of the klp_target_state write and future
|
||||
* TIF_PATCH_PENDING writes to ensure klp_update_patch_state() and
|
||||
* __klp_sched_try_switch() don't set a task->patch_state to
|
||||
* KLP_UNDEFINED.
|
||||
* KLP_TRANSITION_IDLE.
|
||||
*/
|
||||
smp_wmb();
|
||||
|
||||
|
@ -653,7 +653,7 @@ void klp_reverse_transition(void)
|
|||
|
||||
pr_debug("'%s': reversing transition from %s\n",
|
||||
klp_transition_patch->mod->name,
|
||||
klp_target_state == KLP_PATCHED ? "patching to unpatching" :
|
||||
klp_target_state == KLP_TRANSITION_PATCHED ? "patching to unpatching" :
|
||||
"unpatching to patching");
|
||||
|
||||
/*
|
||||
|
@ -742,7 +742,7 @@ void klp_force_transition(void)
|
|||
klp_update_patch_state(idle_task(cpu));
|
||||
|
||||
/* Set forced flag for patches being removed. */
|
||||
if (klp_target_state == KLP_UNPATCHED)
|
||||
if (klp_target_state == KLP_TRANSITION_UNPATCHED)
|
||||
klp_transition_patch->forced = true;
|
||||
else if (klp_transition_patch->replace) {
|
||||
klp_for_each_patch(patch) {
|
||||
|
|
|
@ -8,7 +8,8 @@ obj-$(CONFIG_TEST_LIVEPATCH) += test_klp_atomic_replace.o \
|
|||
test_klp_callbacks_busy.o \
|
||||
test_klp_callbacks_mod.o \
|
||||
test_klp_livepatch.o \
|
||||
test_klp_shadow_vars.o \
|
||||
test_klp_state.o \
|
||||
test_klp_state2.o \
|
||||
test_klp_state3.o
|
||||
test_klp_state3.o \
|
||||
test_klp_shadow_vars.o \
|
||||
test_klp_syscall.o
|
||||
|
|
|
@ -0,0 +1,116 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2017-2023 SUSE
|
||||
* Authors: Libor Pechacek <lpechacek@suse.cz>
|
||||
* Nicolai Stange <nstange@suse.de>
|
||||
* Marcos Paulo de Souza <mpdesouza@suse.com>
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/livepatch.h>
|
||||
|
||||
#if defined(__x86_64__)
|
||||
#define FN_PREFIX __x64_
|
||||
#elif defined(__s390x__)
|
||||
#define FN_PREFIX __s390x_
|
||||
#elif defined(__aarch64__)
|
||||
#define FN_PREFIX __arm64_
|
||||
#else
|
||||
/* powerpc does not select ARCH_HAS_SYSCALL_WRAPPER */
|
||||
#define FN_PREFIX
|
||||
#endif
|
||||
|
||||
/* Protects klp_pids */
|
||||
static DEFINE_MUTEX(kpid_mutex);
|
||||
|
||||
static unsigned int npids, npids_pending;
|
||||
static int klp_pids[NR_CPUS];
|
||||
module_param_array(klp_pids, int, &npids_pending, 0);
|
||||
MODULE_PARM_DESC(klp_pids, "Array of pids to be transitioned to livepatched state.");
|
||||
|
||||
static ssize_t npids_show(struct kobject *kobj, struct kobj_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
return sprintf(buf, "%u\n", npids_pending);
|
||||
}
|
||||
|
||||
static struct kobj_attribute klp_attr = __ATTR_RO(npids);
|
||||
static struct kobject *klp_kobj;
|
||||
|
||||
static asmlinkage long lp_sys_getpid(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
mutex_lock(&kpid_mutex);
|
||||
if (npids_pending > 0) {
|
||||
for (i = 0; i < npids; i++) {
|
||||
if (current->pid == klp_pids[i]) {
|
||||
klp_pids[i] = 0;
|
||||
npids_pending--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
mutex_unlock(&kpid_mutex);
|
||||
|
||||
return task_tgid_vnr(current);
|
||||
}
|
||||
|
||||
static struct klp_func vmlinux_funcs[] = {
|
||||
{
|
||||
.old_name = __stringify(FN_PREFIX) "sys_getpid",
|
||||
.new_func = lp_sys_getpid,
|
||||
}, {}
|
||||
};
|
||||
|
||||
static struct klp_object objs[] = {
|
||||
{
|
||||
/* name being NULL means vmlinux */
|
||||
.funcs = vmlinux_funcs,
|
||||
}, {}
|
||||
};
|
||||
|
||||
static struct klp_patch patch = {
|
||||
.mod = THIS_MODULE,
|
||||
.objs = objs,
|
||||
};
|
||||
|
||||
static int livepatch_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
klp_kobj = kobject_create_and_add("test_klp_syscall", kernel_kobj);
|
||||
if (!klp_kobj)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = sysfs_create_file(klp_kobj, &klp_attr.attr);
|
||||
if (ret) {
|
||||
kobject_put(klp_kobj);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Save the number pids to transition to livepatched state before the
|
||||
* number of pending pids is decremented.
|
||||
*/
|
||||
npids = npids_pending;
|
||||
|
||||
return klp_enable_patch(&patch);
|
||||
}
|
||||
|
||||
static void livepatch_exit(void)
|
||||
{
|
||||
kobject_put(klp_kobj);
|
||||
}
|
||||
|
||||
module_init(livepatch_init);
|
||||
module_exit(livepatch_exit);
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_INFO(livepatch, "Y");
|
||||
MODULE_AUTHOR("Libor Pechacek <lpechacek@suse.cz>");
|
||||
MODULE_AUTHOR("Nicolai Stange <nstange@suse.de>");
|
||||
MODULE_AUTHOR("Marcos Paulo de Souza <mpdesouza@suse.com>");
|
||||
MODULE_DESCRIPTION("Livepatch test: syscall transition");
|
|
@ -34,7 +34,8 @@ TEST_GEN_PROGS := $(patsubst %,$(OUTPUT)/%,$(TEST_GEN_PROGS))
|
|||
TEST_GEN_PROGS_EXTENDED := $(patsubst %,$(OUTPUT)/%,$(TEST_GEN_PROGS_EXTENDED))
|
||||
TEST_GEN_FILES := $(patsubst %,$(OUTPUT)/%,$(TEST_GEN_FILES))
|
||||
|
||||
all: $(TEST_GEN_PROGS) $(TEST_GEN_PROGS_EXTENDED) $(TEST_GEN_FILES)
|
||||
all: $(TEST_GEN_PROGS) $(TEST_GEN_PROGS_EXTENDED) $(TEST_GEN_FILES) \
|
||||
$(if $(TEST_GEN_MODS_DIR),gen_mods_dir)
|
||||
|
||||
define RUN_TESTS
|
||||
BASE_DIR="$(selfdir)"; \
|
||||
|
@ -64,8 +65,8 @@ endef
|
|||
|
||||
run_tests: all
|
||||
ifdef building_out_of_srctree
|
||||
@if [ "X$(TEST_PROGS)$(TEST_PROGS_EXTENDED)$(TEST_FILES)" != "X" ]; then \
|
||||
rsync -aLq $(TEST_PROGS) $(TEST_PROGS_EXTENDED) $(TEST_FILES) $(OUTPUT); \
|
||||
@if [ "X$(TEST_PROGS)$(TEST_PROGS_EXTENDED)$(TEST_FILES)$(TEST_GEN_MODS_DIR)" != "X" ]; then \
|
||||
rsync -aLq $(TEST_PROGS) $(TEST_PROGS_EXTENDED) $(TEST_FILES) $(TEST_GEN_MODS_DIR) $(OUTPUT); \
|
||||
fi
|
||||
@$(INSTALL_INCLUDES)
|
||||
@if [ "X$(TEST_PROGS)" != "X" ]; then \
|
||||
|
@ -78,11 +79,22 @@ else
|
|||
@$(call RUN_TESTS, $(TEST_GEN_PROGS) $(TEST_CUSTOM_PROGS) $(TEST_PROGS))
|
||||
endif
|
||||
|
||||
gen_mods_dir:
|
||||
$(Q)$(MAKE) -C $(TEST_GEN_MODS_DIR)
|
||||
|
||||
clean_mods_dir:
|
||||
$(Q)$(MAKE) -C $(TEST_GEN_MODS_DIR) clean
|
||||
|
||||
define INSTALL_SINGLE_RULE
|
||||
$(if $(INSTALL_LIST),@mkdir -p $(INSTALL_PATH))
|
||||
$(if $(INSTALL_LIST),rsync -aL $(INSTALL_LIST) $(INSTALL_PATH)/)
|
||||
endef
|
||||
|
||||
define INSTALL_MODS_RULE
|
||||
$(if $(INSTALL_LIST),@mkdir -p $(INSTALL_PATH)/$(INSTALL_LIST))
|
||||
$(if $(INSTALL_LIST),rsync -a --copy-unsafe-links $(INSTALL_LIST)/*.ko $(INSTALL_PATH)/$(INSTALL_LIST))
|
||||
endef
|
||||
|
||||
define INSTALL_RULE
|
||||
$(eval INSTALL_LIST = $(TEST_PROGS)) $(INSTALL_SINGLE_RULE)
|
||||
$(eval INSTALL_LIST = $(TEST_PROGS_EXTENDED)) $(INSTALL_SINGLE_RULE)
|
||||
|
@ -91,6 +103,7 @@ define INSTALL_RULE
|
|||
$(eval INSTALL_LIST = $(TEST_CUSTOM_PROGS)) $(INSTALL_SINGLE_RULE)
|
||||
$(eval INSTALL_LIST = $(TEST_GEN_PROGS_EXTENDED)) $(INSTALL_SINGLE_RULE)
|
||||
$(eval INSTALL_LIST = $(TEST_GEN_FILES)) $(INSTALL_SINGLE_RULE)
|
||||
$(eval INSTALL_LIST = $(notdir $(TEST_GEN_MODS_DIR))) $(INSTALL_MODS_RULE)
|
||||
$(eval INSTALL_LIST = $(wildcard config settings)) $(INSTALL_SINGLE_RULE)
|
||||
endef
|
||||
|
||||
|
@ -117,7 +130,7 @@ define CLEAN
|
|||
$(RM) -r $(TEST_GEN_PROGS) $(TEST_GEN_PROGS_EXTENDED) $(TEST_GEN_FILES) $(EXTRA_CLEAN)
|
||||
endef
|
||||
|
||||
clean:
|
||||
clean: $(if $(TEST_GEN_MODS_DIR),clean_mods_dir)
|
||||
$(CLEAN)
|
||||
|
||||
# When make O= with kselftest target from main level
|
||||
|
@ -143,4 +156,4 @@ $(OUTPUT)/%:%.S
|
|||
$(LINK.S) $^ $(LDLIBS) -o $@
|
||||
endif
|
||||
|
||||
.PHONY: run_tests all clean install emit_tests
|
||||
.PHONY: run_tests all clean install emit_tests gen_mods_dir clean_mods_dir
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
test_klp-call_getpid
|
|
@ -1,5 +1,6 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
TEST_GEN_FILES := test_klp-call_getpid
|
||||
TEST_PROGS_EXTENDED := functions.sh
|
||||
TEST_PROGS := \
|
||||
test-livepatch.sh \
|
||||
|
@ -7,7 +8,8 @@ TEST_PROGS := \
|
|||
test-shadow-vars.sh \
|
||||
test-state.sh \
|
||||
test-ftrace.sh \
|
||||
test-sysfs.sh
|
||||
test-sysfs.sh \
|
||||
test-syscall.sh
|
||||
|
||||
TEST_FILES := settings
|
||||
|
||||
|
|
|
@ -4,7 +4,9 @@
|
|||
|
||||
. $(dirname $0)/functions.sh
|
||||
|
||||
MOD_LIVEPATCH=test_klp_livepatch
|
||||
MOD_LIVEPATCH1=test_klp_livepatch
|
||||
MOD_LIVEPATCH2=test_klp_syscall
|
||||
MOD_LIVEPATCH3=test_klp_callbacks_demo
|
||||
MOD_REPLACE=test_klp_atomic_replace
|
||||
|
||||
setup_config
|
||||
|
@ -16,33 +18,33 @@ setup_config
|
|||
|
||||
start_test "basic function patching"
|
||||
|
||||
load_lp $MOD_LIVEPATCH
|
||||
load_lp $MOD_LIVEPATCH1
|
||||
|
||||
if [[ "$(cat /proc/cmdline)" != "$MOD_LIVEPATCH: this has been live patched" ]] ; then
|
||||
if [[ "$(cat /proc/cmdline)" != "$MOD_LIVEPATCH1: this has been live patched" ]] ; then
|
||||
echo -e "FAIL\n\n"
|
||||
die "livepatch kselftest(s) failed"
|
||||
fi
|
||||
|
||||
disable_lp $MOD_LIVEPATCH
|
||||
unload_lp $MOD_LIVEPATCH
|
||||
disable_lp $MOD_LIVEPATCH1
|
||||
unload_lp $MOD_LIVEPATCH1
|
||||
|
||||
if [[ "$(cat /proc/cmdline)" == "$MOD_LIVEPATCH: this has been live patched" ]] ; then
|
||||
if [[ "$(cat /proc/cmdline)" == "$MOD_LIVEPATCH1: this has been live patched" ]] ; then
|
||||
echo -e "FAIL\n\n"
|
||||
die "livepatch kselftest(s) failed"
|
||||
fi
|
||||
|
||||
check_result "% modprobe $MOD_LIVEPATCH
|
||||
livepatch: enabling patch '$MOD_LIVEPATCH'
|
||||
livepatch: '$MOD_LIVEPATCH': initializing patching transition
|
||||
livepatch: '$MOD_LIVEPATCH': starting patching transition
|
||||
livepatch: '$MOD_LIVEPATCH': completing patching transition
|
||||
livepatch: '$MOD_LIVEPATCH': patching complete
|
||||
% echo 0 > /sys/kernel/livepatch/$MOD_LIVEPATCH/enabled
|
||||
livepatch: '$MOD_LIVEPATCH': initializing unpatching transition
|
||||
livepatch: '$MOD_LIVEPATCH': starting unpatching transition
|
||||
livepatch: '$MOD_LIVEPATCH': completing unpatching transition
|
||||
livepatch: '$MOD_LIVEPATCH': unpatching complete
|
||||
% rmmod $MOD_LIVEPATCH"
|
||||
check_result "% modprobe $MOD_LIVEPATCH1
|
||||
livepatch: enabling patch '$MOD_LIVEPATCH1'
|
||||
livepatch: '$MOD_LIVEPATCH1': initializing patching transition
|
||||
livepatch: '$MOD_LIVEPATCH1': starting patching transition
|
||||
livepatch: '$MOD_LIVEPATCH1': completing patching transition
|
||||
livepatch: '$MOD_LIVEPATCH1': patching complete
|
||||
% echo 0 > /sys/kernel/livepatch/$MOD_LIVEPATCH1/enabled
|
||||
livepatch: '$MOD_LIVEPATCH1': initializing unpatching transition
|
||||
livepatch: '$MOD_LIVEPATCH1': starting unpatching transition
|
||||
livepatch: '$MOD_LIVEPATCH1': completing unpatching transition
|
||||
livepatch: '$MOD_LIVEPATCH1': unpatching complete
|
||||
% rmmod $MOD_LIVEPATCH1"
|
||||
|
||||
|
||||
# - load a livepatch that modifies the output from /proc/cmdline and
|
||||
|
@ -53,7 +55,7 @@ livepatch: '$MOD_LIVEPATCH': unpatching complete
|
|||
|
||||
start_test "multiple livepatches"
|
||||
|
||||
load_lp $MOD_LIVEPATCH
|
||||
load_lp $MOD_LIVEPATCH1
|
||||
|
||||
grep 'live patched' /proc/cmdline > /dev/kmsg
|
||||
grep 'live patched' /proc/meminfo > /dev/kmsg
|
||||
|
@ -69,26 +71,26 @@ unload_lp $MOD_REPLACE
|
|||
grep 'live patched' /proc/cmdline > /dev/kmsg
|
||||
grep 'live patched' /proc/meminfo > /dev/kmsg
|
||||
|
||||
disable_lp $MOD_LIVEPATCH
|
||||
unload_lp $MOD_LIVEPATCH
|
||||
disable_lp $MOD_LIVEPATCH1
|
||||
unload_lp $MOD_LIVEPATCH1
|
||||
|
||||
grep 'live patched' /proc/cmdline > /dev/kmsg
|
||||
grep 'live patched' /proc/meminfo > /dev/kmsg
|
||||
|
||||
check_result "% modprobe $MOD_LIVEPATCH
|
||||
livepatch: enabling patch '$MOD_LIVEPATCH'
|
||||
livepatch: '$MOD_LIVEPATCH': initializing patching transition
|
||||
livepatch: '$MOD_LIVEPATCH': starting patching transition
|
||||
livepatch: '$MOD_LIVEPATCH': completing patching transition
|
||||
livepatch: '$MOD_LIVEPATCH': patching complete
|
||||
$MOD_LIVEPATCH: this has been live patched
|
||||
check_result "% modprobe $MOD_LIVEPATCH1
|
||||
livepatch: enabling patch '$MOD_LIVEPATCH1'
|
||||
livepatch: '$MOD_LIVEPATCH1': initializing patching transition
|
||||
livepatch: '$MOD_LIVEPATCH1': starting patching transition
|
||||
livepatch: '$MOD_LIVEPATCH1': completing patching transition
|
||||
livepatch: '$MOD_LIVEPATCH1': patching complete
|
||||
$MOD_LIVEPATCH1: this has been live patched
|
||||
% modprobe $MOD_REPLACE replace=0
|
||||
livepatch: enabling patch '$MOD_REPLACE'
|
||||
livepatch: '$MOD_REPLACE': initializing patching transition
|
||||
livepatch: '$MOD_REPLACE': starting patching transition
|
||||
livepatch: '$MOD_REPLACE': completing patching transition
|
||||
livepatch: '$MOD_REPLACE': patching complete
|
||||
$MOD_LIVEPATCH: this has been live patched
|
||||
$MOD_LIVEPATCH1: this has been live patched
|
||||
$MOD_REPLACE: this has been live patched
|
||||
% echo 0 > /sys/kernel/livepatch/$MOD_REPLACE/enabled
|
||||
livepatch: '$MOD_REPLACE': initializing unpatching transition
|
||||
|
@ -96,35 +98,54 @@ livepatch: '$MOD_REPLACE': starting unpatching transition
|
|||
livepatch: '$MOD_REPLACE': completing unpatching transition
|
||||
livepatch: '$MOD_REPLACE': unpatching complete
|
||||
% rmmod $MOD_REPLACE
|
||||
$MOD_LIVEPATCH: this has been live patched
|
||||
% echo 0 > /sys/kernel/livepatch/$MOD_LIVEPATCH/enabled
|
||||
livepatch: '$MOD_LIVEPATCH': initializing unpatching transition
|
||||
livepatch: '$MOD_LIVEPATCH': starting unpatching transition
|
||||
livepatch: '$MOD_LIVEPATCH': completing unpatching transition
|
||||
livepatch: '$MOD_LIVEPATCH': unpatching complete
|
||||
% rmmod $MOD_LIVEPATCH"
|
||||
$MOD_LIVEPATCH1: this has been live patched
|
||||
% echo 0 > /sys/kernel/livepatch/$MOD_LIVEPATCH1/enabled
|
||||
livepatch: '$MOD_LIVEPATCH1': initializing unpatching transition
|
||||
livepatch: '$MOD_LIVEPATCH1': starting unpatching transition
|
||||
livepatch: '$MOD_LIVEPATCH1': completing unpatching transition
|
||||
livepatch: '$MOD_LIVEPATCH1': unpatching complete
|
||||
% rmmod $MOD_LIVEPATCH1"
|
||||
|
||||
|
||||
# - load a livepatch that modifies the output from /proc/cmdline and
|
||||
# verify correct behavior
|
||||
# - load an atomic replace livepatch and verify that only the second is active
|
||||
# - remove the first livepatch and verify that the atomic replace livepatch
|
||||
# is still active
|
||||
# - load two additional livepatches and check the number of livepatch modules
|
||||
# applied
|
||||
# - load an atomic replace livepatch and check that the other three modules were
|
||||
# disabled
|
||||
# - remove all livepatches besides the atomic replace one and verify that the
|
||||
# atomic replace livepatch is still active
|
||||
# - remove the atomic replace livepatch and verify that none are active
|
||||
|
||||
start_test "atomic replace livepatch"
|
||||
|
||||
load_lp $MOD_LIVEPATCH
|
||||
load_lp $MOD_LIVEPATCH1
|
||||
|
||||
grep 'live patched' /proc/cmdline > /dev/kmsg
|
||||
grep 'live patched' /proc/meminfo > /dev/kmsg
|
||||
|
||||
for mod in $MOD_LIVEPATCH2 $MOD_LIVEPATCH3; do
|
||||
load_lp "$mod"
|
||||
done
|
||||
|
||||
mods=(/sys/kernel/livepatch/*)
|
||||
nmods=${#mods[@]}
|
||||
if [ "$nmods" -ne 3 ]; then
|
||||
die "Expecting three modules listed, found $nmods"
|
||||
fi
|
||||
|
||||
load_lp $MOD_REPLACE replace=1
|
||||
|
||||
grep 'live patched' /proc/cmdline > /dev/kmsg
|
||||
grep 'live patched' /proc/meminfo > /dev/kmsg
|
||||
|
||||
unload_lp $MOD_LIVEPATCH
|
||||
loop_until 'mods=(/sys/kernel/livepatch/*); nmods=${#mods[@]}; [[ "$nmods" -eq 1 ]]' ||
|
||||
die "Expecting only one moduled listed, found $nmods"
|
||||
|
||||
# These modules were disabled by the atomic replace
|
||||
for mod in $MOD_LIVEPATCH3 $MOD_LIVEPATCH2 $MOD_LIVEPATCH1; do
|
||||
unload_lp "$mod"
|
||||
done
|
||||
|
||||
grep 'live patched' /proc/cmdline > /dev/kmsg
|
||||
grep 'live patched' /proc/meminfo > /dev/kmsg
|
||||
|
@ -135,13 +156,27 @@ unload_lp $MOD_REPLACE
|
|||
grep 'live patched' /proc/cmdline > /dev/kmsg
|
||||
grep 'live patched' /proc/meminfo > /dev/kmsg
|
||||
|
||||
check_result "% modprobe $MOD_LIVEPATCH
|
||||
livepatch: enabling patch '$MOD_LIVEPATCH'
|
||||
livepatch: '$MOD_LIVEPATCH': initializing patching transition
|
||||
livepatch: '$MOD_LIVEPATCH': starting patching transition
|
||||
livepatch: '$MOD_LIVEPATCH': completing patching transition
|
||||
livepatch: '$MOD_LIVEPATCH': patching complete
|
||||
$MOD_LIVEPATCH: this has been live patched
|
||||
check_result "% modprobe $MOD_LIVEPATCH1
|
||||
livepatch: enabling patch '$MOD_LIVEPATCH1'
|
||||
livepatch: '$MOD_LIVEPATCH1': initializing patching transition
|
||||
livepatch: '$MOD_LIVEPATCH1': starting patching transition
|
||||
livepatch: '$MOD_LIVEPATCH1': completing patching transition
|
||||
livepatch: '$MOD_LIVEPATCH1': patching complete
|
||||
$MOD_LIVEPATCH1: this has been live patched
|
||||
% modprobe $MOD_LIVEPATCH2
|
||||
livepatch: enabling patch '$MOD_LIVEPATCH2'
|
||||
livepatch: '$MOD_LIVEPATCH2': initializing patching transition
|
||||
livepatch: '$MOD_LIVEPATCH2': starting patching transition
|
||||
livepatch: '$MOD_LIVEPATCH2': completing patching transition
|
||||
livepatch: '$MOD_LIVEPATCH2': patching complete
|
||||
% modprobe $MOD_LIVEPATCH3
|
||||
livepatch: enabling patch '$MOD_LIVEPATCH3'
|
||||
livepatch: '$MOD_LIVEPATCH3': initializing patching transition
|
||||
$MOD_LIVEPATCH3: pre_patch_callback: vmlinux
|
||||
livepatch: '$MOD_LIVEPATCH3': starting patching transition
|
||||
livepatch: '$MOD_LIVEPATCH3': completing patching transition
|
||||
$MOD_LIVEPATCH3: post_patch_callback: vmlinux
|
||||
livepatch: '$MOD_LIVEPATCH3': patching complete
|
||||
% modprobe $MOD_REPLACE replace=1
|
||||
livepatch: enabling patch '$MOD_REPLACE'
|
||||
livepatch: '$MOD_REPLACE': initializing patching transition
|
||||
|
@ -149,7 +184,9 @@ livepatch: '$MOD_REPLACE': starting patching transition
|
|||
livepatch: '$MOD_REPLACE': completing patching transition
|
||||
livepatch: '$MOD_REPLACE': patching complete
|
||||
$MOD_REPLACE: this has been live patched
|
||||
% rmmod $MOD_LIVEPATCH
|
||||
% rmmod $MOD_LIVEPATCH3
|
||||
% rmmod $MOD_LIVEPATCH2
|
||||
% rmmod $MOD_LIVEPATCH1
|
||||
$MOD_REPLACE: this has been live patched
|
||||
% echo 0 > /sys/kernel/livepatch/$MOD_REPLACE/enabled
|
||||
livepatch: '$MOD_REPLACE': initializing unpatching transition
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Copyright (C) 2023 SUSE
|
||||
# Author: Marcos Paulo de Souza <mpdesouza@suse.com>
|
||||
|
||||
. $(dirname $0)/functions.sh
|
||||
|
||||
MOD_SYSCALL=test_klp_syscall
|
||||
|
||||
setup_config
|
||||
|
||||
# - Start _NRPROC processes calling getpid and load a livepatch to patch the
|
||||
# getpid syscall. Check if all the processes transitioned to the livepatched
|
||||
# state.
|
||||
|
||||
start_test "patch getpid syscall while being heavily hammered"
|
||||
|
||||
NPROC=$(getconf _NPROCESSORS_ONLN)
|
||||
MAXPROC=128
|
||||
|
||||
for i in $(seq 1 $(($NPROC < $MAXPROC ? $NPROC : $MAXPROC))); do
|
||||
./test_klp-call_getpid &
|
||||
pids[$i]="$!"
|
||||
done
|
||||
|
||||
pid_list=$(echo ${pids[@]} | tr ' ' ',')
|
||||
load_lp $MOD_SYSCALL klp_pids=$pid_list
|
||||
|
||||
# wait for all tasks to transition to patched state
|
||||
loop_until 'grep -q '^0$' /sys/kernel/test_klp_syscall/npids'
|
||||
|
||||
pending_pids=$(cat /sys/kernel/test_klp_syscall/npids)
|
||||
log "$MOD_SYSCALL: Remaining not livepatched processes: $pending_pids"
|
||||
|
||||
for pid in ${pids[@]}; do
|
||||
kill $pid || true
|
||||
done
|
||||
|
||||
disable_lp $MOD_SYSCALL
|
||||
unload_lp $MOD_SYSCALL
|
||||
|
||||
check_result "% modprobe $MOD_SYSCALL klp_pids=$pid_list
|
||||
livepatch: enabling patch '$MOD_SYSCALL'
|
||||
livepatch: '$MOD_SYSCALL': initializing patching transition
|
||||
livepatch: '$MOD_SYSCALL': starting patching transition
|
||||
livepatch: '$MOD_SYSCALL': completing patching transition
|
||||
livepatch: '$MOD_SYSCALL': patching complete
|
||||
$MOD_SYSCALL: Remaining not livepatched processes: 0
|
||||
% echo 0 > /sys/kernel/livepatch/$MOD_SYSCALL/enabled
|
||||
livepatch: '$MOD_SYSCALL': initializing unpatching transition
|
||||
livepatch: '$MOD_SYSCALL': starting unpatching transition
|
||||
livepatch: '$MOD_SYSCALL': completing unpatching transition
|
||||
livepatch: '$MOD_SYSCALL': unpatching complete
|
||||
% rmmod $MOD_SYSCALL"
|
||||
|
||||
exit 0
|
|
@ -18,6 +18,7 @@ check_sysfs_rights "$MOD_LIVEPATCH" "" "drwxr-xr-x"
|
|||
check_sysfs_rights "$MOD_LIVEPATCH" "enabled" "-rw-r--r--"
|
||||
check_sysfs_value "$MOD_LIVEPATCH" "enabled" "1"
|
||||
check_sysfs_rights "$MOD_LIVEPATCH" "force" "--w-------"
|
||||
check_sysfs_rights "$MOD_LIVEPATCH" "replace" "-r--r--r--"
|
||||
check_sysfs_rights "$MOD_LIVEPATCH" "transition" "-r--r--r--"
|
||||
check_sysfs_value "$MOD_LIVEPATCH" "transition" "0"
|
||||
check_sysfs_rights "$MOD_LIVEPATCH" "vmlinux/patched" "-r--r--r--"
|
||||
|
@ -83,4 +84,51 @@ test_klp_callbacks_demo: post_unpatch_callback: vmlinux
|
|||
livepatch: 'test_klp_callbacks_demo': unpatching complete
|
||||
% rmmod test_klp_callbacks_demo"
|
||||
|
||||
start_test "sysfs test replace enabled"
|
||||
|
||||
MOD_LIVEPATCH=test_klp_atomic_replace
|
||||
load_lp $MOD_LIVEPATCH replace=1
|
||||
|
||||
check_sysfs_rights "$MOD_LIVEPATCH" "replace" "-r--r--r--"
|
||||
check_sysfs_value "$MOD_LIVEPATCH" "replace" "1"
|
||||
|
||||
disable_lp $MOD_LIVEPATCH
|
||||
unload_lp $MOD_LIVEPATCH
|
||||
|
||||
check_result "% modprobe $MOD_LIVEPATCH replace=1
|
||||
livepatch: enabling patch '$MOD_LIVEPATCH'
|
||||
livepatch: '$MOD_LIVEPATCH': initializing patching transition
|
||||
livepatch: '$MOD_LIVEPATCH': starting patching transition
|
||||
livepatch: '$MOD_LIVEPATCH': completing patching transition
|
||||
livepatch: '$MOD_LIVEPATCH': patching complete
|
||||
% echo 0 > /sys/kernel/livepatch/$MOD_LIVEPATCH/enabled
|
||||
livepatch: '$MOD_LIVEPATCH': initializing unpatching transition
|
||||
livepatch: '$MOD_LIVEPATCH': starting unpatching transition
|
||||
livepatch: '$MOD_LIVEPATCH': completing unpatching transition
|
||||
livepatch: '$MOD_LIVEPATCH': unpatching complete
|
||||
% rmmod $MOD_LIVEPATCH"
|
||||
|
||||
start_test "sysfs test replace disabled"
|
||||
|
||||
load_lp $MOD_LIVEPATCH replace=0
|
||||
|
||||
check_sysfs_rights "$MOD_LIVEPATCH" "replace" "-r--r--r--"
|
||||
check_sysfs_value "$MOD_LIVEPATCH" "replace" "0"
|
||||
|
||||
disable_lp $MOD_LIVEPATCH
|
||||
unload_lp $MOD_LIVEPATCH
|
||||
|
||||
check_result "% modprobe $MOD_LIVEPATCH replace=0
|
||||
livepatch: enabling patch '$MOD_LIVEPATCH'
|
||||
livepatch: '$MOD_LIVEPATCH': initializing patching transition
|
||||
livepatch: '$MOD_LIVEPATCH': starting patching transition
|
||||
livepatch: '$MOD_LIVEPATCH': completing patching transition
|
||||
livepatch: '$MOD_LIVEPATCH': patching complete
|
||||
% echo 0 > /sys/kernel/livepatch/$MOD_LIVEPATCH/enabled
|
||||
livepatch: '$MOD_LIVEPATCH': initializing unpatching transition
|
||||
livepatch: '$MOD_LIVEPATCH': starting unpatching transition
|
||||
livepatch: '$MOD_LIVEPATCH': completing unpatching transition
|
||||
livepatch: '$MOD_LIVEPATCH': unpatching complete
|
||||
% rmmod $MOD_LIVEPATCH"
|
||||
|
||||
exit 0
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2023 SUSE
|
||||
* Authors: Libor Pechacek <lpechacek@suse.cz>
|
||||
* Marcos Paulo de Souza <mpdesouza@suse.com>
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/types.h>
|
||||
#include <signal.h>
|
||||
|
||||
static int stop;
|
||||
static int sig_int;
|
||||
|
||||
void hup_handler(int signum)
|
||||
{
|
||||
stop = 1;
|
||||
}
|
||||
|
||||
void int_handler(int signum)
|
||||
{
|
||||
stop = 1;
|
||||
sig_int = 1;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
long count = 0;
|
||||
|
||||
signal(SIGHUP, &hup_handler);
|
||||
signal(SIGINT, &int_handler);
|
||||
|
||||
while (!stop) {
|
||||
(void)syscall(SYS_getpid);
|
||||
count++;
|
||||
}
|
||||
|
||||
if (sig_int)
|
||||
printf("%ld iterations done\n", count);
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue