nx_xenocell.nx source
↩ module page · 298 lines · 12206 B
1// nx_xenocell.nx -- hostile foreign-agent virtual cell.
2//
3// Biological analogue: a xenobiotic is a substance foreign to the
4// organism with NO cooperative function (vs symbiote which is non-
5// self but mutualistic). Nishi xenocell wraps adversarial-by-default
6// foreign agents:
7// - Intel ME (ring -3 management engine running MINIX)
8// - AMD PSP (Platform Security Processor)
9// - Qualcomm modem baseband (direct-memory access on phones)
10// - Vendor BMC (server management; out-of-band network access)
11// - Vendor anti-cheat kernel drivers (EAC / BattlEye / Vanguard)
12// - UEFI rootkit-class persistence
13//
14// Distinct from nx_symbiote: a symbiote can be PARTNERED with via
15// nx_treaty (Steam-NMS cooperatively sharing VRAM). A xenocell
16// CANNOT be partnered with -- it does not consent to anything; its
17// presence is imposed by the hardware vendor or by capture. The
18// substrate's job is OBSERVE + RECORD + CONTAIN, never NEGOTIATE.
19//
20// THE JUDO: every observation written into nx_evict_journal becomes
21// signed forensic evidence. Vendor's covert action -> user's
22// court-admissible record. Per [[feedback-captain-moroni-doctrine]]
23// + [[feedback-cell-immune-system-ransomware-judo-ddos-by-bit]] +
24// [[feedback-reclamation-doctrine-captain-moroni]]: the judo is of
25// INFORMATION not retaliation. We never attack back. We make every
26// adversarial action visible + recorded.
27//
28// Composes:
29// nx_evict_journal -- where signed observations land
30// nx_organism -- xenocell registered alongside native cells;
31// organism aggregates xeno consumption into
32// host pressure (so ME's RAM use is counted)
33// nx_attest_silicon -- declares WHICH xenocells the host has and
34// their known threat surfaces
35// nx_homeostasis -- fires INTRUSION signal not MIGRATE when
36// xeno activity exceeds threshold
37// nx_budget -- the xeno's observed_* fields drive the
38// host_budget pressure calculation
39// nx_brane -- capability-token refusal at IO boundaries
40// for any payload tagged xeno-touched
41//
42// V1 ships:
43// - 5 intrusion-state enum values
44// - 5 observation-kind enum values (RAM_READ / NET_EGRESS /
45// DMA_PEEK / FIRMWARE_WRITE / RADIO_ACTIVATE)
46// - signed_observation append with externally-supplied signature
47// (V2 will integrate nx_ml_dsa_65 for inline signing)
48// - intrusion-state transitions logged loudly
49//
50// Gap list (V1 honest perf verdict):
51// - signatures are externally supplied (no inline crypto yet)
52// - no real ME/PSP probe (caller supplies observed numbers)
53// - no automatic intrusion-state classifier (caller declares)
54// - no public-attestation publication (V2 federates to peer mesh
55// for community-shared intrusion intelligence)
56//
57// genealogy_id: nishi_cardinal_2026-05-07_captain_moroni_doctrine +
58// cardinal_2026-05-17_cell_immune_judo +
59// cardinal_2026-05-19_reclamation_doctrine
60// lineage_id: substrate_xenocell_v1
61//
62// nx_safety_envelope:
63// intended_use: "Hostile foreign-agent observation and
64// forensic-evidence capture; NEVER offensive"
65// sil_target: SIL3
66// asil_target: QM
67// evidence: [no_offensive_path, observation_only,
68// signed_provenance_chain, captain_moroni_aligned]
69// hazard_register: [bug-tape-xeno-misclassification-as-symbiote,
70// bug-tape-judo-becomes-attack-attempt]
71// residual_risk: "Substrate can only OBSERVE what host
72// kernel and instrumentation expose; ring -3
73// components remain partially opaque without
74// external nx_vitals (queued)."
75// verdict: NOT_YET_EVALUATED
76
77import "nx_syscalls.nx"
78import "nx_tier.nx"
79import "nx_budget.nx"
80import "nx_attention_class.nx"
81import "nx_evict_journal.nx"
82
83// ===== Sealed enum: NxIntrusionState =============================
84
85const NX_INTR_DORMANT: nx_int = 0 // present but idle (ME idle)
86const NX_INTR_PROBING: nx_int = 1 // reading what it shouldn't
87const NX_INTR_INFILTRATING: nx_int = 2 // writing where it shouldn't
88const NX_INTR_EXFILTRATING: nx_int = 3 // network egress to vendor
89const NX_INTR_COMPROMISING: nx_int = 4 // active hostile action
90const NX_INTR_N_STATES: nx_int = 5
91
92// ===== Sealed enum: NxObservationKind ============================
93//
94// What the xenocell was caught doing. Forensic record includes one
95// of these so downstream analysis (cross-session pattern detection,
96// shared with peer-mesh, submitted to Citizen Lab) is structured.
97
98const NX_OBS_RAM_READ: nx_int = 0 // peeked at user RAM
99const NX_OBS_DMA_PEEK: nx_int = 1 // DMA access to memory region
100const NX_OBS_NET_EGRESS: nx_int = 2 // sent bytes to vendor
101const NX_OBS_FIRMWARE_WRITE: nx_int = 3 // modified firmware blob
102const NX_OBS_RADIO_ACTIVATE: nx_int = 4 // turned on a transponder
103const NX_OBS_MICROCODE_PATCH: nx_int = 5 // pushed CPU microcode
104const NX_OBS_BOOT_INTERPOSE: nx_int = 6 // pre-OS boot hook
105const NX_OBS_N_KINDS: nx_int = 7
106
107// ===== Sealed enum: NxXenocellVerdict =============================
108
109const NX_XENO_OK: nx_int = 0
110const NX_XENO_ERR_BAD_STATE: nx_int = 1
111const NX_XENO_ERR_BAD_KIND: nx_int = 2
112const NX_XENO_ERR_BAD_SIG: nx_int = 3
113const NX_XENO_ERR_LOG_FULL: nx_int = 4
114
115// ===== Struct: NxSignedObservation ===============================
116//
117// One forensic event. sig_bytes_len is the length of the externally-
118// supplied signature; V1 doesn't validate the signature shape (any
119// caller-supplied bytes accepted), V2 integrates nx_ml_dsa_65 to
120// require ML-DSA-65 verified signatures.
121
122struct NxSignedObservation {
123 ts_us: nx_size,
124 xeno_id: nx_int,
125 kind: nx_int,
126 payload_hash: nx_size, // BLAKE3 of the evidence body (caller-supplied)
127 sig_ptr: *u8, // ML-DSA-65 signature bytes (caller-supplied)
128 sig_bytes_len: nx_size,
129 intrusion_state_after: nx_int,
130}
131
132// ===== Struct: NxXenocell ========================================
133//
134// id is a stable identifier for the foreign agent (e.g. CHIP_INTEL_ME,
135// CHIP_AMD_PSP, BASEBAND_QUALCOMM). name is a caller-supplied byte
136// buffer for human-readable logs. observed_* are the same fields as
137// nx_symbiote, EXCEPT we read them with skepticism -- the xeno never
138// declares anything truthfully so observed bytes are the only truth.
139//
140// observations_capacity is the size of the signed-observation ring;
141// observations_head wraps at capacity. obs_count is monotonic so
142// callers can detect overwrites.
143
144struct NxXenocell {
145 id: nx_int,
146 name: *u8,
147 attention_class: nx_int,
148 intrusion_state: nx_int,
149 observed_ram_bytes: nx_size,
150 observed_vram_bytes: nx_size,
151 observed_net_bytes: nx_size,
152 last_observe_us: nx_size,
153 observations: *NxSignedObservation,
154 observations_capacity: nx_size,
155 observations_head: nx_size,
156 obs_count: nx_size,
157}
158
159const NX_XENO_OBS_BYTES: nx_size = 56
160const NX_XENO_OBS_DEFAULT_CAPACITY: nx_size = 256
161
162// ===== nx_intr_is_valid ==========================================
163
164func nx_intr_is_valid(s: nx_int) -> nx_int {
165 if s < 0 { return 0 }
166 if s >= NX_INTR_N_STATES { return 0 }
167 return 1
168}
169
170// ===== nx_obs_is_valid ===========================================
171
172func nx_obs_is_valid(k: nx_int) -> nx_int {
173 if k < 0 { return 0 }
174 if k >= NX_OBS_N_KINDS { return 0 }
175 return 1
176}
177
178// ===== nx_xenocell_new ===========================================
179
180func nx_xenocell_new(id: nx_int,
181 name: *u8,
182 attention_class: nx_int,
183 observations_capacity: nx_size) -> *NxXenocell {
184 let x: *NxXenocell = (sys_mmap(96)) as *NxXenocell
185 x.id = id
186 x.name = name
187 x.attention_class = attention_class
188 x.intrusion_state = NX_INTR_DORMANT
189 x.observed_ram_bytes = 0
190 x.observed_vram_bytes = 0
191 x.observed_net_bytes = 0
192 x.last_observe_us = 0
193 let obs_bytes: nx_size = observations_capacity * NX_XENO_OBS_BYTES
194 x.observations = (sys_mmap(obs_bytes)) as *NxSignedObservation
195 x.observations_capacity = observations_capacity
196 x.observations_head = 0
197 x.obs_count = 0
198 return x
199}
200
201// ===== nx_xenocell_update ========================================
202//
203// Refresh observed_* fields. Same shape as nx_symbiote_update but
204// the xeno's numbers are treated as PROBES not commitments.
205
206func nx_xenocell_update(x: *NxXenocell,
207 ram_bytes: nx_size,
208 vram_bytes: nx_size,
209 net_bytes: nx_size,
210 now_us: nx_size) -> nx_int {
211 x.observed_ram_bytes = ram_bytes
212 x.observed_vram_bytes = vram_bytes
213 x.observed_net_bytes = net_bytes
214 x.last_observe_us = now_us
215 return NX_XENO_OK
216}
217
218// ===== _xenocell_obs_at ==========================================
219
220func _xenocell_obs_at(x: *NxXenocell, idx: nx_size) -> *NxSignedObservation {
221 return (x.observations as i64 + (idx as i64) * NX_XENO_OBS_BYTES) as *NxSignedObservation
222}
223
224// ===== nx_xenocell_record ========================================
225//
226// THE JUDO PRIMITIVE. Records one signed observation of a hostile
227// action and (optionally) updates intrusion_state. The signature is
228// externally supplied (caller has the private key); V2 integrates
229// nx_ml_dsa_65 to sign inline.
230//
231// Returns OK on success or BAD_KIND/BAD_SIG. The observation ring
232// wraps at capacity; obs_count is monotonic.
233
234func nx_xenocell_record(x: *NxXenocell,
235 ts_us: nx_size,
236 kind: nx_int,
237 payload_hash: nx_size,
238 sig_ptr: *u8,
239 sig_bytes_len: nx_size,
240 next_state: nx_int) -> nx_int {
241 if nx_obs_is_valid(kind) == 0 { return NX_XENO_ERR_BAD_KIND }
242 if nx_intr_is_valid(next_state) == 0 { return NX_XENO_ERR_BAD_STATE }
243 if (sig_ptr as i64) == 0 { return NX_XENO_ERR_BAD_SIG }
244 if sig_bytes_len <= 0 { return NX_XENO_ERR_BAD_SIG }
245
246 let slot: *NxSignedObservation = _xenocell_obs_at(x, x.observations_head)
247 slot.ts_us = ts_us
248 slot.xeno_id = x.id
249 slot.kind = kind
250 slot.payload_hash = payload_hash
251 slot.sig_ptr = sig_ptr
252 slot.sig_bytes_len = sig_bytes_len
253 slot.intrusion_state_after = next_state
254
255 x.observations_head = x.observations_head + 1
256 if x.observations_head >= x.observations_capacity { x.observations_head = 0 }
257 x.obs_count = x.obs_count + 1
258
259 x.intrusion_state = next_state
260 return NX_XENO_OK
261}
262
263// ===== nx_xenocell_count_by_kind =================================
264//
265// Walk the live ring and tally observations of a given kind. Used
266// by analysis tools to spot patterns: "how many RAM_READ events
267// did ME do this session?" -- if it's high, evidence of probing.
268
269func nx_xenocell_count_by_kind(x: *NxXenocell, kind: nx_int) -> nx_int {
270 var hits: nx_int = 0
271 var live: nx_size = x.obs_count
272 if live > x.observations_capacity { live = x.observations_capacity }
273 var i: nx_size = 0
274 while i < live {
275 let obs: *NxSignedObservation = _xenocell_obs_at(x, i)
276 if obs.kind == kind { hits = hits + 1 }
277 i = i + 1
278 }
279 return hits
280}
281
282// ===== nx_xenocell_is_hostile_now ================================
283//
284// Returns 1 if intrusion_state is anything ABOVE DORMANT -- the xeno
285// has been caught actively doing something. Use this to gate brane
286// capability checks: hostile-now xenos lose access to capabilities
287// they MIGHT have held while dormant.
288
289func nx_xenocell_is_hostile_now(x: *NxXenocell) -> nx_int {
290 if x.intrusion_state > NX_INTR_DORMANT { return 1 }
291 return 0
292}
293
294// ===== nx_xenocell_evidence_count ================================
295
296func nx_xenocell_evidence_count(x: *NxXenocell) -> nx_size {
297 return x.obs_count
298}