Events
owLSM produces two types of output: Events and Errors.
Events - These are the normal output that informs us on whats happening on the system. The events are sent to STDOUT.
Errors - Error messages that report about errors and issues owLSM kernel component has faced. The errors are sent to STDERR.
Most of the errors aren’t critical and just inform us about thing like “failed to get cmd of pid 1778”
Event Structure
Every event shares a common top-level structure. The data field varies depending on the event type.
{
"id": 42,
"type": "FILE_CREATE",
"action": "ALLOW_EVENT",
"matched_rule_id": 0,
"matched_rule_metadata": {
"description": ""
},
"had_error": 0,
"process": { },
"parent_process": { },
"time": 123456789012345,
"data": { }
}
Top-Level Fields
| Field | Type | Description |
|---|---|---|
id |
int | Monotonically increasing event ID, global across all event types |
type |
string | Event type. See Event Types |
action |
string | Action taken. See Actions |
matched_rule_id |
int | ID of the matched rule (0 if no rule matched) |
matched_rule_metadata |
object | Metadata from the matched rule (e.g. description) |
had_error |
int | Currently not supported |
process |
object | The process that triggered the event. See Process Object |
parent_process |
object | The parent of the triggering process. See Process Object |
time |
int | Nanoseconds since system boot (bpf_ktime_get_ns). This is a monotonic clock that starts at 0 when the system boots — it is not Unix epoch time. To convert to wall-clock time, add the difference between the current epoch time and the system uptime. |
data |
object | Event-specific data (varies by type). See Event Data by Type |
Event Types
| Type | Description |
|---|---|
EXEC |
Process execution |
FORK |
Process fork |
EXIT |
Process exit |
FILE_CREATE |
Regular file creation |
UNLINK |
File deletion |
MKDIR |
Directory creation |
RMDIR |
Directory deletion |
CHMOD |
Permission change |
CHOWN |
Ownership change |
WRITE |
File write |
READ |
File read |
RENAME |
File rename / move |
NETWORK |
Network connection (TCP) |
Actions
| Action | Description |
|---|---|
ALLOW_EVENT |
Do nothing. Event is sent normally |
BLOCK_EVENT |
Block the syscall/event |
BLOCK_KILL_PROCESS |
Block the event and terminate the process |
BLOCK_KILL_PROCESS_KILL_PARENT |
Block the event and terminate the process and its parent |
KILL_PROCESS |
Don’t block the event but terminate the process |
EXCLUDE_EVENT |
Don’t send the event. Excluded events are not sent to userspace, so you will never recieve such event |
File Types
| Value | Description |
|---|---|
UNKNOWN_FILE_TYPE | Unknown or unrecognized file type |
REGULAR_FILE | Regular file |
DIRECTORY | Directory |
SYMLINK | Symbolic link |
BLOCK_DEVICE | Block device |
CHAR_DEVICE | Character device |
SOCKET | Socket |
FIFO | Named pipe (FIFO) |
NO_FILE | No file (e.g. anonymous fd) |
Connection Directions
| Value | Description |
|---|---|
INCOMING | Inbound connection |
OUTGOING | Outbound connection |
Process Object
Process Object — All process objects share this structure: process, parent_process, target.process, etc
{
"pid": 1234,
"ppid": 1000,
"ruid": 0,
"rgid": 0,
"euid": 0,
"egid": 0,
"suid": 0,
"cgroup_id": 5678,
"start_time": 1707561200000000,
"ptrace_flags": 0,
"file": { File Object },
"cmd": "bash -c echo hello",
"shell_command": "ls -la /etc",
"stdio_file_descriptors_at_process_creation": {
"stdin": "REGULAR_FILE",
"stdout": "REGULAR_FILE",
"stderr": "REGULAR_FILE"
}
}
| Field | Type | Description |
|---|---|---|
pid | int | Process ID |
ppid | int | Parent process ID |
ruid | int | Real user ID |
rgid | int | Real group ID |
euid | int | Effective user ID |
egid | int | Effective group ID |
suid | int | SUID |
cgroup_id | int | Cgroup ID |
start_time | int | Process start time (nanoseconds since boot) |
ptrace_flags | int | Ptrace flags |
file | object | Process executable. See File Object |
cmd | string | Command line arguments |
shell_command | string | (Beta) Shell command typed in an interactive session. Populated only for monitored shells (Bash, Zsh, Dash). See Shell Commands |
stdio_file_descriptors_at_process_creation | object | File types of stdin, stdout, stderr at process creation. Values are FILE_TYPE enums |
File Object
File Object — All file objects share this structure: target.file, process.file, etc.
{
"inode": 654321,
"dev": 2049,
"path": "/usr/bin/bash",
"owner": {
"uid": 0,
"gid": 0
},
"mode": 33261,
"type": "REGULAR_FILE",
"suid": 0,
"sgid": 0,
"last_modified_seconds": 1700000000,
"nlink": 1,
"filename": "bash"
}
| Field | Type | Description |
|---|---|---|
inode | int | Inode number |
dev | int | Device number |
path | string | Absolute file path |
owner.uid | int | File owner user ID |
owner.gid | int | File owner group ID |
mode | int | File permission mode |
type | enum FILE_TYPE | File type |
suid | int | SUID bit |
sgid | int | SGID bit |
last_modified_seconds | int | Last modification time in seconds (epoch) |
nlink | int | Hard link count |
filename | string | Filename (basename only) |
Event Data by Type
FILE_CREATE / UNLINK / MKDIR / RMDIR / READ / WRITE — Target file events
These events all share the same data structure — a single target file.
For MKDIR and RMDIR, the file type will be DIRECTORY.
"data": {
"target": {
"file": { File Object }
}
}
EXEC — Process execution event
"data": {
"target": {
"process": { Process Object }
}
}
CHMOD — Permission change event
"data": {
"target": {
"file": { File Object }
},
"chmod": {
"requested_mode": 33261
}
}
CHOWN — Ownership change event
"data": {
"target": {
"file": { File Object }
},
"chown": {
"requested_owner_uid": 0, // Due to an LSM bug, these are always 0
"requested_owner_gid": 0 // Due to an LSM bug, these are always 0
}
}
RENAME — File rename / move event
"data": {
"flags": 0,
"rename": {
"source_file": { File Object },
"destination_file": { File Object }
}
}
NETWORK — Network connection event
"data": {
"network": {
"direction": "OUTGOING",
"source_ip": "192.168.1.100",
"destination_ip": "93.184.216.34",
"source_port": 54321,
"destination_port": 443,
"protocol": 6,
"ip_type": 2
}
}
EXIT — Process exit event
"data": {
"exit_code": 0,
"signal": 0
}
FORK — Process fork event
Fork events have no additional data fields. The data field is an empty object {}.
Error Structure
{
"details": "bpf_probe_read_user failed. pid: 1837369",
"error_code": -1,
"location": "get_cmd_from_task:34"
}
Error Fields
| Field | Type | Description |
|---|---|---|
details |
string | the message that is logged in owLSM kernel componenet |
error_code |
int | code. mostly -1 |
location |
string | function name:line number |
FlatBuffers output
When output_type is set to "FLATBUFFERS", owLSM writes events and errors as size-prefixed FlatBuffers instead of JSON. The FlatBuffers structure is identical to the JSON structure.
Wire Format
Each message on the stream is framed as:
┌─────────────────────┬────────────────────┐┌─────────────────────┬────────────────────┐
│ 4 bytes prefix │ N bytes ││ 4 bytes prefix │ M bytes │
│ indicating message │ FlatBuffer payload ││ indicating message │ FlatBuffer payload │
│ size. Size N | |│ size. Size M | |
└─────────────────────┴────────────────────┘└─────────────────────┴────────────────────┘
- Events are written to stdout; Errors are written to stderr.
- Read 4 bytes (little-endian
uint32) to get the payload size, then read exactly that many bytes for the FlatBuffer. - Use
GetSizePrefixedRoot<Event>()orGetSizePrefixedRoot<Error>()to access the data with zero-copy reads.
Schema and Headers
The FlatBuffers schema and pre-generated C++ headers are included in the release package:
owlsm/flatbuffers/
├── README.md
├── schema/
│ └── owlsm_events.fbs # Source-of-truth schema
└── include/
└── owlsm_events_generated.h # Generated C++ header
Use the .fbs schema to generate bindings for any language supported by FlatBuffers (Python, Go, Rust, Java, etc.).
The same schema applies to both events and errors.