mirror of
https://github.com/torvalds/linux.git
synced 2026-04-18 14:53:58 -04:00
livepatch_trampoline relies on livepatch sysfs and livepatch-sample.ko. When CONFIG_LIVEPATCH is disabled or the samples module isn't built, the test fails with ENOENT and causes false failures in minimal CI configs. Skip the test when livepatch sysfs or the sample module is unavailable. Also avoid writing to livepatch sysfs when it's not present. Signed-off-by: Sun Jian <sun.jian.kdev@gmail.com> Acked-by: Jiri Olsa <jolsa@kernel.org> Link: https://lore.kernel.org/r/20260309104448.817401-1-sun.jian.kdev@gmail.com Signed-off-by: Alexei Starovoitov <ast@kernel.org>
124 lines
2.8 KiB
C
124 lines
2.8 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/* Copyright (c) 2025 Meta Platforms, Inc. and affiliates. */
|
|
|
|
#include <test_progs.h>
|
|
#include "testing_helpers.h"
|
|
#include "livepatch_trampoline.skel.h"
|
|
|
|
#define LIVEPATCH_ENABLED_PATH "/sys/kernel/livepatch/livepatch_sample/enabled"
|
|
|
|
static int load_livepatch(void)
|
|
{
|
|
char path[4096];
|
|
|
|
/* CI will set KBUILD_OUTPUT */
|
|
snprintf(path, sizeof(path), "%s/samples/livepatch/livepatch-sample.ko",
|
|
getenv("KBUILD_OUTPUT") ? : "../../../..");
|
|
|
|
return load_module(path, env_verbosity > VERBOSE_NONE);
|
|
}
|
|
|
|
static void unload_livepatch(void)
|
|
{
|
|
/* Disable the livepatch before unloading the module */
|
|
if (!access(LIVEPATCH_ENABLED_PATH, F_OK))
|
|
system("echo 0 > " LIVEPATCH_ENABLED_PATH);
|
|
|
|
unload_module("livepatch_sample", env_verbosity > VERBOSE_NONE);
|
|
}
|
|
|
|
static void read_proc_cmdline(void)
|
|
{
|
|
char buf[4096];
|
|
int fd, ret;
|
|
|
|
fd = open("/proc/cmdline", O_RDONLY);
|
|
if (!ASSERT_OK_FD(fd, "open /proc/cmdline"))
|
|
return;
|
|
|
|
ret = read(fd, buf, sizeof(buf));
|
|
if (!ASSERT_GT(ret, 0, "read /proc/cmdline"))
|
|
goto out;
|
|
|
|
ASSERT_OK(strncmp(buf, "this has been live patched", 26), "strncmp");
|
|
|
|
out:
|
|
close(fd);
|
|
}
|
|
|
|
static void __test_livepatch_trampoline(bool fexit_first)
|
|
{
|
|
struct livepatch_trampoline *skel = NULL;
|
|
int err;
|
|
|
|
skel = livepatch_trampoline__open_and_load();
|
|
if (!ASSERT_OK_PTR(skel, "skel_open_and_load"))
|
|
goto out;
|
|
|
|
skel->bss->my_pid = getpid();
|
|
|
|
if (!fexit_first) {
|
|
/* fentry program is loaded first by default */
|
|
err = livepatch_trampoline__attach(skel);
|
|
if (!ASSERT_OK(err, "skel_attach"))
|
|
goto out;
|
|
} else {
|
|
/* Manually load fexit program first. */
|
|
skel->links.fexit_cmdline = bpf_program__attach(skel->progs.fexit_cmdline);
|
|
if (!ASSERT_OK_PTR(skel->links.fexit_cmdline, "attach_fexit"))
|
|
goto out;
|
|
|
|
skel->links.fentry_cmdline = bpf_program__attach(skel->progs.fentry_cmdline);
|
|
if (!ASSERT_OK_PTR(skel->links.fentry_cmdline, "attach_fentry"))
|
|
goto out;
|
|
}
|
|
|
|
read_proc_cmdline();
|
|
|
|
ASSERT_EQ(skel->bss->fentry_hit, 1, "fentry_hit");
|
|
ASSERT_EQ(skel->bss->fexit_hit, 1, "fexit_hit");
|
|
out:
|
|
livepatch_trampoline__destroy(skel);
|
|
}
|
|
|
|
void test_livepatch_trampoline(void)
|
|
{
|
|
int retry_cnt = 0;
|
|
int err;
|
|
|
|
/* Skip if kernel was built without CONFIG_LIVEPATCH */
|
|
if (access("/sys/kernel/livepatch", F_OK)) {
|
|
test__skip();
|
|
return;
|
|
}
|
|
|
|
retry:
|
|
err = load_livepatch();
|
|
if (err) {
|
|
if (err == -ENOENT) {
|
|
test__skip();
|
|
return;
|
|
}
|
|
|
|
if (retry_cnt) {
|
|
ASSERT_OK(1, "load_livepatch");
|
|
goto out;
|
|
}
|
|
/*
|
|
* Something else (previous run of the same test?) loaded
|
|
* the KLP module. Unload the KLP module and retry.
|
|
*/
|
|
unload_livepatch();
|
|
retry_cnt++;
|
|
goto retry;
|
|
}
|
|
|
|
if (test__start_subtest("fentry_first"))
|
|
__test_livepatch_trampoline(false);
|
|
|
|
if (test__start_subtest("fexit_first"))
|
|
__test_livepatch_trampoline(true);
|
|
out:
|
|
unload_livepatch();
|
|
}
|