commit 409a3ed8f7c3eab88eef8563a5ab4d8503b6da0f
parent e4464a0e0b0c43b655369ba77274188bbb1477d0
Author: Jared Tobin <jared@jtobin.io>
Date: Sat, 28 Feb 2026 16:19:20 +0400
meta: readme
Diffstat:
| M | README.md | | | 91 | +++++++++++++++++++++++++++++++++++++++++++++++++------------------------------- |
1 file changed, 56 insertions(+), 35 deletions(-)
diff --git a/README.md b/README.md
@@ -2,28 +2,32 @@

-A Haskell tool for static analysis of GHC-generated AArch64 assembly,
-focused on constant-time auditing for cryptographic code.
+A Haskell tool for static analysis of AArch64 assembly, focused on
+constant-time auditing for cryptographic code.
## Overview
ppad-auditor provides two analysis modes:
-1. **Taint analysis** (default): Tracks how secret data flows through
- registers and memory, flagging loads/stores where the address may
- depend on secret values (cache timing side-channels).
+1. **Taint analysis** (default): Tracks how secret data flows
+ through registers and memory, flagging loads/stores where the
+ address may depend on secret values (cache timing
+ side-channels).
2. **NCT scan** (`--scan-nct`): Identifies non-constant-time
- instructions (variable-time division, conditional branches, etc.)
- that may leak secrets through execution timing.
+ instructions (variable-time division, conditional branches,
+ etc.) that may leak secrets through execution timing.
-The tool understands GHC's calling conventions, treating registers like
-X19-X22 and SP as public pointers, and tracking taint propagation
-through arithmetic, data movement, and function calls.
+The tool is parameterised over a runtime configuration, so it can
+adapt to different compilers and calling conventions. The default
+runtime (`haskell`) understands GHC's STG calling conventions,
+treating registers like X19-X22 and SP as public pointers. A
+`generic` runtime is also available as a baseline for C, Rust, or
+Go code.
## Taint Analysis
-Basic usage:
+Basic usage (defaults to Haskell/GHC runtime):
```
$ auditor -i input.s
@@ -40,10 +44,25 @@ Memory accesses: 37
Violations: 2
```
+### Runtime Selection
+
+Use `--runtime` to select the target runtime:
+
+```
+$ auditor -i input.s --runtime haskell # default
+$ auditor -i input.s --runtime generic # C/Rust/Go baseline
+```
+
+The `haskell` runtime configures GHC's STG register conventions,
+secondary stack tracking (X20), pointer untagging masks, and
+runtime pattern filtering. The `generic` runtime uses only
+hardware stack/frame pointers and zero registers as public roots,
+with no secondary stack or untagging heuristics.
+
### Inter-procedural Analysis
-Use `-p` to enable inter-procedural analysis, which computes function
-summaries and propagates taint across call boundaries:
+Use `-p` to enable inter-procedural analysis, which computes
+function summaries and propagates taint across call boundaries:
```
$ auditor -i input.s -p
@@ -51,8 +70,8 @@ $ auditor -i input.s -p
### Taint Configuration
-Seed specific registers or STG stack slots as secret using a JSON
-config file:
+Seed specific registers or secondary stack slots as secret using a
+JSON config file:
```json
{
@@ -68,9 +87,10 @@ config file:
- `secret`: Registers containing secret scalar values
- `public`: Registers to mark as public
-- `secret_pointee`: Registers that are public pointers to secret data
- (loads through them produce secret values)
-- `stg_secret` / `stg_public`: STG stack slot offsets (X20-relative)
+- `secret_pointee`: Registers that are public pointers to secret
+ data (loads through them produce secret values)
+- `stg_secret` / `stg_public`: Secondary stack slot offsets
+ (X20-relative when using the `haskell` runtime)
Apply with:
@@ -84,8 +104,9 @@ $ auditor -i input.s -p --taint-config config.json
default)
- `-q`: Quiet mode (violations only, no summary)
- `-j`: JSON output format
-- `--assume-stg-private`: Treat untracked STG stack slots as private
- (default assumes they're public closure pointers)
+- `--assume-secondary-private`: Treat untracked secondary stack
+ slots as private (default assumes they're public closure
+ pointers)
## NCT Scan
@@ -108,21 +129,23 @@ Analyze a specific function and its callees:
$ auditor -i input.s --scan-nct --symbol _my_func_info
```
-Or use human-readable z-encoded symbols:
+Or use human-readable z-encoded symbols (Haskell runtime only):
```
-$ auditor -i input.s --scan-nct --zsymbol "pkg-1.0:Module.Name:function"
+$ auditor -i input.s --scan-nct \
+ --zsymbol "pkg-1.0:Module.Name:function"
```
-Use `-c` to show callers instead of callees (reverse reachability).
+Use `-c` to show callers instead of callees (reverse
+reachability).
-### GHC Runtime Filtering
+### Runtime Pattern Filtering
-GHC runtime patterns (heap checks, stack checks, closure evaluation)
-are hidden by default. Show them with:
+Runtime-specific patterns (heap checks, stack checks, closure
+evaluation) are hidden by default. Show them with:
```
-$ auditor -i input.s --scan-nct --show-ghc-runtime
+$ auditor -i input.s --scan-nct --show-runtime-patterns
```
## Utility Commands
@@ -141,19 +164,17 @@ $ auditor -i input.s --list-symbols --filter "multiply"
## Limitations
-- **Conservative analysis**: Unknown taint is treated as potentially
- secret, which may cause over-reporting
-- **GHC-specific**: Assumes GHC's STG calling convention and register
- usage; may not work well with other compilers
-- **No alias analysis**: Heap accesses use coarse tracking; complex
- pointer aliasing may cause false positives/negatives
+- **Conservative analysis**: Unknown taint is treated as
+ potentially secret, which may cause over-reporting
+- **No alias analysis**: Heap accesses use coarse tracking;
+ complex pointer aliasing may cause false positives/negatives
Manual review of flagged accesses is recommended.
## Development
-Requires [Nix][nixos] with [flake][flake] support. Enter a development
-shell:
+Requires [Nix][nixos] with [flake][flake] support. Enter a
+development shell:
```
$ nix develop