| # uBPF Validation Plan |
| |
| **Document Version:** 1.2.0 |
| **Date:** 2026-06-12 |
| **Status:** Draft — Refreshed from current test inventory |
| |
| --- |
| |
| ## 1. Overview |
| |
| ### 1.1 Objectives |
| |
| This validation plan defines how the uBPF virtual machine library is verified against its requirements specification (`docs/specs/requirements.md`). It maps existing tests to requirements, identifies coverage gaps, and provides a framework for ongoing validation. |
| |
| ### 1.2 System Under Test |
| |
| The uBPF library including: |
| - Core VM interpreter (`vm/ubpf_vm.c`) |
| - JIT compilers (`vm/ubpf_jit_x86_64.c`, `vm/ubpf_jit_arm64.c`) |
| - ELF loader (`vm/ubpf_loader.c`) |
| - Instruction validator (`vm/ubpf_instruction_valid.c`) |
| - Public API (`vm/inc/ubpf.h`) |
| - Python assembler/disassembler (`ubpf/`) |
| |
| ### 1.3 Validation Approach |
| |
| uBPF uses a multi-layered testing strategy: |
| 1. **Data-driven tests** — `.data` files parsed by Python test framework |
| 2. **Custom C++ tests** — targeted scenarios for specific features |
| 3. **Conformance suite** — BPF ISA standard compliance (313 tests) |
| 4. **Differential fuzzing** — interpreter vs. JIT comparison with PREVAIL verifier |
| 5. **Static analysis** — CodeQL, scan-build, cpplint, pylint |
| 6. **Dynamic analysis** — ASan, UBSan, Valgrind |
| |
| --- |
| |
| ## 2. Scope of Validation |
| |
| ### 2.1 In Scope |
| |
| - All public API functions in `ubpf.h` |
| - Interpreter execution correctness |
| - JIT compilation correctness (x86-64, ARM64) |
| - ELF loading and relocation processing |
| - Instruction validation and error handling |
| - Security feature effectiveness |
| - Platform-specific behavior (Windows, Linux, macOS) |
| - Python assembler/disassembler correctness |
| |
| ### 2.2 Out of Scope |
| |
| - Performance benchmarking (no perf regression tests exist) |
| - Thread safety / concurrency testing |
| - Formal verification of JIT output |
| - External verifier (PREVAIL) correctness |
| - Stress testing (large programs, deep recursion) |
| |
| ### 2.3 Constraints |
| |
| - ARM64 JIT tests require QEMU on x86-64 hosts or native ARM64 hardware |
| - Fuzzing requires Clang (libFuzzer integration) |
| - Some tests require environment variables (e.g., `UBPF_ENABLE_CONSTANT_BLINDING=1`) |
| - Valgrind only available on Linux |
| |
| --- |
| |
| ## 3. Test Strategy |
| |
| ### 3.1 Test Levels |
| |
| | Level | Description | Tools | Coverage | |
| |-------|-------------|-------|----------| |
| | **Unit** | Individual instruction execution | `.data` files + test_vm.py | ISA compliance | |
| | **Integration** | VM lifecycle + loading + execution | Custom C++ tests | API interactions | |
| | **System** | Full pipeline (load ELF → compile → execute) | test_elf.py, ubpf_plugin | End-to-end | |
| | **Regression** | Prevent reintroduction of fixed bugs | Full CTest suite | All areas | |
| | **Fuzzing** | Find edge cases and differential bugs | libFuzzer + PREVAIL | Interpreter/JIT parity | |
| |
| ### 3.2 Test Techniques |
| |
| | Technique | Application | |
| |-----------|-------------| |
| | **Equivalence partitioning** | ALU operations by operand type (reg/imm, 32/64-bit) | |
| | **Boundary value analysis** | Register ranges (0, 9, 10), instruction count limits, stack boundaries | |
| | **Error guessing** | Division by zero, stack overflow, invalid opcodes | |
| | **Differential testing** | Interpreter vs. JIT output comparison (fuzzer) | |
| | **Mutation testing** | Register offset variations (20 per test in JIT) | |
| | **Conformance testing** | BPF ISA standard (RFC 9669) compliance | |
| |
| ### 3.3 Test Infrastructure |
| |
| **Python Framework (`test_framework/`):** |
| - `testdata.py` — Parses `.data` files into test parameters |
| - `test_vm.py` — Interpreter execution (1 test per `.data` file) |
| - `test_jit.py` — JIT compilation (20 register-offset variants per `.data` file) |
| - `test_elf.py` — ELF format loading |
| - `test_assembler.py` — Assembly → binary verification |
| - `test_disassembler.py` — Binary → assembly verification |
| - `test_roundtrip.py` — Assembler → binary → disassembler consistency |
| |
| **Custom Tests (`custom_tests/`):** |
| - 17 C++20 test programs with markdown descriptors |
| - Each returns 0 (pass) or non-zero (fail) |
| - Some read input from stdin via `.input` data files |
| |
| **Conformance Suite (`external/bpf_conformance/`):** |
| - 313 `.data` files for standard eBPF instruction semantics |
| - Executed via `ubpf_plugin` for both interpreter and JIT |
| - The uBPF CTest wiring also routes the repository's 104 local `.data` files through the same plugin contract |
| |
| **Fuzzer (`libfuzzer/libfuzz_harness.cc`):** |
| - Differential testing: interpreter vs. JIT |
| - Optional PREVAIL verifier integration |
| - Configurable via environment variables |
| |
| --- |
| |
| ## 4. Requirements Traceability Matrix |
| |
| ### 4.1 VM Lifecycle |
| |
| | REQ-ID | Requirement | Test Cases | Coverage | |
| |--------|-------------|------------|----------| |
| | REQ-LIFE-001 | VM creation | TC-LIFE-001 | **High** — implicitly tested by all tests | |
| | REQ-LIFE-002 | VM default state | TC-LIFE-004 | **Medium** — tested indirectly via default behavior | |
| | REQ-LIFE-003 | VM creation — allocations | TC-LIFE-006 | **Low** — `[GAP: no explicit OOM tests]` | |
| | REQ-LIFE-004 | Platform JIT selection | TC-LIFE-005 | **High** — CI runs on x86-64, ARM64, macOS | |
| | REQ-LIFE-005 | VM destruction | TC-LIFE-002 | **Medium** — Valgrind checks, reload_code_memleak | |
| | REQ-LIFE-006 | Code unloading | TC-LIFE-003 | **High** — unload_reload.data, reload.data | |
| |
| ### 4.2 Program Loading |
| |
| | REQ-ID | Requirement | Test Cases | Coverage | |
| |--------|-------------|------------|----------| |
| | REQ-LOAD-001 | Code length validation | TC-LOAD-002 | **Medium** — `[GAP: no test for non-multiple-of-8]` | |
| | REQ-LOAD-002 | Maximum instruction count | TC-LOAD-003 | **Low** — `[GAP: no test with 65536+ instructions]` | |
| | REQ-LOAD-003 | Double-load prevention | TC-LOAD-001 | **High** — all .data tests call ubpf_load | |
| | REQ-LOAD-004 | Instruction validation | TC-LOAD-004 | **High** — tests/errors/*, atomic_validate custom test | |
| | REQ-LOAD-005 | Read-only bytecode storage | TC-LOAD-007, TC-LOAD-008 | **Medium** — readonly_bytecode custom test (toggles mode only; `[GAP: no direct test that bytecode pages are read-only when enabled]`) | |
| | REQ-LOAD-006 | Pointer secret encoding | TC-LOAD-009 | **Medium** — `[GAP: no direct test of pointer secret encoding correctness]` | |
| | REQ-LOAD-007 | Local function marking | TC-LOAD-010 | **High** — call_local_use_stack.data, factorial.data | |
| | REQ-LOAD-008 | Stack alignment validation | TC-LOAD-005 | **High** — custom_local_function_stack_size tests | |
| | REQ-LOAD-009 | Sub-program containment | TC-LOAD-006 | **Medium** — tested via local call tests | |
| | REQ-LOAD-010 | Jump target validation | TC-LOAD-004 | **High** — tested via instruction validation | |
| | REQ-LOAD-011 | LDDW pairing validation | TC-LOAD-004 | **High** — tested via instruction validation | |
| |
| ### 4.3 Program Execution |
| |
| | REQ-ID | Requirement | Test Cases | Coverage | |
| |--------|-------------|------------|----------| |
| | REQ-EXEC-001 | Interpreter entry point | TC-EXEC-001 | **High** — test_vm.py runs all .data files | |
| | REQ-EXEC-002 | Extended interpreter entry point | TC-EXEC-002 | **Medium** — `[GAP: limited direct exec_ex tests]` | |
| | REQ-EXEC-003 | Register initialization | TC-EXEC-003 | **High** — mem/result comparison in all tests | |
| | REQ-EXEC-004 | Code-not-loaded guard | TC-EXEC-004 | **Medium** — `[GAP: no explicit test for exec without load]` | |
| | REQ-EXEC-005 | Instruction limit enforcement | TC-EXEC-009 | **Low** — `[GAP: no direct instruction limit test]` | |
| | REQ-EXEC-006 | Call depth limit | TC-EXEC-007 | **High** — factorial.data, call_local_use_stack.data, stack tests | |
| | REQ-EXEC-007 | XOR-decoded instruction fetch | TC-EXEC-004 | **High** — 360+ .data tests + fuzzer (implicit) | |
| | REQ-EXEC-008 | Unwind function support | TC-EXEC-008 | **Medium** — call_unwind.data | |
| | REQ-EXEC-009 | Debug callback invocation | TC-EXEC-010 | **High** — debug_function custom test | |
| |
| ### 4.4 JIT Compilation |
| |
| | REQ-ID | Requirement | Test Cases | Coverage | |
| |--------|-------------|------------|----------| |
| | REQ-JIT-001 | compile API | TC-JIT-001 | **High** — test_jit.py runs all .data files through JIT | |
| | REQ-JIT-002 | compile_ex API (BasicJitMode & ExtendedJitMode) | TC-JIT-002, TC-JIT-003, TC-JIT-004 | **High** — BasicJitMode is the default in test_jit.py; ExtendedJitMode tested via ubpf_plugin with --jit | |
| | REQ-JIT-003 | Code caching | TC-JIT-005 | **Low** — `[GAP: no explicit caching test]` | |
| | REQ-JIT-004 | Executable memory (W⊕X) | TC-JIT-006 | **Medium** — implicitly tested; ASan would catch violations | |
| | REQ-JIT-005 | JIT buffer sizing | TC-JIT-011 | **High** — jit_buffer_too_small custom test | |
| | REQ-JIT-006 | copy_jit API | TC-JIT-008 | **Medium** — indirectly exercised by `ubpf_plugin`; `[GAP: no dedicated API-focused unit test]` | |
| | REQ-JIT-007 | translate API | TC-JIT-007 | **Low** — `[GAP: no direct translate API test]` | |
| | REQ-JIT-008 | Instruction limit non-applicability | TC-JIT-012 | **Low** — `[GAP: no test verifying JIT ignores instruction limit]` | |
| | REQ-JIT-009 | x86-64 calling conventions | TC-JIT-009 | **High** — CI tests on Windows + Linux (different ABIs) | |
| | REQ-JIT-010 | ARM64 backend support | TC-JIT-010 | **High** — CI tests on ARM64 (native + QEMU) | |
| | REQ-JIT-011 | Post-compilation helper update | TC-JIT-013 | **High** — update_helpers, update_dispatcher custom tests | |
| |
| ### 4.5 ELF Loading |
| |
| | REQ-ID | Requirement | Test Cases | Coverage | |
| |--------|-------------|------------|----------| |
| | REQ-ELF-001 | ELF header validation | TC-ELF-002 | **Medium** — `[GAP: no tests with malformed ELF headers]` | |
| | REQ-ELF-002 | Section count limit | TC-ELF-008 | **Low** — `[GAP: no test with >32 sections]` | |
| | REQ-ELF-003 | ELF bounds checking | TC-ELF-003 | **High** — tests/elf/ directory | |
| | REQ-ELF-004 | R_BPF_64_64 data relocation | TC-ELF-004 | **High** — bpf/rel_64_32.bpf.c, tests/elf/ | |
| | REQ-ELF-005 | R_BPF_64_32 helper relocation | TC-ELF-005 | **High** — conformance suite helper tests | |
| | REQ-ELF-006 | ELF wrapper functions (load_elf) | TC-ELF-001 | **High** — test_elf.py | |
| | REQ-ELF-007 | Multi-function ELF linking | TC-ELF-006, TC-ELF-007 | **Medium** — tested via multi-function ELF programs; `[GAP: no explicit named-main test]` | |
| |
| ### 4.6 Instruction Set |
| |
| | REQ-ID | Requirement | Test Cases | Coverage | |
| |--------|-------------|------------|----------| |
| | REQ-ISA-001 | Instruction format (8 bytes) | TC-ISA-001 | **High** — assembler/raw comparison in all .data tests | |
| | REQ-ISA-002 | Register model (r0-r10) | TC-ISA-002 | **High** — frame_pointer custom test, JIT register offset variants | |
| | REQ-ISA-003 | ALU operations (32-bit and 64-bit) | TC-ISA-003, TC-ISA-004 | **High** — alu.data, alu64.data, 100+ conformance tests | |
| | REQ-ISA-004 | Signed division and modulo | TC-ISA-013 | **High** — sdiv32.data, sdiv64.data, smod32.data, smod64.data | |
| | REQ-ISA-005 | MOV with sign-extension (MOVSX) | TC-ISA-008 | **High** — conformance movsx tests | |
| | REQ-ISA-006 | Byte swap operations | TC-ISA-014 | **High** — conformance be16/32/64, le16/32/64 tests | |
| | REQ-ISA-007 | Memory load/store and LDDW | TC-ISA-005, TC-ISA-006 | **High** — ldx.data, st.data, stx.data, 80+ conformance tests (including lddw.data) | |
| | REQ-ISA-008 | Sign-extending loads | TC-ISA-007 | **High** — ldxsb-positive.data, ldxsh.data, conformance tests | |
| | REQ-ISA-009 | Jump instructions (64-bit and 32-bit) | TC-ISA-009, TC-ISA-010 | **High** — jmp.data, 40+ conformance jmp/jmp32 tests | |
| | REQ-ISA-010 | Atomic operations | TC-ISA-011 | **Medium** — atomic_validate custom test (validation only) | |
| | REQ-ISA-011 | CALL instruction variants | TC-ISA-012 | **High** — call.data, factorial.data | |
| | REQ-ISA-012 | EXIT instruction | TC-ISA-015 | **High** — early-exit.data, all tests terminate via EXIT | |
| |
| ### 4.7 Security |
| |
| | REQ-ID | Requirement | Test Cases | Coverage | |
| |--------|-------------|------------|----------| |
| | REQ-SEC-001 | Bounds checking | TC-SEC-001 | **High** — 10+ error tests (err-stack-oob, err-address-*) | |
| | REQ-SEC-002 | Bounds check toggle | TC-SEC-010 | **Medium** — implicitly tested (bounds on by default); `[GAP: no explicit toggle test]` | |
| | REQ-SEC-003 | Undefined behavior detection (shadow stack & registers) | TC-SEC-002, TC-SEC-008, TC-SEC-009 | **Low** — `[GAP: no explicit UB detection, shadow stack, or shadow register tests]` | |
| | REQ-SEC-004 | Constant blinding | TC-SEC-003 | **High** — constant_blinding custom test, CI env var | |
| | REQ-SEC-005 | Read-only bytecode | TC-SEC-004 | **Medium** — readonly_bytecode custom test (toggles mode; `[GAP: no test verifying pages are actually read-only]`) | |
| | REQ-SEC-006 | Pointer secret / XOR encoding | TC-SEC-005 | **Low** — `[GAP: no test verifying XOR encoding effectiveness]` | |
| | REQ-SEC-007 | Retpolines | TC-SEC-006 | **Medium** — CI runs with/without retpolines; no functional test | |
| | REQ-SEC-008 | W⊕X enforcement | TC-SEC-007 | **Medium** — implicitly tested by JIT execution | |
| | REQ-SEC-009 | Custom bounds check callback | TC-EXT-005 | **Low** — `[GAP: no explicit custom bounds check test]` | |
| |
| ### 4.8 Extensibility |
| |
| | REQ-ID | Requirement | Test Cases | Coverage | |
| |--------|-------------|------------|----------| |
| | REQ-EXT-001 | Helper registration | TC-EXT-001 | **High** — call.data, call-memfrob.data, update_helpers | |
| | REQ-EXT-002 | Helper function limit | TC-EXT-008 | **Low** — `[GAP: no test filling all 64 helper slots]` | |
| | REQ-EXT-003 | External dispatcher | TC-EXT-002 | **High** — 3 dispatcher custom tests | |
| | REQ-EXT-004 | Data relocation callback | TC-EXT-004 | **Medium** — tested via ELF loading | |
| | REQ-EXT-005 | Stack usage calculator | TC-EXT-006 | **High** — 3 custom_local_function_stack_size tests | |
| | REQ-EXT-006 | Debug function | TC-EXT-007 | **High** — debug_function custom test | |
| | REQ-EXT-007 | Unwind function | TC-EXT-003 | **High** — call_unwind.data | |
| |
| ### 4.9 Configuration |
| |
| | REQ-ID | Requirement | Test Cases | Coverage | |
| |--------|-------------|------------|----------| |
| | REQ-CFG-001 | Error print redirection | TC-CFG-001 | **Medium** — used in custom tests but not directly tested | |
| | REQ-CFG-002 | JIT buffer sizing | TC-CFG-002 | **High** — jit_buffer_too_small custom test | |
| | REQ-CFG-003 | Instruction limit | TC-CFG-003 | **Low** — `[GAP: no instruction limit test]` | |
| | REQ-CFG-004 | Register access (get/set) | TC-CFG-004 | **Low** — `[GAP: no get/set register test]` | |
| |
| ### 4.10 Platform |
| |
| | REQ-ID | Requirement | Test Cases | Coverage | |
| |--------|-------------|------------|----------| |
| | REQ-PLAT-001 | Windows support | TC-PLAT-001 | **High** — CI: windows-2022, Debug + Release | |
| | REQ-PLAT-002 | Linux support | TC-PLAT-002 | **High** — CI: ubuntu-latest, coverage + sanitizers | |
| | REQ-PLAT-003 | macOS support | TC-PLAT-003 | **High** — CI: macos-latest | |
| | REQ-PLAT-004 | JIT architecture support (x86-64) | TC-PLAT-004 | **High** — CI on all x86-64 platforms | |
| | REQ-PLAT-005 | Cryptographic random generation | TC-PLAT-007 | **Low** — `[GAP: no dedicated test verifies RNG output or fallback behavior]` | |
| | REQ-PLAT-006 | Platform atomic operations | TC-PLAT-008 | **Medium** — atomic_validate custom test; `[GAP: no cross-platform atomic correctness test]` | |
| |
| ### 4.11 Error Handling |
| |
| | REQ-ID | Requirement | Test Cases | Coverage | |
| |--------|-------------|------------|----------| |
| | REQ-ERR-001 | Error message allocation | TC-ERR-001 | **High** — error tests check stderr output | |
| | REQ-ERR-002 | Error output function | TC-ERR-002 | **Medium** — used but not directly validated | |
| | REQ-ERR-003 | Toggle return values | TC-ERR-003 | **Medium** — toggles used in custom tests | |
| |
| ### 4.12 Constants |
| |
| | REQ-ID | Requirement | Test Cases | Coverage | |
| |--------|-------------|------------|----------| |
| | REQ-CONST-001 | System constants | TC-CONST-001 | **Medium** — constants used throughout tests but not boundary-tested | |
| |
| ### 4.13 Safe Interpreter Profile |
| |
| | REQ-ID | Requirement | Test Cases | Coverage | |
| |--------|-------------|------------|----------| |
| | REQ-SAFE-001 | Additive safe execution profile | TC-SAFE-001 | **High** — safe-profile opt-in, immutability-after-load, interpreter-only execution, and legacy-vs-safe interpreter parity are covered in both local conformance runs and generated CTest cases | |
| | REQ-SAFE-002 | Tagged register provenance model | TC-SAFE-002 | **Medium** — stack-root and no-input-memory behavior are exercised indirectly, but explicit entry-state checks for R0/R3-R9 and R1-without-mem remain open | |
| | REQ-SAFE-003 | Provenance-checked memory access choke points | TC-SAFE-003 | **Medium** — pointer-backed loads/stores and opaque-handle rejection are covered; atomic-result scalar classification still needs direct coverage | |
| | REQ-SAFE-004 | Pointer arithmetic and tag propagation | TC-SAFE-004 | **High** — pointer add/subtract success and failure matrix, ALU32 tag clearing, and the common stack-frame address-computation idiom are covered | |
| | REQ-SAFE-005 | Typed helper metadata and return provenance | TC-SAFE-005 | **Medium** — typed pointer return success and missing-metadata rejection are covered; scalar-return and out-of-bounds return cases remain open | |
| | REQ-SAFE-006 | Descriptor-based external region metadata | TC-SAFE-006 | **Low** — single-region descriptor resolution is covered, but multi-region distinction and legacy-bounds-callback insufficiency are still gaps | |
| | REQ-SAFE-007 | Spill and call-frame provenance preservation | TC-SAFE-007 | **Medium** — spill restore, spill invalidation, and caller-saved reclassification are covered; direct callee-saved provenance restoration remains open | |
| | REQ-SAFE-008 | Initial safe-profile JIT unavailability | TC-SAFE-008 | **High** — explicit compile rejection is covered by a dedicated custom test | |
| |
| --- |
| |
| ## 5. Test Cases |
| |
| ### TC-LIFE — VM Lifecycle |
| |
| #### TC-LIFE-001: VM Creation |
| - **Traces to:** REQ-LIFE-001 |
| - **Level:** Unit |
| - **Confidence:** High |
| - **Evidence:** Every test implicitly calls `ubpf_create()` / `ubpf_destroy()` |
| - **Pass criteria:** VM pointer is non-NULL, all subsequent operations succeed |
| - **Existing tests:** All test_vm.py, test_jit.py tests |
| |
| #### TC-LIFE-002: VM Destruction / Memory Leaks |
| - **Traces to:** REQ-LIFE-005 |
| - **Level:** Integration |
| - **Confidence:** Medium |
| - **Evidence:** `custom_tests/srcs/ubpf_test_reload_code_memleak.cc`, Valgrind CI job |
| - **Pass criteria:** No memory leaks reported by Valgrind; reload_code_memleak returns 0 |
| - **Existing tests:** reload_code_memleak-Custom, Valgrind CI workflow |
| |
| #### TC-LIFE-003: Code Unloading and Reloading |
| - **Traces to:** REQ-LIFE-006, REQ-LOAD-003 |
| - **Level:** Integration |
| - **Confidence:** High |
| - **Evidence:** `tests/reload.data`, `tests/unload_reload.data` |
| - **Pass criteria:** VM accepts new code after unload; second execution produces correct result |
| - **Existing tests:** test_vm reload/unload_reload tests |
| |
| #### TC-LIFE-004: Default Configuration Values |
| - **Traces to:** REQ-LIFE-002 |
| - **Level:** Unit |
| - **Confidence:** Medium |
| - **Evidence:** Tested indirectly — defaults produce expected behavior in standard tests |
| - **Pass criteria:** Bounds checking enabled, constant blinding disabled, read-only mode enabled |
| - **`[GAP]`:** No test explicitly verifies each default value after `ubpf_create()` |
| |
| #### TC-LIFE-005: Platform JIT Selection |
| - **Traces to:** REQ-LIFE-004 |
| - **Level:** System |
| - **Confidence:** High |
| - **Evidence:** CI matrix runs JIT tests on x86-64 (Windows/Linux/macOS) and ARM64 |
| - **Pass criteria:** JIT compilation succeeds on supported platforms |
| |
| #### TC-LIFE-006: Memory Allocation Failure |
| - **Traces to:** REQ-LIFE-003 |
| - **Level:** Unit |
| - **Confidence:** Low |
| - **`[GAP]`:** No test injects allocation failures. Would require mock allocator or ulimit. |
| |
| ### TC-LOAD — Program Loading |
| |
| #### TC-LOAD-001: Double-Load Prevention |
| - **Traces to:** REQ-LOAD-003 |
| - **Level:** Unit |
| - **Confidence:** High |
| - **Evidence:** All `.data` tests call `ubpf_load` as part of normal flow |
| - **Pass criteria:** Loading code into a VM that already has code loaded returns an error |
| - **Existing tests:** All data-driven tests (implicit) |
| |
| #### TC-LOAD-002: Code Length Validation |
| - **Traces to:** REQ-LOAD-001 |
| - **Level:** Unit |
| - **Confidence:** Medium |
| - **`[GAP]`:** No test for loading code with length that is not a multiple of 8 bytes. |
| |
| #### TC-LOAD-003: Maximum Instruction Count |
| - **Traces to:** REQ-LOAD-002 |
| - **Level:** Unit |
| - **Confidence:** Low |
| - **`[GAP]`:** No test with 65536+ instructions to verify the maximum instruction count limit. |
| |
| #### TC-LOAD-004: Instruction Validation |
| - **Traces to:** REQ-LOAD-004, REQ-LOAD-010, REQ-LOAD-011 |
| - **Level:** Unit |
| - **Confidence:** High |
| - **Evidence:** `tests/errors/*` invalid instruction tests, `atomic_validate` custom test |
| - **Pass criteria:** Invalid instructions, out-of-range jump targets, and unpaired LDDW are rejected at load time |
| - **Existing tests:** tests/errors/*, atomic_validate-Custom |
| |
| #### TC-LOAD-005: Stack Alignment Validation |
| - **Traces to:** REQ-LOAD-008 |
| - **Level:** Unit |
| - **Confidence:** High |
| - **Evidence:** `custom_tests/srcs/ubpf_test_custom_local_function_stack_size.cc` and unaligned variant |
| - **Pass criteria:** Unaligned stack sizes are rejected |
| - **Existing tests:** custom_local_function_stack_size-Custom, custom_local_function_stack_size_unaligned-Custom |
| |
| #### TC-LOAD-006: Sub-Program Containment |
| - **Traces to:** REQ-LOAD-009 |
| - **Level:** Unit |
| - **Confidence:** Medium |
| - **Evidence:** Tested via local function call tests that validate sub-programs stay within bounds |
| - **Pass criteria:** Sub-programs that exceed the program boundary are rejected |
| - **Existing tests:** Local call tests (indirect) |
| |
| #### TC-LOAD-007: Read-Only Bytecode Storage (Enabled) |
| - **Traces to:** REQ-LOAD-005 |
| - **Level:** Unit |
| - **Confidence:** Medium |
| - **Evidence:** `custom_tests/srcs/ubpf_test_readonly_bytecode.cc` |
| - **Pass criteria:** Bytecode pages are marked read-only when feature is enabled |
| - **Existing tests:** readonly_bytecode-Custom |
| - **`[GAP]`:** No test verifying pages are actually read-only (e.g., via write-and-trap). |
| |
| #### TC-LOAD-008: Read-Only Bytecode Storage (Disabled) |
| - **Traces to:** REQ-LOAD-005 |
| - **Level:** Unit |
| - **Confidence:** Medium |
| - **Evidence:** `custom_tests/srcs/ubpf_test_readonly_bytecode.cc` toggles mode |
| - **Pass criteria:** Bytecode is writable when read-only mode is disabled |
| - **Existing tests:** readonly_bytecode-Custom |
| |
| #### TC-LOAD-009: Pointer Secret Encoding |
| - **Traces to:** REQ-LOAD-006 |
| - **Level:** Unit |
| - **Confidence:** Medium |
| - **`[GAP]`:** No direct test of pointer secret encoding correctness. Encoding is exercised implicitly via all interpreter tests. |
| |
| #### TC-LOAD-010: Local Function Marking |
| - **Traces to:** REQ-LOAD-007 |
| - **Level:** Unit |
| - **Confidence:** High |
| - **Evidence:** `tests/extensions/call_local_use_stack.data`, `tests/factorial.data` |
| - **Pass criteria:** Local functions are correctly identified and callable |
| - **Existing tests:** call_local_use_stack, factorial |
| |
| ### TC-ELF — ELF Loading |
| |
| #### TC-ELF-001: ELF Wrapper Functions |
| - **Traces to:** REQ-ELF-006 |
| - **Level:** System |
| - **Confidence:** High |
| - **Evidence:** `test_framework/test_elf.py` runs ELF-based tests |
| - **Pass criteria:** `ubpf_load_elf()` successfully loads valid ELF files and programs execute correctly |
| - **Existing tests:** test_elf.py |
| |
| #### TC-ELF-002: ELF Header Validation |
| - **Traces to:** REQ-ELF-001 |
| - **Level:** Unit |
| - **Confidence:** Medium |
| - **`[GAP]`:** No tests with malformed ELF headers (wrong magic, wrong class, wrong machine type). |
| |
| #### TC-ELF-003: ELF Bounds Checking |
| - **Traces to:** REQ-ELF-003 |
| - **Level:** Unit |
| - **Confidence:** High |
| - **Evidence:** `tests/elf/` directory contains ELF-specific test programs |
| - **Pass criteria:** Out-of-bounds section references in ELF files are rejected |
| - **Existing tests:** tests/elf/* |
| |
| #### TC-ELF-004: R_BPF_64_64 Data Relocation |
| - **Traces to:** REQ-ELF-004 |
| - **Level:** Integration |
| - **Confidence:** High |
| - **Evidence:** `bpf/rel_64_32.bpf.c`, `tests/elf/` relocation tests |
| - **Pass criteria:** 64-bit data relocations are resolved correctly |
| - **Existing tests:** tests/elf/*, bpf/rel_64_32.bpf.c |
| |
| #### TC-ELF-005: R_BPF_64_32 Helper Relocation |
| - **Traces to:** REQ-ELF-005 |
| - **Level:** Integration |
| - **Confidence:** High |
| - **Evidence:** Conformance suite helper tests exercise helper relocations |
| - **Pass criteria:** 32-bit helper function relocations are resolved correctly |
| - **Existing tests:** Conformance helper tests |
| |
| #### TC-ELF-006: Multi-Function ELF Linking |
| - **Traces to:** REQ-ELF-007 |
| - **Level:** Integration |
| - **Confidence:** Medium |
| - **Evidence:** Multi-function ELF programs tested via ELF loader |
| - **Pass criteria:** Multiple functions within an ELF are correctly linked and callable |
| - **Existing tests:** Multi-function ELF programs (indirect) |
| |
| #### TC-ELF-007: Main Function Selection |
| - **Traces to:** REQ-ELF-007 |
| - **Level:** Integration |
| - **Confidence:** Medium |
| - **`[GAP]`:** No explicit test for named-main function selection in multi-function ELF files. |
| |
| #### TC-ELF-008: Section Count Limit |
| - **Traces to:** REQ-ELF-002 |
| - **Level:** Unit |
| - **Confidence:** Low |
| - **`[GAP]`:** No test with >32 sections to verify the section count limit is enforced. |
| |
| ### TC-EXEC — Execution |
| |
| #### TC-EXEC-001: Interpreter Execution (Data-Driven) |
| - **Traces to:** REQ-EXEC-001, REQ-EXEC-003, REQ-EXEC-007 |
| - **Level:** Unit |
| - **Confidence:** High |
| - **Evidence:** `test_framework/test_vm.py` — runs every `.data` file through interpreter |
| - **Pass criteria:** Return value matches `-- result` section; errors match `-- error` section |
| - **Existing tests:** 104 repository `.data` files via `test_vm.py`, plus 417 plugin-driven interpreter runs (104 local + 313 conformance) |
| |
| #### TC-EXEC-002: Extended Interpreter Entry Point |
| - **Traces to:** REQ-EXEC-002 |
| - **Level:** Unit |
| - **Confidence:** Medium |
| - **`[GAP]`:** Limited direct exec_ex tests. No dedicated test exercises `ubpf_exec_ex()` API independently from standard `ubpf_exec()`. |
| |
| #### TC-EXEC-003: Register Initialization |
| - **Traces to:** REQ-EXEC-003 |
| - **Level:** Unit |
| - **Confidence:** High |
| - **Evidence:** Memory and result comparison in all data-driven tests validates correct r1/r2 initialization |
| - **Pass criteria:** r1 points to memory input, r2 contains memory length, r0 returns correct result |
| - **Existing tests:** All local `test_vm.py` data-driven tests plus plugin-driven interpreter coverage |
| |
| #### TC-EXEC-004: Code-Not-Loaded Guard and XOR-Decoded Fetch |
| - **Traces to:** REQ-EXEC-004, REQ-EXEC-007 |
| - **Level:** Unit |
| - **Confidence:** Medium |
| - **Evidence:** XOR decode is implicit in all 360+ data-driven tests (instructions are encoded on load) |
| - **Pass criteria:** Execution without loaded code returns error; XOR-decoded instructions execute correctly |
| - **`[GAP]`:** No explicit test for executing without loading code first. |
| |
| #### TC-EXEC-005: ALU Operations |
| - **Traces to:** REQ-ISA-003, REQ-ISA-004 |
| - **Level:** Unit |
| - **Confidence:** High |
| - **Evidence:** `tests/alu.data`, `tests/alu64.data`, `tests/sdiv32.data`, `tests/sdiv64.data`, `tests/smod32.data`, `tests/smod64.data`, `tests/arsh*.data`, 100+ conformance ALU tests |
| - **Pass criteria:** Correct arithmetic results for all operations, all operand types |
| - **Existing tests:** Comprehensive coverage of ADD, SUB, MUL, DIV, MOD, OR, AND, XOR, LSH, RSH, ARSH, NEG, MOV, SDIV, SMOD |
| |
| #### TC-EXEC-006: Memory Bounds Checking |
| - **Traces to:** REQ-SEC-001 |
| - **Level:** Unit |
| - **Confidence:** High |
| - **Evidence:** `tests/errors/err-stack-oob.data`, `tests/errors/err-address-overflow-offset.data`, `tests/errors/err-address-underflow.data`, `tests/errors/err-integer-overflow-bounds.data` |
| - **Pass criteria:** Out-of-bounds access produces error (non-zero exit, error message) |
| - **Existing tests:** 4+ dedicated error tests |
| |
| #### TC-EXEC-007: Local Function Calls |
| - **Traces to:** REQ-EXEC-006 |
| - **Level:** Integration |
| - **Confidence:** High |
| - **Evidence:** `tests/factorial.data`, `tests/extensions/call_local_use_stack.data`, `tests/stack2.data`, `tests/stack3.data`, custom_local_function_stack_size tests |
| - **Pass criteria:** Correct return values; callee-saved registers (r6-r9) preserved; frame pointer (r10) adjusted correctly |
| - **Existing tests:** 5+ tests covering local calls |
| |
| #### TC-EXEC-008: External Helper Calls |
| - **Traces to:** REQ-EXEC-008, REQ-EXT-001 |
| - **Level:** Integration |
| - **Confidence:** High |
| - **Evidence:** `tests/helpers/call.data`, `tests/helpers/call-memfrob.data`, `tests/helpers/call-save.data` |
| - **Pass criteria:** Helper receives correct parameters; return value propagated to r0 |
| - **Existing tests:** 3 dedicated helper tests + conformance call tests |
| |
| #### TC-EXEC-009: Instruction Limit Enforcement |
| - **Traces to:** REQ-EXEC-005 |
| - **Level:** Unit |
| - **Confidence:** Low |
| - **`[GAP]`:** No test currently exercises `ubpf_set_instruction_limit()`. Should verify interpreter stops after N instructions. |
| |
| #### TC-EXEC-010: Debug Callback Invocation |
| - **Traces to:** REQ-EXEC-009 |
| - **Level:** Unit |
| - **Confidence:** High |
| - **Evidence:** `custom_tests/srcs/ubpf_test_debug_function.cc` |
| - **Pass criteria:** Debug callback invoked before each instruction with correct PC, registers, and stack info |
| - **Existing tests:** debug_function-Custom |
| |
| ### TC-ISA — Instruction Set Architecture |
| |
| #### TC-ISA-001: Instruction Format |
| - **Traces to:** REQ-ISA-001 |
| - **Level:** Unit |
| - **Confidence:** High |
| - **Evidence:** Assembler/raw comparison in all `.data` tests validates instruction encoding |
| - **Pass criteria:** Instructions are correctly encoded and decoded in the 8-byte format |
| - **Existing tests:** 104 local data-driven tests plus plugin-driven coverage over the 313-test conformance suite |
| |
| #### TC-ISA-002: Register Model |
| - **Traces to:** REQ-ISA-002 |
| - **Level:** Unit |
| - **Confidence:** High |
| - **Evidence:** `custom_tests/srcs/ubpf_test_frame_pointer.cc`, JIT register offset variants |
| - **Pass criteria:** All 11 registers (r0-r10) function correctly; r10 is read-only frame pointer |
| - **Existing tests:** frame_pointer-Custom, JIT offset tests |
| |
| #### TC-ISA-003: ALU64 Operations |
| - **Traces to:** REQ-ISA-003 |
| - **Level:** Unit |
| - **Confidence:** High |
| - **Evidence:** `tests/alu64.data`, 50+ conformance ALU64 tests |
| - **Pass criteria:** All 64-bit ALU operations produce correct results |
| - **Existing tests:** alu64, conformance ALU64 tests |
| |
| #### TC-ISA-004: ALU32 Operations |
| - **Traces to:** REQ-ISA-003 |
| - **Level:** Unit |
| - **Confidence:** High |
| - **Evidence:** `tests/alu.data`, 50+ conformance ALU32 tests |
| - **Pass criteria:** All 32-bit ALU operations produce correct results with zero-extension |
| - **Existing tests:** alu, conformance ALU32 tests |
| |
| #### TC-ISA-005: Memory Load/Store |
| - **Traces to:** REQ-ISA-007 |
| - **Level:** Unit |
| - **Confidence:** High |
| - **Evidence:** `tests/ldx.data`, `tests/st.data`, `tests/stx.data`, 80+ conformance memory tests |
| - **Pass criteria:** All memory load and store operations at all widths (8/16/32/64) produce correct results |
| - **Existing tests:** ldx, st, stx, conformance memory tests |
| |
| #### TC-ISA-006: LDDW (64-bit Immediate Load) |
| - **Traces to:** REQ-ISA-007 |
| - **Level:** Unit |
| - **Confidence:** High |
| - **Evidence:** `external/bpf_conformance/tests/lddw.data`, conformance LDDW tests |
| - **Pass criteria:** 64-bit immediate values are correctly loaded via two-instruction LDDW |
| - **Existing tests:** lddw, conformance LDDW tests |
| |
| #### TC-ISA-007: Sign-Extending Loads |
| - **Traces to:** REQ-ISA-008 |
| - **Level:** Unit |
| - **Confidence:** High |
| - **Evidence:** `tests/ldxsb-positive.data`, `tests/ldxsh.data`, conformance sign-extension tests |
| - **Pass criteria:** Sign-extending loads correctly extend signed values to 64 bits |
| - **Existing tests:** ldxsb-positive, ldxsh, conformance tests |
| |
| #### TC-ISA-008: MOVSX (Sign-Extending Move) |
| - **Traces to:** REQ-ISA-005 |
| - **Level:** Unit |
| - **Confidence:** High |
| - **Evidence:** Conformance MOVSX tests |
| - **Pass criteria:** MOVSX instructions correctly sign-extend source to destination register |
| - **Existing tests:** Conformance MOVSX tests |
| |
| #### TC-ISA-009: Jump Instructions (64-bit) |
| - **Traces to:** REQ-ISA-009 |
| - **Level:** Unit |
| - **Confidence:** High |
| - **Evidence:** `tests/jmp.data`, 40+ conformance jump tests |
| - **Pass criteria:** All conditional and unconditional jumps with 64-bit comparisons branch correctly |
| - **Existing tests:** jmp, conformance jump tests |
| |
| #### TC-ISA-010: JMP32 (32-bit Jumps) |
| - **Traces to:** REQ-ISA-009 |
| - **Level:** Unit |
| - **Confidence:** High |
| - **Evidence:** Conformance JMP32 tests |
| - **Pass criteria:** All conditional jumps with 32-bit comparisons branch correctly |
| - **Existing tests:** Conformance JMP32 tests |
| |
| #### TC-ISA-011: Atomic Operations |
| - **Traces to:** REQ-ISA-010 |
| - **Level:** Unit |
| - **Confidence:** Medium |
| - **Evidence:** `custom_tests/srcs/ubpf_test_atomic_validate.cc` (validation only) |
| - **Pass criteria:** Atomic instructions are validated at load time |
| - **Existing tests:** atomic_validate-Custom |
| - **`[GAP]`:** No runtime execution test for atomic operations; only validation is tested. |
| |
| #### TC-ISA-012: CALL Instruction |
| - **Traces to:** REQ-ISA-011 |
| - **Level:** Unit |
| - **Confidence:** High |
| - **Evidence:** `tests/helpers/call.data`, `tests/factorial.data` |
| - **Pass criteria:** CALL instruction correctly invokes helper functions and local functions |
| - **Existing tests:** call, factorial |
| |
| #### TC-ISA-013: Signed Division and Modulo |
| - **Traces to:** REQ-ISA-004 |
| - **Level:** Unit |
| - **Confidence:** High |
| - **Evidence:** `tests/sdiv32.data`, `tests/sdiv64.data`, `tests/smod32.data`, `tests/smod64.data` |
| - **Pass criteria:** Signed division and modulo produce correct results including negative operands |
| - **Existing tests:** sdiv32, sdiv64, smod32, smod64 |
| |
| #### TC-ISA-014: Byte Swap Operations |
| - **Traces to:** REQ-ISA-006 |
| - **Level:** Unit |
| - **Confidence:** High |
| - **Evidence:** Conformance BE16/32/64, LE16/32/64 tests |
| - **Pass criteria:** Byte swap operations correctly convert endianness at all widths |
| - **Existing tests:** Conformance BE/LE tests |
| |
| #### TC-ISA-015: EXIT Instruction |
| - **Traces to:** REQ-ISA-012 |
| - **Level:** Unit |
| - **Confidence:** High |
| - **Evidence:** `tests/early-exit.data`, all tests terminate via EXIT instruction |
| - **Pass criteria:** EXIT instruction terminates execution and returns r0 |
| - **Existing tests:** early-exit, all data-driven tests |
| |
| ### TC-JIT — JIT Compilation |
| |
| #### TC-JIT-001: JIT Execution Correctness |
| - **Traces to:** REQ-JIT-001, REQ-JIT-002 |
| - **Level:** System |
| - **Confidence:** High |
| - **Evidence:** `test_framework/test_jit.py` — runs every `.data` file through JIT with 20 register-offset variants |
| - **Pass criteria:** JIT output matches interpreter output for all tests |
| - **Existing tests:** 104 local `.data` files with up to 20 register-offset variants, plus 417 plugin-driven JIT runs (104 local + 313 conformance) |
| |
| #### TC-JIT-002: compile_ex API |
| - **Traces to:** REQ-JIT-002 |
| - **Level:** Integration |
| - **Confidence:** Medium |
| - **Evidence:** `ubpf_plugin` in ExtendedJitMode exercises `ubpf_compile_ex()` |
| - **Pass criteria:** Extended JIT compilation API succeeds and produces executable code |
| - **Existing tests:** ubpf_plugin ExtendedJitMode tests |
| |
| #### TC-JIT-003: BasicJitMode |
| - **Traces to:** REQ-JIT-002 |
| - **Level:** System |
| - **Confidence:** High |
| - **Evidence:** Default mode in `test_framework/test_jit.py` |
| - **Pass criteria:** JIT compilation in basic mode produces correct results for all tests |
| - **Existing tests:** test_jit.py (default mode) |
| |
| #### TC-JIT-004: ExtendedJitMode |
| - **Traces to:** REQ-JIT-002 |
| - **Level:** System |
| - **Confidence:** Medium |
| - **Evidence:** `ubpf_plugin` with `--jit` flag exercises extended JIT mode |
| - **Pass criteria:** JIT compilation in extended mode produces correct results |
| - **Existing tests:** ubpf_plugin with --jit |
| |
| #### TC-JIT-005: Code Caching |
| - **Traces to:** REQ-JIT-003 |
| - **Level:** Unit |
| - **Confidence:** Low |
| - **`[GAP]`:** No explicit caching test. No test verifies that compiled JIT code is reused across invocations. |
| |
| #### TC-JIT-006: W⊕X Memory |
| - **Traces to:** REQ-JIT-004 |
| - **Level:** Integration |
| - **Confidence:** Medium |
| - **Evidence:** Implicit; ASan would catch memory protection violations |
| - **Pass criteria:** JIT-compiled code memory is not simultaneously writable and executable |
| - **Existing tests:** All JIT tests with ASan (implicit) |
| |
| #### TC-JIT-007: translate API |
| - **Traces to:** REQ-JIT-007 |
| - **Level:** Unit |
| - **Confidence:** Low |
| - **`[GAP]`:** No direct test of the `ubpf_translate()` API for outputting JIT code to an external buffer. |
| |
| #### TC-JIT-008: copy_jit API |
| - **Traces to:** REQ-JIT-006 |
| - **Level:** Unit |
| - **Confidence:** Medium |
| - **Evidence:** `ubpf_plugin/ubpf_plugin.cc` copies JIT output into an executable mapping and executes the copy, comparing it with the original JIT result. |
| - **Pass criteria:** Copied JIT code executes independently and matches the original JIT result. |
| - **`[GAP]`:** No dedicated unit test isolates `ubpf_copy_jit()` failure modes beyond the plugin path. |
| |
| #### TC-JIT-009: x86-64 Dual ABI |
| - **Traces to:** REQ-JIT-009 |
| - **Level:** System |
| - **Confidence:** High |
| - **Evidence:** CI runs JIT tests on both Windows (Win64 ABI) and Linux (System V ABI) |
| - **Pass criteria:** Same tests pass on both platforms |
| - **Existing tests:** CI matrix covers both ABIs |
| |
| #### TC-JIT-010: ARM64 Backend Support |
| - **Traces to:** REQ-JIT-010 |
| - **Level:** System |
| - **Confidence:** High |
| - **Evidence:** CI on ARM64 (native + QEMU emulation) |
| - **Pass criteria:** JIT compilation and execution succeeds on ARM64 architecture |
| - **Existing tests:** CI matrix (ARM64 native and QEMU) |
| |
| #### TC-JIT-011: JIT Buffer Too Small |
| - **Traces to:** REQ-JIT-005, REQ-CFG-002 |
| - **Level:** Unit |
| - **Confidence:** High |
| - **Evidence:** `custom_tests/srcs/ubpf_test_jit_buffer_too_small.cc` |
| - **Pass criteria:** JIT compilation fails gracefully with error message |
| - **Existing tests:** jit_buffer_too_small-Custom |
| |
| #### TC-JIT-012: Instruction Limit Non-Applicability |
| - **Traces to:** REQ-JIT-008 |
| - **Level:** Unit |
| - **Confidence:** Low |
| - **`[GAP]`:** No test verifying that `ubpf_set_instruction_limit()` does not affect JIT execution. |
| |
| #### TC-JIT-013: Post-Compilation Helper Update |
| - **Traces to:** REQ-JIT-011 |
| - **Level:** Integration |
| - **Confidence:** High |
| - **Evidence:** `custom_tests/srcs/ubpf_test_update_helpers.cc`, `ubpf_test_update_dispatcher.cc` |
| - **Pass criteria:** Helpers/dispatcher can be updated after JIT compilation; updated functions are called |
| - **Existing tests:** update_helpers-Custom, update_dispatcher-Custom |
| |
| ### TC-SEC — Security |
| |
| #### TC-SEC-001: Bounds Check Enforcement |
| - **Traces to:** REQ-SEC-001 |
| - **Level:** Unit |
| - **Confidence:** High |
| - **Evidence:** `tests/errors/err-stack-oob.data` and related error tests |
| - **Pass criteria:** OOB access rejected with error |
| - **Existing tests:** 10+ error condition tests |
| |
| #### TC-SEC-003: Constant Blinding |
| - **Traces to:** REQ-SEC-004 |
| - **Level:** Integration |
| - **Confidence:** High |
| - **Evidence:** `custom_tests/srcs/ubpf_test_constant_blinding.cc`, CI runs with `UBPF_ENABLE_CONSTANT_BLINDING=1` |
| - **Pass criteria:** JIT produces correct results with blinding enabled; all CTest passes with blinding |
| - **Existing tests:** constant_blinding-Custom, CI environment flag |
| |
| #### TC-SEC-004: Read-Only Bytecode |
| - **Traces to:** REQ-SEC-005 |
| - **Level:** Unit |
| - **Confidence:** High |
| - **Evidence:** `custom_tests/srcs/ubpf_test_readonly_bytecode.cc` |
| - **Pass criteria:** Bytecode stored in read-only pages; toggling mode works correctly |
| - **Existing tests:** readonly_bytecode-Custom |
| |
| #### TC-SEC-005: Pointer Secret / XOR Encoding |
| - **Traces to:** REQ-SEC-006 |
| - **Level:** Unit |
| - **Confidence:** Low |
| - **`[GAP]`:** No test verifying XOR encoding effectiveness or that pointer secret changes instruction storage. |
| |
| #### TC-SEC-006: Retpolines |
| - **Traces to:** REQ-SEC-007 |
| - **Level:** System |
| - **Confidence:** Medium |
| - **Evidence:** CI runs both with and without `UBPF_DISABLE_RETPOLINES` |
| - **Pass criteria:** Tests pass in both configurations |
| - **Existing tests:** CI matrix (no dedicated functional test) |
| |
| #### TC-SEC-007: W⊕X Enforcement |
| - **Traces to:** REQ-SEC-008 |
| - **Level:** Integration |
| - **Confidence:** Medium |
| - **Evidence:** JIT code executes successfully; ASan/Valgrind would detect violations |
| - **Pass criteria:** JIT memory is executable but not writable during execution |
| - **Existing tests:** Implicitly tested by all JIT tests |
| |
| #### TC-SEC-010: Bounds Check Toggle |
| - **Traces to:** REQ-SEC-002 |
| - **Level:** Unit |
| - **Confidence:** Medium |
| - **`[GAP]`:** No explicit test toggling bounds checking off and verifying behavior change. |
| |
| #### TC-SEC-002: Undefined Behavior Detection |
| - **Traces to:** REQ-SEC-003 |
| - **Level:** Unit |
| - **Confidence:** Low |
| - **`[GAP]`:** No test enabling UB detection and verifying uninitialized register/stack reads are flagged. |
| |
| #### TC-SEC-008: Shadow Stack |
| - **Traces to:** REQ-SEC-003 |
| - **Level:** Unit |
| - **Confidence:** Low |
| - **`[GAP]`:** No test verifying shadow stack bit tracking (marks on write, checks on read). |
| |
| #### TC-SEC-009: Shadow Registers |
| - **Traces to:** REQ-SEC-003 |
| - **Level:** Unit |
| - **Confidence:** Low |
| - **`[GAP]`:** No test verifying shadow register bitmask tracking for uninitialized register detection. |
| |
| ### TC-EXT — Extensibility |
| |
| #### TC-EXT-001: Helper Registration |
| - **Traces to:** REQ-EXT-001 |
| - **Level:** Unit |
| - **Confidence:** High |
| - **Evidence:** `tests/helpers/call.data`, `tests/helpers/call-memfrob.data`, `custom_tests/srcs/ubpf_test_update_helpers.cc` |
| - **Pass criteria:** Helper functions are registered and callable by BPF programs via CALL instruction |
| - **Existing tests:** call, call-memfrob, update_helpers-Custom |
| |
| #### TC-EXT-002: External Dispatcher |
| - **Traces to:** REQ-EXT-003 |
| - **Level:** Integration |
| - **Confidence:** High |
| - **Evidence:** `custom_tests/srcs/ubpf_test_external_dispatcher_simple_context.cc`, `ubpf_test_external_dispatcher_context_overwrite.cc`, `ubpf_test_default_dispatcher_helper_context.cc`, `ubpf_test_update_dispatcher.cc` |
| - **Pass criteria:** Dispatcher receives correct parameters; context handling correct; updates work |
| - **Existing tests:** 4 custom tests |
| |
| #### TC-EXT-003: Unwind Function |
| - **Traces to:** REQ-EXT-007 |
| - **Level:** Unit |
| - **Confidence:** High |
| - **Evidence:** `tests/extensions/call_unwind.data` |
| - **Pass criteria:** Unwind function is called on error; execution terminates with correct error code |
| - **Existing tests:** call_unwind |
| |
| #### TC-EXT-004: Data Relocation Callback |
| - **Traces to:** REQ-EXT-004 |
| - **Level:** Integration |
| - **Confidence:** Medium |
| - **Evidence:** Tested via ELF loading pipeline |
| - **Pass criteria:** Data relocation callback is invoked for map references during ELF loading |
| - **Existing tests:** ELF loading tests (indirect) |
| |
| #### TC-EXT-005: Custom Bounds Check Callback |
| - **Traces to:** REQ-SEC-009 |
| - **Level:** Unit |
| - **Confidence:** Low |
| - **`[GAP]`:** No test registering a custom bounds check callback via `ubpf_register_data_bounds_check()` and verifying it is invoked during memory access. |
| |
| #### TC-EXT-006: Stack Usage Calculator |
| - **Traces to:** REQ-EXT-005 |
| - **Level:** Unit |
| - **Confidence:** High |
| - **Evidence:** `custom_tests/srcs/ubpf_test_custom_local_function_stack_size.cc`, `*_unaligned.cc`, `*_zero.cc`, `ubpf_test_default_local_function_stack_size.cc` |
| - **Pass criteria:** Custom stack sizes applied; unaligned rejected; zero accepted; default works |
| - **Existing tests:** 4 custom tests |
| |
| #### TC-EXT-007: Debug Function |
| - **Traces to:** REQ-EXT-006 |
| - **Level:** Unit |
| - **Confidence:** High |
| - **Evidence:** `custom_tests/srcs/ubpf_test_debug_function.cc` |
| - **Pass criteria:** Debug function callback is invoked before each instruction with correct state |
| - **Existing tests:** debug_function-Custom |
| |
| #### TC-EXT-008: Helper Function Limit |
| - **Traces to:** REQ-EXT-002 |
| - **Level:** Unit |
| - **Confidence:** Low |
| - **`[GAP]`:** No test filling all 64 helper slots to verify the helper function registration limit. |
| |
| ### TC-CFG — Configuration |
| |
| #### TC-CFG-001: Error Print Redirection |
| - **Traces to:** REQ-CFG-001 |
| - **Level:** Unit |
| - **Confidence:** Medium |
| - **Evidence:** Used in custom tests but not directly tested for correctness |
| - **Pass criteria:** Error output is redirected to the configured print function |
| - **Existing tests:** Custom tests (indirect) |
| |
| #### TC-CFG-002: JIT Buffer Sizing |
| - **Traces to:** REQ-CFG-002 |
| - **Level:** Unit |
| - **Confidence:** High |
| - **Evidence:** `custom_tests/srcs/ubpf_test_jit_buffer_too_small.cc` |
| - **Pass criteria:** JIT buffer size can be configured; undersized buffer causes compilation failure |
| - **Existing tests:** jit_buffer_too_small-Custom |
| |
| #### TC-CFG-003: Instruction Limit |
| - **Traces to:** REQ-CFG-003 |
| - **Level:** Unit |
| - **Confidence:** Low |
| - **`[GAP]`:** No test exercises `ubpf_set_instruction_limit()` to verify instruction count limiting. |
| |
| #### TC-CFG-004: Register Access |
| - **Traces to:** REQ-CFG-004 |
| - **Level:** Unit |
| - **Confidence:** Low |
| - **`[GAP]`:** No test exercises get/set register APIs to verify register access functionality. |
| |
| ### TC-PLAT — Platform Support |
| |
| #### TC-PLAT-001: Windows Support |
| - **Traces to:** REQ-PLAT-001 |
| - **Level:** System |
| - **Confidence:** High |
| - **Evidence:** CI: windows-2022, Debug + Release configurations |
| - **Pass criteria:** All tests pass on Windows with MSVC |
| - **Existing tests:** CI matrix (windows-2022) |
| |
| #### TC-PLAT-002: Linux Support |
| - **Traces to:** REQ-PLAT-002 |
| - **Level:** System |
| - **Confidence:** High |
| - **Evidence:** CI: ubuntu-latest, coverage + sanitizers (ASan, UBSan) |
| - **Pass criteria:** All tests pass on Linux with GCC/Clang; no sanitizer violations |
| - **Existing tests:** CI matrix (ubuntu-latest) |
| |
| #### TC-PLAT-003: macOS Support |
| - **Traces to:** REQ-PLAT-003 |
| - **Level:** System |
| - **Confidence:** High |
| - **Evidence:** CI: macos-latest |
| - **Pass criteria:** All tests pass on macOS |
| - **Existing tests:** CI matrix (macos-latest) |
| |
| #### TC-PLAT-004: x86-64 JIT |
| - **Traces to:** REQ-PLAT-004 |
| - **Level:** System |
| - **Confidence:** High |
| - **Evidence:** CI runs JIT tests on all x86-64 platforms (Windows, Linux, macOS) |
| - **Pass criteria:** JIT compilation and execution succeeds on x86-64 |
| - **Existing tests:** CI matrix (all x86-64 platforms) |
| |
| #### TC-PLAT-007: Crypto RNG |
| - **Traces to:** REQ-PLAT-005 |
| - **Level:** System |
| - **Confidence:** Low |
| - **Evidence:** Source inspection shows platform branches in `vm/ubpf_jit_support.c`, but no dedicated runtime assertion validates RNG output or fallback selection. |
| - **`[GAP]`:** No test verifies `BCryptGenRandom`, `getrandom`, `arc4random_buf`, or the `rand()` fallback behavior. |
| |
| #### TC-PLAT-008: Platform Atomics |
| - **Traces to:** REQ-PLAT-006 |
| - **Level:** System |
| - **Confidence:** Medium |
| - **`[GAP]`:** No cross-platform atomic correctness test. Atomics are compiled but not tested for cross-platform behavior. |
| |
| ### TC-ERR — Error Handling |
| |
| #### TC-ERR-001: Error Message Allocation |
| - **Traces to:** REQ-ERR-001 |
| - **Level:** Unit |
| - **Confidence:** High |
| - **Evidence:** Error tests check stderr output for correct error messages |
| - **Pass criteria:** Error messages are allocated and returned correctly via the error string parameter |
| - **Existing tests:** tests/errors/* (error message verification) |
| |
| #### TC-ERR-002: Error Output Function |
| - **Traces to:** REQ-ERR-002 |
| - **Level:** Unit |
| - **Confidence:** Medium |
| - **Evidence:** Error output function is used but not directly validated for correct invocation |
| - **Pass criteria:** Custom error output function receives formatted error messages |
| - **Existing tests:** Custom tests (indirect) |
| |
| #### TC-ERR-003: Toggle Return Values |
| - **Traces to:** REQ-ERR-003 |
| - **Level:** Unit |
| - **Confidence:** Medium |
| - **Evidence:** Toggle functions return values are used in custom tests |
| - **Pass criteria:** Toggle functions return previous state value |
| - **Existing tests:** Custom tests (indirect) |
| |
| ### TC-CONST — Constants |
| |
| #### TC-CONST-001: System Constants |
| - **Traces to:** REQ-CONST-001 |
| - **Level:** Unit |
| - **Confidence:** Medium |
| - **Evidence:** Constants (MAX_INSTS, STACK_SIZE, etc.) are used throughout tests but not boundary-tested |
| - **Pass criteria:** System constants are correctly defined and enforced at boundaries |
| - **Existing tests:** All tests (indirect usage) |
| |
| ### TC-SAFE — Safe Interpreter Profile |
| |
| #### TC-SAFE-001: Safe-Profile Compatibility Gate |
| - **Traces to:** REQ-SAFE-001 |
| - **Level:** Integration |
| - **Confidence:** Medium |
| - **Evidence:** `custom_tests/srcs/ubpf_test_safe_profile_compile_rejection.cc`; `ubpf_plugin/CMakeLists.txt`; `ubpf_plugin/ubpf_plugin.cc` exercised against `external/bpf_conformance/tests` with `--profile legacy --interpret` and `--profile safe --interpret` |
| - **Pass criteria:** `ubpf_set_execution_profile()` opts a VM into safe mode before load, rejects profile changes after load, and leaves interpreter execution available while JIT remains rejected. |
| - **Existing tests:** `ubpf_test_safe_profile_compile_rejection-Custom`; per-file `*-Interpreter` and `*-Safe-Interpreter` CTest cases generated from `external/bpf_conformance/tests/*.data` and `tests/*.data` |
| - **Remaining gap:** Extend parity coverage beyond the default v3 interpreter matrix to typed-pointer helper scenarios that require region descriptors. |
| |
| #### TC-SAFE-002: Root Provenance Initialization |
| - **Traces to:** REQ-SAFE-002 |
| - **Level:** Unit |
| - **Confidence:** Medium |
| - **Evidence:** `custom_tests/srcs/ubpf_test_safe_profile_spills_and_local_calls.cc`, `custom_tests/srcs/ubpf_test_safe_profile_pointer_arithmetic.cc` |
| - **Pass criteria:** Safe-profile entry initializes stack-root provenance correctly, rejects use of reclassified scalars as pointers, and preserves only explicit provenance-bearing values. |
| - **Existing tests:** `ubpf_test_safe_profile_spills_and_local_calls-Custom`, `ubpf_test_safe_profile_pointer_arithmetic-Custom` |
| - **Remaining gap:** Add explicit checks for R0/R3-R9 scalar entry state and for R1 being scalar when `mem == NULL`. |
| |
| #### TC-SAFE-003: Safe Dereference Choke Points |
| - **Traces to:** REQ-SAFE-003 |
| - **Level:** Unit |
| - **Confidence:** Medium |
| - **Evidence:** `custom_tests/srcs/ubpf_test_safe_profile_helpers.cc`, `custom_tests/srcs/ubpf_test_safe_profile_spills_and_local_calls.cc` |
| - **Pass criteria:** Safe-mode dereferences succeed only through pointer-tagged registers within region bounds; dereference through handles or reclassified scalars fails before host access. |
| - **Existing tests:** `ubpf_test_safe_profile_helpers-Custom`, `ubpf_test_safe_profile_spills_and_local_calls-Custom` |
| - **Remaining gap:** Add direct atomic coverage showing fetch-result registers are classified as scalars. |
| |
| #### TC-SAFE-004: Pointer Arithmetic Matrix |
| - **Traces to:** REQ-SAFE-004 |
| - **Level:** Unit |
| - **Confidence:** Medium |
| - **Evidence:** `custom_tests/srcs/ubpf_test_safe_profile_pointer_arithmetic.cc`, `custom_tests/srcs/ubpf_test_safe_profile_spills_and_local_calls.cc`, `external/bpf_conformance/tests/stack.data` |
| - **Pass criteria:** Pointer-plus-pointer and scalar-minus-pointer fail, same-region pointer subtraction produces a scalar, different-region pointer subtraction fails, and pointer-plus-scalar / pointer-minus-scalar remain usable for valid stack access. |
| - **Existing tests:** `ubpf_test_safe_profile_pointer_arithmetic-Custom`, `ubpf_test_safe_profile_spills_and_local_calls-Custom`; local `bpf_conformance_runner` execution of `stack.data` with `--profile safe --interpret` |
| |
| #### TC-SAFE-005: Typed Helper Return Validation |
| - **Traces to:** REQ-SAFE-005 |
| - **Level:** Integration |
| - **Confidence:** Medium |
| - **Evidence:** `custom_tests/srcs/ubpf_test_safe_profile_helpers.cc` |
| - **Pass criteria:** Helpers with safe descriptors can return typed pointers or handles, and helper calls without safe metadata fail before dispatch. |
| - **Existing tests:** `ubpf_test_safe_profile_helpers-Custom` |
| - **Remaining gap:** Add scalar-return and out-of-bounds-pointer negative cases. |
| |
| #### TC-SAFE-006: External Region Descriptor Resolution |
| - **Traces to:** REQ-SAFE-006 |
| - **Level:** Integration |
| - **Confidence:** Low |
| - **Evidence:** `custom_tests/srcs/ubpf_test_safe_profile_helpers.cc` |
| - **Pass criteria:** Safe helper metadata resolves to registered region descriptors, and returned pointers remain constrained to their registered region. |
| - **Existing tests:** `ubpf_test_safe_profile_helpers-Custom` |
| - **Remaining gap:** Add two-disjoint-region coverage and a regression proving the legacy bool bounds callback alone does not establish provenance. |
| |
| #### TC-SAFE-007: Spill and Local-Call Provenance |
| - **Traces to:** REQ-SAFE-007 |
| - **Level:** Integration |
| - **Confidence:** Medium |
| - **Evidence:** `custom_tests/srcs/ubpf_test_safe_profile_spills_and_local_calls.cc` |
| - **Pass criteria:** Full-width stack spills restore provenance, partial writes invalidate it, and caller-saved registers lose provenance on local-call return. |
| - **Existing tests:** `ubpf_test_safe_profile_spills_and_local_calls-Custom` |
| - **Remaining gap:** Add a direct callee-saved provenance-preservation case using R6-R9 across a local call. |
| |
| #### TC-SAFE-008: Safe-Profile Compile Rejection |
| - **Traces to:** REQ-SAFE-008 |
| - **Level:** Unit |
| - **Confidence:** High |
| - **Evidence:** `custom_tests/srcs/ubpf_test_safe_profile_compile_rejection.cc` |
| - **Pass criteria:** `ubpf_compile*()` and `ubpf_translate*()` reject safe-profile VMs with an explicit interpreter-only error. |
| - **Existing tests:** `ubpf_test_safe_profile_compile_rejection-Custom` |
| |
| ### TC-FUZZ — Fuzzing |
| |
| #### TC-FUZZ-001: Differential Interpreter/JIT Testing |
| - **Traces to:** REQ-EXEC-007, REQ-JIT-001 |
| - **Level:** System |
| - **Confidence:** High |
| - **Evidence:** `libfuzzer/libfuzz_harness.cc` |
| - **Pass criteria:** Interpreter and JIT produce identical results for all generated inputs |
| - **Existing tests:** Daily 1-hour fuzzing runs, corpus regression in CI |
| |
| #### TC-FUZZ-002: PREVAIL Verifier Integration |
| - **Traces to:** REQ-EXEC-007 |
| - **Level:** System |
| - **Confidence:** Medium |
| - **Evidence:** `libfuzzer/libfuzz_harness.cc` with `UBPF_FUZZER_VERIFY_BYTE_CODE=1` |
| - **Pass criteria:** Verifier-approved programs execute without crashes |
| - **Existing tests:** Fuzzer with verifier enabled |
| |
| --- |
| |
| ## 6. Risk-Based Test Prioritization |
| |
| ### 6.1 Risk Categories |
| |
| | Risk ID | Category | Impact | Likelihood | Priority | |
| |---------|----------|--------|------------|----------| |
| | R1 | JIT produces incorrect results | **Critical** — silent data corruption | Medium | **P1** | |
| | R2 | Bounds check bypass | **Critical** — arbitrary memory access | Low | **P1** | |
| | R3 | Memory corruption in VM | **Critical** — host process crash | Medium | **P1** | |
| | R4 | ELF loader accepts malformed input | **High** — potential code execution | Medium | **P2** | |
| | R5 | Constant blinding bypass | **High** — JIT spraying attack | Low | **P2** | |
| | R6 | Platform-specific failures | **Medium** — limited to one platform | Medium | **P2** | |
| | R7 | Helper function parameter corruption | **Medium** — incorrect helper behavior | Low | **P3** | |
| | R8 | Stack overflow in local calls | **Medium** — program crash | Low | **P3** | |
| | R9 | Configuration API misuse | **Low** — unexpected behavior | Medium | **P3** | |
| | R10 | Safe-profile provenance bypass | **Critical** — verifier-like memory safety defeated | Medium | **P1** | |
| |
| ### 6.2 Prioritization Rationale |
| |
| **P1 (Must test):** JIT correctness, bounds checking, memory safety, and safe-profile provenance enforcement — these are the core security and correctness guarantees. |
| - **Covered by:** Differential fuzzing (TC-FUZZ-001), error tests (TC-SEC-001), sanitizers (ASan/UBSan), Valgrind |
| - **Gap:** Safe-profile provenance coverage exists, but direct regressions for null-input root state, multi-region descriptors, and legacy-vs-safe side-by-side behavior remain open |
| |
| **P2 (Should test):** ELF robustness, constant blinding effectiveness, platform parity — important but lower likelihood. |
| - **Covered by:** CI matrix (TC-PLAT-*), constant blinding tests (TC-SEC-003), some ELF tests |
| - **Gap:** No adversarial ELF fuzzing |
| |
| **P3 (Nice to test):** Helper correctness, stack depth, configuration edge cases — lower impact. |
| - **Covered by:** Helper tests (TC-EXT-001), stack tests (TC-EXEC-007) |
| - **Gaps:** Instruction limit, register get/set, deep call chains |
| |
| --- |
| |
| ## 7. Pass/Fail Criteria |
| |
| ### 7.1 Entry Criteria |
| |
| Before test execution: |
| - Code compiles successfully on all target platforms |
| - All submodules initialized (`git submodule update --init --recursive`) |
| - Test dependencies installed (Python: parcon, nose, pyelftools) |
| - Environment configured (platform-specific build prerequisites) |
| |
| ### 7.2 Exit Criteria |
| |
| Test suite passes when: |
| - **All CTest tests pass** on every CI platform (Windows, Linux, macOS, ARM64) |
| - **Zero ASan/UBSan violations** in sanitizer builds |
| - **Zero Valgrind errors** (Linux) |
| - **Fuzzer runs for 1 hour** without finding new crashes |
| - **Code coverage does not decrease** vs. previous baseline (Coveralls) |
| |
| ### 7.3 Acceptance Thresholds |
| |
| | Metric | Threshold | Current Status | |
| |--------|-----------|----------------| |
| | CTest pass rate | 100% | Enforced by CI | |
| | ASan violations | 0 | Enforced by CI | |
| | Valgrind errors | 0 | Enforced by CI (Linux) | |
| | Fuzzer crashes | 0 new | Enforced by CI | |
| | Code coverage | Non-decreasing | Tracked by Coveralls | |
| |
| --- |
| |
| ## 8. Coverage Gap Summary |
| |
| ### 8.1 High-Priority Gaps |
| |
| | Gap | REQ-IDs Affected | Risk | Recommendation | |
| |-----|-----------------|------|----------------| |
| | No UB detection tests | REQ-SEC-003 | Medium | Add tests enabling UB checks, verify shadow stack/register detection | |
| | No instruction limit test | REQ-CFG-003 | Low | Add test setting limit and verifying execution stops | |
| | No malformed ELF tests | REQ-ELF-001 | Medium | Fuzz the ELF loader with invalid headers/sections | |
| | No register get/set tests | REQ-CFG-004 | Low | Add test calling ubpf_set_registers/ubpf_get_registers | |
| | No custom bounds check test | REQ-SEC-009 | Medium | Add test registering custom bounds check callback | |
| |
| ### 8.2 Medium-Priority Gaps |
| |
| | Gap | REQ-IDs Affected | Risk | Recommendation | |
| |-----|-----------------|------|----------------| |
| | No OOM handling tests | REQ-LIFE-003 | Low | Test with constrained memory or mock allocator | |
| | No explicit exec_ex test | REQ-EXEC-002 | Low | Add test calling ubpf_exec_ex with custom stack | |
| | No translate/copy_jit tests | REQ-JIT-007, REQ-JIT-006 | Low | Add tests for these less-used APIs | |
| | No JIT caching verification | REQ-JIT-003 | Low | Verify compile returns same pointer on second call | |
| | No XOR encoding verification | REQ-LOAD-006, REQ-SEC-006 | Medium | Verify instructions are XOR-encoded in memory | |
| | No direct safe-profile entry-state regression for null input memory | REQ-SAFE-002 | Medium | Add a test that dereferences R1 with `mem == NULL` and proves safe mode treats it as a scalar | |
| | No multi-region safe descriptor regression | REQ-SAFE-006 | Medium | Add two disjoint safe regions plus helper returns that prove provenance remains region-specific | |
| |
| ### 8.3 Structural Gaps |
| |
| | Gap | Impact | Recommendation | |
| |-----|--------|----------------| |
| | No concurrency tests | Unknown thread safety | Define thread-safety model, add tests | |
| | No stress tests | Unknown scalability limits | Test with MAX_INSTS programs, deep call chains | |
| | No performance regression | Silent performance degradation | Add benchmark suite | |
| | No adversarial ELF fuzzing | Potential loader vulnerabilities | Add ELF-specific fuzzer | |
| | Atomic operations: validation only | Correctness unverified at runtime | Add atomic execution correctness tests | |
| |
| --- |
| |
| ## 9. Revision History |
| |
| | Version | Date | Author | Description | |
| |---------|------|--------|-------------| |
| | 1.2.0 | 2026-06-12 | Evolve refresh | Added validation scope for the additive safe-interpreter profile, including planned coverage for provenance enforcement and safe-mode JIT rejection. | |
| | 1.1.0 | 2026-06-12 | Bootstrap refresh | Reconciled current test inventory counts, credited indirect `ubpf_copy_jit()` coverage via `ubpf_plugin`, and downgraded overstated RNG coverage claims. | |
| | 1.0.0 | 2026-03-31 | Extracted by AI | Initial draft — mapped existing tests to requirements, identified gaps | |