K8SEC / KERNEL DETECTION MODEL
Watch the kernel operation, then prove the effect
The operation has a lifecycle: userspace request → kernel entry → object resolution → LSM decision → return value → Tetragon event → workload enrichment → independent API evidence → analyst conclusion. Hook placement decides what is visible. A kprobe at entry can show intent before authorization; a return probe can establish the interface result; an LSM hook can show an authorization point; none by itself reconstructs the complete attack path.
Solid sequence = records present in the synthetic example. A displayed join is conditional; it does not prove causation. These are research diagrams, not live telemetry.
Four paths through the same evidence architecture
Select a path. The graph changes, but the conclusion never jumps from a sensor event straight to malware or escape. This is a synthetic exercise, not a live detector dashboard.
R03 · staged execution is a hypothesis, not a malware verdict
- Observed
- In the synthetic trace, N03 sees an execve request from a writable path, N04 sees memfd creation, and N06 sees a process-name change in that order within 180 seconds.
- Join gate
- Require the same cluster and Pod UID, event-time container identity, then inspect exec IDs and parent/child lineage. The shared Pod alone cannot prove one process performed all three actions.
- Benign alternative
- A compiler or update worker can stage a temporary executable and allocate anonymous files. A Java process can rename itself for legitimate diagnostics.
- Next evidence
- Pair entry with result, inspect image digest and executable provenance, compare with the approved workload baseline, and establish whether the anonymous object was executed.
R01 · credential access and accepted cross-namespace placement
- Observed
- A Tetragon file-permission event is followed by an API audit record for an accepted, non-dry-run cross-namespace Pod create within 120 seconds.
- Join gate
- Resolve a unique source Pod at request time, verify direct source-IP attribution rather than proxy/NAT inference, and match the effective ServiceAccount. A shared SA name or close timestamps alone are insufficient.
- Still unknown
- File access is not proof that a token was copied or used by this process. An accepted API request is not proof that the Pod reached Running or that code executed there.
- Negative control
- If the source IP maps to several Pods, the caller is a controller, the API operation is denied, or the request is dry-run, do not promote this to the cross-plane candidate.
R05 · three denied requests do not make a container escape
- Observed
- A same-Pod sequence requests setns, mount and a BPF operation within 90 seconds. In this control fixture all results are denied.
- Decision
- Report boundary-sensitive probing and the negative results. Do not call host access, kernel compromise, or successful privilege escalation.
- Next evidence
- For a success claim, establish return values, effective capabilities, relevant namespace IDs, the host object reached, and an independently observed host-side effect.
- Coverage caveat
- N21 raw syscall mapping can duplicate these signals; duplicate events do not count as independent stages. A missing event may reflect hook or collector loss.
Approved build worker · an expected signal is a negative control
- Observed
- A signed, scheduled build job executes a temporary build helper under an expected parent and image digest.
- Decision
- The N03 signal still exists, but the owner-approved job and executable provenance explain it. Keep the raw event; suppress only the narrow workload context after review.
- Regression test
- Change the parent, image digest, namespace or time window. The same broad exception must no longer match. If it does, the exception is unsafe.
- Limit
- An approved identity does not make every later action benign; a successful sensitive API operation needs its own authorization review.
Instrumentation choice is part of the detection claim
| Point | Good for | Blind spot / stability | Verification |
|---|---|---|---|
| Syscall entry / tracepoint | Architecture-specific operation request, arguments and attempted sequence. | An entry event precedes the result; a library call can map to another interface or no syscall. | Pair invocation and return, test denied and permitted controls, inspect ABI and event loss. |
| kprobe / fentry | Selected internal kernel function and object context. | Internal symbols and arguments vary by kernel/build; observing a function is not a stable user ABI. | Confirm BTF/symbol support on every node image and compare against a canary. |
| LSM hook | Security-relevant subject/object decision point such as file permission or socket connect. | One hook does not represent every authorization check or later effect. | Identify the exact hook, object, policy and result; test allowed and denied paths. |
| Process lifecycle event | Executable provenance, ancestry and event-time container context. | A process start alone does not identify malicious purpose or a later API caller. | Join stable exec and Pod identities; inspect image digest and expected workload behavior. |
| API audit | Authenticated actor, verb, resource, stage and server-side result. | Not a syscall feed; actor SA may be shared; accepted API call does not prove downstream execution. | Preserve auditID, stage, source provenance, resource UID and resulting object state. |
Observe versus enforce: the supplied Tetragon design’s 31 N/C policies are Post-only. R01–R08 are correlation candidates built on top of normalized events. A purple “kill candidate” in that draft is not deployed protection. Any Sigkill or Override experiment needs separate workload scope, compatible kernel/hook, canary, rollback and approval; it does not undo an earlier API write.
For a rigorous finding, record the policy ID and version, loaded nodes, hook, selector, raw event ID, return/errno, process exec ID, event-time Pod UID, enrichment source, auditID if any, and the independent result. A missing join or sensor gap is unknown, not a negative detection. Compare duplicate policy families before interpreting a multi-step sequence as multiple independent behaviors.
References: Tetragon TracingPolicy reference · advanced process execution · kernel trace events · Kubernetes audit logging.
- 01 · User spaceApplication and libraries inside a container. The image is a filesystem and process context, not a private kernel.Identity: UID/GID, capabilities, namespaces, cgroup, Pod/container UID.
- 02 · Entry and decisionSyscall, fault, interrupt or packet path enters privileged execution. Seccomp can filter syscall invocation; LSM checks are operation/object specific.Tracepoint/kprobe visibility is different from LSM enforcement and return status.
- 03 · Shared Linux kernelScheduler/process management ↔ memory management ↔ VFS/filesystems ↔ network stack ↔ drivers. These subsystems cooperate; there is no universal linear path.eBPF programs may attach at supported hooks after loader permission and verifier checks.
- 04 · Host and effectsCPU, RAM, storage and network interfaces; container-visible resources are constrained views of host-managed objects.Verify the returned result and independently observed host/API effect.
The supplied hero illustration uses a “HAL” band as a teaching shorthand. Linux does not require every syscall to traverse a single HAL layer; interrupts, page faults and receive paths can enter elsewhere. This diagram corrects that simplification.
Do not conflate filter and tracer: seccomp classic BPF filters syscall number, architecture and raw arguments before the handler; it does not resolve a pointed-to pathname. eBPF tracing or LSM instrumentation asks a different question and cannot by itself prove that a policy denied an operation. Kernel seccomp semantics.
01Speak precisely about the boundary
A syscall alert without a subject, an object and a result is a lead—not a finding. A web worker opening a socket, a debugger reading memory and an implant doing the same can produce superficially similar events. Detection engineering reconstructs the operation, establishes whether it belongs to the workload, and records the limits of the evidence.
This companion to K8SEC’s kernel-boundary guide moves from hardening to investigation. All traces in the interactive exercise are synthetic. The page does not collect host data, execute malware or claim that a production detector has been validated.
Three paths, three meanings: /sys/devices/… describes kernel objects and attributes; /proc/sys/kernel/… exposes kernel sysctl settings; a function call path describes execution. A path string alone does not capture a mount namespace, underlying object or permission decision. Sources: Linux syscall reference, sysfs documentation, LSM architecture (conceptual background; that page warns that its API descriptions are outdated).
Conceptual Linux container model. Layers organize responsibilities; they are not independent security walls.
↓ request via syscall ABI ↑ result / errno
↓ backing operations when needed ↑ completion / interrupt
Read the diagram as an architecture, not a literal call stack
Conventional containers share the host kernel. A file operation can involve both VFS and memory management; network and device events may run in asynchronous contexts. The diagram does not imply that every syscall visits every subsystem, that hardware I/O is always necessary, or that one LSM hook explains all authorization.
Architecture references: entry and exit handling, memory-management concepts. Conventional container assumptions do not automatically apply to VM-backed runtimes.
Infer the behavior from an evidence chain. Never infer malware merely from the name of an API.
02Choose sensors by the question they can answer
The following flow is conceptual, not a mandatory ordering for every subsystem. Several policy checks, asynchronous operations and object lifetimes may intervene.
- User intent → ABI
Wrapper, syscall number, arguments and calling task.
- Kernel operation → policy
Resolved object, relevant LSM checks and subsystem execution.
- Result → evidence
Return status, subsequent effect and collector health.
Dynamic syscall lifecycle · openat()
Step through a simplified regular-file open. This is a teaching model, not a captured stack trace. Lookup, filesystem methods and policy checks can interleave; exact symbols and ordering vary by kernel, filesystem and flags.
All conceptual paths are shown. No kernel operation is executed.
Open allowed
- 01User requestStep 1
- 02Kernel entryStep 2
- 03Resolve objectStep 3
- 04Evaluate accessStep 4
- 05Establish handleStep 5
- 06Return fd = 3Step 6
Step 1 · User request
- Userspace
- Application asks to open /training/report.txt read-only. The wrapper supplies a directory context and flags; the string is still untrusted input.
- Detection interpretation
- Observe caller identity and requested arguments. Do not yet claim an object was opened.
Step 2 · Kernel entry
- ABI boundary
- The architecture-specific entry path dispatches the syscall. Configured entry-time controls may reject a request before deeper work.
- Detection interpretation
- A syscall-entry event proves invocation, not completion. This scenario assumes the request passes entry controls.
Step 3 · Resolve object
- VFS / namespace
- Path lookup uses the task’s root, working directory or directory descriptor, mounts and filesystem objects. A pathname does not identify a global host file.
- Detection interpretation
- Preserve mount namespace and resolved object context. Checks can happen during lookup, not only at the next illustrated node.
Step 4 · Evaluate access
- Authorization boundary
- Relevant permissions and LSM checks are evaluated. Here they permit this open; this is not a grant for every later operation.
- Detection interpretation
- A particular allow decision is not proof that all checks passed or that the operation completed.
Step 5 · Establish handle
- Open-file state
- The successful open establishes an open file description and a descriptor in the process. The illustrative descriptor is 3.
- Detection interpretation
- Correlate the handle with its underlying object and lifetime. The number 3 will be reusable after close.
Step 6 · Return fd = 3
- Kernel → userspace
- The caller receives a nonnegative descriptor. File content has not been read by this open alone.
- Detection interpretation
- Supported claim: this open succeeded. Reading bytes requires a separate operation and result.
Access denied
- 01User requestStep 1
- 02Kernel entryStep 2
- 03Resolve objectStep 3
- 04Reject accessStep 4
- 05Return -1 / EACCESStep 5
Step 1 · User request
- Userspace
- The same read-only file-open request is made by a different effective security context.
- Detection interpretation
- Compare identities and policy context, not just the identical pathname.
Step 2 · Kernel entry
- ABI boundary
- This illustrative request passes entry controls and reaches filesystem processing.
- Detection interpretation
- Entry visibility does not prove that later authorization will allow access.
Step 3 · Resolve object
- VFS / namespace
- The scenario reaches the relevant object after lookup. Earlier lookup denials are also possible in real systems.
- Detection interpretation
- Do not assume every EACCES means this same lookup stage was reached.
Step 4 · Reject access
- Authorization boundary
- A relevant access check denies this modeled request. No successful descriptor is returned.
- Detection interpretation
- A return error alone cannot distinguish DAC from a specific LSM denial; obtain the relevant policy evidence.
Step 5 · Return -1 / EACCES
- Kernel → wrapper
- The wrapper exposes failure and errno. The successful-handle stage is absent from this scenario.
- Detection interpretation
- Supported claim: this request did not produce a successful open. It does not prove the host is clean.
Object not found
- 01User requestStep 1
- 02Kernel entryStep 2
- 03Lookup failsStep 3
- 04Return -1 / ENOENTStep 4
Step 1 · User request
- Userspace
- The caller requests a regular file that does not exist in this scenario’s visible namespace.
- Detection interpretation
- The same string can resolve differently for another task or mount namespace.
Step 2 · Kernel entry
- ABI boundary
- The request enters kernel handling and proceeds to lookup.
- Detection interpretation
- A seen syscall still has no known successful effect.
Step 3 · Lookup fails
- Resolution boundary
- A required path component is missing in this synthetic path.
- Detection interpretation
- Distinguish a resolution failure from an authorization control deliberately blocking access.
Step 4 · Return -1 / ENOENT
- Kernel → wrapper
- The wrapper reports the missing-path result. Later open and descriptor-success stages are not reached.
- Detection interpretation
- Supported claim: failure for this path resolution. This is not evidence that a security policy worked.
Lifecycle semantics: open/openat reference. The error values shown here are wrapper-level conventions; a kernel event may encode errno differently.
Inside the kernel · a buffered regular-file read
Start with an already-open, readable regular-file descriptor. Compare a simplified cached read, storage-backed read and rejected read. These are not universal paths for sockets, device files, direct I/O or asynchronous I/O.
All conceptual paths are shown. No kernel operation is executed.
Page-cache hit
- 01read(fd, buffer, count)Step 1
- 02Resolve file + validateStep 2
- 03Dispatch file operationStep 3
- 04Use cached dataStep 4
- 05Transfer + return 64Step 5
Step 1 · read(fd, buffer, count)
- ABI boundary
- The process requests bytes through an existing descriptor.
- Detection interpretation
- The descriptor number is meaningful only inside the correct descriptor-table and lifetime context.
Step 2 · Resolve file + validate
- VFS / access boundary
- Kernel handling resolves the open file, checks suitability and performs relevant access checks before this modeled transfer.
- Detection interpretation
- A previous successful open does not prove every later read succeeds.
Step 3 · Dispatch file operation
- Filesystem boundary
- The implementation associated with the open file handles the request. For this example, it is a buffered regular-file read.
- Detection interpretation
- Trace the actual implementation on the target build; do not universalize one internal function name.
Step 4 · Use cached data
- Memory subsystem
- The requested data is available in the page cache in this simplified case. No new storage read is required to satisfy it.
- Detection interpretation
- No matching disk event does not disprove a file read.
Step 5 · Transfer + return 64
- Result boundary
- The caller receives 64 bytes in this synthetic result. A short read is possible; zero can indicate end-of-file.
- Detection interpretation
- Bytes transferred do not establish the content’s sensitivity, malicious intent or later exfiltration.
Page-cache miss
- 01read(fd, buffer, count)Step 1
- 02Resolve file + validateStep 2
- 03Dispatch file operationStep 3
- 04Request storage + waitStep 4
- 05Transfer + return 64Step 5
Step 1 · read(fd, buffer, count)
- ABI boundary
- The same kind of read request enters kernel handling.
- Detection interpretation
- Retain caller and invocation identity across subsequent events.
Step 2 · Resolve file + validate
- VFS / access boundary
- The open file and relevant access conditions are checked for this modeled request.
- Detection interpretation
- Different filesystem types and states can take different paths.
Step 3 · Dispatch file operation
- Filesystem boundary
- The buffered regular-file implementation needs data that is not currently available in cache.
- Detection interpretation
- Kernel operations may fan out; one request is not necessarily one block-device event.
Step 4 · Request storage + wait
- I/O / scheduling boundary
- The filesystem arranges backing I/O; the requesting task may sleep while work progresses and completion makes data available.
- Detection interpretation
- Do not attribute every worker or completion event by the worker’s PID alone. Preserve request/object relationships.
Step 5 · Transfer + return 64
- Result boundary
- This synthetic operation completes and transfers 64 bytes to the caller.
- Detection interpretation
- Latency and storage activity add context; the read result, not an I/O request alone, establishes this transfer.
Read rejected
- 01read(fd, buffer, count)Step 1
- 02Access check rejectsStep 2
- 03Return -1 / EACCESStep 3
Step 1 · read(fd, buffer, count)
- ABI boundary
- The read is requested through an existing descriptor.
- Detection interpretation
- A valid descriptor and a prior open do not by themselves guarantee this operation is permitted.
Step 2 · Access check rejects
- Policy boundary
- A relevant access check rejects this modeled operation before the file-data transfer.
- Detection interpretation
- Identify the actual rejecting control using its decision evidence; the diagram does not infer it from errno.
Step 3 · Return -1 / EACCES
- Result boundary
- This fixture reports failure without a successful transfer.
- Detection interpretation
- This does not imply a universal one-check read path or prove that other requests were blocked.
Operation references: VFS object and operation model, read results and page cache.
| Point | Useful evidence | Do not conclude |
|---|---|---|
| Syscall entry / exit | Arguments at entry; completion or failure from the corresponding return. Pair by task and invocation. | Entry proves success; pathname arguments are resolved object identities. |
| Tracepoint | A deliberately instrumented event and its advertised fields. Discover actual event names and formats on the target. | Every kernel build has the same event schema or every relevant event is enabled. |
| kprobe / kretprobe | Execution at eligible implementation locations and returns. Useful when a higher-level event omits required context. | Function names, prototypes and offsets are portable contracts. |
| LSM / BPF LSM | Operation-specific object and policy context; supported hook return contracts can enable enforcement. | Loading a tracing BPF program automatically blocks the operation. |
| Userspace tracer | A controlled workload’s calls, returns, signals and children when configured. | Unperturbed timing, kernel-wide visibility or zero exposure of sensitive arguments. |
eBPF is an execution mechanism for programs attached to supported hooks. The attachment type and program logic determine whether it observes, transforms or participates in enforcement. A BPF LSM policy must respect its hook’s semantics and preserve an existing denial where the contract requires it. A tracing probe should not be advertised as an authorization control. For example, an inode-permission hook addresses filesystem permission checks; an execution-related hook examines a different stage. Do not use either as a substitute for a successful operation event. Read the BPF LSM contract, event tracing interfaces and kprobe limitations.
Visibility is a measurable dependency
Capture sensor version, kernel release/build, architecture, loaded attachments, enabled events, namespace visibility, clock source, sampling configuration and loss counters. A healthy agent process does not prove that its required hooks are active. Establish canary operations and check that their expected events arrive.
Account for asynchronous I/O and kernel-worker attribution when testing your sensor. A syscall-only model is not automatically a complete model of file or network effects. Conversely, do not claim that io_uring is universally invisible: coverage depends on the operation, kernel and collector. User-space work may also occur without a new syscall. State the coverage you tested instead of guessing.
03Read /proc/sys/kernel as a security control surface
The kernel sysctl reference describes controls, not a universal hardening profile. Verify availability and vendor behavior on the actual kernel. These concise semantics are the starting point:
unprivileged_bpf_disabled: 0 allows unprivileged BPF calls; 2 disables them reversibly; 1 cannot be cleared in the running kernel.modules_disabled=1prevents module loading and unloading;kexec_load_disabled=1disables further kexec image loading. Both are one-way for the running kernel.kptr_restrictconstrains pointer disclosure through the documented formatting interfaces;dmesg_restrictlimits kernel-log access. Neither is a universal information-leak fix.core_patternconfigures core handling; an initial pipe character selects a userspace handler.io_uring_disabledrestricts new ring creation; existing rings remain usable. Mode 1 permits the documented privileged/group exceptions; mode 2 blocks creation for everyone.bpf_stats_enabledenables runtime statistics with overhead; it is not an incident recorder.
For perf restrictions, use the separate perf security model; capabilities and distribution-specific settings matter. For process inspection, Yama’s ptrace_scope distinguishes traditional checks, relationship-restricted attachment, admin-only attachment and a no-attach mode. This is additional policy, not a replacement for all process-access checks.
Turn configuration into an investigation contract
K8SEC’s proposed analytic is not “value differs from my laptop.” Maintain a versioned node baseline with approved exceptions. Join a change observation to the responsible process identity, authenticated operator or configuration-management job, expected value transition and maintenance window. A current value proves state at collection time; it does not identify who changed it. A failed write proves neither a changed value nor a later successful attempt.
Prioritize unexplained policy weakening or changes to execution-sensitive handlers. Review legitimate crash collectors, monitoring agents and driver maintenance before alerting. Do not paste a batch of irreversible settings into a worker. Establish required drivers and recovery procedures, test on a disposable node, then deploy through the supported node-management mechanism.
for key in kernel.unprivileged_bpf_disabled kernel.modules_disabled \
kernel.kexec_load_disabled kernel.kptr_restrict kernel.dmesg_restrict \
kernel.perf_event_paranoid kernel.yama.ptrace_scope kernel.io_uring_disabled
do
if value=$(sysctl -n "$key" 2>/dev/null); then
printf '%s=%s\n' "$key" "$value"
else
printf '%s=UNKNOWN (unavailable or not readable)\n' "$key"
fi
doneThis inventory makes no changes and does not establish collector coverage. A container’s view is not necessarily the host’s view. Record where it ran; keep inaccessible values UNKNOWN rather than treating them as disabled.
04Translate malware objectives into observable behavior
Reverse engineering starts with a hypothesis about a capability. Detection starts with what your telemetry can establish. An import, string or disassembled branch may reveal a possible operation without proving that execution reached it. Dynamic execution covers only the inputs, environment and branches exercised.
| Hypothesis | Evidence to seek | Alternative explanation / limit |
|---|---|---|
| Anonymous-file-backed execution | Creation of an anonymous file, correlated writes, then a successful execution transition resolving to that object. Track descriptor reuse and object lifetime. | Legitimate launchers and IPC use anonymous files. Creation alone is not execution; an executable mapping is not proof that instructions ran. |
| Cross-process memory access | Source and target process identities, requested operation, returned byte count and independent authorization context. | Debuggers and diagnostics read memory. A read is not an injection; it does not prove secrets were present or left the host. |
| Unexpected child process | Service lineage, successful image transition, executable provenance, credentials, namespace and workload expectations. | A shell can be legitimate maintenance; an attacker need not invoke a shell. Names and command lines can mislead. |
| Credential access followed by outbound activity | Resolved sensitive object, successful access, same-subject or explicit IPC lineage, connection outcome and controlled evidence of content transfer. | Temporal proximity alone does not prove that the file’s bytes were transmitted. A successful connect is not exfiltration. |
| Telemetry or policy tampering | Unauthorized configuration/attachment change, responsible identity, before/after state, sensor-health impact and an independent log source. | Maintenance can detach probes or rotate agents. Lost events can also reflect pressure, crashes or misconfiguration. |
memfd_create supplies anonymous file-backed storage, not a malware verdict. execve replaces the current program image; a successful exec does not return to the old program. Model successful execution using the collector’s completion/event semantics, not a fabricated universal “exec returned zero” record. process_vm_readv returns transferred bytes and can complete partially; ptrace has multiple operations whose meanings differ. Sources: memfd_create, execve, process_vm_readv, ptrace.
Attacker lens, defender discipline
An attacker seeks a useful effect: inspect another identity, reach a protected object or alter a policy. Your rule should describe that effect and its prerequisites, not a particular utility name. Start with the shortest defensible claim. “An unexpected process read bytes from another process” is stronger evidence than “malware injection detected” when all you have is a read result.
Do not automatically attach a technique, campaign or exploit chain to a syscall. Record the mapping rationale and leave unsupported claims unmapped. A successful host operation also does not establish a container escape: reconstruct the expected boundary, actual namespace/mount exposure and effective authority first.
05From reverse engineering to a detection specification
- Establish the specimen and scope. Record hashes, acquisition provenance, allowed environment and analyst ownership. Real malware belongs in a dedicated isolated analysis environment, not a production cluster or this website.
- Extract capability hypotheses. Describe relevant data flow, call sites and prerequisites. Mark static-only observations separately from exercised behavior. Identify inputs and branches that remain untested.
- Design controlled observations. Use disposable workloads, synthetic files and memory, bounded network simulation and independent outcome checks. Include an authorized positive baseline and a deliberately denied operation.
- Normalize semantics. Specify sensor-specific success/failure conventions, partial results, task identity and object resolution. Preserve raw event references; avoid flattening everything into “syscall happened.”
- Write the behavior contract. Declare the join keys, time window, required events, trust source for approval and missing-data behavior. Declare what the rule does not detect.
- Challenge the rule. Replay benign lookalikes, missing events, duplicates, reordered timestamps, reused PIDs and mismatched objects. Have another analyst reject any conclusion the evidence cannot support.
- Ship with observability. Version the rule, fixtures, sensor matrix and reviewer sign-off. Measure coverage and triage cost before enabling response automation.
A harmless trace to learn the recording format
In an authorized disposable Linux environment with strace, trace a fixed, benign shell command. It creates no payload and does not change kernel policy. The output file is created in your current directory. Loader and shell behavior will vary by system; that variation is part of the lesson.
strace -f -ttt -yy -e trace=execve,openat,read,write,close \
-o benign-trace.log -- /bin/sh -c 'printf "K8SEC benign fixture\n"'Match a few entries to returns, resolve the visible file descriptors and explain the loader’s activity before writing a rule. -f follows child processes; timestamps and descriptor decoding help reconstruction, but do not magically provide immutable object identity. Tracing perturbs execution and can expose argument or buffer contents. See the strace manual. This article’s validation checks shell syntax; it does not execute this capture.
06Interactive evidence graph: one API, four investigations
Select a path and follow the directional relationships. Observed means supplied in this synthetic fixture, not measured on a real host. Inferred marks the analyst interpretation. Disproven applies only to the stated claim for this call. Approval is independent fixture context, not something a syscall authenticates.
Process → kernel result → analyst conclusion
Trust boundary: one process requests access to another process's memory. Decision boundary: kernel result is interpreted using independent authorization context.
All synthetic traces are readable below. This is not a live sensor.
Unexpected memory read
- Process boundary · observedSource → target memoryprocess_vm_readv request, invocation read-01. Compound process identities identify separate lifetimes.
- Result boundaryObserved · 64 bytes returnedEntry-to-exit correlation requires the same subject, target and call identity.
- Interpretation boundaryInferred · investigate scopeThe byte transfer is observed in this fixture. Whether the content was sensitive, maliciously used or transmitted elsewhere remains unproven.
- Evaluation · synthetic records only
- investigate-read: Unexpected cross-process byte transfer. This is not proof of injection or exfiltration.
- Next evidence to obtain
- Bind the subject to its workload and compare target scope against an independently managed entitlement.
Inspect normalized evidence and approval context
{
"id": "unexpected",
"label": "Unexpected memory read",
"authorization": "unexpected",
"coverage": "complete",
"events": [
{
"phase": "enter",
"at": 100,
"call": "read-01",
"subject": "nodeA/bootA/pid410/start90",
"target": "nodeA/bootA/pid620/start70",
"operation": "process_vm_readv"
},
{
"phase": "exit",
"at": 120,
"call": "read-01",
"subject": "nodeA/bootA/pid410/start90",
"target": "nodeA/bootA/pid620/start70",
"operation": "process_vm_readv",
"result": 64
}
]
}Approved diagnostic
- Process boundary · observedSource → target memoryprocess_vm_readv request, invocation read-02. Compound process identities identify separate lifetimes.
- Result boundaryObserved · 64 bytes returnedEntry-to-exit correlation requires the same subject, target and call identity.
- Interpretation boundaryContext · approved diagnosticThe same low-level behavior has an approved purpose in this fixture. Approval is contextual evidence, not a syscall property or a global allowlist.
- Evaluation · synthetic records only
- approved-read: Bytes transferred under the fixture's independently supplied approval; retain the evidence.
- Next evidence to obtain
- Check the diagnostic's operator, target scope, executable provenance and expiry; retain the successful read record.
Inspect normalized evidence and approval context
{
"id": "approved",
"label": "Approved diagnostic",
"authorization": "approved",
"coverage": "complete",
"events": [
{
"phase": "enter",
"at": 100,
"call": "read-02",
"subject": "nodeA/bootA/pid411/start91",
"target": "nodeA/bootA/pid620/start70",
"operation": "process_vm_readv"
},
{
"phase": "exit",
"at": 120,
"call": "read-02",
"subject": "nodeA/bootA/pid411/start91",
"target": "nodeA/bootA/pid620/start70",
"operation": "process_vm_readv",
"result": 64
}
]
}Denied attempt
- Process boundary · observedSource → target memoryprocess_vm_readv request, invocation read-03. Compound process identities identify separate lifetimes.
- Result boundaryObserved · -1 / EPERMEntry-to-exit correlation requires the same subject, target and call identity.
- Interpretation boundaryDisproven · bytes read by this callThe claim that this specific paired call transferred bytes is contradicted. Which policy denied it is unknown; another call or interface is outside this fixture.
- Evaluation · synthetic records only
- denied-attempt: The paired operation was denied; the responsible control is not identified.
- Next evidence to obtain
- Correlate relevant authorization records. Verify a controlled allowed baseline before concluding the policy is correct.
Inspect normalized evidence and approval context
{
"id": "denied",
"label": "Denied attempt",
"authorization": "unexpected",
"coverage": "complete",
"events": [
{
"phase": "enter",
"at": 100,
"call": "read-03",
"subject": "nodeA/bootA/pid412/start92",
"target": "nodeA/bootA/pid620/start70",
"operation": "process_vm_readv"
},
{
"phase": "exit",
"at": 120,
"call": "read-03",
"subject": "nodeA/bootA/pid412/start92",
"target": "nodeA/bootA/pid620/start70",
"operation": "process_vm_readv",
"result": -1,
"error": "EPERM"
}
]
}Missing return event
- Process boundary · observedSource → target memoryprocess_vm_readv request, invocation read-04. Compound process identities identify separate lifetimes.
- Result boundaryMissing · return eventEntry-to-exit correlation requires the same subject, target and call identity.
- Interpretation boundaryUnknown · outcome and authorityAn entry is recorded, but the return and complete telemetry are absent. Do not infer denial, success or a clean host.
- Evaluation · synthetic records only
- unknown: Missing records or collector coverage is incomplete.
- Next evidence to obtain
- Investigate sensor loss and recover independent evidence; the missing record cannot be manufactured by the graph.
Inspect normalized evidence and approval context
{
"id": "incomplete",
"label": "Missing return event",
"authorization": "unknown",
"coverage": "loss",
"events": [
{
"phase": "enter",
"at": 100,
"call": "read-04",
"subject": "nodeA/bootA/pid413/start93",
"target": "nodeA/bootA/pid620/start70",
"operation": "process_vm_readv"
}
]
}The graph deliberately keeps the same API across scenarios. Changing the outcome, approval or telemetry completeness changes the conclusion. No scenario yields a “malware confirmed” result. A denial does not prove which security control caused it, and absence of a return does not prove that nothing happened.
07A reproducible, deliberately narrow correlation rule
The downloadable model evaluates exactly one normalized process_vm_readv entry/exit pair. It requires matching call, subject and target identities, complete coverage, a finite ordered time interval of no more than five seconds, and an integer result. That window is a teaching parameter—not a production tuning recommendation.
A positive byte count plus independently supplied “unexpected” context produces investigate-read. An approved diagnostic produces approved-read, which retains the observation rather than calling the machine clean. A normalized -1/EPERM produces denied-attempt. Missing, conflicting or unsupported evidence remains unknown. Zero bytes produces no-bytes-observed, not “safe.”
Normalization warning: the fixture uses libc-style -1 plus symbolic errno. A kernel exit sensor may expose a negative errno directly. A production adapter must normalize and test that convention. The compound identity strings are readable stand-ins for collector-issued identities; this model cannot verify their authenticity, host clock, coverage assertion or approval authority.
node --input-type=module -e '
import {readFileSync} from "node:fs";
import {assess} from "./kernel-detection-v1.mjs";
const fixture = JSON.parse(readFileSync("./kernel-detection-fixtures-v1.json", "utf8"));
for (const trace of fixture.cases) console.log(trace.id, assess(trace));
'Download reference evaluator v1 · JavaScript module · Download synthetic evidence v1 · JSON
What a production implementation still needs
This is not a kernel collector, malware classifier or SIEM integration. Build and test the trusted ingestion adapter, immutable process/object identities, event deduplication, bounded buffering, late-arrival policy and retention controls. If you support out-of-order events, distinguish reorderable arrival time from contradictory event time. Never join different boots or process lifetimes merely because a PID matches.
Replace the fixture’s approval label with an independently verified entitlement or bounded maintenance record. A process-controlled name, command line, environment variable or annotation cannot grant itself an exception. Bind exceptions to workload identity, operation, target scope and expiry. Treat incomplete instrumentation as degraded detection coverage and surface it separately from suspicious activity.
Detection versus response
Start in observation mode. A false positive on a node security agent can remove the very telemetry needed to investigate. Escalate with the raw event references and context, not an automatic kill based on one syscall. For enforcement, specify the supported control, compatibility tests, rollback and a separate proof that the deployed policy rejects the intended operation.
08eBPF is a programmable kernel surface—not a security verdict
eBPF allows approved programs to run at supported kernel hooks, with program-type-specific access to context, helpers and data. Networking, observability and security tools use it for different purposes. A userspace loader prepares an object, creates maps, asks the kernel to load programs, then attaches them. Successful loading alone does not prove attachment or useful events. libbpf lifecycle.
- 1 · Load requestThe loader’s credentials, kernel configuration and permissions constrain the requested program and attachment.
- 2 · VerifyThe verifier analyses register types, pointer bounds and valid accesses before acceptance; rejection is a load failure, not a detection event.
- 3 · Attach and runAccepted programs execute when their hook runs, through an interpreter or JIT-compiled code as supported. Hook type defines possible effects.
- 4 · Export and correlateMaps or event buffers carry state to a collector. Loss, sampling, restarts and identity enrichment determine evidence quality.
The verifier enforces rules about program safety; it does not decide whether your organization authorized the loader or whether a telemetry policy covers the attack path. Verifier/JIT implementation defects also remain part of the kernel patching threat model. Verifier design.
Maps hold state shared between BPF programs and, subject to access, userspace. Configuration maps deserve change control; changing one can alter a sensor’s behavior without a new program load. Pinning can keep referenced objects alive beyond a loader’s lifetime, so process exit is not a complete uninstall audit. BPF maps and object lifetime.
Permission review: loader, program and attachment
CAP_BPF separates privileged BPF operations on supporting kernels; tracing may also require CAP_PERFMON, and networking operations may require CAP_NET_ADMIN. Legacy checks can involve CAP_SYS_ADMIN. These are not a universal three-capability recipe: program type, attach target, user namespace, LSM and distro configuration affect the decision. An application does not need these merely because the node runs an eBPF-based CNI. Linux capabilities.
Maintain an owner, image digest, program type, attachment, required authority and approved data fields for every sensor. Prefer hashes/build identities over program names as identity evidence. Treat raw arguments, paths and process data as potentially sensitive; do not export secrets in pursuit of a richer dashboard.
bpftool prog show, bpftool link show and bpftool map show help enumerate objects. Attachments are not all represented by modern BPF links; inspect network/cgroup hooks through the supported toolchain too. Permission denial means UNKNOWN, not “no eBPF”. Do not dump map contents or disable a CNI/security agent to make the inventory easier. bpftool inventory reference.09What a container escape actually changes
A container escape is an action that crosses the workload’s intended isolation boundary into host resources or authority it should not possess. The phrase describes the result, not one particular exploit. Access to a host directory intentionally mounted into a pod may be a dangerous grant rather than a bypass; record the intended policy before calling it an escape.
There are at least three different mechanisms: an over-granted interface, a vulnerable userspace runtime, and a vulnerable kernel. They require different fixes. MITRE T1611, Escape to Host, is an investigation category—not proof that a weak configuration has already been exploited.
Interactive escape-path comparison
Choose a path to compare its boundary, controls and evidence. This is an explanatory model, not a live cluster test.
All paths shown. No JavaScript is required to read them.
Path A · dangerous grant, no kernel bug required
- ApplicationCompromised workloadStarts with its actual process credentials and mounts.
- Grant boundaryWritable host path / runtime interfaceRequires an exposed interface and sufficient effective access.
- Host userspaceUnauthorized host effectThe kernel may simply be honoring an over-broad grant.
- Authority / control
- Prerequisites: reachable sensitive interface, effective permissions and no other control blocking the operation.
- Observation
- Evidence: admitted configuration, mount/object identity, process authority and an independently recorded benign host effect in an isolated test.
- Effect / remediation
- Interrupt: remove the grant and restrict admission. A kernel patch alone does not remove a writable host mount.
Path B · container runtime isolation failure
- Application / imageAttacker-controlled runtime inputReachable start, exec or filesystem operation; depends on the specific flaw.
- Runtime boundaryAffected userspace runtimeA concrete defect mishandles isolation, a path or a descriptor.
- Host userspaceAccess outside intended isolationHost impact is conditional; the kernel itself need not be corrupted.
- Authority / control
- Prerequisites: affected runtime build, exact triggering conditions and reachable runtime operation.
- Observation
- Evidence: vendor advisory match, runtime version, safe isolated reproduction and host-object result. Do not infer exposure from a kernel version.
- Effect / remediation
- Interrupt: update the affected runtime through the supported platform release and remove unnecessary triggering authority.
Path C · a reachable kernel defect
- ApplicationProcess reaches a vulnerable interfaceThe relevant syscall/device/protocol must be permitted and available.
- Kernel integrityAffected kernel path and exploit primitiveSuccessful exploitation may alter privileged state; a crash alone is not proof.
- Node / neighborsPotential shared-host impactConfidentiality, integrity or availability depends on the demonstrated primitive.
- Authority / control
- Prerequisites: affected vendor build, reachable interface and the exploit’s exact configuration/privilege requirements.
- Observation
- Evidence: payload/advisory mapping and authorized isolated validation; separate failed attempts, crashes and controlled impact.
- Effect / remediation
- Interrupt: patch the node kernel and reduce reachability. Additional cluster access still requires credentials, permissions and network paths.
How does escape impact the kernel?
Host userspace control
A host file or runtime socket can expose node authority while the kernel executes its configured rules correctly. The primary failure can be the permission grant, not kernel memory corruption.
Kernel confidentiality / integrity
A reachable kernel defect may disclose memory or permit a privileged state change. Its exact primitive and prerequisites determine impact; a crash is not proof of code execution.
Shared-node availability
A kernel panic can interrupt other workloads on that worker. Resource exhaustion may also affect neighbors without an escape. Keep denial of service separate from demonstrated host control.
Conditional cluster reach
Host access may expose workload or node credentials. Further access still depends on credential scope, RBAC, network reachability and additional controls. Node compromise is not automatically cluster-admin.
Root inside a container, visibility of host PIDs, an allowed syscall, and successful host access are four different observations. Report the narrowest supported claim. A service-account token used against the Kubernetes API can produce a serious cluster attack path without any kernel escape at all.
10Collect effective state before assigning severity
Start with API metadata. Preserve node and pod UIDs, container identity, release, timestamps and collection errors. The following triage includes regular, init and ephemeral containers; it deliberately does not fetch Secret objects or values.
bash# Authorized read-only API inventory; jq 1.6+.
oc get clusterversion -o jsonpath='{.items[0].status.desired.version}{"\n"}'
oc get mcp
oc get co
oc get pods -A -o json | jq -c '
.items[] as $p
| (($p.spec.containers // []) + ($p.spec.initContainers // [])
+ ($p.spec.ephemeralContainers // []))[] as $c
| select(
$c.securityContext.privileged == true
or $p.spec.hostPID == true or $p.spec.hostIPC == true
or $p.spec.hostNetwork == true
or any($p.spec.volumes[]?; has("hostPath"))
or any($c.securityContext.capabilities.add[]?;
. == "SYS_ADMIN" or . == "SYS_PTRACE" or . == "SYS_MODULE"
or . == "BPF" or . == "PERFMON" or . == "NET_ADMIN"))
| {namespace:$p.metadata.namespace, pod:$p.metadata.name,
podUID:$p.metadata.uid, node:$p.spec.nodeName,
serviceAccount:($p.spec.serviceAccountName // "default"),
scc:($p.metadata.annotations["openshift.io/scc"] // "UNKNOWN"),
container:$c.name, securityContext:$c.securityContext}'
This flags candidate paths, not vulnerabilities. Inspect volume mounts, device exposure, runtime defaults and the actual process credentials next. For SCC entitlement, combine RBAC grants with the SCC’s own users/groups; a single oc auth can-i result is not a complete SCC grant inventory. Red Hat SCC reference.
Host inspection has a different authorization boundary
oc debug node is not a read-only Kubernetes operation: it creates a privileged debugging workload. chroot /host changes the filesystem view; it does not manufacture safe access. Use an approved administrator session and an explicitly selected canary node. Do not grant host-debug privilege to ordinary application accounts or to the production K8SEC Agent.
Within an already approved host inspection session, the following script reads metadata. Missing files and denied reads remain UNKNOWN. It does not prove every control is enforced or capture a trusted forensic image.
bash#!/bin/sh
# Run in an already authorized host inspection session, not inside an app pod.
# Prints metadata only. Does not change sysctls, load BPF or read Secret values.
show_file() {
printf '\nFILE %s\n' "$1"
if [ -r "$1" ]; then
cat "$1" || printf 'UNKNOWN: read failed\n'
else
printf 'UNKNOWN: unavailable or not readable\n'
fi
}
date -u '+UTC %Y-%m-%dT%H:%M:%SZ'
hostname
uname -r
show_file /proc/sys/kernel/random/boot_id
show_file /proc/cmdline
show_file /sys/fs/selinux/enforce
show_file /sys/kernel/security/lsm
show_file /sys/kernel/security/lockdown
for key in kernel.yama.ptrace_scope kernel.unprivileged_bpf_disabled \
kernel.perf_event_paranoid kernel.kptr_restrict kernel.dmesg_restrict \
kernel.randomize_va_space fs.suid_dumpable; do
printf '\nSYSCTL %s\n' "$key"
sysctl "$key" || printf 'UNKNOWN: sysctl failed\n'
done
for f in /sys/devices/system/cpu/vulnerabilities/*; do
[ -e "$f" ] || continue
show_file "$f"
done
Download the read-only host snapshot script (SH · v1). Review before use; this article does not claim it has been run on your OpenShift workers.
| Evidence | Supported interpretation | Do not infer |
|---|---|---|
| SELinux enforce = 1 | Live SELinux enforcement at collection time; inspect process labels and policy too. | All workload actions are denied or every container is correctly labeled. |
| Seccomp = 2 in process status | A filter is installed for that process. | The exact allowed syscall set or effective policy version. |
| ptrace_scope = 0 | Traditional access checks still apply, including identity/dumpability. | Any pod can inspect every host process. |
| randomize_va_space = 2 | Userspace ASLR setting. | Kernel ASLR, signed boot, PIE or stack canaries are proven. |
| No BPF module in lsmod | No useful BPF availability conclusion. | Built-in eBPF support is absent. |
| A kernel release string | One input to payload and vendor advisory matching. | Whether the distro has backported a particular fix. |
For ptrace restrictions, use the Yama semantics. For kernel knobs, use the sysctl reference, and map the actual OpenShift/RHCOS payload to vendor advisories instead of comparing upstream version strings alone.
11Break the path without breaking the cluster
Choose controls for the transition they constrain. Admission governs requested privileges; runtime policy governs execution; patching removes known defects. A sensor can support all three with evidence, but it does not substitute for any of them.
| Boundary | Control to validate | Residual question |
|---|---|---|
| Pod → host features | Constrained SCC, no unapproved privileged/host namespaces/hostPath, drop capabilities. | Who can grant exceptions or change the workload? |
| Process → kernel API | RuntimeDefault seccomp and workload-tested tighter profiles where needed. | What does the actual runtime profile allow? |
| Subject → object | Enforcing SELinux and correct labels/MCS separation. | Did policy deny the controlled cross-label test? |
| Loader → kernel instrumentation | Approved BPF loaders, minimal required privilege, unprivileged BPF restrictions. | Can an unauthorized workload load or attach the relevant program type? |
| Node → trusted execution | Supported payload updates, measured boot controls and supported lockdown/module-signing policy. | What is the evidence for this node, rather than its template? |
restricted-v2 drops capabilities and applies runtime-default seccomp; newer SCC options and user namespaces depend on release/configuration. Inspect the admitted pod rather than assuming a default. Avoid blanket changes to built-in SCCs. SCC behavior.
A scoped TuneD example—not a universal baseline
Evaluate host sysctls through the Node Tuning Operator. This example inherits openshift-node and matches one explicit label; lower priority numbers win. Adapt inheritance and conflicts to your pool, especially performance-tuned nodes. NTO profile matching.
yamlapiVersion: tuned.openshift.io/v1
kind: Tuned
metadata:
name: k8sec-kernel-canary
namespace: openshift-cluster-node-tuning-operator
spec:
profile:
- name: k8sec-kernel-canary
data: |
[main]
summary=K8SEC single-worker evaluation
include=openshift-node
[sysctl]
kernel.yama.ptrace_scope=1
kernel.unprivileged_bpf_disabled=2
kernel.perf_event_paranoid=2
kernel.kptr_restrict=1
kernel.dmesg_restrict=1
fs.suid_dumpable=0
recommend:
- match:
- label: k8sec.io/kernel-canary
value: "true"
type: node
priority: 10
profile: k8sec-kernel-canary
unprivileged_bpf_disabled=2 disables unprivileged BPF reversibly on supporting kernels; 1 cannot be reversed until reboot. Neither revokes all privileged BPF access. Check existing values first. kptr_restrict and dmesg_restrict reduce information exposure, not exploitability to zero. Kernel knob semantics. Profiling restrictions need separate evaluation for legitimate agents and CAP_PERFMON: perf security.
- Baseline: choose a replaceable worker; record its active TuneD profile, original values, BPF consumers, operator health and application SLOs.
- Review: server-side dry-run the manifest, check inherited settings and ensure only the intended node bears the canary label.
- Change: apply only in the approved window. Confirm selected profile, live values and positive/negative control results—not just an accepted YAML object.
- Compatibility: exercise CNI, CSI, APM, security sensors, profiling, crash collection and workload probes before widening scope.
- Rollback: remove the canary match and restore the recorded prior profile/values through the supported operator process. Verify every value. Removing a label alone is not proof that all sysctls reverted.
Kernel arguments and RHCOS lifecycle changes need separate Machine Config Operator planning, disruption budgets and maintenance windows. MachineConfig guidance. An SELinux-disabled boot is not repaired by setenforce 1; inspect the configuration source and plan supported recovery. Do not turn broad audit2allow output into an unreviewed exception.
- HypothesisState attacker objective, expected behavior, valid alternative and required outcome.
- Coverage contractRecord hook, policy version, supported nodes, loss, event-time identity and safe canary.
- Raw evidenceKeep the syscall/LSM/Tetragon event, return value, lineage and Kubernetes audit separately.
- Correlation gateDeduplicate, time-bound, join on stable IDs; ambiguous or missing edges stay unknown.
- AdjudicationConfirmed effect, denied attempt, benign control or unresolved candidate—with reasons.
12Operate the detector, not just the rule
A detection is a maintained system: sensor, parser, identity mapping, correlation, enrichment, alert route and reviewer. Measure each part. A rule that never alerts because its event vanished after a kernel update is broken, not precise.
- Coverage: maintain a kernel/architecture/runtime/sensor matrix. Replay the expected allowed and denied canaries after upgrades. Record unsupported configurations.
- Evidence quality: track lost records, queue latency, attachment failures, unresolved identities and clock discontinuities. Keep UNKNOWN visible instead of counting it as a passed negative control.
- Evaluation: report precision on labeled reviewed alerts, and recall on your explicitly bounded test corpus—not all malware. Also measure false positives per workload-hour, investigation time and repeated alerts per incident.
- Privacy: default to metadata. Arguments, paths, environment and buffers may expose credentials or tenant data. Minimize collection, restrict access, redact deliberately and document the evidence lost through redaction.
- Cluster correlation: join runtime subject identity to pod UID, container ID, image digest, node and Kubernetes audit records. The ServiceAccount is not the Linux UID, and Kubernetes RBAC does not explain every kernel decision.
- Resilience: forward evidence off-node under controlled access. A compromised kernel can undermine host telemetry; a clean local event stream is not proof of kernel integrity.
1 · Name the mechanism
ABI syscall, internal function, tracepoint or LSM hook? Separate sysfs object paths from sysctl settings.
2 · Prove sensor coverage
Build, configuration, attachments, canary events, loss counters and namespace visibility.
3 · Join the right objects
Host and boot, process birth identity, invocation, target identity and bounded time. PID is not enough.
4 · Test alternatives
Approved diagnostic, denied attempt, missing result and contradictory evidence. Retain uncertainty.
5 · Separate effect from intent
Bytes read are not injection, connection is not exfiltration, and a policy request is not a successful change.
6 · Maintain the contract
Versioned fixtures, review, exceptions with expiry, privacy, upgrade tests and response rollback.
Operator cheat sheet
Request only: attempted operation. Failure: rejected or failed call, cause needs attribution. Successful bytes: transfer for this call, not content classification. Approval: independent contextual record. Missing telemetry: unknown. Same PID: insufficient identity. Same time window: insufficient causality.
This checklist is a reading aid, not an automated security score. Ticks reset when the page reloads.
0 controls verified
Source and validation boundary
Mechanism references are linked alongside the relevant claims; reviewed October 17, 2026. The correlation contract and investigation guidance are K8SEC’s analysis. Automated tests validate synthetic logic, page behavior and links; they do not validate a live kernel sensor or establish real-world malware detection rates.
Continue with Kubernetes audit-log investigations and kernel boundaries and OpenShift hardening. K8SEC Agent remains read-only Kubernetes graph intelligence: no Secret-value collection, pod exec, resource mutation or autonomous exploitation.
I want an alert that can survive a skeptical investigation: the exact subject, the exact operation, the result, the policy context and the evidence we could not collect. A frightening syscall name is not enough.
The goal is not more kernel events. It is fewer unsupported conclusions.
Riad DAHMANI — K8SEC Security Research
Follow the evidence across boundaries.
Explore the documented relationships behind K8SEC research. A graph relationship is a hypothesis or a sourced statement—not automatic proof of compromise.
Explore K8Map research