@vigolium/piolium 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (271) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +117 -0
  3. package/agents/access-auditor.md +300 -0
  4. package/agents/assumption-breaker.md +154 -0
  5. package/agents/attack-designer.md +116 -0
  6. package/agents/code-scanner.md +139 -0
  7. package/agents/concurrency-auditor.md +238 -0
  8. package/agents/confirm-writer.md +257 -0
  9. package/agents/context-reviewer.md +274 -0
  10. package/agents/cross-verifier.md +165 -0
  11. package/agents/cve-scout.md +381 -0
  12. package/agents/env-builder.md +282 -0
  13. package/agents/env-profiler.md +205 -0
  14. package/agents/evidence-collector.md +140 -0
  15. package/agents/finding-grader.md +142 -0
  16. package/agents/finding-writer.md +148 -0
  17. package/agents/flow-tracer.md +106 -0
  18. package/agents/goal-backtracer.md +146 -0
  19. package/agents/history-miner.md +467 -0
  20. package/agents/independent-verifier.md +118 -0
  21. package/agents/intent-mapper.md +183 -0
  22. package/agents/longshot-collector.md +128 -0
  23. package/agents/longshot-prober.md +126 -0
  24. package/agents/patch-auditor.md +73 -0
  25. package/agents/poc-author.md +124 -0
  26. package/agents/poc-runner.md +194 -0
  27. package/agents/probe-lead.md +269 -0
  28. package/agents/red-challenger.md +101 -0
  29. package/agents/report-composer.md +208 -0
  30. package/agents/review-adjudicator.md +216 -0
  31. package/agents/spec-auditor.md +155 -0
  32. package/agents/taint-tracer.md +265 -0
  33. package/agents/test-locator.md +209 -0
  34. package/agents/threat-modeler.md +132 -0
  35. package/agents/variant-scanner.md +108 -0
  36. package/agents/variant-spotter.md +110 -0
  37. package/bin/piolium.mjs +376 -0
  38. package/extensions/piolium/_vendor/yaml.bundle.d.mts +6 -0
  39. package/extensions/piolium/_vendor/yaml.bundle.mjs +139 -0
  40. package/extensions/piolium/agent-runner.ts +322 -0
  41. package/extensions/piolium/agents.ts +266 -0
  42. package/extensions/piolium/audit-state.ts +522 -0
  43. package/extensions/piolium/bundled-resources.ts +97 -0
  44. package/extensions/piolium/candidate-scan.ts +966 -0
  45. package/extensions/piolium/command-target.ts +177 -0
  46. package/extensions/piolium/console-stream.ts +57 -0
  47. package/extensions/piolium/export-results.ts +380 -0
  48. package/extensions/piolium/findings.ts +448 -0
  49. package/extensions/piolium/heartbeat.ts +182 -0
  50. package/extensions/piolium/help.ts +234 -0
  51. package/extensions/piolium/index.ts +1865 -0
  52. package/extensions/piolium/longshot.ts +530 -0
  53. package/extensions/piolium/matcher-suggestions.ts +196 -0
  54. package/extensions/piolium/matcher-utils.ts +83 -0
  55. package/extensions/piolium/modes/balanced.ts +750 -0
  56. package/extensions/piolium/modes/confirm-bootstrap.ts +186 -0
  57. package/extensions/piolium/modes/confirm.ts +697 -0
  58. package/extensions/piolium/modes/deep.ts +917 -0
  59. package/extensions/piolium/modes/diff.ts +177 -0
  60. package/extensions/piolium/modes/lite.ts +540 -0
  61. package/extensions/piolium/modes/longshot.ts +595 -0
  62. package/extensions/piolium/modes/merge.ts +204 -0
  63. package/extensions/piolium/modes/phase-runner.ts +267 -0
  64. package/extensions/piolium/modes/reinvest.ts +546 -0
  65. package/extensions/piolium/modes/revisit.ts +279 -0
  66. package/extensions/piolium/modes.ts +48 -0
  67. package/extensions/piolium/phase-labels.ts +123 -0
  68. package/extensions/piolium/phase-status-strip.ts +92 -0
  69. package/extensions/piolium/prompt-prefix-editor.ts +39 -0
  70. package/extensions/piolium/providers/anthropic-vertex.ts +836 -0
  71. package/extensions/piolium/recon.ts +409 -0
  72. package/extensions/piolium/result-stats.ts +105 -0
  73. package/extensions/piolium/retry.ts +120 -0
  74. package/extensions/piolium/scheduler.ts +212 -0
  75. package/extensions/piolium/secrets.ts +368 -0
  76. package/extensions/piolium/tools/web-tools.ts +148 -0
  77. package/package.json +77 -0
  78. package/skills/agentic-actions-auditor/SKILL.md +327 -0
  79. package/skills/agentic-actions-auditor/references/action-profiles.md +186 -0
  80. package/skills/agentic-actions-auditor/references/cross-file-resolution.md +209 -0
  81. package/skills/agentic-actions-auditor/references/foundations.md +94 -0
  82. package/skills/agentic-actions-auditor/references/vector-a-env-var-intermediary.md +77 -0
  83. package/skills/agentic-actions-auditor/references/vector-b-direct-expression-injection.md +83 -0
  84. package/skills/agentic-actions-auditor/references/vector-c-cli-data-fetch.md +83 -0
  85. package/skills/agentic-actions-auditor/references/vector-d-pr-target-checkout.md +88 -0
  86. package/skills/agentic-actions-auditor/references/vector-e-error-log-injection.md +88 -0
  87. package/skills/agentic-actions-auditor/references/vector-f-subshell-expansion.md +82 -0
  88. package/skills/agentic-actions-auditor/references/vector-g-eval-of-ai-output.md +91 -0
  89. package/skills/agentic-actions-auditor/references/vector-h-dangerous-sandbox-configs.md +102 -0
  90. package/skills/agentic-actions-auditor/references/vector-i-wildcard-allowlists.md +88 -0
  91. package/skills/audit/SKILL.md +562 -0
  92. package/skills/audit/assets/icon.svg +7 -0
  93. package/skills/audit/hooks/scripts/validate_phase_output.py +550 -0
  94. package/skills/audit/references/adversarial-review.md +148 -0
  95. package/skills/audit/references/architecture-aware-sast.md +306 -0
  96. package/skills/audit/references/audit-workflow.md +737 -0
  97. package/skills/audit/references/chamber-protocol.md +384 -0
  98. package/skills/audit/references/creative-attack-modes.md +221 -0
  99. package/skills/audit/references/deep-analysis.md +273 -0
  100. package/skills/audit/references/domain-attack-playbooks.md +1129 -0
  101. package/skills/audit/references/knowledge-base-template.md +513 -0
  102. package/skills/audit/references/real-env-validation.md +191 -0
  103. package/skills/audit/references/report-templates.md +417 -0
  104. package/skills/audit/references/triage-and-prereqs.md +134 -0
  105. package/skills/audit/scripts/consolidate_drafts.py +554 -0
  106. package/skills/audit/scripts/partition_findings.py +152 -0
  107. package/skills/audit/scripts/rg-hotspots.sh +121 -0
  108. package/skills/audit/scripts/stamp_file_state.py +349 -0
  109. package/skills/code-reviewer/SKILL.md +65 -0
  110. package/skills/codeql/SKILL.md +281 -0
  111. package/skills/codeql/references/build-fixes.md +90 -0
  112. package/skills/codeql/references/diagnostic-query-templates.md +339 -0
  113. package/skills/codeql/references/extension-yaml-format.md +209 -0
  114. package/skills/codeql/references/important-only-suite.md +153 -0
  115. package/skills/codeql/references/language-details.md +207 -0
  116. package/skills/codeql/references/macos-arm64e-workaround.md +179 -0
  117. package/skills/codeql/references/performance-tuning.md +111 -0
  118. package/skills/codeql/references/quality-assessment.md +172 -0
  119. package/skills/codeql/references/ruleset-catalog.md +63 -0
  120. package/skills/codeql/references/run-all-suite.md +92 -0
  121. package/skills/codeql/references/sarif-processing.md +79 -0
  122. package/skills/codeql/references/threat-models.md +51 -0
  123. package/skills/codeql/workflows/build-database.md +280 -0
  124. package/skills/codeql/workflows/create-data-extensions.md +261 -0
  125. package/skills/codeql/workflows/run-analysis.md +301 -0
  126. package/skills/differential-review/SKILL.md +220 -0
  127. package/skills/differential-review/adversarial.md +203 -0
  128. package/skills/differential-review/methodology.md +234 -0
  129. package/skills/differential-review/patterns.md +300 -0
  130. package/skills/differential-review/reporting.md +369 -0
  131. package/skills/fp-check/SKILL.md +125 -0
  132. package/skills/fp-check/references/bug-class-verification.md +114 -0
  133. package/skills/fp-check/references/deep-verification.md +143 -0
  134. package/skills/fp-check/references/evidence-templates.md +91 -0
  135. package/skills/fp-check/references/false-positive-patterns.md +115 -0
  136. package/skills/fp-check/references/gate-reviews.md +27 -0
  137. package/skills/fp-check/references/standard-verification.md +78 -0
  138. package/skills/insecure-defaults/SKILL.md +117 -0
  139. package/skills/insecure-defaults/references/examples.md +409 -0
  140. package/skills/last30days/SKILL.md +444 -0
  141. package/skills/sarif-parsing/SKILL.md +483 -0
  142. package/skills/sarif-parsing/resources/jq-queries.md +162 -0
  143. package/skills/sarif-parsing/resources/sarif_helpers.py +331 -0
  144. package/skills/security-threat-model/LICENSE.txt +201 -0
  145. package/skills/security-threat-model/SKILL.md +81 -0
  146. package/skills/security-threat-model/agents/openai.yaml +4 -0
  147. package/skills/security-threat-model/references/prompt-template.md +255 -0
  148. package/skills/security-threat-model/references/security-controls-and-assets.md +32 -0
  149. package/skills/semgrep/SKILL.md +212 -0
  150. package/skills/semgrep/references/rulesets.md +162 -0
  151. package/skills/semgrep/references/scan-modes.md +110 -0
  152. package/skills/semgrep/references/scanner-task-prompt.md +140 -0
  153. package/skills/semgrep/scripts/merge_sarif.py +203 -0
  154. package/skills/semgrep/workflows/scan-workflow.md +311 -0
  155. package/skills/semgrep-rule-creator/SKILL.md +168 -0
  156. package/skills/semgrep-rule-creator/references/quick-reference.md +202 -0
  157. package/skills/semgrep-rule-creator/references/workflow.md +240 -0
  158. package/skills/semgrep-rule-variant-creator/SKILL.md +205 -0
  159. package/skills/semgrep-rule-variant-creator/references/applicability-analysis.md +250 -0
  160. package/skills/semgrep-rule-variant-creator/references/language-syntax-guide.md +324 -0
  161. package/skills/semgrep-rule-variant-creator/references/workflow.md +518 -0
  162. package/skills/sharp-edges/SKILL.md +292 -0
  163. package/skills/sharp-edges/references/auth-patterns.md +252 -0
  164. package/skills/sharp-edges/references/case-studies.md +274 -0
  165. package/skills/sharp-edges/references/config-patterns.md +333 -0
  166. package/skills/sharp-edges/references/crypto-apis.md +190 -0
  167. package/skills/sharp-edges/references/lang-c.md +205 -0
  168. package/skills/sharp-edges/references/lang-csharp.md +285 -0
  169. package/skills/sharp-edges/references/lang-go.md +270 -0
  170. package/skills/sharp-edges/references/lang-java.md +263 -0
  171. package/skills/sharp-edges/references/lang-javascript.md +269 -0
  172. package/skills/sharp-edges/references/lang-kotlin.md +265 -0
  173. package/skills/sharp-edges/references/lang-php.md +245 -0
  174. package/skills/sharp-edges/references/lang-python.md +274 -0
  175. package/skills/sharp-edges/references/lang-ruby.md +273 -0
  176. package/skills/sharp-edges/references/lang-rust.md +272 -0
  177. package/skills/sharp-edges/references/lang-swift.md +287 -0
  178. package/skills/sharp-edges/references/language-specific.md +588 -0
  179. package/skills/spec-to-code-compliance/SKILL.md +357 -0
  180. package/skills/spec-to-code-compliance/resources/COMPLETENESS_CHECKLIST.md +69 -0
  181. package/skills/spec-to-code-compliance/resources/IR_EXAMPLES.md +417 -0
  182. package/skills/spec-to-code-compliance/resources/OUTPUT_REQUIREMENTS.md +105 -0
  183. package/skills/supply-chain-risk-auditor/SKILL.md +67 -0
  184. package/skills/supply-chain-risk-auditor/resources/results-template.md +41 -0
  185. package/skills/variant-analysis/METHODOLOGY.md +327 -0
  186. package/skills/variant-analysis/SKILL.md +142 -0
  187. package/skills/variant-analysis/resources/codeql/cpp.ql +119 -0
  188. package/skills/variant-analysis/resources/codeql/go.ql +69 -0
  189. package/skills/variant-analysis/resources/codeql/java.ql +71 -0
  190. package/skills/variant-analysis/resources/codeql/javascript.ql +63 -0
  191. package/skills/variant-analysis/resources/codeql/python.ql +80 -0
  192. package/skills/variant-analysis/resources/semgrep/cpp.yaml +98 -0
  193. package/skills/variant-analysis/resources/semgrep/go.yaml +63 -0
  194. package/skills/variant-analysis/resources/semgrep/java.yaml +61 -0
  195. package/skills/variant-analysis/resources/semgrep/javascript.yaml +60 -0
  196. package/skills/variant-analysis/resources/semgrep/python.yaml +72 -0
  197. package/skills/variant-analysis/resources/variant-report-template.md +75 -0
  198. package/skills/vuln-report/SKILL.md +137 -0
  199. package/skills/vuln-report/agents/openai.yaml +4 -0
  200. package/skills/vuln-report/references/report-template.md +135 -0
  201. package/skills/wooyun-legacy/SKILL.md +367 -0
  202. package/skills/wooyun-legacy/references/bank-penetration.md +222 -0
  203. package/skills/wooyun-legacy/references/checklists/command-execution-checklist.md +119 -0
  204. package/skills/wooyun-legacy/references/checklists/csrf-checklist.md +74 -0
  205. package/skills/wooyun-legacy/references/checklists/file-upload-checklist.md +108 -0
  206. package/skills/wooyun-legacy/references/checklists/info-disclosure-checklist.md +114 -0
  207. package/skills/wooyun-legacy/references/checklists/logic-flaws-checklist.md +95 -0
  208. package/skills/wooyun-legacy/references/checklists/misconfig-checklist.md +124 -0
  209. package/skills/wooyun-legacy/references/checklists/path-traversal-checklist.md +87 -0
  210. package/skills/wooyun-legacy/references/checklists/rce-checklist.md +93 -0
  211. package/skills/wooyun-legacy/references/checklists/sql-injection-checklist.md +97 -0
  212. package/skills/wooyun-legacy/references/checklists/ssrf-checklist.md +99 -0
  213. package/skills/wooyun-legacy/references/checklists/unauthorized-access-checklist.md +89 -0
  214. package/skills/wooyun-legacy/references/checklists/weak-password-checklist.md +115 -0
  215. package/skills/wooyun-legacy/references/checklists/xss-checklist.md +103 -0
  216. package/skills/wooyun-legacy/references/checklists/xxe-checklist.md +130 -0
  217. package/skills/wooyun-legacy/references/info-disclosure.md +975 -0
  218. package/skills/wooyun-legacy/references/logic-flaws.md +721 -0
  219. package/skills/wooyun-legacy/references/path-traversal.md +1191 -0
  220. package/skills/wooyun-legacy/references/telecom-penetration.md +156 -0
  221. package/skills/wooyun-legacy/references/unauthorized-access.md +980 -0
  222. package/skills/wooyun-legacy/references/xss.md +746 -0
  223. package/skills/zeroize-audit/SKILL.md +371 -0
  224. package/skills/zeroize-audit/configs/c.yaml +21 -0
  225. package/skills/zeroize-audit/configs/default.yaml +128 -0
  226. package/skills/zeroize-audit/configs/rust.yaml +83 -0
  227. package/skills/zeroize-audit/prompts/report_template.md +238 -0
  228. package/skills/zeroize-audit/prompts/system.md +163 -0
  229. package/skills/zeroize-audit/prompts/task.md +97 -0
  230. package/skills/zeroize-audit/references/compile-commands.md +231 -0
  231. package/skills/zeroize-audit/references/detection-strategy.md +191 -0
  232. package/skills/zeroize-audit/references/ir-analysis.md +252 -0
  233. package/skills/zeroize-audit/references/mcp-analysis.md +221 -0
  234. package/skills/zeroize-audit/references/poc-generation.md +470 -0
  235. package/skills/zeroize-audit/references/rust-zeroization-patterns.md +867 -0
  236. package/skills/zeroize-audit/schemas/input.json +83 -0
  237. package/skills/zeroize-audit/schemas/output.json +140 -0
  238. package/skills/zeroize-audit/tools/analyze_asm.sh +202 -0
  239. package/skills/zeroize-audit/tools/analyze_cfg.py +381 -0
  240. package/skills/zeroize-audit/tools/analyze_heap.sh +211 -0
  241. package/skills/zeroize-audit/tools/analyze_ir_semantic.py +429 -0
  242. package/skills/zeroize-audit/tools/diff_ir.sh +135 -0
  243. package/skills/zeroize-audit/tools/diff_rust_mir.sh +189 -0
  244. package/skills/zeroize-audit/tools/emit_asm.sh +67 -0
  245. package/skills/zeroize-audit/tools/emit_ir.sh +77 -0
  246. package/skills/zeroize-audit/tools/emit_rust_asm.sh +178 -0
  247. package/skills/zeroize-audit/tools/emit_rust_ir.sh +150 -0
  248. package/skills/zeroize-audit/tools/emit_rust_mir.sh +158 -0
  249. package/skills/zeroize-audit/tools/extract_compile_flags.py +284 -0
  250. package/skills/zeroize-audit/tools/generate_poc.py +1329 -0
  251. package/skills/zeroize-audit/tools/mcp/apply_confidence_gates.py +113 -0
  252. package/skills/zeroize-audit/tools/mcp/check_mcp.sh +68 -0
  253. package/skills/zeroize-audit/tools/mcp/normalize_mcp_evidence.py +125 -0
  254. package/skills/zeroize-audit/tools/scripts/check_llvm_patterns.py +481 -0
  255. package/skills/zeroize-audit/tools/scripts/check_mir_patterns.py +554 -0
  256. package/skills/zeroize-audit/tools/scripts/check_rust_asm.py +424 -0
  257. package/skills/zeroize-audit/tools/scripts/check_rust_asm_aarch64.py +300 -0
  258. package/skills/zeroize-audit/tools/scripts/check_rust_asm_x86.py +283 -0
  259. package/skills/zeroize-audit/tools/scripts/find_dangerous_apis.py +375 -0
  260. package/skills/zeroize-audit/tools/scripts/semantic_audit.py +923 -0
  261. package/skills/zeroize-audit/tools/track_dataflow.sh +196 -0
  262. package/skills/zeroize-audit/tools/validate_rust_toolchain.sh +298 -0
  263. package/skills/zeroize-audit/workflows/phase-0-preflight.md +150 -0
  264. package/skills/zeroize-audit/workflows/phase-1-source-analysis.md +144 -0
  265. package/skills/zeroize-audit/workflows/phase-2-compiler-analysis.md +139 -0
  266. package/skills/zeroize-audit/workflows/phase-3-interim-report.md +46 -0
  267. package/skills/zeroize-audit/workflows/phase-4-poc-generation.md +46 -0
  268. package/skills/zeroize-audit/workflows/phase-5-poc-validation.md +136 -0
  269. package/skills/zeroize-audit/workflows/phase-6-final-report.md +44 -0
  270. package/skills/zeroize-audit/workflows/phase-7-test-generation.md +42 -0
  271. package/themes/piolium-srcery.json +94 -0
