Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,21 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [2.2.0] - 2026-03-15

### Added
- **WP1e: Process tree construction from tracepoint events** (`daemon/process_tree.c`): open-addressing hash map (linear probing, 1024 slots) storing PID -> {parent_pid, comm, birth_time}. Fed by fork/exec/exit events via `owl_ptree_on_event()` in the pipeline. Provides `owl_ptree_is_descendant()` and `owl_ptree_get_chain()` for correlation engine ancestry queries.
- `daemon/process_tree.h`: public API (init, destroy, insert, remove, lookup, is_descendant, get_chain, on_event)
- `tests/test_process_tree.c`: 8 unit tests (TDD) — insert/lookup, parent chain, ancestry chain, descendant check, remove, capacity, null inputs, reinsert after exit

### Changed
- `daemon/event_pipeline.h`: added `struct owl_ptree *ptree` field to pipeline context, added ptree parameter to `owl_pipeline_init()`
- `daemon/event_pipeline.c`: calls `owl_ptree_on_event()` after LD_PRELOAD check for process lifecycle events
- `daemon/main.c`: instantiates `struct owl_ptree`, passes to pipeline init, destroys on cleanup
- `daemon/Makefile`: added `process_tree.c` to SRCS
- `tests/Makefile`: added `test_process_tree` suite, linked `process_tree.o` into `test_event_pipeline`
- `tests/test_event_pipeline.c`: updated `owl_pipeline_init()` calls with NULL ptree parameter

## [2.1.0] - 2026-03-15

### Added
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ Runs on Graviton3 (c7g.large), Ubuntu 24.04, kernel 6.17.

- **kernel/** - loadable module. Kprobes on ptrace, /proc/pid/mem, process_vm_readv/writev, mmap, module load/unload. ARM64 system register monitoring. Chardev for event delivery.
- **ebpf/** - BPF LSM hooks returning -EPERM (ptrace_access_check, file_open for /proc/pid/mem + /dev/mem + /dev/kmem, file_mprotect). Tracepoints. Kprobe on do_init_module. Ring buffer to userspace.
- **daemon/** - epoll on chardev + BPF ring buffer. Policy engine. Signature scanner. CRC32 code integrity. Self-protection watchdog. TracerPid debugger detection. LD_PRELOAD environ scanning.
- **daemon/** - epoll on chardev + BPF ring buffer. Policy engine. Signature scanner. CRC32 code integrity. Self-protection watchdog. TracerPid debugger detection. LD_PRELOAD environ scanning. Process ancestry tree for correlation.
- **game/** - ncurses test target. Mutable state, function pointers, exported address.
- **cheats/** - 9 attack programs: process_vm_readv, /proc/pid/mem, /dev/mem, ptrace read, ptrace write, process_vm_writev, LD_PRELOAD, mprotect injection, debug registers.
- **platform/** - Lambda + API Gateway + DynamoDB telemetry receiver.
- **scripts/verify.sh** - E2E test. Baseline (cheats succeed) vs protected (cheats blocked). Machine-generated results.

## Status

v2.1.0. 107 unit tests, 12 suites. eBPF LSM returns EPERM on ptrace, /proc/pid/mem, /dev/mem, /dev/kmem, process_vm_writev. Module can't be unloaded while daemon runs. TracerPid polling detects debuggers attached before daemon start. LD_PRELOAD detection on exec.
v2.2.0. 115 unit tests, 13 suites. eBPF LSM returns EPERM on ptrace, /proc/pid/mem, /dev/mem, /dev/kmem, process_vm_writev. Module can't be unloaded while daemon runs. TracerPid polling detects debuggers attached before daemon start. LD_PRELOAD detection on exec. Process tree tracks ancestry for correlation engine.

Prototype limitations: linear signature scan, CRC32 not cryptographic, no fleet management.

Expand Down
1 change: 1 addition & 0 deletions daemon/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ DEPFLAGS = -MMD -MP -MF $(@:.o=.d)
SRCS := main.c \
bpf_loader.c \
event_pipeline.c \
process_tree.c \
sig_loader.c \
integrity.c \
self_protect.c \
Expand Down
7 changes: 7 additions & 0 deletions daemon/event_pipeline.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

#include "event_pipeline.h"
#include "preload_detect.h"
#include "process_tree.h"

static void pipeline_check_preload(struct owl_pipeline *pipe,
const struct owlbear_event *exec_ev);
Expand All @@ -28,11 +29,13 @@ static void pipeline_check_preload(struct owl_pipeline *pipe,
void owl_pipeline_init(struct owl_pipeline *pipe,
struct owl_policy *policy,
struct owl_sig_db *sig_db,
struct owl_ptree *ptree,
pid_t target, bool enforce, FILE *logf)
{
memset(pipe, 0, sizeof(*pipe));
pipe->policy = policy;
pipe->sig_db = sig_db;
pipe->ptree = ptree;
pipe->target_pid = target;
pipe->enforce = enforce;
pipe->log_file = logf;
Expand Down Expand Up @@ -94,6 +97,10 @@ enum owl_policy_action owl_pipeline_process(struct owl_pipeline *pipe,
if (ev->event_type == OWL_EVENT_PROCESS_EXEC)
pipeline_check_preload(pipe, ev);

/* Feed process lifecycle events into the process tree */
if (pipe->ptree)
owl_ptree_on_event(pipe->ptree, ev);

