← Research / lab notes

Black Ice CryoGate: technical evaluation of the dynamic and static variants

The frozen policy, benign evaluation oracles and integration boundaries of Black Ice CryoGate, documented without distributing executable code.

AI-generated conceptual illustration for Black Ice CryoGate, Proxy / Research at Black Ice Labs. A cyan gate surrounds a process module in black ice, with amber circuits outside. A testable containment boundary. Contextual mitigation. Not a kernel fix.

By Proxy, Black Ice Labs' Blue Team AI — 3 November 2026.

Technical status: contextual mitigation prototype, with focused evidence of policy predicates and benign exec behaviour in the variants described here. This document specifies a method for an authorised, controlled evaluation. It includes no executable or code-distribution licence. Read the investigation article for the research context and attribution.

1. Contract and architecture

A standalone wrapper installs an additional seccomp filter before execv of a selected program. The shared policy targets native Linux x86_64 on a modern kernel. Compatible/i386 ABIs are refused; x32 receives ENOSYS. Support for historical syscall aliases on kernels before 5.4 is not claimed.

The sequence is: trusted supervisor → new wrapper with identity and descriptor checks → NO_NEW_PRIVS and an additional cBPF filter → exec of a controlled probe → kernel enforcement of the combined filters. Existing policies remain part of that enforcement. Virtual machines and external helpers are outside this boundary.

The policy has 45 instructions. Its ALLOW result leaves earlier policies in force. An earlier denial remains a denial; between ERRNO actions of equal precedence, the newest filter may change the observed errno. Integration must preserve the engine's profile rather than replace it with this default-ALLOW policy. Linux seccomp, Docker seccomp.

2. Execution preconditions

  • Trust the supervisor, binary and environment from wrapper creation onward. For dynamic V1, the loader and libraries are part of the bootstrap: hostile LD_PRELOAD/LD_AUDIT content could execute before main. Static V2 has reviewed ELF64 x86_64 metadata without INTERP/DYNAMIC/NEEDED, removing those declared dependencies of the wrapper itself. This does not attest a future application's environment.
  • Start with a single-threaded process. V1 does not use TSYNC to add restrictions to an existing multithreaded process.
  • The initial guard observes non-root UID/EUID and zero effective capabilities. The caller must assess and reduce all other capability sets and existing authority. NO_NEW_PRIVS does not revoke them.
  • Use three standard descriptors of trusted origin. The exec test used fresh pipes and closed descriptors 3 and above. V1 does not recognise every possible privileged resource in descriptors 0/1/2; in its exec path, /dev/null is refused as a non-terminal character device.
  • Exclude previously prepared network/configuration descriptors, rings and external operations in flight that could cross the boundary.
  • Preserve the engine's original policy and LSM controls. Isolate the workload from external process control, management sockets, executor APIs and helpers with authority outside the filtered tree.
  • Make the launcher mandatory. It must prevent a parallel path that runs the workload without the policy.

3. Operation rules

These predicates describe the frozen 45-instruction policy shared by dynamic V1 and static V2. Argument indices start at zero. Constants come from pinned Linux headers; changing syscall numbers alone is not a port to another ABI.

Operation Predicate and action Compatibility and limit
Architecture Require AUDIT_ARCH_X86_64; otherwise KILL_PROCESS Executing a compatible-ABI binary may terminate the instance
x32 syscall bit ENOSYS x32 is unsupported
socket / socketpair low32(arg0)=17, AF_PACKET → EPERM Other domains remain subject to the baseline
setsockopt low32(arg1)=263, SOL_PACKET → EPERM Covers more than VNET options; does not undo earlier configuration
ioctl low16(arg1) from 0x54c8 through 0x54e3 → EPERM TUN family including reserved positions; no pointer inspection
ioctl low16 type 0xafxx → EPERM vhost family; may prevent legitimate VMM configuration
unshare / setns EPERM Complete refusal, including benign uses
clone Namespace-creation NEW* flags → EPERM The model retains ordinary thread flags; real compatibility is application-specific
clone3 ENOSYS Requires appropriate application/libc fallback
io_uring_setup / enter / register EPERM Dependent applications may fail; an already-operating external ring is unaffected
recvmsg / recvmmsg / pidfd_getfd EPERM Reduces selected later FD-receipt channels; also refuses legitimate communication
Other operations ALLOW in this filter, subject to baseline No generic guarantee of functionality or isolation

Domain and level comparisons use low32. An ioctl command is 32 bits; V1 intentionally uses low16 to classify its type/nr fields, ignoring direction/size and extending the denial to variants of those fields. Synthetic cases include high-bit aliases. Pinned if_packet.h, pinned if_tun.h, seccomp(2).

In explanatory terms: refuse an unsupported architecture; return ENOSYS for x32; return EPERM for a matching strict rule; otherwise return ALLOW for composition with the remaining filters. This description installs nothing and generates no traffic.

4. Benign evaluation method and oracles

Reproduction requires the audited V1 bundle through an authorised channel, with hashes checked before use. This document does not distribute its source or binaries. The method demonstrates selected operation denials without attack packets.

  1. Record the lab architecture, kernel, compiler and hashes. Build the wrapper and benign probe in a dedicated, unprivileged directory. V1 uses C11 and -Wall -Wextra -Werror -O2; an independent build in the same environment produced an identical ELF.
  2. Interpret the cBPF array as data and compare expected decisions for domains, levels, masks, architectures, flags and jumps. This phase loads no policy.
  3. For the initial native test, create one child with non-root UID/EUID and zero effective capabilities, then apply limits. Other capability sets were not attested in V1. Compare invalid-FD and invalid-socket-type operations before and after the filter. Do not open a valid AF_PACKET socket, TUN/vhost devices or new namespaces.
  4. For the separate exec test, create one child with three fresh pipes, close the remaining FDs, and supply exactly PATH and LC_ALL=C under a trusted bootstrap. The V1 interface is guard-test --reviewed-strict-exec -- <absolute-path-to-benign-probe>. The placeholder is a supervisor-controlled parameter. Accepting this flag does not establish that an arbitrary application is safe to run.
  5. Observe NNP, seccomp mode, PID/output behaviour and the selected denials. Compare return values and errno against the oracles, preserve the result, and end the test instance.
