Harden BCC syscall probe attachment
This commit is contained in:
parent
2d23e8b878
commit
93ac47dd82
2 changed files with 44 additions and 6 deletions
|
|
@ -22,7 +22,7 @@ _BPF_PROGRAM = r"""
|
|||
#include <uapi/linux/ptrace.h>
|
||||
#include <linux/sched.h>
|
||||
|
||||
#define ARGLEN 160
|
||||
#define ARGLEN 128
|
||||
|
||||
struct data_t {
|
||||
u32 pid;
|
||||
|
|
@ -64,6 +64,42 @@ int syscall__execve(struct pt_regs *ctx,
|
|||
"""
|
||||
|
||||
|
||||
def attach_kprobe_candidates(bpf, syscall: str, fn_name: str,
|
||||
extra: tuple[str, ...] = ()) -> str:
|
||||
"""Attach a kprobe to the first syscall symbol that exists on this kernel."""
|
||||
candidates = []
|
||||
try:
|
||||
candidates.append(bpf.get_syscall_fnname(syscall))
|
||||
except Exception:
|
||||
pass
|
||||
candidates.extend(extra)
|
||||
candidates.extend([
|
||||
f"__x64_sys_{syscall}",
|
||||
f"__x64_sys_{syscall}at",
|
||||
f"__arm64_sys_{syscall}",
|
||||
f"__arm64_sys_{syscall}at",
|
||||
f"__ia32_sys_{syscall}",
|
||||
f"__ia32_sys_{syscall}at",
|
||||
f"__sys_{syscall}",
|
||||
f"sys_{syscall}",
|
||||
])
|
||||
seen: set[str] = set()
|
||||
last_exc: Exception | None = None
|
||||
for fnname in candidates:
|
||||
if not fnname or fnname in seen:
|
||||
continue
|
||||
seen.add(fnname)
|
||||
try:
|
||||
bpf.attach_kprobe(event=fnname, fn_name=fn_name)
|
||||
return fnname
|
||||
except Exception as exc:
|
||||
last_exc = exc
|
||||
continue
|
||||
raise RuntimeError(
|
||||
f"could not attach {syscall} kprobe (tried {', '.join(sorted(seen))})"
|
||||
) from last_exc
|
||||
|
||||
|
||||
def available() -> tuple[bool, str]:
|
||||
"""Return (ok, reason). ok=True means the probe can be loaded."""
|
||||
if os.geteuid() != 0:
|
||||
|
|
@ -91,11 +127,14 @@ class BccExecSource:
|
|||
from bcc import BPF
|
||||
|
||||
self._bpf = BPF(text=_BPF_PROGRAM)
|
||||
fnname = self._bpf.get_syscall_fnname("execve")
|
||||
self._bpf.attach_kprobe(event=fnname, fn_name="syscall__execve")
|
||||
fnname = self._attach_execve_probe()
|
||||
self._bpf["events"].open_perf_buffer(self._handle, page_cnt=64)
|
||||
self._running = True
|
||||
|
||||
def _attach_execve_probe(self) -> str:
|
||||
assert self._bpf is not None
|
||||
return attach_kprobe_candidates(self._bpf, "execve", "syscall__execve")
|
||||
|
||||
def poll(self, timeout_ms: int = 200) -> None:
|
||||
if self._bpf is not None:
|
||||
self._bpf.perf_buffer_poll(timeout=timeout_ms)
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ from __future__ import annotations
|
|||
|
||||
from collections.abc import Callable
|
||||
|
||||
from .bcc_source import _decode, available
|
||||
from .bcc_source import _decode, attach_kprobe_candidates, available
|
||||
from .syscall_event import SyscallEvent
|
||||
|
||||
_BPF_PROGRAM = r"""
|
||||
|
|
@ -180,8 +180,7 @@ class BccSyscallSource:
|
|||
attached = 0
|
||||
for syscall, fn_name in _PROBES.items():
|
||||
try:
|
||||
event = self._bpf.get_syscall_fnname(syscall)
|
||||
self._bpf.attach_kprobe(event=event, fn_name=fn_name)
|
||||
attach_kprobe_candidates(self._bpf, syscall, fn_name)
|
||||
attached += 1
|
||||
except Exception as exc:
|
||||
self.attach_errors.append(f"{syscall}: {exc!r}")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue