Fix the poison offset: a released finger was reading as a rejection
PoisonFid takes the payload and offsets to the fid field internally. It was being handed a span already offset by the payload offset, so the poison landed at payload+0x20 and the real fid field stayed zero. A frame where the matcher never ran then looks exactly like a frame where it ran and rejected -- which is the specific failure this project has recorded three times and is precisely what the poison exists to prevent. Visible in a real run: the frames marked REJECTED were 138, 138, 133, 137, 134 against a floor of 136, i.e. every one of them was a finger-RELEASE frame with nothing on the sensor. Five rejections that never happened. The two offsets are numerically equal, which is why double-applying is silent, so the test now pins both directions: poisoning the payload marks the fid field, and poisoning an already-offset span leaves it zero and misclassifies. Also adds --rescan=N, which patches common.max_authentication_rescan_times into the config. The stock budget lets a whole run end with no terminal verdict -- correct for shipping, useless as a measurement, because a wrong-finger control that never reaches a verdict has not demonstrated a rejection. Forcing 0 makes every frame terminal. It prints MEASUREMENT ONLY because a rate taken that way is a per-frame figure with the retry mechanism disabled, and is not a shipping reject rate.
This commit is contained in:
parent
a8c989857a
commit
afb7496ef6
2 changed files with 45 additions and 1 deletions
|
|
@ -276,6 +276,19 @@ int main() {
|
|||
Check(Get32(payload, RespFidOff) == FidPoison, "poison written at +0x10");
|
||||
Check(Classify(0, Get32(payload, RespFidOff)) == Verdict::MatcherNeverRan,
|
||||
"an untouched poisoned payload classifies as never-ran");
|
||||
|
||||
// PoisonFid takes the PAYLOAD and offsets internally. Handing it a
|
||||
// span already offset by ResponsePayloadOff double-counts and poisons
|
||||
// payload+0x20, leaving the real fid field zero -- which makes every
|
||||
// released finger read as a rejection. That shipped once.
|
||||
Check(RespFidOff == ResponsePayloadOff,
|
||||
"the two offsets are equal, which is exactly why double-applying is silent");
|
||||
std::vector<std::byte> wrong(64);
|
||||
PoisonFid(std::span(wrong).subspan(ResponsePayloadOff));
|
||||
Check(Get32(wrong, RespFidOff) != FidPoison,
|
||||
"double-offsetting leaves the fid field unpoisoned");
|
||||
Check(Classify(0, Get32(wrong, RespFidOff)) == Verdict::Rejected,
|
||||
"and an unpoisoned release is then misread as a rejection");
|
||||
}
|
||||
|
||||
// ---- Init chain
|
||||
|
|
|
|||
Loading…
Reference in a new issue