LKML Archive on lore.kernel.org
help / color / mirror / Atom feed
From: Miroslav Benes <mbenes@suse.cz>
To: jpoimboe@redhat.com, jikos@kernel.org, pmladek@suse.com,
	joe.lawrence@redhat.com
Cc: peterz@infradead.org, linux-kernel@vger.kernel.org,
	live-patching@vger.kernel.org, shuah@kernel.org,
	linux-kselftest@vger.kernel.org, Miroslav Benes <mbenes@suse.cz>
Subject: [PATCH 3/3] selftests/livepatch: Test of the API for specifying functions to search for on a stack
Date: Fri, 19 Nov 2021 10:03:27 +0100	[thread overview]
Message-ID: <20211119090327.12811-4-mbenes@suse.cz> (raw)
In-Reply-To: <20211119090327.12811-1-mbenes@suse.cz>

Add a test for the API which allows the user to specify functions which
are then searched for on any tasks's stack during a transition process.

Signed-off-by: Miroslav Benes <mbenes@suse.cz>
---
 lib/Kconfig.debug                             |  1 +
 lib/livepatch/Makefile                        |  4 +-
 lib/livepatch/test_klp_funcstack_demo.c       | 61 +++++++++++++
 lib/livepatch/test_klp_funcstack_mod.c        | 72 +++++++++++++++
 tools/testing/selftests/livepatch/Makefile    |  3 +-
 .../selftests/livepatch/test-func-stack.sh    | 88 +++++++++++++++++++
 6 files changed, 227 insertions(+), 2 deletions(-)
 create mode 100644 lib/livepatch/test_klp_funcstack_demo.c
 create mode 100644 lib/livepatch/test_klp_funcstack_mod.c
 create mode 100755 tools/testing/selftests/livepatch/test-func-stack.sh

diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 9ef7ce18b4f5..aa4c97098f41 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -2529,6 +2529,7 @@ config TEST_LIVEPATCH
 	default n
 	depends on DYNAMIC_DEBUG
 	depends on LIVEPATCH
+	depends on DEBUG_FS
 	depends on m
 	help
 	  Test kernel livepatching features for correctness.  The tests will
diff --git a/lib/livepatch/Makefile b/lib/livepatch/Makefile
index dcc912b3478f..584e3b8b5415 100644
--- a/lib/livepatch/Makefile
+++ b/lib/livepatch/Makefile
@@ -11,4 +11,6 @@ obj-$(CONFIG_TEST_LIVEPATCH) += test_klp_atomic_replace.o \
 				test_klp_shadow_vars.o \
 				test_klp_state.o \
 				test_klp_state2.o \