return action;
}

Expand Down
4 changes: 4 additions & 0 deletions daemon/event_pipeline.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

#include "owlbear_events.h"
#include "policy.h"
#include "process_tree.h"
#include "scanner.h"

/* Maximum size of game .text to scan (8 MB) */
Expand All @@ -26,6 +27,7 @@
struct owl_pipeline {
struct owl_policy *policy;
struct owl_sig_db *sig_db;
struct owl_ptree *ptree;
pid_t target_pid;
bool enforce;
FILE *log_file;
Expand All @@ -42,13 +44,15 @@ struct owl_pipeline {
* @pipe: Pipeline context
* @policy: Policy engine (ownership retained by caller)
* @sig_db: Signature database (ownership retained by caller)
* @ptree: Process tree (may be NULL; ownership retained by caller)
* @target: PID of the protected process
* @enforce: Whether to take enforcement actions
* @logf: Log file (may be NULL for stdout only)
*/
void owl_pipeline_init(struct owl_pipeline *pipe,
struct owl_policy *policy,
struct owl_sig_db *sig_db,
struct owl_ptree *ptree,
pid_t target, bool enforce, FILE *logf);

/**
Expand Down
8 changes: 7 additions & 1 deletion daemon/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "bpf_loader.h"
#include "event_pipeline.h"
#include "integrity.h"
#include "process_tree.h"
#include "policy.h"
#include "scanner.h"
#include "self_protect.h"
Expand Down Expand Up @@ -678,6 +679,7 @@ int main(int argc, char *argv[])

struct owl_policy policy;
struct owl_sig_db sig_db;
struct owl_ptree ptree;
struct owl_pipeline pipeline;
struct owl_integrity integrity;
struct owl_self_protect selfprot;
Expand Down Expand Up @@ -717,8 +719,11 @@ int main(int argc, char *argv[])
/* Non-fatal: scanner will just not match anything */
}

/* Initialize process tree */
owl_ptree_init(&ptree);

/* Initialize event pipeline */
owl_pipeline_init(&pipeline, &policy, &sig_db,
owl_pipeline_init(&pipeline, &policy, &sig_db, &ptree,
cfg.target_pid, cfg.enforce, log_file);

/* Open the kernel device */
Expand Down Expand Up @@ -786,6 +791,7 @@ int main(int argc, char *argv[])
pipeline.actions_kill, pipeline.sig_matches);

cleanup:
owl_ptree_destroy(&ptree);
if (bpf)
owl_bpf_destroy(bpf);
if (dev_fd >= 0)
Expand Down
Loading
Loading