auditor

An aarch64 constant-time memory access auditing tool.
git clone git://git.ppad.tech/auditor.git
Log | Files | Refs | README | LICENSE

commit 1024a263bdbf80cc9451e5171b376aa104d6c4be
parent c226539fea1c99fb6df434406eae0419d39aea00
Author: Jared Tobin <jared@jtobin.io>
Date:   Fri, 13 Feb 2026 07:34:27 +0400

misc: improve nct output

Diffstat:
Mapp/Main.hs | 10+++++++---
Metc/taint.json | 3+--
Aetc/taint_inv.json | 8++++++++
Aetc/taint_mul_wnaf.json | 5+++++
Mlib/Audit/AArch64/NCT.hs | 25+------------------------
Mtest/Main.hs | 45+++++++++++++++------------------------------
6 files changed, 37 insertions(+), 59 deletions(-)

diff --git a/app/Main.hs b/app/Main.hs @@ -185,8 +185,14 @@ outputNct opts findings = do else exitFailure printNctSummary :: (Text, [NctFinding]) -> IO () -printNctSummary (sym, fs) = +printNctSummary (sym, fs) = do TIO.putStrLn $ sym <> ": " <> T.pack (show (length fs)) + mapM_ printFindingIndented fs + +printFindingIndented :: NctFinding -> IO () +printFindingIndented f = TIO.putStrLn $ + " " <> T.pack (show (nctLine f)) <> ": " + <> nctReasonText (nctReason f) <> ": " <> instrText (nctInstr f) printNctDetail :: (Text, [NctFinding]) -> IO () printNctDetail (sym, fs) = mapM_ (printFinding sym) fs @@ -201,8 +207,6 @@ nctReasonText r = case r of CondBranch -> "cond-branch" IndirectBranch -> "indirect-branch" Div -> "div" - MulOp -> "mul" - VarShift -> "var-shift" RegIndexAddr -> "reg-index" instrText :: Instr -> Text diff --git a/etc/taint.json b/etc/taint.json @@ -1,7 +1,6 @@ { "_mul_wnaf_info": { - "secret": ["X23"], - "public": ["X19", "X20", "X21", "X22"] + "secret": ["X23", "X24"] }, "_Numeric.Montgomery.Secp256k1.Curve.inv#_info": { "secret": ["X23", "X24", "X25", "X26"] diff --git a/etc/taint_inv.json b/etc/taint_inv.json @@ -0,0 +1,8 @@ +{ +"_ppadzmfixedzm0zi1zi3zminplace_NumericziMontgomeryziSecp256k1ziCurve_invzh_info$def": { + "secret": ["X22", "X23", "X24", "X25", "X26"] + } +} + + + diff --git a/etc/taint_mul_wnaf.json b/etc/taint_mul_wnaf.json @@ -0,0 +1,5 @@ +{ + "_mul_wnaf_info": { + "stg_secret": [8, 152] + } +} diff --git a/lib/Audit/AArch64/NCT.hs b/lib/Audit/AArch64/NCT.hs @@ -33,8 +33,6 @@ data NctReason = CondBranch -- ^ Conditional branch (b.<cond>, cbz, cbnz, tbz, tbnz) | IndirectBranch -- ^ Indirect branch (br, blr) | Div -- ^ Division (udiv, sdiv) - | MulOp -- ^ Multiplication (mul, madd, msub, umulh, smulh) - | VarShift -- ^ Variable shift (lsl, lsr, asr, ror with reg operand) | RegIndexAddr -- ^ Register-indexed memory access deriving (Eq, Ord, Show, Generic, NFData) @@ -86,23 +84,10 @@ classifyInstr instr = case instr of Br _ -> Just IndirectBranch Blr _ -> Just IndirectBranch - -- Division + -- Division (not DIT per ARM docs) Udiv _ _ _ -> Just Div Sdiv _ _ _ -> Just Div - -- Multiplication - Mul _ _ _ -> Just MulOp - Madd _ _ _ _ -> Just MulOp - Msub _ _ _ _ -> Just MulOp - Umulh _ _ _ -> Just MulOp - Smulh _ _ _ -> Just MulOp - - -- Variable shifts (only when shift amount is register) - Lsl _ _ op -> checkVarShiftOp op - Lsr _ _ op -> checkVarShiftOp op - Asr _ _ op -> checkVarShiftOp op - Ror _ _ op -> checkVarShiftOp op - -- Load/store with register index Ldr _ addr -> checkRegIndexAddr addr Ldrb _ addr -> checkRegIndexAddr addr @@ -144,14 +129,6 @@ classifyInstr instr = case instr of _ -> Nothing --- | Check if operand indicates variable shift (register-based). -checkVarShiftOp :: Operand -> Maybe NctReason -checkVarShiftOp op = case op of - OpReg _ -> Just VarShift - OpShiftedReg _ _ -> Just VarShift - OpExtendedReg _ _ -> Just VarShift - _ -> Nothing - -- | Check if address mode uses register indexing. checkRegIndexAddr :: AddrMode -> Maybe NctReason checkRegIndexAddr addr = case addr of diff --git a/test/Main.hs b/test/Main.hs @@ -1175,65 +1175,50 @@ nctTests = testGroup "NCT" [ [f] -> assertEqual "reason" Div (nctReason f) _ -> assertFailure "expected 1 finding" - , testCase "mul: mul" $ do + , testCase "no finding: mul (DIT)" $ do + -- mul is DIT per ARM docs let src = "foo:\n mul x0, x1, x2\n" case parseAsm src of Left e -> assertFailure $ "parse failed: " ++ show e Right lns -> do let m = scanNct lns - case Map.lookup "foo" m of - Nothing -> assertFailure "no findings" - Just fs -> case fs of - [f] -> assertEqual "reason" MulOp (nctReason f) - _ -> assertFailure "expected 1 finding" + assertEqual "no findings" Nothing (Map.lookup "foo" m) - , testCase "mul: madd" $ do + , testCase "no finding: madd (DIT)" $ do + -- madd is DIT per ARM docs let src = "foo:\n madd x0, x1, x2, x3\n" case parseAsm src of Left e -> assertFailure $ "parse failed: " ++ show e Right lns -> do let m = scanNct lns - case Map.lookup "foo" m of - Nothing -> assertFailure "no findings" - Just fs -> case fs of - [f] -> assertEqual "reason" MulOp (nctReason f) - _ -> assertFailure "expected 1 finding" + assertEqual "no findings" Nothing (Map.lookup "foo" m) - , testCase "mul: umulh" $ do + , testCase "no finding: umulh (DIT)" $ do + -- umulh is DIT per ARM docs let src = "foo:\n umulh x0, x1, x2\n" case parseAsm src of Left e -> assertFailure $ "parse failed: " ++ show e Right lns -> do let m = scanNct lns - case Map.lookup "foo" m of - Nothing -> assertFailure "no findings" - Just fs -> case fs of - [f] -> assertEqual "reason" MulOp (nctReason f) - _ -> assertFailure "expected 1 finding" + assertEqual "no findings" Nothing (Map.lookup "foo" m) - , testCase "var-shift: lsl with reg" $ do + , testCase "no finding: lsl with reg (DIT)" $ do + -- variable shifts are DIT per ARM docs let src = "foo:\n lsl x0, x1, x2\n" case parseAsm src of Left e -> assertFailure $ "parse failed: " ++ show e Right lns -> do let m = scanNct lns - case Map.lookup "foo" m of - Nothing -> assertFailure "no findings" - Just fs -> case fs of - [f] -> assertEqual "reason" VarShift (nctReason f) - _ -> assertFailure "expected 1 finding" + assertEqual "no findings" Nothing (Map.lookup "foo" m) - , testCase "var-shift: lsr with reg" $ do + , testCase "no finding: lsr with reg (DIT)" $ do + -- variable shifts are DIT per ARM docs let src = "foo:\n lsr x0, x1, x2\n" case parseAsm src of Left e -> assertFailure $ "parse failed: " ++ show e Right lns -> do let m = scanNct lns - case Map.lookup "foo" m of - Nothing -> assertFailure "no findings" - Just fs -> case fs of - [f] -> assertEqual "reason" VarShift (nctReason f) - _ -> assertFailure "expected 1 finding" + assertEqual "no findings" Nothing (Map.lookup "foo" m) , testCase "no finding: lsl with imm" $ do -- lsl x0, x1, #5 should NOT flag (immediate shift)