-				test_klp_state3.o
+				test_klp_state3.o \
+				test_klp_funcstack_mod.o \
+				test_klp_funcstack_demo.o
diff --git a/lib/livepatch/test_klp_funcstack_demo.c b/lib/livepatch/test_klp_funcstack_demo.c
new file mode 100644
index 000000000000..902798077f05
--- /dev/null
+++ b/lib/livepatch/test_klp_funcstack_demo.c
@@ -0,0 +1,61 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2021 Miroslav Benes <mbenes@suse.cz>
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/livepatch.h>
+
+static int funcstack;
+module_param(funcstack, int, 0644);
+MODULE_PARM_DESC(funcstack, "func_stack (default=0)");
+
+static noinline void livepatch_child2_function(void)
+{
+	pr_info("%s\n", __func__);
+}
+
+static struct klp_func funcs[] = {
+	{
+		.old_name = "child2_function",
+		.new_func = livepatch_child2_function,
+	}, {}
+};
+
+static struct klp_func funcs_stack[] = {
+	{
+		.old_name = "parent_function",
+	}, {}
+};
+
+static struct klp_object objs[] = {
+	{
+		.name = "test_klp_funcstack_mod",
+		.funcs = funcs,
+	}, {}
+};
+
+static struct klp_patch patch = {
+	.mod = THIS_MODULE,
+	.objs = objs,
+};
+
+static int test_klp_funcstack_demo_init(void)
+{
+	if (funcstack)
+		objs[0].funcs_stack = funcs_stack;
+
+	return klp_enable_patch(&patch);
+}
+
+static void test_klp_funcstack_demo_exit(void)
+{
+}
+
+module_init(test_klp_funcstack_demo_init);
+module_exit(test_klp_funcstack_demo_exit);
+MODULE_LICENSE("GPL");
+MODULE_INFO(livepatch, "Y");
+MODULE_AUTHOR("Miroslav Benes <mbenes@suse.cz>");
+MODULE_DESCRIPTION("Livepatch test: func_stack demo");
diff --git a/lib/livepatch/test_klp_funcstack_mod.c b/lib/livepatch/test_klp_funcstack_mod.c
new file mode 100644
index 000000000000..127c6093d890
--- /dev/null
+++ b/lib/livepatch/test_klp_funcstack_mod.c
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2021 Miroslav Benes <mbenes@suse.cz>
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+
+static int sleep_length = 10000;
+module_param(sleep_length, int, 0644);
+MODULE_PARM_DESC(sleep_length, "length of sleep in seconds (default=10)");
+
+static noinline void child_function(void)
+{
+	pr_info("%s enter\n", __func__);
+	msleep(sleep_length);
+	pr_info("%s exit\n", __func__);
+}
+
+static noinline void child2_function(void)
+{
+	pr_info("%s\n", __func__);
+}
+
+static noinline void parent_function(void)
+{
+	pr_info("%s enter\n", __func__);
+	child_function();
+	child2_function();
+	pr_info("%s exit\n", __func__);
+}
+
+static int parent_function_get(void *data, u64 *val)
+{
+	*val = 0;
+	parent_function();
+
+	return 0;
+}
+
+DEFINE_DEBUGFS_ATTRIBUTE(fops_parent_function, parent_function_get, NULL, "%llu\n");
+
+static struct dentry *debugfs_dir;
+
+static int test_klp_funcstack_mod_init(void)
+{
+	struct dentry *d;
+
+	debugfs_dir = debugfs_create_dir("test_klp_funcstack", NULL);
+	if (IS_ERR(debugfs_dir))
+		return PTR_ERR(debugfs_dir);
+
+	d = debugfs_create_file("parent_function", 0400, debugfs_dir, NULL,
+				&fops_parent_function);
+	if (IS_ERR(d))
+		debugfs_remove_recursive(debugfs_dir);
+
+	return 0;
+}
+
+static void test_klp_funcstack_mod_exit(void)
+{
+	debugfs_remove_recursive(debugfs_dir);
+}
+
+module_init(test_klp_funcstack_mod_init);
+module_exit(test_klp_funcstack_mod_exit);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Miroslav Benes <mbenes@suse.cz>");
+MODULE_DESCRIPTION("Livepatch test: func_stack module");
diff --git a/tools/testing/selftests/livepatch/Makefile b/tools/testing/selftests/livepatch/Makefile
index 1acc9e1fa3fb..40f8a3a2e9aa 100644
--- a/tools/testing/selftests/livepatch/Makefile
+++ b/tools/testing/selftests/livepatch/Makefile
@@ -6,7 +6,8 @@ TEST_PROGS := \
 	test-callbacks.sh \
 	test-shadow-vars.sh \
 	test-state.sh \
-	test-ftrace.sh
+	test-ftrace.sh \
+	test-func-stack.sh
 
 TEST_FILES := settings
 
