Skip to content

Commit 43ec3ba

Browse files
electronlsrKernel Patches Daemon
authored andcommitted
selftests/bpf: fix and consolidate d_path LSM regression test
Add a regression test for bpf_d_path() when invoked from an LSM program. The test attaches to the bprm_check_security hook, calls bpf_d_path() on the binary being executed, and verifies that a simple prefix comparison on the returned pathname behaves correctly after the fix in patch 1. To avoid nondeterminism, the LSM program now filters based on the expected PID, which is populated from userspace before the test binary is executed. This prevents unrelated processes that also trigger the bprm_check_security LSM hook from overwriting test results. Parent and child processes are synchronized through a pipe to ensure the PID is set before the child execs the test binary. Per review feedback, the new test is merged into the existing d_path selftest rather than adding new prog_tests/ or progs/ files. Co-developed-by: Zesen Liu <[email protected]> Signed-off-by: Zesen Liu <[email protected]> Co-developed-by: Peili Gao <[email protected]> Signed-off-by: Peili Gao <[email protected]> Co-developed-by: Haoran Ni <[email protected]> Signed-off-by: Haoran Ni <[email protected]> Signed-off-by: Shuran Liu <[email protected]> Reviewed-by: Matt Bobrowski <[email protected]>
1 parent cb9a11d commit 43ec3ba

File tree

2 files changed

+97
-0
lines changed

2 files changed

+97
-0
lines changed

tools/testing/selftests/bpf/prog_tests/d_path.c

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,67 @@ static void test_d_path_check_types(void)
195195
test_d_path_check_types__destroy(skel);
196196
}
197197

198+
static void test_d_path_lsm(void)
199+
{
200+
struct test_d_path *skel;
201+
int err;
202+
int pipefd[2];
203+
pid_t pid;
204+
205+
skel = test_d_path__open_and_load();
206+
if (!ASSERT_OK_PTR(skel, "d_path skeleton failed"))
207+
return;
208+
209+
err = test_d_path__attach(skel);
210+
if (!ASSERT_OK(err, "attach failed"))
211+
goto cleanup;
212+
213+
/* Prepare the test binary */
214+
system("cp /bin/true /tmp/bpf_d_path_test 2>/dev/null || :");
215+
216+
if (!ASSERT_OK(pipe(pipefd), "pipe failed"))
217+
goto cleanup;
218+
219+
pid = fork();
220+
if (!ASSERT_GE(pid, 0, "fork failed")) {
221+
close(pipefd[0]);
222+
close(pipefd[1]);
223+
goto cleanup;
224+
}
225+
226+
if (pid == 0) {
227+
/* Child */
228+
char buf;
229+
230+
close(pipefd[1]);
231+
/* Wait for parent to set PID in BPF map */
232+
if (read(pipefd[0], &buf, 1) != 1)
233+
exit(1);
234+
close(pipefd[0]);
235+
execl("/tmp/bpf_d_path_test", "/tmp/bpf_d_path_test", NULL);
236+
exit(1);
237+
}
238+
239+
/* Parent */
240+
close(pipefd[0]);
241+
242+
/* Update BPF map with child PID */
243+
skel->bss->my_pid = pid;
244+
245+
/* Signal child to proceed */
246+
write(pipefd[1], "G", 1);
247+
close(pipefd[1]);
248+
249+
/* Wait for child */
250+
waitpid(pid, NULL, 0);
251+
252+
ASSERT_EQ(skel->bss->called_lsm, 1, "lsm hook called");
253+
ASSERT_EQ(skel->bss->lsm_match, 1, "lsm match");
254+
255+
cleanup:
256+
test_d_path__destroy(skel);
257+
}
258+
198259
void test_d_path(void)
199260
{
200261
if (test__start_subtest("basic"))
@@ -205,4 +266,7 @@ void test_d_path(void)
205266

206267
if (test__start_subtest("check_alloc_mem"))
207268
test_d_path_check_types();
269+
270+
if (test__start_subtest("lsm"))
271+
test_d_path_lsm();
208272
}

tools/testing/selftests/bpf/progs/test_d_path.c

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ int rets_close[MAX_FILES] = {};
1717

1818
int called_stat = 0;
1919
int called_close = 0;
20+
int called_lsm = 0;
21+
int lsm_match = 0;
2022

2123
SEC("fentry/security_inode_getattr")
2224
int BPF_PROG(prog_stat, struct path *path, struct kstat *stat,
@@ -62,4 +64,35 @@ int BPF_PROG(prog_close, struct file *file, void *id)
6264
return 0;
6365
}
6466

67+
SEC("lsm/bprm_check_security")
68+
int BPF_PROG(prog_lsm, struct linux_binprm *bprm)
69+
{
70+
pid_t pid = bpf_get_current_pid_tgid() >> 32;
71+
char path[MAX_PATH_LEN] = {};
72+
int ret;
73+
74+
if (pid != my_pid)
75+
return 0;
76+
77+
called_lsm = 1;
78+
ret = bpf_d_path(&bprm->file->f_path, path, MAX_PATH_LEN);
79+
if (ret < 0)
80+
return 0;
81+
82+
{
83+
static const char target_dir[] = "/tmp/";
84+
85+
#pragma unroll
86+
for (int i = 0; i < sizeof(target_dir) - 1; i++) {
87+
if (path[i] != target_dir[i]) {
88+
lsm_match = -1; /* mismatch */
89+
return 0;
90+
}
91+
}
92+
}
93+
94+
lsm_match = 1; /* prefix match */
95+
return 0;
96+
}
97+
6598
char _license[] SEC("license") = "GPL";

0 commit comments

Comments
 (0)