
SunnyDayBPF: eBPF-based post-syscall user-buffer telemetry deception research by Azizcan Daştan
SunnyDayBPF is an eBPF-based post-syscall user-buffer telemetry deception research technique originally proposed and researched by Azizcan Dastan.
The technique investigates whether data observed by user-space security, logging, or telemetry agents can be altered after a read-like syscall has completed, but before the agent parses, analyzes, or forwards that data to a downstream security pipeline.
The core idea is:
The event still happens.
The monitoring agent still reads data.
But the data observed by the agent may no longer fully represent the original event.
SunnyDayBPF focuses on the gap between ground truth and observed telemetry.
SunnyDayBPF Hook Points
========================
Telemetry Agent Process
+---------------------------------------------------------+
| |
| read() pread64() recvfrom() |
| | | | |
+-----|----------------|------------------|---------------+
| | |
======|================|==================|======= KERNEL BOUNDARY
| | |
kprobe:ksys_read kprobe:__x64_sys_ kprobe:__sys_
(save buf ptr) pread64 recvfrom
| (nested pt_regs) (save buf ptr)
| (save buf ptr) |
v v v
[syscall executes — data enters user buffer]
| | |
kretprobe kretprobe kretprobe
| | |
+--------+-------+---------+--------+
| |
read buffer into initialize
BPF scratch space scan_state
|
v
+------------------+
| TAIL CALL CHAIN |
| |
| scan_g0: SECURITY (4 rules, scan=177 bytes)
| scan_g1: SECURITY (4 rules, scan=173 bytes)
| scan_g2: SEVERITY (4 rules, scan=177 bytes)
| scan_g3: SEVERITY (1 rule, scan=251 bytes)
| scan_g4: PATH (4 rules, scan=132 bytes)
| scan_g5: AUTH (4 rules, scan=190 bytes)
| scan_g6: AUTH (1 rule, scan=249 bytes)
| scan_g7: NETWORK (3 rules, scan=249 bytes)
| scan_g8: PROCESS (4 rules, scan=173 bytes)
| scan_g9: CUSTOM (2 rules, scan=243 bytes)
| |
| emit_event: |
| perf event |
| + stats |
+------------------+
|
v
bpf_probe_write_user()
(modify agent's buffer)
|
v
read-back verification
(confirm write succeeded)
|
v
Agent continues with
modified data
| Syscall | Kernel Hook | Arg Extraction | Coverage |
|---|---|---|---|
read() | ksys_read | PT_REGS_PARM2 (direct) | File reads, pipes, /proc, log files |
pread64() | __x64_sys_pread64 | Nested pt_regs via bpf_probe_read_kernel (offset 104/RSI) | Random-access file reads, journald |
recvfrom() | __sys_recvfrom | PT_REGS_PARM2 (direct) | Network sockets, syslog forwarding |
The BPF verifier enforces a jump sequence limit of 8,192 conditional branches per program. SunnyDayBPF works around this using:
BPF_PROG_ARRAY): 31 rules split across 10 independent programs, each with its own verifier budget(d[i]|32)==lower reduces jumps per byte from 2 to 1 for alphabetic charactersmin(BUF_SIZE - max_pat, 7800 / jumps_per_iter) to stay within verifier limitsBPF_PERCPU_ARRAY for scratch buffer and scan state, shared across tail-called programsModern Linux security systems often rely on user-space agents that collect telemetry from files, sockets, pipes, APIs, kernel interfaces, or event streams.
These agents may forward telemetry to:
A common assumption is:
actual system behavior == collected telemetry == observed security data
SunnyDayBPF challenges that assumption.
The research explores a post-syscall deception model where a monitoring process receives data normally, but the buffer containing that data is modified before the process consumes it.
actual system behavior != observed telemetry
SunnyDayBPF is a post-syscall telemetry deception technique that studies the manipulation of user-space buffers belonging to selected telemetry-consuming processes.
At a high level, the technique follows this model:
sys_enter_*:
identify a target telemetry-consuming process
record the user-space buffer pointer involved in the read-like operation
sys_exit_*:
verify that the read-like operation completed successfully
inspect the returned user-space buffer
selectively alter telemetry-relevant content
verify write success via read-back
allow the target process to continue execution normally
This creates a mismatch between:
what happened on the system
and:
what the monitoring agent later observes, parses, and forwards
SunnyDayBPF identifies target processes by 5-character command name prefix matching.
| Agent | Prefix | Read Method | Effective? |
|---|---|---|---|
| Wazuh | wazuh | read() on log files, syslog, audit logs | Yes |
| OSSEC | ossec | read() on log files | Yes |
| Splunk UF | splun | read() on monitored files | Yes |
| Elastic Agent | elast | read() on log sources | Yes |
| Datadog Agent | datad | read() on logs and metrics | Yes |
| Cribl | cribl | read() for log routing | Yes |
| Agent | Prefix | Read Method | Effective? |
|---|---|---|---|
| rsyslog | rsysl | read() / recvfrom() on syslog | Yes |
| syslog-ng | syslo | read() / recvfrom() on syslog | Yes |
| Filebeat | fileb | read() on log files | Yes |
| Fluent-bit | fluen | read() / recvfrom() on inputs | Yes |
| Fluentd | fluen | read() / recvfrom() on inputs | Yes |
| Logstash | logst | read() / recvfrom() on pipeline | Yes |
| Promtail | promt | read() on log files (Loki) | Yes |
| Vector | vecto | read() on log sources | Yes |
| Agent | Prefix | Read Method | Effective? |
|---|---|---|---|
| Falco | falco | eBPF events collected via read() on perf buffer | Yes |
| osquery | osque | read() on /proc, log files, system tables | Yes |
| Agent | Prefix | Read Method | Effective? |
|---|---|---|---|
| Snort | snort | recvfrom() on packet capture | Yes |
| Suricata | suric | recvfrom() on packet capture | Yes |
| Zeek | zeek_ | recvfrom() on packet capture | Yes |