diff --git a/tools/testing/selftests/livepatch/test-func-stack.sh b/tools/testing/selftests/livepatch/test-func-stack.sh
new file mode 100755
index 000000000000..b7da62c9f5a1
--- /dev/null
+++ b/tools/testing/selftests/livepatch/test-func-stack.sh
@@ -0,0 +1,88 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (C) 2021 Miroslav Benes <mbenes@suse.cz>
+
+. $(dirname $0)/functions.sh
+
+MOD_TARGET=test_klp_funcstack_mod
+MOD_LIVEPATCH=test_klp_funcstack_demo
+
+setup_config
+
+# - load a target module and call its parent_function(). It will sleep in its
+#   child_function() callee.
+# - load a live patch with new child2_function() called from parent_function()
+#   too. The patching does not wait for child_function() to return, because
+#   child2_function() is not on any stack.
+# - clean up afterwards
+
+start_test "non-blocking patching without the function on a stack"
+
+load_mod $MOD_TARGET
+
+(cat /sys/kernel/debug/test_klp_funcstack/parent_function) >/dev/null &
+PID=$!
+
+load_lp $MOD_LIVEPATCH
+
+wait $PID
+
+disable_lp $MOD_LIVEPATCH
+unload_lp $MOD_LIVEPATCH
+unload_mod $MOD_TARGET
+
+check_result "% modprobe $MOD_TARGET
+$MOD_TARGET: parent_function enter
+$MOD_TARGET: child_function enter
+% 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_TARGET: child_function exit
+$MOD_LIVEPATCH: livepatch_child2_function
+$MOD_TARGET: parent_function exit
+% 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
+% rmmod $MOD_TARGET"
+
+# Similar to the previous test but now the patching has to wait for
+# child2_function() to return, because parent_function() is also checked for.
+
+start_test "patching delayed due to the function on a stack"
+
+load_mod $MOD_TARGET
+
+(cat /sys/kernel/debug/test_klp_funcstack/parent_function) >/dev/null &
+
+load_lp $MOD_LIVEPATCH funcstack=1
+disable_lp $MOD_LIVEPATCH
+unload_lp $MOD_LIVEPATCH
+unload_mod $MOD_TARGET
+
+check_result "% modprobe $MOD_TARGET
+$MOD_TARGET: parent_function enter
+$MOD_TARGET: child_function enter
+% modprobe $MOD_LIVEPATCH funcstack=1
+livepatch: enabling patch '$MOD_LIVEPATCH'
+livepatch: '$MOD_LIVEPATCH': initializing patching transition
+livepatch: '$MOD_LIVEPATCH': starting patching transition
+$MOD_TARGET: child_function exit
+$MOD_TARGET: child2_function
+$MOD_TARGET: parent_function exit
+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
+% rmmod $MOD_TARGET"
+
+exit 0
-- 
2.33.1


  parent reply	other threads:[~2021-11-19  9:03 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-11-19  9:03 [PATCH 0/3] livepatch: Allow user to specify " Miroslav Benes
2021-11-19  9:03 ` [PATCH 1/3] livepatch: Move the initialization of old_func to a new function Miroslav Benes
2021-11-19  9:03 ` [PATCH 2/3] livepatch: Allow user to specify functions to search for on a stack Miroslav Benes
2021-11-19 10:17   ` Peter Zijlstra
2021-11-19 18:20   ` Josh Poimboeuf
2021-11-22  7:57     ` Miroslav Benes
2021-11-22 15:53       ` Joe Lawrence
2021-11-25 10:07         ` Petr Mladek
2021-11-25 10:20           ` Miroslav Benes
2021-12-03 16:01             ` Petr Mladek
2021-11-19  9:03 ` Miroslav Benes [this message]
2021-11-25 14:39   ` [PATCH 3/3] selftests/livepatch: Test of the API for specifying " Petr Mladek
2021-11-26  9:20     ` Miroslav Benes
2021-11-26 14:06       ` Petr Mladek

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20211119090327.12811-4-mbenes@suse.cz \
    --to=mbenes@suse.cz \
    --cc=jikos@kernel.org \
    --cc=joe.lawrence@redhat.com \
    --cc=jpoimboe@redhat.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-kselftest@vger.kernel.org \
    --cc=live-patching@vger.kernel.org \
    --cc=peterz@infradead.org \
    --cc=pmladek@suse.com \
    --cc=shuah@kernel.org \
    --subject='Re: [PATCH 3/3] selftests/livepatch: Test of the API for specifying functions to search for on a stack' \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).