1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (c) 2025 Meta Platforms, Inc. and affiliates. */ 3 4 #include <test_progs.h> 5 #include "testing_helpers.h" 6 #include "livepatch_trampoline.skel.h" 7 8 #define LIVEPATCH_ENABLED_PATH "/sys/kernel/livepatch/livepatch_sample/enabled" 9 10 static int load_livepatch(void) 11 { 12 char path[4096]; 13 14 /* CI will set KBUILD_OUTPUT */ 15 snprintf(path, sizeof(path), "%s/samples/livepatch/livepatch-sample.ko", 16 getenv("KBUILD_OUTPUT") ? : "../../../.."); 17 18 return load_module(path, env_verbosity > VERBOSE_NONE); 19 } 20 21 static void unload_livepatch(void) 22 { 23 /* Disable the livepatch before unloading the module */ 24 if (!access(LIVEPATCH_ENABLED_PATH, F_OK)) 25 system("echo 0 > " LIVEPATCH_ENABLED_PATH); 26 27 unload_module("livepatch_sample", env_verbosity > VERBOSE_NONE); 28 } 29 30 static void read_proc_cmdline(void) 31 { 32 char buf[4096]; 33 int fd, ret; 34 35 fd = open("/proc/cmdline", O_RDONLY); 36 if (!ASSERT_OK_FD(fd, "open /proc/cmdline")) 37 return; 38 39 ret = read(fd, buf, sizeof(buf)); 40 if (!ASSERT_GT(ret, 0, "read /proc/cmdline")) 41 goto out; 42 43 ASSERT_OK(strncmp(buf, "this has been live patched", 26), "strncmp"); 44 45 out: 46 close(fd); 47 } 48 49 static void __test_livepatch_trampoline(bool fexit_first) 50 { 51 struct livepatch_trampoline *skel = NULL; 52 int err; 53 54 skel = livepatch_trampoline__open_and_load(); 55 if (!ASSERT_OK_PTR(skel, "skel_open_and_load")) 56 goto out; 57 58 skel->bss->my_pid = getpid(); 59 60 if (!fexit_first) { 61 /* fentry program is loaded first by default */ 62 err = livepatch_trampoline__attach(skel); 63 if (!ASSERT_OK(err, "skel_attach")) 64 goto out; 65 } else { 66 /* Manually load fexit program first. */ 67 skel->links.fexit_cmdline = bpf_program__attach(skel->progs.fexit_cmdline); 68 if (!ASSERT_OK_PTR(skel->links.fexit_cmdline, "attach_fexit")) 69 goto out; 70 71 skel->links.fentry_cmdline = bpf_program__attach(skel->progs.fentry_cmdline); 72 if (!ASSERT_OK_PTR(skel->links.fentry_cmdline, "attach_fentry")) 73 goto out; 74 } 75 76 read_proc_cmdline(); 77 78 ASSERT_EQ(skel->bss->fentry_hit, 1, "fentry_hit"); 79 ASSERT_EQ(skel->bss->fexit_hit, 1, "fexit_hit"); 80 out: 81 livepatch_trampoline__destroy(skel); 82 } 83 84 void test_livepatch_trampoline(void) 85 { 86 int retry_cnt = 0; 87 int err; 88 89 /* Skip if kernel was built without CONFIG_LIVEPATCH */ 90 if (access("/sys/kernel/livepatch", F_OK)) { 91 test__skip(); 92 return; 93 } 94 95 retry: 96 err = load_livepatch(); 97 if (err) { 98 if (err == -ENOENT) { 99 test__skip(); 100 return; 101 } 102 103 if (retry_cnt) { 104 ASSERT_OK(1, "load_livepatch"); 105 goto out; 106 } 107 /* 108 * Something else (previous run of the same test?) loaded 109 * the KLP module. Unload the KLP module and retry. 110 */ 111 unload_livepatch(); 112 retry_cnt++; 113 goto retry; 114 } 115 116 if (test__start_subtest("fentry_first")) 117 __test_livepatch_trampoline(false); 118 119 if (test__start_subtest("fexit_first")) 120 __test_livepatch_trampoline(true); 121 out: 122 unload_livepatch(); 123 } 124