Skip to content

Commit 49ca519

Browse files
committed
Add comments, use PATH_LEN_CLAMP and restore a missing stop condition
Added comments to help clarify some of the logic around d_path. Used PATH_LEN_CLAMP instead of raw `& (PATH_MAX -1)` operations, documenting the macro itself to make its purpose more obvious. Restored the d_path stop condition of reaching the root of the current task fs, which was accidentally removed when moving from the original implementation.
1 parent bd4821d commit 49ca519

3 files changed

Lines changed: 48 additions & 13 deletions

File tree

fact-ebpf/src/bpf/bound_path.h

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,8 @@
1111
#include <bpf/bpf_core_read.h>
1212
// clang-format on
1313

14-
#define PATH_MAX_MASK (PATH_MAX - 1)
15-
#define path_len_clamp(len) ((len) & PATH_MAX_MASK)
16-
1714
__always_inline static char* path_safe_access(char* p, unsigned int offset) {
18-
return &p[path_len_clamp(offset)];
15+
return &p[PATH_LEN_CLAMP(offset)];
1916
}
2017

2118
__always_inline static void path_write_char(char* p, unsigned int offset, char c) {
@@ -34,7 +31,7 @@ __always_inline static struct bound_path_t* _path_read(struct path* path, bool u
3431
}
3532

3633
// Ensure length is within PATH_MAX for the verifier
37-
bound_path->len = path_len_clamp(bound_path->len);
34+
bound_path->len = PATH_LEN_CLAMP(bound_path->len);
3835

3936
return bound_path;
4037
}
@@ -63,7 +60,7 @@ __always_inline static enum path_append_status_t path_append_dentry(struct bound
6360
}
6461

6562
char* path_offset = path_safe_access(path->path, path->len);
66-
if (bpf_probe_read_kernel(path_offset, path_len_clamp(len), d_name.name)) {
63+
if (bpf_probe_read_kernel(path_offset, PATH_LEN_CLAMP(len), d_name.name)) {
6764
return PATH_APPEND_READ_ERROR;
6865
}
6966

fact-ebpf/src/bpf/d_path.h

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,24 @@
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+
1227
struct 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

fact-ebpf/src/bpf/types.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,13 @@
66
* other sources of bloat into this file.
77
*/
88

9+
/**
10+
* Kernel constant, taken from:
11+
* https://github.com/torvalds/linux/blob/f0b9d8eb98dfee8d00419aa07543bdc2c1a44fb1/include/uapi/linux/limits.h#L13
12+
*/
913
#define PATH_MAX 4096
1014
#define TASK_COMM_LEN 16
15+
1116
#define LINEAGE_MAX 2
1217

1318
#define LPM_SIZE_MAX 256

0 commit comments

Comments
 (0)