Skip to content

Commit 942e0cd

Browse files
committed
Add BPF LSM ptrace_access_check hook for cross-branch ptrace denial
Signed-off-by: Cong Wang <cwang@multikernel.io>
1 parent be542ca commit 942e0cd

1 file changed

Lines changed: 40 additions & 3 deletions

File tree

src/branching/process/bpf/branch_tracker.bpf.c

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@
22
/*
33
* branch_tracker.bpf.c — BPF LSM program for branch process tracking.
44
*
5-
* Hooks task_alloc, task_free, and task_kill to inescapably track all
6-
* descendants of registered branch root PIDs. Supports atomic
7-
* fork-denial during branch teardown and cross-branch signal isolation.
5+
* Hooks task_alloc, task_free, task_kill, and ptrace_access_check to
6+
* inescapably track all descendants of registered branch root PIDs.
7+
* Supports atomic fork-denial during branch teardown, cross-branch
8+
* signal isolation, and cross-branch ptrace denial.
89
*
910
* Compile:
1011
* clang -g -O2 -target bpf -D__TARGET_ARCH_x86 \
@@ -99,6 +100,42 @@ int BPF_PROG(branch_task_kill, struct task_struct *target,
99100
return 0;
100101
}
101102

103+
/*
104+
* LSM hook: ptrace_access_check — fires on ptrace attach/peek/poke.
105+
*
106+
* Same boundary logic as task_kill: a tracked process can only ptrace
107+
* processes within its own branch. Untracked processes (the parent
108+
* orchestrator) are unrestricted.
109+
*
110+
* Without this, a malicious child could ptrace the parent or a sibling
111+
* branch process and read/write its memory, bypassing all other
112+
* isolation.
113+
*/
114+
SEC("lsm/ptrace_access_check")
115+
int BPF_PROG(branch_ptrace_access_check, struct task_struct *child,
116+
unsigned int mode)
117+
{
118+
__u32 tracer_pid = bpf_get_current_pid_tgid() >> 32;
119+
__u64 *tracer_bid = bpf_map_lookup_elem(&branch_pids, &tracer_pid);
120+
121+
/* Untracked tracer (parent/orchestrator) — always allow. */
122+
if (!tracer_bid)
123+
return 0;
124+
125+
__u32 target_pid = BPF_CORE_READ(child, tgid);
126+
__u64 *target_bid = bpf_map_lookup_elem(&branch_pids, &target_pid);
127+
128+
/* Target is not tracked — deny (protects parent). */
129+
if (!target_bid)
130+
return -1; /* -EPERM */
131+
132+
/* Both tracked — allow only within the same branch. */
133+
if (*tracer_bid != *target_bid)
134+
return -1; /* -EPERM */
135+
136+
return 0;
137+
}
138+
102139
/*
103140
* LSM hook: task_free — fires when a process exits.
104141
*

0 commit comments

Comments
 (0)