@@ -2645,6 +2645,9 @@ int xc_livepatch_revert(xc_interface *xch, char *name, uint32_t timeout, uint32_
int xc_livepatch_unload(xc_interface *xch, char *name, uint32_t timeout, uint32_t flags);
int xc_livepatch_replace(xc_interface *xch, char *name, uint32_t timeout, uint32_t flags);
+/* Dummy hypercall to test livepatch functionality. */
+int xc_livepatch_test(xc_interface *xch, uint32_t *result);
+
/*
* Ensure cache coherency after memory modifications. A call to this function
* is only required on ARM as the x86 architecture provides cache coherency
@@ -1021,6 +1021,20 @@ int xc_livepatch_replace(xc_interface *xch, char *name, uint32_t timeout, uint32
return _xc_livepatch_action(xch, name, LIVEPATCH_ACTION_REPLACE, timeout, flags);
}
+int xc_livepatch_test(xc_interface *xch, uint32_t *result)
+{
+ struct xen_sysctl sysctl = {
+ .cmd = XEN_SYSCTL_livepatch_op,
+ .u.livepatch.cmd = XEN_SYSCTL_LIVEPATCH_TEST,
+ };
+ int rc = do_sysctl(xch, &sysctl);
+
+ if ( !rc )
+ *result = sysctl.u.livepatch.u.test.result;
+
+ return rc;
+}
+
/*
* Local variables:
* mode: C
@@ -37,6 +37,7 @@ void show_help(void)
" replace <name> apply <name> patch and revert all others.\n"
" unload <name> unload name <name> patch.\n"
" load <file> [flags] upload and apply <file> with name as the <file> name\n"
+ " test print the result of the test hypercall (for testing purposes only)\n"
" Supported flags:\n"
" --nodeps Disable inter-module buildid dependency check.\n"
" Check only against hypervisor buildid.\n",
@@ -542,6 +543,29 @@ error:
return rc;
}
+static int test_func(int argc, char *argv[])
+{
+ int rc;
+ uint32_t result = 0;
+
+ if ( argc != 0 )
+ {
+ show_help();
+ return -1;
+ }
+
+ rc = xc_livepatch_test(xch, &result);
+ if ( rc )
+ {
+ fprintf(stderr, "test operation failed: %s\n", strerror(errno));
+ return -1;
+ }
+
+ printf("%u\n", result);
+
+ return 0;
+}
+
/*
* These are also functions in action_options that are called in case
* none of the ones in main_options match.
@@ -554,6 +578,7 @@ struct {
{ "list", list_func },
{ "upload", upload_func },
{ "load", load_func },
+ { "test", test_func },
};
int main(int argc, char *argv[])
@@ -23,7 +23,7 @@ obj-y += kernel.o
obj-y += keyhandler.o
obj-$(CONFIG_KEXEC) += kexec.o
obj-$(CONFIG_KEXEC) += kimage.o
-obj-$(CONFIG_LIVEPATCH) += livepatch.o livepatch_elf.o
+obj-$(CONFIG_LIVEPATCH) += livepatch.o livepatch_elf.o livepatch-test.o
obj-$(CONFIG_MEM_ACCESS) += mem_access.o
obj-y += memory.o
obj-y += multicall.o
new file mode 100644
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/* Dummy file for testing livepatch functionality. */
+#include <xen/livepatch.h>
+
+int livepatch_test(struct xen_sysctl_livepatch_test *test)
+{
+ test->result = 1;
+ return 0;
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
@@ -2116,6 +2116,10 @@ int livepatch_op(struct xen_sysctl_livepatch_op *livepatch)
rc = livepatch_action(&livepatch->u.action);
break;
+ case XEN_SYSCTL_LIVEPATCH_TEST:
+ rc = livepatch_test(&livepatch->u.test);
+ break;
+
default:
rc = -EOPNOTSUPP;
break;
@@ -1137,6 +1137,12 @@ struct xen_sysctl_livepatch_action {
uint32_t pad; /* IN: Always zero. */
};
+/* Dummy hypercall for testing live patches. */
+#define XEN_SYSCTL_LIVEPATCH_TEST 4
+struct xen_sysctl_livepatch_test {
+ uint32_t result; /* OUT: dummy result for testing. */
+};
+
struct xen_sysctl_livepatch_op {
uint32_t cmd; /* IN: XEN_SYSCTL_LIVEPATCH_*. */
uint32_t pad; /* IN: Always zero. */
@@ -1145,6 +1151,7 @@ struct xen_sysctl_livepatch_op {
struct xen_sysctl_livepatch_list list;
struct xen_sysctl_livepatch_get get;
struct xen_sysctl_livepatch_action action;
+ struct xen_sysctl_livepatch_test test;
} u;
};
@@ -11,6 +11,8 @@ struct livepatch_elf_sec;
struct livepatch_elf_sym;
struct xen_sysctl_livepatch_op;
+#include <xen/types.h> /* For elfstructs.h */
+
#include <xen/elfstructs.h>
#include <xen/errno.h> /* For -ENOSYS or -EOVERFLOW */
@@ -165,6 +167,8 @@ static inline void common_livepatch_revert(const struct livepatch_func *func,
arch_livepatch_revert(func, state);
state->applied = LIVEPATCH_FUNC_NOT_APPLIED;
}
+
+int livepatch_test(struct xen_sysctl_livepatch_test *test);
#else
/*
new file mode 100644
@@ -0,0 +1,13 @@
+diff --git a/xen/common/livepatch-test.c b/xen/common/livepatch-test.c
+index 05b638b2ac..876173ab6f 100644
+--- a/xen/common/livepatch-test.c
++++ b/xen/common/livepatch-test.c
+@@ -5,7 +5,7 @@
+
+ int livepatch_test(struct xen_sysctl_livepatch_test *test)
+ {
+- test->result = 1;
++ test->result = 2;
+ return 0;
+ }
+
Introduce a dummy XEN_SYSCTL_LIVEPATCH_TEST hypercall to be used in order to test livepatch functionality. The hypercall fills a value in the passed structure, which is returned to the caller. The xen-livepatch utility is expanded to allow calling that hypercall, and printing the returned value on stdout. Finally, add dummy patch that changes the returned value of the hypercall from 1 to 2. Such patch can be used with livepatch-build-tools in order to generate a livepatch payload, that when applied to the hypervisor change the printed value of `xen-livepatch test`. Signed-off-by: Roger Pau Monné <roger.pau@citrix.com> --- The whole logic is very simple now. I think it's enough to have a skeleton we can later expand. Unsure whether we should do some kind of test (with `patch -F0`) that the patch still applies cleanly as part of Xen build. --- tools/include/xenctrl.h | 3 +++ tools/libs/ctrl/xc_misc.c | 14 ++++++++++++++ tools/misc/xen-livepatch.c | 25 +++++++++++++++++++++++++ xen/common/Makefile | 2 +- xen/common/livepatch-test.c | 20 ++++++++++++++++++++ xen/common/livepatch.c | 4 ++++ xen/include/public/sysctl.h | 7 +++++++ xen/include/xen/livepatch.h | 4 ++++ xen/test/livepatch/patches/test1.patch | 13 +++++++++++++ 9 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 xen/common/livepatch-test.c create mode 100644 xen/test/livepatch/patches/test1.patch