@@ -0,0 +1,300 @@
1
+ #!/usr/bin/env python3
2
+ # /// script
3
+ # requires-python = ">=3.11"
4
+ # dependencies = []
5
+ # ///
6
+ """
7
+ check_rust_asm_aarch64.py — AArch64 Rust assembly analysis backend.
8
+
9
+ ⚠ EXPERIMENTAL — AArch64 support is incomplete. Findings should be treated as
10
+ indicative only and require manual verification before inclusion in a report.
11
+
12
+ Known limitations:
13
+ - x29 (frame pointer) and x30 (link register) are always saved in the prologue
14
+ via `stp x29, x30, [sp, #-N]!`. These appear as REGISTER_SPILL findings
15
+ because both are in AARCH64_CALLEE_SAVED. They are almost never carrying
16
+ secret values — reviewers should verify in context.
17
+ - `dc zva` (Data Cache Zero by Virtual Address) is not detected as a zero-store.
18
+ This instruction is rare in Rust-generated code but may be used in
19
+ highly-optimised zeroize implementations.
20
+ - AArch64 has no red zone (neither Linux nor macOS AAPCS64 define one). Leaf
21
+ functions must allocate stack space explicitly; no red-zone analysis needed.
22
+ - Apple AArch64 (M1/M2) and Linux AArch64 both use AAPCS64 with no red zone;
23
+ the analysis is platform-agnostic.
24
+
25
+ Called by check_rust_asm.py. Not intended for direct invocation.
26
+ """
27
+
28
+ import re
29
+
30
+ # ---------------------------------------------------------------------------
31
+ # AArch64 register sets (AAPCS64)
32
+ # ---------------------------------------------------------------------------
33
+
34
+ AARCH64_CALLER_SAVED = {
35
+ # Integer/pointer: argument registers and temporaries
36
+ "x0",
37
+ "x1",
38
+ "x2",
39
+ "x3",
40
+ "x4",
41
+ "x5",
42
+ "x6",
43
+ "x7",
44
+ "x8",
45
+ "x9",
46
+ "x10",
47
+ "x11",
48
+ "x12",
49
+ "x13",
50
+ "x14",
51
+ "x15",
52
+ "x16",
53
+ "x17",
54
+ # SIMD/FP: v0–v7 and v16–v31 are caller-saved (argument/scratch)
55
+ "v0",
56
+ "v1",
57
+ "v2",
58
+ "v3",
59
+ "v4",
60
+ "v5",
61
+ "v6",
62
+ "v7",
63
+ "v16",
64
+ "v17",
65
+ "v18",
66
+ "v19",
67
+ "v20",
68
+ "v21",
69
+ "v22",
70
+ "v23",
71
+ "v24",
72
+ "v25",
73
+ "v26",
74
+ "v27",
75
+ "v28",
76
+ "v29",
77
+ "v30",
78
+ "v31",
79
+ }
80
+
81
+ AARCH64_CALLEE_SAVED = {
82
+ # Integer: x19–x28 must be preserved if used
83
+ "x19",
84
+ "x20",
85
+ "x21",
86
+ "x22",
87
+ "x23",
88
+ "x24",
89
+ "x25",
90
+ "x26",
91
+ "x27",
92
+ "x28",
93
+ # x29 = frame pointer (fp), x30 = link register (lr)
94
+ # NOTE: x29 and x30 are always saved in prologues; see limitations above.
95
+ "x29",
96
+ "x30",
97
+ # SIMD/FP: lower 64 bits of v8–v15 must be preserved
98
+ "v8",
99
+ "v9",
100
+ "v10",
101
+ "v11",
102
+ "v12",
103
+ "v13",
104
+ "v14",
105
+ "v15",
106
+ }
107
+
108
+ # ---------------------------------------------------------------------------
109
+ # Patterns (ARM GNU syntax, as emitted by LLVM for AArch64)
110
+ # ---------------------------------------------------------------------------
111
+
112
+ # Frame allocation
113
+ # Most common: pre-index pair store that saves fp/lr and decrements sp
114
+ RE_A64_FRAME_STP = re.compile(r"stp\s+x29,\s+x30,\s+\[sp,\s+#-(\d+)\]!")
115
+ # Alternative: explicit sub
116
+ RE_A64_FRAME_SUB = re.compile(r"sub\s+sp,\s+sp,\s+#(\d+)")
117
+
118
+ # Zero-store patterns
119
+ # str xzr/wzr, [sp, #N] — single 64-bit (xzr) or 32-bit (wzr) zero store to stack
120
+ RE_A64_STR_XZR = re.compile(r"\bstr\s+[xw]zr,\s+\[sp(?:,\s*#-?\d+)?\]")
121
+ # stp xzr, xzr / wzr, wzr, [sp, #N] — paired zero store (most efficient)
122
+ RE_A64_STP_XZR = re.compile(r"\bstp\s+[xw]zr,\s+[xw]zr,\s+\[sp(?:,\s*#-?\d+)?\]")
123
+ # movi vN.*, #0 — SIMD register zeroing (precedes stp qN)
124
+ RE_A64_MOVI_ZERO = re.compile(r"\bmovi\s+v\d+\.\w+,\s+#0\b")
125
+ # bl ...(memset|zeroize) — call to zeroize/memset routine
126
+ RE_A64_MEMSET = re.compile(r"\bbl\s+.*(?:memset|volatile_set_memory|zeroize)")
127
+
128
+ # Register spill patterns
129
+ # str xN/vN/qN, [sp, #offset] — single store to stack
130
+ RE_A64_STR_SPILL = re.compile(r"\bstr\s+(x\d+|v\d+|q\d+),\s+\[sp(?:,\s*#-?\d+)?\]")
131
+ # stp xN, xM / qN, qM, [sp, #offset] — pair store to stack (I31: also covers SIMD q pairs)
132
+ RE_A64_STP_SPILL = re.compile(r"\bstp\s+((?:x|q)\d+),\s+((?:x|q)\d+),\s+\[sp(?:,\s*#-?\d+)?\]")
133
+
134
+ # Return instruction (no suffix on AArch64, unlike x86-64's retq)
135
+ RE_A64_RET = re.compile(r"\bret\b")
136
+
137
+
138
+ # ---------------------------------------------------------------------------
139
+ # STACK_RETENTION (AArch64)
140
+ # ---------------------------------------------------------------------------
141
+
142
+
143
+ def check_stack_retention(
144
+ func_name: str,
145
+ func_lines: list[tuple[int, str]],
146
+ ) -> dict | None:
147
+ """
148
+ Detect AArch64 stack frame allocated but not zeroed before return.
149
+
150
+ [EXPERIMENTAL] Findings require manual verification.
151
+ """
152
+ frame_alloc_line: tuple[int, str] | None = None
153
+ frame_size = 0
154
+ has_zero_store = False
155
+ ret_line: tuple[int, str] | None = None
156
+
157
+ for lineno, line in func_lines:
158
+ # stp x29, x30, [sp, #-N]! — most common AArch64 prologue (pre-index)
159
+ m = RE_A64_FRAME_STP.search(line)
160
+ if m:
161
+ if frame_alloc_line is None:
162
+ frame_alloc_line = (lineno, line.strip())
163
+ frame_size += int(m.group(1))
164
+
165
+ # sub sp, sp, #N — additional explicit allocation (common with stp prologue)
166
+ # Accumulate rather than taking only the first allocation so that prologues
167
+ # using both stp+sub report the correct total frame size (I28).
168
+ m2 = RE_A64_FRAME_SUB.search(line)
169
+ if m2:
170
+ if frame_alloc_line is None:
171
+ frame_alloc_line = (lineno, line.strip())
172
+ frame_size += int(m2.group(1))
173
+
174
+ # Zero-store detection
175
+ if RE_A64_STR_XZR.search(line) or RE_A64_STP_XZR.search(line):
176
+ has_zero_store = True
177
+ if RE_A64_MOVI_ZERO.search(line) or RE_A64_MEMSET.search(line):
178
+ has_zero_store = True
179
+
180
+ if RE_A64_RET.search(line):
181
+ ret_line = (lineno, line.strip())
182
+
183
+ if frame_alloc_line and ret_line and not has_zero_store and frame_size > 0:
184
+ alloc_lineno, alloc_text = frame_alloc_line
185
+ ret_lineno, _ = ret_line
186
+ return {
187
+ "category": "STACK_RETENTION",
188
+ "severity": "high",
189
+ "symbol": func_name,
190
+ "detail": (
191
+ f"[EXPERIMENTAL] AArch64 stack frame of {frame_size} bytes allocated "
192
+ f"at line {alloc_lineno} ({alloc_text!r}) but no zero-store "
193
+ f"(str xzr / stp xzr,xzr / movi+stp / zeroize call) found "
194
+ f"before return at line {ret_lineno}"
195
+ ),
196
+ "evidence_detail": (
197
+ f"{alloc_text} at line {alloc_lineno}; "
198
+ f"no str/stp xzr or zeroize call before ret at line {ret_lineno}"
199
+ ),
200
+ }
201
+ return None
202
+
203
+
204
+ # ---------------------------------------------------------------------------
205
+ # REGISTER_SPILL (AArch64)
206
+ # ---------------------------------------------------------------------------
207
+
208
+
209
+ def check_register_spill(
210
+ func_name: str,
211
+ func_lines: list[tuple[int, str]],
212
+ ) -> list[dict]:
213
+ """
214
+ Detect AArch64 registers spilled to the stack.
215
+
216
+ [EXPERIMENTAL] x29/x30 prologue saves will always appear here because both
217
+ are in AARCH64_CALLEE_SAVED. Reviewers should check whether those registers
218
+ actually hold sensitive values in the function under analysis.
219
+ """
220
+ spills: list[tuple[int, str, str]] = [] # (lineno, reg, line)
221
+
222
+ for lineno, line in func_lines:
223
+ # Single store: str xN/vN/qN, [sp, ...]
224
+ m = RE_A64_STR_SPILL.search(line)
225
+ if m:
226
+ reg = m.group(1)
227
+ if reg in AARCH64_CALLEE_SAVED or reg in AARCH64_CALLER_SAVED:
228
+ spills.append((lineno, reg, line.strip()))
229
+ elif re.match(r"^q\d+$", reg):
230
+ # q registers are the 128-bit view of v registers; q8–q15 are
231
+ # partially callee-saved (lower 64 bits). For simplicity,
232
+ # classify all q-register spills as caller-saved (I31).
233
+ spills.append((lineno, reg, line.strip()))
234
+
235
+ # Pair store: stp xN, xM / qN, qM, [sp, ...]
236
+ m2 = RE_A64_STP_SPILL.search(line)
237
+ if m2:
238
+ for reg in (m2.group(1), m2.group(2)):
239
+ if reg == "xzr":
240
+ continue # zero register — this is a zero-store, not a spill
241
+ if (
242
+ reg in AARCH64_CALLEE_SAVED
243
+ or reg in AARCH64_CALLER_SAVED
244
+ or re.match(r"^q\d+$", reg)
245
+ ):
246
+ spills.append((lineno, reg, line.strip()))
247
+
248
+ findings: list[dict] = []
249
+ seen: set[str] = set()
250
+ for lineno, reg, line_text in spills:
251
+ if reg not in seen:
252
+ seen.add(reg)
253
+ if reg in AARCH64_CALLEE_SAVED:
254
+ reg_class, severity = "callee-saved", "high"
255
+ elif (m := re.match(r"^q(\d+)$", reg)) and int(m.group(1)) in range(8, 16):
256
+ # q8–q15: lower 64 bits callee-saved per AAPCS64
257
+ reg_class, severity = "callee-saved (partial)", "high"
258
+ else:
259
+ reg_class, severity = "caller-saved", "medium"
260
+ findings.append(
261
+ {
262
+ "category": "REGISTER_SPILL",
263
+ "severity": severity,
264
+ "symbol": func_name,
265
+ "detail": (
266
+ f"[EXPERIMENTAL] AArch64 register {reg} ({reg_class}) spilled to "
267
+ f"stack at line {lineno} in function '{func_name}' "
268
+ f"— may expose secret value"
269
+ ),
270
+ "evidence_detail": f"{line_text} at line {lineno}",
271
+ }
272
+ )
273
+ return findings
274
+
275
+
276
+ # ---------------------------------------------------------------------------
277
+ # Public entry point
278
+ # ---------------------------------------------------------------------------
279
+
280
+
281
+ def analyze_function(
282
+ func_name: str,
283
+ func_lines: list[tuple[int, str]],
284
+ ) -> list[dict]:
285
+ """
286
+ Run all AArch64 checks for one sensitive function.
287
+ Returns a (possibly empty) list of finding dicts.
288
+
289
+ [EXPERIMENTAL] All returned findings carry [EXPERIMENTAL] in their detail
290
+ field and require manual verification.
291
+ """
292
+ findings: list[dict] = []
293
+
294
+ f = check_stack_retention(func_name, func_lines)
295
+ if f:
296
+ findings.append(f)
297
+
298
+ findings.extend(check_register_spill(func_name, func_lines))
299
+
300
+ return findings
@@ -0,0 +1,283 @@
1
+ #!/usr/bin/env python3
2
+ # /// script
3
+ # requires-python = ">=3.11"
4
+ # dependencies = []
5
+ # ///
6
+ """
7
+ check_rust_asm_x86.py — x86-64 Rust assembly analysis backend.
8
+
9
+ Called by check_rust_asm.py. Not intended for direct invocation.
10
+
11
+ Detects STACK_RETENTION, REGISTER_SPILL, and red-zone STACK_RETENTION in x86-64
12
+ AT&T-syntax assembly emitted by `cargo +nightly rustc --emit=asm`.
13
+ """
14
+
15
+ import re
16
+
17
+ # ---------------------------------------------------------------------------
18
+ # x86-64 register sets (System V ABI — identical for C/C++ and Rust)
19
+ # ---------------------------------------------------------------------------
20
+ CALLER_SAVED = {
21
+ "rax",
22
+ "rcx",
23
+ "rdx",
24
+ "rsi",
25
+ "rdi",
26
+ "r8",
27
+ "r9",
28
+ "r10",
29
+ "r11",
30
+ # xmm0-xmm7 are function arguments / scratch; xmm8-xmm15 are also caller-saved
31
+ # (System V AMD64 ABI §3.2.1: XMM registers 0–15 are all caller-saved)
32
+ "xmm0",
33
+ "xmm1",
34
+ "xmm2",
35
+ "xmm3",
36
+ "xmm4",
37
+ "xmm5",
38
+ "xmm6",
39
+ "xmm7",
40
+ "xmm8",
41
+ "xmm9",
42
+ "xmm10",
43
+ "xmm11",
44
+ "xmm12",
45
+ "xmm13",
46
+ "xmm14",
47
+ "xmm15",
48
+ }
49
+ CALLEE_SAVED = {"rbx", "r12", "r13", "r14", "r15", "rbp"}
50
+
51
+ # ---------------------------------------------------------------------------
52
+ # Patterns
53
+ # ---------------------------------------------------------------------------
54
+
55
+ # Frame allocation
56
+ RE_FRAME_ALLOC = re.compile(r"subq\s+\$(\d+),\s+%rsp")
57
+ RE_PUSH = re.compile(r"push[ql]\s+%(\w+)")
58
+
59
+ # Zero-store patterns (volatile wipe) — all widths that can clear secret bytes
60
+ RE_MOVQ_ZERO = re.compile(r"movq\s+\$0,\s+-?\d+\(%r[sb]p\)")
61
+ RE_MOVL_ZERO = re.compile(r"movl\s+\$0,\s+-?\d+\(%r[sb]p\)")
62
+ RE_MOVW_ZERO = re.compile(r"movw\s+\$0,\s+-?\d+\(%r[sb]p\)")
63
+ RE_MOVB_ZERO = re.compile(r"movb\s+\$0,\s+-?\d+\(%r[sb]p\)")
64
+ RE_MEMSET_CALL = re.compile(r"call\s+.*(?:memset|volatile_set_memory|zeroize)")
65
+ # SIMD self-XOR zeroing: xorps/pxor/vpxor %regN, %regN — register is zeroed,
66
+ # typically followed by a store that constitutes the actual wipe.
67
+ RE_SIMD_ZERO = re.compile(r"(?:xorps|xorpd|pxor|vpxor)\s+%(\w+),\s+%(\w+)")
68
+
69
+ # Register spills: movq/movdqa/movups/movaps %reg, N(%rsp|%rbp)
70
+ RE_REG_SPILL = re.compile(r"mov(?:q|dqa|ups|aps)\s+%(\w+),\s+(-?\d+)\(%r[sb]p\)")
71
+
72
+ # Return instruction. Stripping the AT&T comment character (#) before
73
+ # applying this pattern prevents false matches inside assembly comments
74
+ # (e.g. "# retq is the encoding for ...").
75
+ RE_RET = re.compile(r"\bret[ql]?\b")
76
+
77
+ # Red zone: stores to [rsp - N] (N ≤ 128) in leaf functions without subq
78
+ RE_RED_ZONE = re.compile(r"mov(?:q|l|b|w)\s+%\w+,\s+-(\d+)\(%rsp\)")
79
+
80
+
81
+ # ---------------------------------------------------------------------------
82
+ # STACK_RETENTION
83
+ # ---------------------------------------------------------------------------
84
+
85
+
86
+ def check_stack_retention(
87
+ func_name: str,
88
+ func_lines: list[tuple[int, str]],
89
+ ) -> dict | None:
90
+ """
91
+ Detect stack frame allocated (subq $N, %rsp) but not zeroed before return.
92
+ """
93
+ frame_alloc_line: tuple[int, str] | None = None
94
+ frame_size = 0
95
+ has_zero_store = False
96
+ ret_line: tuple[int, str] | None = None
97
+
98
+ for lineno, line in func_lines:
99
+ # Strip trailing AT&T-style comments before pattern matching to avoid
100
+ # false positives from `# retq` or `# movq $0, ...` in comments (I25).
101
+ code = line.split("#", 1)[0]
102
+
103
+ m = RE_FRAME_ALLOC.search(code)
104
+ if m and frame_alloc_line is None:
105
+ frame_alloc_line = (lineno, line.strip())
106
+ frame_size = int(m.group(1))
107
+
108
+ if (
109
+ RE_MOVQ_ZERO.search(code)
110
+ or RE_MOVL_ZERO.search(code)
111
+ or RE_MOVW_ZERO.search(code)
112
+ or RE_MOVB_ZERO.search(code)
113
+ ):
114
+ has_zero_store = True
115
+ if RE_MEMSET_CALL.search(code):
116
+ has_zero_store = True
117
+ # SIMD self-XOR (xorps/pxor %xmmN, %xmmN) zeroes a register; treat
118
+ # as a zero-store signal to avoid false-positive STACK_RETENTION when
119
+ # the function wipes data via SIMD before returning (I26).
120
+ m2 = RE_SIMD_ZERO.search(code)
121
+ if m2 and m2.group(1) == m2.group(2):
122
+ has_zero_store = True
123
+
124
+ if RE_RET.search(code):
125
+ ret_line = (lineno, line.strip())
126
+
127
+ if frame_alloc_line and ret_line and not has_zero_store and frame_size > 0:
128
+ alloc_lineno, alloc_text = frame_alloc_line
129
+ ret_lineno, _ = ret_line
130
+ return {
131
+ "category": "STACK_RETENTION",
132
+ "severity": "high",
133
+ "symbol": func_name,
134
+ "detail": (
135
+ f"Stack frame of {frame_size} bytes allocated at line {alloc_lineno} "
136
+ f"({alloc_text!r}) but no zero-store found before return at line {ret_lineno}"
137
+ ),
138
+ "evidence_detail": (
139
+ f"{alloc_text} at line {alloc_lineno}; "
140
+ f"no volatile wipe before retq at line {ret_lineno}"
141
+ ),
142
+ }
143
+ return None
144
+
145
+
146
+ # ---------------------------------------------------------------------------
147
+ # REGISTER_SPILL
148
+ # ---------------------------------------------------------------------------
149
+
150
+
151
+ def check_register_spill(
152
+ func_name: str,
153
+ func_lines: list[tuple[int, str]],
154
+ ) -> list[dict]:
155
+ """
156
+ Detect registers spilled to the stack (potential secret exposure).
157
+ """
158
+ spills: list[tuple[int, str, str, str]] = [] # (lineno, reg, line, class)
159
+
160
+ for lineno, line in func_lines:
161
+ m = RE_REG_SPILL.search(line)
162
+ if m:
163
+ reg = m.group(1)
164
+ if reg in CALLER_SAVED:
165
+ spills.append((lineno, reg, line.strip(), "caller-saved"))
166
+ elif reg in CALLEE_SAVED:
167
+ spills.append((lineno, reg, line.strip(), "callee-saved"))
168
+
169
+ findings = []
170
+ seen: set[str] = set()
171
+ for lineno, reg, line_text, reg_class in spills:
172
+ if reg not in seen:
173
+ seen.add(reg)
174
+ severity = "high" if reg_class == "callee-saved" else "medium"
175
+ findings.append(
176
+ {
177
+ "category": "REGISTER_SPILL",
178
+ "severity": severity,
179
+ "symbol": func_name,
180
+ "detail": (
181
+ f"Register %{reg} ({reg_class}) spilled to stack at line {lineno} "
182
+ f"in function '{func_name}' — may expose secret value"
183
+ ),
184
+ "evidence_detail": f"{line_text} at line {lineno}",
185
+ }
186
+ )
187
+ return findings
188
+
189
+
190
+ # ---------------------------------------------------------------------------
191
+ # RED ZONE (x86-64 specific)
192
+ # ---------------------------------------------------------------------------
193
+
194
+
195
+ def check_red_zone(
196
+ func_name: str,
197
+ func_lines: list[tuple[int, str]],
198
+ ) -> dict | None:
199
+ """
200
+ Detect x86-64 leaf functions that store data in the red zone without zeroing.
201
+
202
+ The x86-64 System V ABI reserves 128 bytes below %rsp as a "red zone" that
203
+ leaf functions may use as scratch space without adjusting %rsp. Sensitive data
204
+ written to this region is NOT zeroed by the callee and persists after return.
205
+ This check only fires when no subq frame allocation is present (non-leaf
206
+ functions are covered by check_stack_retention).
207
+ """
208
+ # Only applies to leaf functions (no regular frame allocation)
209
+ if any(RE_FRAME_ALLOC.search(line) for _, line in func_lines):
210
+ return None
211
+
212
+ red_zone_depth = 0
213
+ has_zero_store = False
214
+ has_ret = False
215
+
216
+ for _, line in func_lines:
217
+ code = line.split("#", 1)[0] # strip AT&T comments (I25)
218
+
219
+ m = RE_RED_ZONE.search(code)
220
+ if m:
221
+ offset = int(m.group(1))
222
+ if offset <= 128:
223
+ red_zone_depth = max(red_zone_depth, offset)
224
+
225
+ if (
226
+ RE_MOVQ_ZERO.search(code)
227
+ or RE_MOVL_ZERO.search(code)
228
+ or RE_MOVW_ZERO.search(code)
229
+ or RE_MOVB_ZERO.search(code)
230
+ ):
231
+ has_zero_store = True
232
+ if RE_MEMSET_CALL.search(code):
233
+ has_zero_store = True
234
+ m2 = RE_SIMD_ZERO.search(code)
235
+ if m2 and m2.group(1) == m2.group(2):
236
+ has_zero_store = True
237
+ if RE_RET.search(code):
238
+ has_ret = True
239
+
240
+ if red_zone_depth > 0 and has_ret and not has_zero_store:
241
+ return {
242
+ "category": "STACK_RETENTION",
243
+ "severity": "high",
244
+ "symbol": func_name,
245
+ "detail": (
246
+ f"Leaf function '{func_name}' stores {red_zone_depth} bytes in the "
247
+ f"x86-64 red zone (below %rsp) without zeroing before return — "
248
+ f"sensitive data may persist in the 128-byte region below %rsp"
249
+ ),
250
+ "evidence_detail": (
251
+ f"red zone depth -{red_zone_depth}(%rsp); "
252
+ f"no mov[qwlb] $0 or memset/zeroize call before retq"
253
+ ),
254
+ }
255
+ return None
256
+
257
+
258
+ # ---------------------------------------------------------------------------
259
+ # Public entry point
260
+ # ---------------------------------------------------------------------------
261
+
262
+
263
+ def analyze_function(
264
+ func_name: str,
265
+ func_lines: list[tuple[int, str]],
266
+ ) -> list[dict]:
267
+ """
268
+ Run all x86-64 checks for one sensitive function.
269
+ Returns a (possibly empty) list of finding dicts.
270
+ """
271
+ findings: list[dict] = []
272
+
273
+ f = check_stack_retention(func_name, func_lines)
274
+ if f:
275
+ findings.append(f)
276
+
277
+ findings.extend(check_register_spill(func_name, func_lines))
278
+
279
+ f = check_red_zone(func_name, func_lines)
280
+ if f:
281
+ findings.append(f)
282
+
283
+ return findings