99#include <bpf/bpf_core_read.h>
1010// clang-format on
1111
12+ /**
13+ * PATH_MAX is defined in the kernel as 4096 which translates to 0x1000.
14+ * This define gives as an easy way to clamp path lengths
15+ */
16+ #define PATH_MAX_MASK (PATH_MAX - 1)
17+
18+ /**
19+ * Helper for keeping the verifier happy.
20+ *
21+ * Whenever a path is interacted with in a buffer, this macro can be
22+ * used to convince the verifier no more than PATH_MAX bytes will be
23+ * accessed.
24+ */
25+ #define PATH_LEN_CLAMP (len ) ((len) & PATH_MAX_MASK)
26+
1227struct d_path_ctx {
1328 struct helper_t * helper ;
14- struct path root ;
29+ struct path * root ;
1530 struct mount * mnt ;
1631 struct dentry * dentry ;
1732 int offset ;
@@ -26,24 +41,42 @@ static long __d_path_inner(uint32_t index, void* _ctx) {
2641 struct mount * mnt = ctx -> mnt ;
2742 struct dentry * mnt_root = BPF_CORE_READ (mnt , mnt .mnt_root );
2843
44+ if (dentry == ctx -> root -> dentry && & mnt -> mnt == ctx -> root -> mnt ) {
45+ // Found the root of the process, we are done
46+ ctx -> success = true;
47+ return 1 ;
48+ }
49+
2950 if (dentry == mnt_root ) {
3051 struct mount * m = BPF_CORE_READ (mnt , mnt_parent );
3152 if (m != mnt ) {
53+ // Current dentry is a mount root different to the previous one we
54+ // had (to prevent looping), switch over to that mount position
55+ // and keep walking up the path.
3256 ctx -> dentry = BPF_CORE_READ (mnt , mnt_mountpoint );
3357 ctx -> mnt = m ;
3458 return 0 ;
3559 }
60+
61+ // Ended up in a global root, the path might need re-processing or
62+ // the root is not attached yet, we are not getting a better path,
63+ // so we assume we are correct and stop iterating.
3664 ctx -> success = true;
3765 return 1 ;
3866 }
3967
4068 if (dentry == parent ) {
69+ // We escaped the mounts and ended up at (most likely) the root of
70+ // the device, the path we formed will be wrong.
71+ //
72+ // This may happen in race conditions where some dentries go away
73+ // while we are iterating.
4174 return 1 ;
4275 }
4376
4477 struct qstr d_name ;
4578 BPF_CORE_READ_INTO (& d_name , dentry , d_name );
46- int len = d_name .len & ( PATH_MAX - 1 );
79+ int len = PATH_LEN_CLAMP ( d_name .len );
4780 if (len <= 0 || len >= ctx -> buflen ) {
4881 return 1 ;
4982 }
@@ -52,7 +85,7 @@ static long __d_path_inner(uint32_t index, void* _ctx) {
5285 if (offset <= 0 ) {
5386 return 1 ;
5487 }
55- offset &= PATH_MAX - 1 ;
88+ offset = PATH_LEN_CLAMP ( offset ) ;
5689
5790 if (bpf_probe_read_kernel (& ctx -> helper -> buf [offset ], len , d_name .name ) != 0 ) {
5891 return 1 ;
@@ -80,7 +113,7 @@ __always_inline static long __d_path(const struct path* path, char* buf, int buf
80113 return -1 ;
81114 }
82115
83- int offset = (buflen - 1 ) & ( PATH_MAX - 1 );
116+ int offset = PATH_LEN_CLAMP (buflen - 1 );
84117 struct d_path_ctx ctx = {
85118 .buflen = buflen ,
86119 .helper = get_helper (),
@@ -91,10 +124,10 @@ __always_inline static long __d_path(const struct path* path, char* buf, int buf
91124 return -1 ;
92125 }
93126
94- struct task_struct * task = (struct task_struct * )bpf_get_current_task ();
127+ struct task_struct * task = (struct task_struct * )bpf_get_current_task_btf ();
95128 ctx .helper -> buf [offset ] = '\0' ; // Ensure null termination
96129
97- BPF_CORE_READ_INTO ( & ctx .root , task , fs , root ) ;
130+ ctx .root = & task -> fs -> root ;
98131 ctx .mnt = container_of (path -> mnt , struct mount , mnt );
99132 BPF_CORE_READ_INTO (& ctx .dentry , path , dentry );
100133
@@ -103,7 +136,7 @@ __always_inline static long __d_path(const struct path* path, char* buf, int buf
103136 return -1 ;
104137 }
105138
106- bpf_probe_read_str (buf , buflen , & ctx .helper -> buf [ctx .offset & ( PATH_MAX - 1 )]);
139+ bpf_probe_read_str (buf , buflen , & ctx .helper -> buf [PATH_LEN_CLAMP ( ctx .offset )]);
107140 return buflen - ctx .offset ;
108141}
109142
0 commit comments