Appearance
Kprobes Reference
Kprobes attach to kernel functions or syscall entry/return points. They are the primary collection mechanism for process execution, network activity, file access, and security-sensitive syscall monitoring. Unlike BPF LSM hooks, kprobes can run at both entry and return (via returnArg), making them suitable for capturing return values and confirming whether an operation succeeded.
Kprobes support Post (observe) and Signal (kill) actions. The Override (block) action is not supported on kprobes. It is available only on BPF LSM hooks.
Always-on baseline policies
The sensor writes and loads the following kprobe policies at startup. They are active on every node from the first heartbeat. They cannot be removed while the sensor is running; removing them would require restarting the sensor process.
| Policy file | What it covers |
|---|---|
telovix-network-baseline | TCP connect, close, accept; UDP sendmsg |
telovix-dns-uprobe | getaddrinfo hostname lookups (uprobe on libc) |
telovix-privilege-baseline | setuid, setgid, setreuid, setregid, setresuid, setresgid |
telovix-syscall-kprobes | ptrace, mount, socket, chroot, chmod/fchmodat, extended attribute writes, symlink/rename to authorized_keys, seccomp, flock, process_vm_writev, ioctl(FS_IOC_SETFLAGS), setns, unshare |
telovix-listen-baseline | inet_listen (new listening sockets) |
telovix-file-open (3 parts) | sys_openat for file reads and writes to credential, config, binary, library, log, persistence, and kernel paths |
telovix-security-syscalls | sys_kill, sys_dup2, sys_dup3, sys_mmap with PROT_EXEC, sys_capset |
telovix-kmod-monitor | sys_init_module, sys_finit_module, sys_delete_module |
telovix-lsm-baseline | BPF LSM hooks (see LSM Hooks Reference) |
telovix-process-lifecycle | sys_clone, sys_execveat, sys_memfd_create, sys_chdir, sys_fchdir, sys_unshare, sys_clone3 |
Network baseline (telovix-network-baseline)
| Call | syscall | Key args | Event kind | Purpose |
|---|---|---|---|---|
tcp_connect | false | sock (index 0) | network_connect | Outbound TCP connection attempt |
tcp_close | false | sock (index 0) | network_flow | TCP flow completion; triggers flow duration and state recording |
inet_csk_accept | false | sock (index 0) | network_accept | Inbound TCP connection accepted |
udp_sendmsg | false | sock (index 0) | dns_query or network_connect | UDP send; DNS port 53/853/5353 produces dns_query, others produce network_connect |
sys_sendto | true | sockaddr (index 4) | network_connect | UDP connect via sendto with explicit destination |
These hooks are kernel-level functions (syscall: false) except for sys_sendto. They use the sock type which exposes the full socket metadata including source and destination addresses.
DNS uprobe (telovix-dns-uprobe)
| Call | Type | Args | Event kind |
|---|---|---|---|
getaddrinfo (libc uprobe) | uprobe | string hostname (index 0), string service (index 1) | dns_lookup |
The uprobe attaches to getaddrinfo in the libc shared library. The libc path is architecture-specific:
x86_64:/lib/x86_64-linux-gnu/libc.so.6aarch64:/lib/aarch64-linux-gnu/libc.so.6
This uprobe enables the sensor to correlate hostname lookups with subsequent tcp_connect events to produce dns_resolution events.
Privilege baseline (telovix-privilege-baseline)
All hooks use syscall: true and capture return values.
| Call | Args | Event kind | What it captures |
|---|---|---|---|
sys_setuid | uint32 (new UID) | privilege_change | UID change; return value confirms success |
sys_setgid | uint32 (new GID) | privilege_change | GID change |
sys_setreuid | int, int (real UID, effective UID) | privilege_change | Real + effective UID swap |
sys_setregid | int, int | privilege_change | Real + effective GID swap |
sys_setresuid | int, int, int (real, effective, saved) | privilege_change | Three-UID change |
sys_setresgid | int, int, int | privilege_change | Three-GID change |
Syscall kprobes (telovix-syscall-kprobes)
| Call | Key selector | Event kind | Purpose |
|---|---|---|---|
sys_ptrace | None (all ptrace calls) | ptrace | Debugger attach, trace operations |
sys_setns | None | namespace_create | Namespace switch |
sys_mount | None (all mounts) | mount | Filesystem mount |
sys_socket | index 0 == 44 (AF_XDP) | socket_create | AF_XDP raw socket creation (kernel bypass indicator) |
sys_chroot | None | chroot | Chroot jail creation |
sys_fchmodat | index 2 Mask 3072 (setuid/setgid bits) | setcap | SUID/SGID bit set on a file |
sys_chmod | index 1 Mask 3072 (setuid/setgid bits) | setcap | SUID/SGID bit set |
sys_setxattr | None | file_write | Extended attribute write |
sys_lsetxattr | None | file_write | Extended attribute write (symlink) |
sys_fsetxattr | None | file_write | Extended attribute write (fd) |
sys_ioctl | index 1 == 21520 (FS_IOC_SETFLAGS, 0x5410) | file_write | chattr immutable flag set (suppressed for shell binaries) |
sys_symlinkat | index 2 Postfix authorized_keys | file_write | Symlink targeting authorized_keys |
sys_symlink | index 1 Postfix authorized_keys | file_write | Symlink targeting authorized_keys |
sys_renameat2 | index 3 Postfix authorized_keys | file_write | Rename into authorized_keys |
sys_renameat | index 3 Postfix authorized_keys | file_write | Rename into authorized_keys |
sys_rename | index 1 Postfix authorized_keys | file_write | Rename into authorized_keys |
sys_seccomp | index 0 == 1 (SECCOMP_SET_MODE_FILTER) | file_write | Seccomp filter installation |
sys_flock | index 1 Mask 2 (exclusive lock) | file_write | Exclusive file lock (single-instance guard pattern) |
sys_process_vm_writev | None | ptrace | Cross-process memory write (ptrace-equivalent capability) |
The sys_socket hook uses selector index 0 == 44 which corresponds to AF_XDP (eXpress Data Path), a kernel-bypass socket family. Creating an AF_XDP socket is an indicator that a process may be bypassing the normal network stack and thus eBPF visibility.
The sys_ioctl hook fires on FS_IOC_SETFLAGS (0x5410 = 21520 decimal), which is the chattr immutable flag ioctl. Events are suppressed for known shell binaries because shells use the numerically-identical TIOCSPGRP ioctl for job control.
The mask value 3072 for sys_chmod/sys_fchmodat captures mode bits 0o6000 (octal), which is the bitmask for SUID (0o4000) and SGID (0o2000).
Listen baseline (telovix-listen-baseline)
| Call | Args | Event kind |
|---|---|---|
inet_listen | sock (index 0), int backlog (index 1) | network_listen |
Fires when a process calls listen() to accept incoming TCP connections. Every new listening socket is recorded.
File open policies (telovix-file-open, telovix-file-open-2, telovix-file-open-3)
All three policies hook sys_openat (syscall: true) with args int (dirfd, index 0), string (path, index 1), int (flags, index 2).
The single policy was split into three parts because Tetragon enforces a maximum of 5 selectors per policy (reduced from 8 in older versions). With 19+ selectors, the original single policy exceeded that limit and failed to load.
Policy 1 (telovix-file-open) monitors:
- Credential files:
/etc/shadow,/etc/passwd,/etc/sudoers,/etc/gshadow,/etc/pam.d/ - Kubernetes credentials:
/var/run/secrets/kubernetes.io/,/etc/kubernetes/,/root/.kube/ - SSH server host keys:
/etc/ssh/ssh_host* - System binary directories:
/usr/bin/,/usr/sbin/,/bin/,/sbin/ - Library directories:
/lib/,/lib64/,/usr/lib/, and architecture-specific security subdirectories - Security logs:
/var/log/auth*,/var/log/secure,/var/log/audit/ - Persistence paths:
/etc/profile*,/etc/bash.bashrc,/etc/systemd/system/,/etc/udev/rules.d/ - Kernel module paths:
/lib/modules/,/etc/modprobe.d/,/proc/sysrq-trigger,/sys/kernel/ - DPDK/VFIO paths:
/dev/vfio/,/dev/hugepages/, SR-IOV sysfs paths (telecom user plane bypass detection) - Per-user shell rc files (Postfix match on
/.bashrc,/.zshrc, etc.) - PAM module files:
pam_unix.so,pam_exec.so, etc. - LD preload hijack:
/etc/ld.so*
Policies 2 and 3 cover additional paths with the same sys_openat hook, split across additional selector groups.
Event kind: file_open
Security syscalls (telovix-security-syscalls)
| Call | Key selector | Event kind | Purpose |
|---|---|---|---|
sys_kill | None | signal | Signal sent between processes |
sys_dup2 | None | fd_dup | File descriptor duplication |
sys_dup3 | None | fd_dup | File descriptor duplication (with flags) |
sys_mmap | index 2 Mask 4 (PROT_EXEC) | mmap_exec | Executable memory mapping (JIT, shellcode detection) |
sys_capset | None | cap_change | Capability set change |
The sys_mmap selector Mask: 4 captures mappings with PROT_EXEC set in the protection flags (bit 2). This detects code injection and JIT compilation into anonymous executable memory regions.
Kernel module monitor (telovix-kmod-monitor)
| Call | Args | Event kind | Purpose |
|---|---|---|---|
sys_init_module | uint64 (memory image) | module_load or kmod_load | Kernel module loading from memory |
sys_finit_module | int (fd) | module_load or kmod_load | Kernel module loading from file descriptor |
sys_delete_module | string (name), int (flags) | module_load | Kernel module unloading |
This policy is removed during kernel module enforcement activation (block-kmod-load template). The LSM-based kernel_read_file hook in telovix-lsm-baseline handles blocking; this kprobe policy handles observation only.
Process lifecycle (telovix-process-lifecycle)
| Call | Args | Event kind | Purpose |
|---|---|---|---|
sys_clone | uint64 (flags) | namespace_create or process_fork | Process creation and namespace flags detection |
sys_execveat | int (dirfd), string (path), int (flags) | process_exec | Execution from file descriptor |
sys_memfd_create | string (name), uint64 (flags) | mmap_exec | Anonymous in-memory file creation (fileless execution) |
sys_chdir | string (path) | chdir | Working directory change (return value captured) |
sys_fchdir | int (fd) | chdir | Working directory change via fd |
sys_unshare | int (flags) | namespace_create | Namespace detach without fork |
sys_clone3 | uint64 (struct clone_args flags field) | namespace_create or process_fork | Modern clone variant (container runtimes) |
The comment in the source notes: "sys_clone3: modern clone variant used by unshare --fork and newer container runtimes."
Writing custom kprobe rules
Custom kprobe rules follow the same TracingPolicy schema. A minimal observe rule:
yaml
apiVersion: cilium.io/v1alpha1
kind: TracingPolicy
metadata:
name: telovix-custom-observe-execve-args
spec:
kprobes:
- call: sys_execve
syscall: true
args:
- index: 0
type: string
- index: 1
type: string
selectors:
- matchArgs:
- index: 1
operator: Prefix
values:
- "/tmp/"
matchActions:
- action: PostCommon arg types for kprobes:
| Type string | Used for |
|---|---|
string | Null-terminated string arguments (file paths, names) |
int | Signed 32-bit integers |
uint32 | Unsigned 32-bit integers (UIDs, GIDs) |
uint64 | Unsigned 64-bit integers (memory addresses, clone flags) |
int64 | Signed 64-bit integers |
sock | Socket objects (kernel struct sock *) |
sockaddr | Socket address structures |
Limitations of kprobes
- No
Overrideaction: kprobes cannot block operations. Use BPF LSM hooks for pre-execution denial. - PREEMPT_RT kernels: kprobes with
syscall: truethat useBPF_MODIFY_RETURNfail verification on real-time kernels. The sensor detects RT kernels at startup and loads RT-safe policies only. - Return value hooks (
returnArg): Available but the function must be compiled with frame pointers or be accessible to BTF. Not all kernel functions support return kprobes on all kernel versions.