mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-12-27 10:01:39 -05:00
selftests/bpf: add regression test for bpf_d_path()
Add a regression test for bpf_d_path() to cover incorrect verifier assumptions caused by an incorrect function prototype. The test attaches to the fallocate hook, calls bpf_d_path() and verifies that a simple prefix comparison on the returned pathname behaves correctly after the fix in patch 1. It ensures the verifier does not assume the buffer remains unwritten. Co-developed-by: Zesen Liu <ftyg@live.com> Signed-off-by: Zesen Liu <ftyg@live.com> Co-developed-by: Peili Gao <gplhust955@gmail.com> Signed-off-by: Peili Gao <gplhust955@gmail.com> Co-developed-by: Haoran Ni <haoran.ni.cs@gmail.com> Signed-off-by: Haoran Ni <haoran.ni.cs@gmail.com> Signed-off-by: Shuran Liu <electronlsr@gmail.com> Link: https://lore.kernel.org/r/20251206141210.3148-3-electronlsr@gmail.com Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
committed by
Alexei Starovoitov
parent
ac44dcc788
commit
79e247d660
@@ -38,6 +38,14 @@ static int set_pathname(int fd, pid_t pid)
|
||||
return readlink(buf, src.paths[src.cnt++], MAX_PATH_LEN);
|
||||
}
|
||||
|
||||
static inline long syscall_close(int fd)
|
||||
{
|
||||
return syscall(__NR_close_range,
|
||||
(unsigned int)fd,
|
||||
(unsigned int)fd,
|
||||
0u);
|
||||
}
|
||||
|
||||
static int trigger_fstat_events(pid_t pid)
|
||||
{
|
||||
int sockfd = -1, procfd = -1, devfd = -1;
|
||||
@@ -104,36 +112,47 @@ static int trigger_fstat_events(pid_t pid)
|
||||
/* sys_close no longer triggers filp_close, but we can
|
||||
* call sys_close_range instead which still does
|
||||
*/
|
||||
#define close(fd) syscall(__NR_close_range, fd, fd, 0)
|
||||
|
||||
close(pipefd[0]);
|
||||
close(pipefd[1]);
|
||||
close(sockfd);
|
||||
close(procfd);
|
||||
close(devfd);
|
||||
close(localfd);
|
||||
close(indicatorfd);
|
||||
|
||||
#undef close
|
||||
syscall_close(pipefd[0]);
|
||||
syscall_close(pipefd[1]);
|
||||
syscall_close(sockfd);
|
||||
syscall_close(procfd);
|
||||
syscall_close(devfd);
|
||||
syscall_close(localfd);
|
||||
syscall_close(indicatorfd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void attach_and_load(struct test_d_path **skel)
|
||||
{
|
||||
int err;
|
||||
|
||||
*skel = test_d_path__open_and_load();
|
||||
if (CHECK(!*skel, "setup", "d_path skeleton failed\n"))
|
||||
goto cleanup;
|
||||
|
||||
err = test_d_path__attach(*skel);
|
||||
if (CHECK(err, "setup", "attach failed: %d\n", err))
|
||||
goto cleanup;
|
||||
|
||||
(*skel)->bss->my_pid = getpid();
|
||||
return;
|
||||
|
||||
cleanup:
|
||||
test_d_path__destroy(*skel);
|
||||
*skel = NULL;
|
||||
}
|
||||
|
||||
static void test_d_path_basic(void)
|
||||
{
|
||||
struct test_d_path__bss *bss;
|
||||
struct test_d_path *skel;
|
||||
int err;
|
||||
|
||||
skel = test_d_path__open_and_load();
|
||||
if (CHECK(!skel, "setup", "d_path skeleton failed\n"))
|
||||
goto cleanup;
|
||||
|
||||
err = test_d_path__attach(skel);
|
||||
if (CHECK(err, "setup", "attach failed: %d\n", err))
|
||||
attach_and_load(&skel);
|
||||
if (!skel)
|
||||
goto cleanup;
|
||||
|
||||
bss = skel->bss;
|
||||
bss->my_pid = getpid();
|
||||
|
||||
err = trigger_fstat_events(bss->my_pid);
|
||||
if (err < 0)
|
||||
@@ -195,6 +214,39 @@ static void test_d_path_check_types(void)
|
||||
test_d_path_check_types__destroy(skel);
|
||||
}
|
||||
|
||||
/* Check if the verifier correctly generates code for
|
||||
* accessing the memory modified by d_path helper.
|
||||
*/
|
||||
static void test_d_path_mem_access(void)
|
||||
{
|
||||
int localfd = -1;
|
||||
char path_template[] = "/dev/shm/d_path_loadgen.XXXXXX";
|
||||
struct test_d_path__bss *bss;
|
||||
struct test_d_path *skel;
|
||||
|
||||
attach_and_load(&skel);
|
||||
if (!skel)
|
||||
goto cleanup;
|
||||
|
||||
bss = skel->bss;
|
||||
|
||||
localfd = mkstemp(path_template);
|
||||
if (CHECK(localfd < 0, "trigger", "mkstemp failed\n"))
|
||||
goto cleanup;
|
||||
|
||||
if (CHECK(fallocate(localfd, 0, 0, 1024) < 0, "trigger", "fallocate failed\n"))
|
||||
goto cleanup;
|
||||
remove(path_template);
|
||||
|
||||
if (CHECK(!bss->path_match_fallocate, "check",
|
||||
"failed to read fallocate path"))
|
||||
goto cleanup;
|
||||
|
||||
cleanup:
|
||||
syscall_close(localfd);
|
||||
test_d_path__destroy(skel);
|
||||
}
|
||||
|
||||
void test_d_path(void)
|
||||
{
|
||||
if (test__start_subtest("basic"))
|
||||
@@ -205,4 +257,7 @@ void test_d_path(void)
|
||||
|
||||
if (test__start_subtest("check_alloc_mem"))
|
||||
test_d_path_check_types();
|
||||
|
||||
if (test__start_subtest("check_mem_access"))
|
||||
test_d_path_mem_access();
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ int rets_close[MAX_FILES] = {};
|
||||
|
||||
int called_stat = 0;
|
||||
int called_close = 0;
|
||||
int path_match_fallocate = 0;
|
||||
|
||||
SEC("fentry/security_inode_getattr")
|
||||
int BPF_PROG(prog_stat, struct path *path, struct kstat *stat,
|
||||
@@ -62,4 +63,26 @@ int BPF_PROG(prog_close, struct file *file, void *id)
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("fentry/vfs_fallocate")
|
||||
int BPF_PROG(prog_fallocate, struct file *file, int mode, loff_t offset, loff_t len)
|
||||
{
|
||||
pid_t pid = bpf_get_current_pid_tgid() >> 32;
|
||||
int ret = 0;
|
||||
char path_fallocate[MAX_PATH_LEN] = {};
|
||||
|
||||
if (pid != my_pid)
|
||||
return 0;
|
||||
|
||||
ret = bpf_d_path(&file->f_path,
|
||||
path_fallocate, MAX_PATH_LEN);
|
||||
if (ret < 0)
|
||||
return 0;
|
||||
|
||||
if (!path_fallocate[0])
|
||||
return 0;
|
||||
|
||||
path_match_fallocate = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
char _license[] SEC("license") = "GPL";
|
||||
|
||||
Reference in New Issue
Block a user