From: Roman Rashchupkin <[email protected]>

Signed-off-by: Roman Rashchupkin <[email protected]>
---
 tools/testing/selftests/livepatch/Makefile    |   3 +-
 .../selftests/livepatch/test-kprefcount.sh    |  16 +++
 .../selftests/livepatch/test_modules/Makefile |   4 +-
 .../test_modules/test_klp_kprefcount.c        | 120 ++++++++++++++++++
 .../test_modules/test_klp_refcount.c          |  65 ++++++++++
 5 files changed, 206 insertions(+), 2 deletions(-)
 create mode 100755 tools/testing/selftests/livepatch/test-kprefcount.sh
 create mode 100644 
tools/testing/selftests/livepatch/test_modules/test_klp_kprefcount.c
 create mode 100644 
tools/testing/selftests/livepatch/test_modules/test_klp_refcount.c

diff --git a/tools/testing/selftests/livepatch/Makefile 
b/tools/testing/selftests/livepatch/Makefile
index 35418a4790be..48926ebc77f2 100644
--- a/tools/testing/selftests/livepatch/Makefile
+++ b/tools/testing/selftests/livepatch/Makefile
@@ -10,7 +10,8 @@ TEST_PROGS := \
        test-state.sh \
        test-ftrace.sh \
        test-sysfs.sh \
-       test-syscall.sh
+       test-syscall.sh \
+       test-kprefcount.sh
 
 TEST_FILES := settings
 
diff --git a/tools/testing/selftests/livepatch/test-kprefcount.sh 
b/tools/testing/selftests/livepatch/test-kprefcount.sh
new file mode 100755
index 000000000000..8ea6c18f59dd
--- /dev/null
+++ b/tools/testing/selftests/livepatch/test-kprefcount.sh
@@ -0,0 +1,16 @@
+#!/bin/sh
+insmod test_modules/test_klp_refcount.ko
+insmod test_modules/test_klp_kprefcount.ko
+livepatch_enabled=/sys/kernel/livepatch/test_klp_kprefcount/enabled
+while [ ! -e $livepatch_enabled -o $(cat $livepatch_enabled) -eq 0 ]; do
+       sleep 0.01;
+done
+echo 0 > $livepatch_enabled
+while [ $(cat $livepatch_enabled) -eq 1 ]; do
+       sleep 0.01;
+done
+while [ -e $livepatch_enabled ]; do
+       sleep 0.01;
+done
+rmmod test_klp_kprefcount
+rmmod test_klp_refcount
diff --git a/tools/testing/selftests/livepatch/test_modules/Makefile 
b/tools/testing/selftests/livepatch/test_modules/Makefile
index e6e638c4bcba..c26797372e0d 100644
--- a/tools/testing/selftests/livepatch/test_modules/Makefile
+++ b/tools/testing/selftests/livepatch/test_modules/Makefile
@@ -11,7 +11,9 @@ obj-m += test_klp_atomic_replace.o \
        test_klp_state2.o \
        test_klp_state3.o \
        test_klp_shadow_vars.o \
-       test_klp_syscall.o
+       test_klp_syscall.o \
+       test_klp_refcount.o \
+       test_klp_kprefcount.o
 
 # Ensure that KDIR exists, otherwise skip the compilation
 modules:
diff --git 
a/tools/testing/selftests/livepatch/test_modules/test_klp_kprefcount.c 
b/tools/testing/selftests/livepatch/test_modules/test_klp_kprefcount.c
new file mode 100644
index 000000000000..063f286ebcec
--- /dev/null
+++ b/tools/testing/selftests/livepatch/test_modules/test_klp_kprefcount.c
@@ -0,0 +1,120 @@
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/livepatch.h>
+#include <linux/livepatch_refcount.h>
+
+extern refcount_t test_refcount;
+extern int TEST_LIVEPATCH_KPREFCOUNT;
+
+#define ITER 100
+#define NREF 10
+#define KP_NREF 10
+static struct ref_holder {
+       unsigned char v;
+} kp_ref_holders[KP_NREF] = { 0 };
+kprefcount_t *kp_test_ref = 0;
+
+static int livepatch_refcount_test_iter(void)
+{
+       int k, i;
+       for (k=0; k<ITER; k++) {
+               for (i=0; i<KP_NREF; i++)
+                       refcount_inc(&test_refcount);
+               for (i=0; i<KP_NREF; i++)
+                       if (kprefcount_dec_and_test(kp_test_ref, 0, 1)) {
+                               pr_alert("livepatch refcount underflow\n");
+                               return -1;
+                       }
+       }
+       TEST_LIVEPATCH_KPREFCOUNT = 0;
+       return 0;
+}
+
+struct delayed_work kp_work_refcount;
+static void kp_test_refcount(struct work_struct *work)
+{
+       int i, k;
+       for (k=0; k<ITER; k++) {
+               for (i=0; i<KP_NREF; i++)
+                       kprefcount_dec(kp_test_ref, &kp_ref_holders[i].v, 1);
+               // Intentional refcounter underflow for additional testing
+               for (i=0; i<KP_NREF-1; i++)
+                       kprefcount_inc(kp_test_ref, &kp_ref_holders[i].v, 1);
+       }
+}
+
+static void kp_post_patch_callback(struct klp_object *klp_obj)
+{
+       schedule_delayed_work(&kp_work_refcount, 0);
+}
+
+static void kp_pre_unpatch_callback(struct klp_object *klp_obj)
+{
+       cancel_delayed_work_sync(&kp_work_refcount);
+}
+
+static struct klp_func funcs[] = {
+       {
+               .old_name = "refcount_test_iter",
+               .new_func = livepatch_refcount_test_iter,
+       }, { }
+};
+
+static struct klp_object objs[] = {
+       {
+               .name = "test_klp_refcount",
+               .funcs = funcs,
+               .callbacks = {
+                       .post_patch = kp_post_patch_callback,
+                       .pre_unpatch = kp_pre_unpatch_callback,
+               },
+       }, { }
+};
+
+static struct klp_patch patch = {
+       .mod = THIS_MODULE,
+       .objs = objs,
+};
+
+struct delayed_work work_refcount;
+
+static void do_test_refcount(struct work_struct *work)
+{
+       int i;
+       for (i=0; i<NREF; i++) {
+               if (refcount_read(&test_refcount) <= 1)
+                       pr_info("LIVEPATCH refcount test done.\n");
+                       return;
+               refcount_dec(&test_refcount);
+               if (refcount_read(&test_refcount) < 0)
+                       pr_alert("post-livepatch refcount underflow\n");
+       }
+       for (i=0; i<NREF; i++)
+               refcount_inc(&test_refcount);
+}
+
+static int refcount_test_init(void)
+{
+       int ret;
+       kp_test_ref = kprefcount_alloc(&test_refcount, GFP_KERNEL);
+       if (!kp_test_ref) {
+               pr_alert("kprefcount_livepatch: memory allocation_failed");
+               return -1;
+       }
+       ret = klp_enable_patch(&patch);
+       INIT_DELAYED_WORK(&kp_work_refcount, kp_test_refcount);
+       return 0;
+}
+
+static void refcount_test_exit(void)
+{
+}
+
+module_init(refcount_test_init);
+module_exit(refcount_test_exit);
+MODULE_INFO(livepatch, "Y");
+MODULE_AUTHOR("Roman Rashchupkin <[email protected]>");
+MODULE_DESCRIPTION("Livepatch test: kprefcount");
+MODULE_LICENSE("GPL");
diff --git a/tools/testing/selftests/livepatch/test_modules/test_klp_refcount.c 
b/tools/testing/selftests/livepatch/test_modules/test_klp_refcount.c
new file mode 100644
index 000000000000..bd9c57e63476
--- /dev/null
+++ b/tools/testing/selftests/livepatch/test_modules/test_klp_refcount.c
@@ -0,0 +1,65 @@
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/livepatch.h>
+#include <linux/livepatch_refcount.h>
+
+#define ITER 100
+#define NREF 10
+int TEST_LIVEPATCH_KPREFCOUNT = 1;
+EXPORT_SYMBOL(TEST_LIVEPATCH_KPREFCOUNT);
+refcount_t test_refcount = REFCOUNT_INIT(1);
+EXPORT_SYMBOL(test_refcount);
+
+int refcount_test_iter(void)
+{
+       int i;
+       for (i=0; i<NREF; i++)
+               refcount_inc(&test_refcount);
+       for (i=0; i<NREF; i++)
+               if (refcount_dec_and_test(&test_refcount))
+                       return -1;
+       return 0;
+}
+
+int refcount_test(void)
+{
+       int i;
+       for (i=0; i<ITER; i++) {
+               if (refcount_test_iter())
+                       return -1;
+       }
+       return 0;
+}
+EXPORT_SYMBOL(refcount_test);
+
+struct delayed_work kp_test_work;
+void start_refcount_test(struct work_struct *work)
+{
+       if (!TEST_LIVEPATCH_KPREFCOUNT)
+               return;
+       if (refcount_test()) {
+               pr_alert(KERN_ERR "refcount_test: error.\n");
+               return;
+       }
+       schedule_delayed_work(&kp_test_work, msecs_to_jiffies(50));
+}
+
+static int refcount_test_init(void)
+{
+       INIT_DELAYED_WORK(&kp_test_work, start_refcount_test);
+       schedule_delayed_work(&kp_test_work, msecs_to_jiffies(50));
+       return 0;
+}
+
+static void refcount_test_exit(void)
+{
+       cancel_delayed_work_sync(&kp_test_work);
+}
+
+module_init(refcount_test_init);
+module_exit(refcount_test_exit);
+MODULE_AUTHOR("Roman Rashchupkin <[email protected]>");
+MODULE_DESCRIPTION("Livepatch test: refcount");
+MODULE_LICENSE("GPL");
-- 
2.43.0


Reply via email to