Some kernels builds might inline vfs_getattr call within fstat syscall code path, so fentry/vfs_getattr trampoline is not called. Add security_inode_getattr to allowlist and switch the d_path test stat trampoline to security_inode_getattr. Keeping dentry_open and filp_close, because they are in their own files, so unlikely to be inlined, but in case they are, adding security_file_open. Adding flags that indicate trampolines were called and failing the test if any of them got missed, so it's easier to identify the issue next time.
Unified · Split
| @@ -1114,6 +1114,14 @@ BPF_CALL_3(bpf_d_path, struct path *, path, char *, buf, u32, sz) · 1113 unmodified lines | |||
| 1114 | } | 1114 | } |
| 1115 | 1115 | ||
| 1116 | BTF_SET_START(btf_allowlist_d_path) | 1116 | BTF_SET_START(btf_allowlist_d_path) |
| 1117 | #ifdef CONFIG_SECURITY | ||
| 1118 | BTF_ID(func, security_file_permission) | ||
| 1119 | BTF_ID(func, security_inode_getattr) | ||
| 1120 | BTF_ID(func, security_file_open) | ||
| 1121 | #endif | ||
| 1122 | #ifdef CONFIG_SECURITY_PATH | ||
| 1123 | BTF_ID(func, security_path_truncate) | ||
| 1124 | #endif | ||
| 1117 | BTF_ID(func, vfs_truncate) | 1125 | BTF_ID(func, vfs_truncate) |
| 1118 | BTF_ID(func, vfs_fallocate) | 1126 | BTF_ID(func, vfs_fallocate) |
| 1119 | BTF_ID(func, dentry_open) | 1127 | BTF_ID(func, dentry_open) |
| @@ -120,6 +120,16 @@ void test_d_path(void) · 119 unmodified lines | |||
| 120 | if (err < 0) | 120 | if (err < 0) |
| 121 | goto cleanup; | 121 | goto cleanup; |
| 122 | 122 | ||
| 123 | if (CHECK(!bss->called_stat, | ||
| 124 | "stat", | ||
| 125 | "trampoline for security_inode_getattr was not called\n")) | ||
| 126 | goto cleanup; | ||
| 127 | |||
| 128 | if (CHECK(!bss->called_close, | ||
| 129 | "close", | ||
| 130 | "trampoline for filp_close was not called\n")) | ||
| 131 | goto cleanup; | ||
| 132 | |||
| 123 | for (int i = 0; i < MAX_FILES; i++) { | 133 | for (int i = 0; i < MAX_FILES; i++) { |
| 124 | CHECK(strncmp(src.paths[i], bss->paths_stat[i], MAX_PATH_LEN), | 134 | CHECK(strncmp(src.paths[i], bss->paths_stat[i], MAX_PATH_LEN), |
| 125 | "check", | 135 | "check", |
| @@ -15,7 +15,10 @@ char paths_close[MAX_FILES][MAX_PATH_LEN] = {}; · 14 unmodified lines | |||
| 15 | int rets_stat[MAX_FILES] = {}; | 15 | int rets_stat[MAX_FILES] = {}; |
| 16 | int rets_close[MAX_FILES] = {}; | 16 | int rets_close[MAX_FILES] = {}; |
| 17 | 17 | ||
| 18 | SEC("fentry/vfs_getattr") | 18 | int called_stat = 0; |
| 19 | int called_close = 0; | ||
| 20 | |||
| 21 | SEC("fentry/security_inode_getattr") | ||
| 19 | int BPF_PROG(prog_stat, struct path *path, struct kstat *stat, | 22 | int BPF_PROG(prog_stat, struct path *path, struct kstat *stat, |
| 20 | __u32 request_mask, unsigned int query_flags) | 23 | __u32 request_mask, unsigned int query_flags) |
| 21 | { | 24 | { |
| @@ -23,6 +26,8 @@ int BPF_PROG(prog_stat, struct path *path, struct kstat *stat, · 1 unmodified line | |||
| 23 | __u32 cnt = cnt_stat; | 26 | __u32 cnt = cnt_stat; |
| 24 | int ret; | 27 | int ret; |
| 25 | 28 | ||
| 29 | called_stat = 1; | ||
| 30 | |||
| 26 | if (pid != my_pid) | 31 | if (pid != my_pid) |
| 27 | return 0; | 32 | return 0; |
| 28 | 33 | ||
| @@ -42,6 +47,8 @@ int BPF_PROG(prog_close, struct file *file, void *id) · 13 unmodified lines | |||
| 42 | __u32 cnt = cnt_close; | 47 | __u32 cnt = cnt_close; |
| 43 | int ret; | 48 | int ret; |
| 44 | 49 | ||
| 50 | called_close = 1; | ||
| 51 | |||
| 45 | if (pid != my_pid) | 52 | if (pid != my_pid) |
| 46 | return 0; | 53 | return 0; |
| 47 | 54 | ||