1 // SPDX-License-Identifier: GPL-2.0
3 #include <test_progs.h>
5 #include <linux/sched.h>
6 #include <sys/syscall.h>
8 #define MAX_PATH_LEN 128
11 #include "test_d_path.skel.h"
17 char paths
[MAX_FILES
][MAX_PATH_LEN
];
20 static int set_pathname(int fd
, pid_t pid
)
22 char buf
[MAX_PATH_LEN
];
24 snprintf(buf
, MAX_PATH_LEN
, "/proc/%d/fd/%d", pid
, fd
);
25 return readlink(buf
, src
.paths
[src
.cnt
++], MAX_PATH_LEN
);
28 static int trigger_fstat_events(pid_t pid
)
30 int sockfd
= -1, procfd
= -1, devfd
= -1;
31 int localfd
= -1, indicatorfd
= -1;
32 int pipefd
[2] = { -1, -1 };
36 /* unmountable pseudo-filesystems */
37 if (CHECK(pipe(pipefd
) < 0, "trigger", "pipe failed\n"))
39 /* unmountable pseudo-filesystems */
40 sockfd
= socket(AF_INET
, SOCK_STREAM
, 0);
41 if (CHECK(sockfd
< 0, "trigger", "socket failed\n"))
43 /* mountable pseudo-filesystems */
44 procfd
= open("/proc/self/comm", O_RDONLY
);
45 if (CHECK(procfd
< 0, "trigger", "open /proc/self/comm failed\n"))
47 devfd
= open("/dev/urandom", O_RDONLY
);
48 if (CHECK(devfd
< 0, "trigger", "open /dev/urandom failed\n"))
50 localfd
= open("/tmp/d_path_loadgen.txt", O_CREAT
| O_RDONLY
, 0644);
51 if (CHECK(localfd
< 0, "trigger", "open /tmp/d_path_loadgen.txt failed\n"))
53 /* bpf_d_path will return path with (deleted) */
54 remove("/tmp/d_path_loadgen.txt");
55 indicatorfd
= open("/tmp/", O_PATH
);
56 if (CHECK(indicatorfd
< 0, "trigger", "open /tmp/ failed\n"))
59 ret
= set_pathname(pipefd
[0], pid
);
60 if (CHECK(ret
< 0, "trigger", "set_pathname failed for pipe[0]\n"))
62 ret
= set_pathname(pipefd
[1], pid
);
63 if (CHECK(ret
< 0, "trigger", "set_pathname failed for pipe[1]\n"))
65 ret
= set_pathname(sockfd
, pid
);
66 if (CHECK(ret
< 0, "trigger", "set_pathname failed for socket\n"))
68 ret
= set_pathname(procfd
, pid
);
69 if (CHECK(ret
< 0, "trigger", "set_pathname failed for proc\n"))
71 ret
= set_pathname(devfd
, pid
);
72 if (CHECK(ret
< 0, "trigger", "set_pathname failed for dev\n"))
74 ret
= set_pathname(localfd
, pid
);
75 if (CHECK(ret
< 0, "trigger", "set_pathname failed for file\n"))
77 ret
= set_pathname(indicatorfd
, pid
);
78 if (CHECK(ret
< 0, "trigger", "set_pathname failed for dir\n"))
81 /* triggers vfs_getattr */
82 fstat(pipefd
[0], &fileStat
);
83 fstat(pipefd
[1], &fileStat
);
84 fstat(sockfd
, &fileStat
);
85 fstat(procfd
, &fileStat
);
86 fstat(devfd
, &fileStat
);
87 fstat(localfd
, &fileStat
);
88 fstat(indicatorfd
, &fileStat
);
91 /* triggers filp_close */
102 void test_d_path(void)
104 struct test_d_path__bss
*bss
;
105 struct test_d_path
*skel
;
108 skel
= test_d_path__open_and_load();
109 if (CHECK(!skel
, "setup", "d_path skeleton failed\n"))
112 err
= test_d_path__attach(skel
);
113 if (CHECK(err
, "setup", "attach failed: %d\n", err
))
117 bss
->my_pid
= getpid();
119 err
= trigger_fstat_events(bss
->my_pid
);
123 if (CHECK(!bss
->called_stat
,
125 "trampoline for security_inode_getattr was not called\n"))
128 if (CHECK(!bss
->called_close
,
130 "trampoline for filp_close was not called\n"))
133 for (int i
= 0; i
< MAX_FILES
; i
++) {
134 CHECK(strncmp(src
.paths
[i
], bss
->paths_stat
[i
], MAX_PATH_LEN
),
136 "failed to get stat path[%d]: %s vs %s\n",
137 i
, src
.paths
[i
], bss
->paths_stat
[i
]);
138 CHECK(strncmp(src
.paths
[i
], bss
->paths_close
[i
], MAX_PATH_LEN
),
140 "failed to get close path[%d]: %s vs %s\n",
141 i
, src
.paths
[i
], bss
->paths_close
[i
]);
142 /* The d_path helper returns size plus NUL char, hence + 1 */
143 CHECK(bss
->rets_stat
[i
] != strlen(bss
->paths_stat
[i
]) + 1,
145 "failed to match stat return [%d]: %d vs %zd [%s]\n",
146 i
, bss
->rets_stat
[i
], strlen(bss
->paths_stat
[i
]) + 1,
148 CHECK(bss
->rets_close
[i
] != strlen(bss
->paths_stat
[i
]) + 1,
150 "failed to match stat return [%d]: %d vs %zd [%s]\n",
151 i
, bss
->rets_close
[i
], strlen(bss
->paths_close
[i
]) + 1,
156 test_d_path__destroy(skel
);