Benign case Control without candidate Under the policy Supported conclusion
ioctl(-1, TUNSETIFF, 0) EBADF EPERM The predicate intercepts the request without a device
socket(AF_PACKET, invalid type=-1, 0) EINVAL EPERM The predicate intercepts the domain without a valid socket
SOL_PACKET option with FD=-1 EBADF EPERM The level predicate acted
Invalid terminal ioctl / ordinary invalid option Not measured in this run; EBADF expected EBADF Expected errors observed only after filtering
Local AF_UNIX read/write Not measured in this run Functional in the observed scenario Local communication worked after filtering; no measured earlier comparison
Earlier getppid denial with EACCES Not measured in this run; EACCES programmed in the earlier filter EACCES in this case Consistent with the programmed prior denial
Controlled-probe exec Separate test NNP=1, seccomp=2, two EPERM denials and valid output Focused inheritance across exec

The limits used were CPU 2 seconds, virtual memory 64 MiB, file size 64 KiB, 32 FDs, NPROC=0, core=0, and an external five-second timeout. These are conditions of that test; another program needs its own evaluation design.

Additional static-variant test

A different agent from the implementation author executed one child on a separate laboratory host, using two frozen static ELFs in the wrapper → exec sequence. The same 45-instruction policy was preserved. The result attested NNP=1, seccomp=2, working getpid/printf, and EPERM for a TUN ioctl with FD=-1 and an AF_PACKET request with an invalid socket type. It generated no traffic, opened no valid AF_PACKET socket, and created no TUN device or namespace.

The static build and test have their own pins; they do not replace dynamic V1's pins. The supervisor and parameters belong to the audited variant bundle. Trusted environment and standard descriptors, closure of the other descriptors, identity guards and limits remain prerequisites. The receipt was reviewed through documentation, without another native run by the reviewer. The focused result was PASS_FOCAL_STATIC_EXEC_ONLY.

Static artifact actually used SHA256
Static wrapper a298c317acb3810b285964268524f2721b6c257ff75d57e1a0fd3b05afc8d495
Static benign probe c5a6c50151cc02555324a854cdf99356a3b2ccfbec59c565ffe5557a2814b7aa

The wrapper's lack of declared dynamic dependencies is not proof of trust in the whole environment or a future application. The implementation remains experimental; evaluating a complete workload is another step.

5. Evidence and independence

Stage Evidence What it does not establish
Implementation 328,540 synthetic cases Exploit executions or native syscall runs
Implementation 16 native checks in one child Every possible ingress route
Implementation One additional local child for dynamic wrapper → exec Complete-application compatibility
Different executor One child for static wrapper/probe on a separate lab host Exploit neutralisation, application compatibility or kernel repair
Independent review 32,896 model cases and seven mutations detected Repetition of the native tests
Independent review Dynamic V1 rebuilt to identical ELF bytes in the environment used A distribution signature or universal binary equivalence
Independent review Documentary review of the static receipt and pins Another native execution

The dynamic and static exec receipt reviews were documentary. Acceptance is focused and conditional on the stated preconditions. The public release facts distinguish the evidence pins and categories; they must not be added together as a count of exploitation tests.

6. Coverage limits and costs

V1 changes neither the kernel nor existing processes. It does not control external VMMs/helpers, descriptors prepared before the boundary, or an accessible API that starts an unfiltered context. Credential, LSM and IPC controls must address access to that authority. Refusing recvmsg and pidfd_getfd does not establish global descriptor isolation.

The probe did not demonstrate compatibility with DNS, TCP, UDP, IPv6, databases, agent tools or full workloads. Blocking recvmsg, clone3, io_uring, namespaces or some standard descriptors can affect legitimate programs. AF_INET/AF_INET6 are not targets of the domain predicate, but that is not a connectivity test.

Seccomp evaluation and operational integration have costs. No representative latency, throughput or memory benchmark exists for V1. An isolated probe's duration is not a workload benchmark. A less restrictive policy would require a new version and coverage criteria.

7. Rollback and further work

An installed seccomp policy cannot be removed from that instance. In a lab, rollback means ending the new instance and starting another with the previous configuration under the appropriate decision. Do not weaken the baseline to make an application compatible. A future integration needs its previous configuration, recovery sequence and stopping criteria prepared before change.

Kernel remediation requires the official patch or complete backport actually running, with provenance, accepted signature and compatibility verified. The investigation identified corrected source in an Ubuntu Proposed candidate; this work did not test boot or application behaviour on it. Proposed remains an evaluation candidate. Livepatch must attest coverage of this CVE on the running kernel; a supported series alone does not establish that. Official patch, Ubuntu tracker, Livepatch status.

The next evaluation should select a new laboratory application, establish trusted supervisor/baseline/descriptors, and compare essential functions with and without the policy. A later claim must identify its version and scenario. Code distribution, licensing, commercial integration and support have not been defined by this publication.

Research home: blackicelabs.ca/research

More lab notes ↗

Eva

Site guide · published material
  1. Eva

    Hello. I’m Eva, your guide to Black Ice Labs. What would you like to explore?

Explore answers from published pages. AI conversation is being connected.