Skip to content

Commit a433010

Browse files
liu-song-6Kernel Patches Daemon
authored andcommitted
selftests/bpf: Path walk test
Add an end-to-end test with path_iter on security hook file_open. A test file is created in folder /tmp/test_progs_path_iter/folder. On file_open, walk file->f_path up to its parent and grand parent, and test bpf_get_dentry_xattr and bpf_path_d_path on the folders. Signed-off-by: Song Liu <[email protected]>
1 parent 5647ca4 commit a433010

File tree

2 files changed

+158
-0
lines changed

2 files changed

+158
-0
lines changed

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

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,110 @@
22
/* Copyright (c) 2025 Meta Platforms, Inc. and affiliates. */
33

44
#include <test_progs.h>
5+
#include <fcntl.h>
56
#include <bpf/libbpf.h>
67
#include <bpf/btf.h>
8+
#include <sys/stat.h>
9+
#include <sys/xattr.h>
10+
711
#include "path_iter.skel.h"
12+
#include "path_walk.skel.h"
13+
14+
static const char grand_parent_path[] = "/tmp/test_progs_path_iter";
15+
static const char parent_path[] = "/tmp/test_progs_path_iter/folder";
16+
static const char file_path[] = "/tmp/test_progs_path_iter/folder/file";
17+
static const char xattr_name[] = "user.bpf.selftests";
18+
static const char xattr_value[] = "selftest_path_iter";
19+
20+
static void cleanup_files(void)
21+
{
22+
remove(file_path);
23+
rmdir(parent_path);
24+
rmdir(grand_parent_path);
25+
}
26+
27+
static int setup_files_and_xattrs(void)
28+
{
29+
int ret = -1;
30+
31+
/* create test folders */
32+
if (mkdir(grand_parent_path, 0755))
33+
goto error;
34+
if (mkdir(parent_path, 0755))
35+
goto error;
36+
37+
/* setxattr for test folders */
38+
ret = setxattr(grand_parent_path, xattr_name,
39+
xattr_value, sizeof(xattr_value), 0);
40+
if (ret < 0) {
41+
/* return errno, so that we can handle EOPNOTSUPP in the caller */
42+
ret = errno;
43+
goto error;
44+
}
45+
ret = setxattr(parent_path, xattr_name,
46+
xattr_value, sizeof(xattr_value), 0);
47+
if (ret < 0) {
48+
/* return errno, so that we can handle EOPNOTSUPP in the caller */
49+
ret = errno;
50+
goto error;
51+
}
52+
53+
return 0;
54+
error:
55+
cleanup_files();
56+
return ret;
57+
}
58+
59+
static void test_path_walk(void)
60+
{
61+
struct path_walk *skel = NULL;
62+
int file_fd;
63+
int err;
64+
65+
err = setup_files_and_xattrs();
66+
if (err == EOPNOTSUPP) {
67+
printf("%s:SKIP:local fs doesn't support xattr (%d)\n"
68+
"To run this test, make sure /tmp filesystem supports xattr.\n",
69+
__func__, errno);
70+
test__skip();
71+
return;
72+
}
73+
74+
if (!ASSERT_OK(err, "setup_file"))
75+
return;
76+
77+
skel = path_walk__open_and_load();
78+
if (!ASSERT_OK_PTR(skel, "path_walk__open_and_load"))
79+
goto cleanup;
80+
81+
skel->bss->monitored_pid = getpid();
82+
if (!ASSERT_OK(path_walk__attach(skel), "path_walk__attach"))
83+
goto cleanup;
84+
85+
file_fd = open(file_path, O_CREAT);
86+
if (!ASSERT_OK_FD(file_fd, "open_file"))
87+
goto cleanup;
88+
close(file_fd);
89+
90+
ASSERT_OK(strncmp(skel->bss->parent_xattr_buf, xattr_value, strlen(xattr_value)),
91+
"parent_xattr");
92+
ASSERT_OK(strncmp(skel->bss->grand_parent_xattr_buf, xattr_value, strlen(xattr_value)),
93+
"grand_parent_xattr");
94+
95+
ASSERT_OK(strncmp(skel->bss->parent_path_buf, parent_path, strlen(parent_path)),
96+
"parent_d_path");
97+
ASSERT_OK(strncmp(skel->bss->grand_parent_path_buf, grand_parent_path,
98+
strlen(grand_parent_path)),
99+
"grand_parent_d_path");
100+
101+
cleanup:
102+
path_walk__destroy(skel);
103+
cleanup_files();
104+
}
8105

9106
void test_path_iter(void)
10107
{
11108
RUN_TESTS(path_iter);
109+
if (test__start_subtest("path_walk_example"))
110+
test_path_walk();
12111
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/* Copyright (c) 2025 Meta Platforms, Inc. and affiliates. */
3+
4+
#include "vmlinux.h"
5+
#include <errno.h>
6+
#include <bpf/bpf_helpers.h>
7+
#include <bpf/bpf_tracing.h>
8+
#include <bpf/bpf_core_read.h>
9+
#include "bpf_kfuncs.h"
10+
#include "bpf_misc.h"
11+
12+
char _license[] SEC("license") = "GPL";
13+
14+
__u32 monitored_pid;
15+
16+
#define BUF_SIZE 1024
17+
char parent_path_buf[BUF_SIZE] = {};
18+
char parent_xattr_buf[BUF_SIZE] = {};
19+
char grand_parent_path_buf[BUF_SIZE] = {};
20+
char grand_parent_xattr_buf[BUF_SIZE] = {};
21+
22+
static __always_inline void d_path_and_read_xattr(struct path *p, char *path, char *xattr)
23+
{
24+
struct bpf_dynptr ptr;
25+
struct dentry *dentry;
26+
27+
if (!p)
28+
return;
29+
bpf_path_d_path(p, path, BUF_SIZE);
30+
bpf_dynptr_from_mem(xattr, BUF_SIZE, 0, &ptr);
31+
dentry = p->dentry;
32+
if (dentry)
33+
bpf_get_dentry_xattr(dentry, "user.bpf.selftests", &ptr);
34+
}
35+
36+
SEC("lsm.s/file_open")
37+
int BPF_PROG(test_file_open, struct file *f)
38+
{
39+
__u32 pid = bpf_get_current_pid_tgid() >> 32;
40+
struct bpf_iter_path path_it;
41+
struct path *p;
42+
43+
if (pid != monitored_pid)
44+
return 0;
45+
46+
bpf_iter_path_new(&path_it, &f->f_path, 0);
47+
48+
/* Get d_path and xattr for the parent directory */
49+
p = bpf_iter_path_next(&path_it);
50+
d_path_and_read_xattr(p, parent_path_buf, parent_xattr_buf);
51+
52+
/* Get d_path and xattr for the grand parent directory */
53+
p = bpf_iter_path_next(&path_it);
54+
d_path_and_read_xattr(p, grand_parent_path_buf, grand_parent_xattr_buf);
55+
56+
bpf_iter_path_destroy(&path_it);
57+
58+
return 0;
59+
}

0 commit comments

Comments
 (0)