Watch
1
0
Fork
You've already forked SouveraineOS
0
SouveraineOS/docs/DUMP-fingerprint-2026-08-09.md
Fimeg b78342a337 dump: fingerprint handoff, and the protocol is recovered
STATE moved to 2026-08-09. One instrument is waiting on a finger;
everything else about the enrol lifecycle is reachable in RAM today.
2026-08-09 10:01:51 -04:00

5.9 KiB

DUMP — fingerprint, 2026-08-09

Handoff. TASK-44 is the owner and carries the design; this is what moved today and what to do first when you sit down.

What moved

The TA's command protocol is recovered. fpctzappfingerprint is not stripped — every handler logs __func__ — so its dispatch tables resolve to real names. Eight targets; the two that matter are 10 (sensor) and 11 (bio), and bio carries the whole lifecycle: begin_enrol, enrol, end_enrol, identify, get_template_ids, delete_template, set_active_fingerprint_set, load_empty_db, get_template_db_id.

Full tables, wire format, method: Pixel3Arch/docs/fpc-ta-protocol.md.

Done statically, from ~/pixel3-work/los-vendor/vendor.img with debugfs. No device, no Android, no Frida. The Frida-tracing plan from earlier in the session was unnecessary.

It cross-checks against your own work. The router's -201 / -210 / -211 are INPUT / CONFIG / NOT_INITIALIZED in the table fp-go.py already carried from the HAL disassembly on 2026-08-01. Two binaries, two methods, weeks apart, same numbers.

Two labels in TASK-44 were wrong. Sensor command 3 is wakeup_setup ("arm" is right in effect). Command 5 is deep_sleep, not "idle" — the part is asleep between events, not idling.

Do this first

ssh pixel
sudo ~/fp-finger.py load 120        # or pass a resident app_id

Arms once, then polls target 10 command 1 check_finger_lost at 10 Hz for two minutes. Touch whenever — no window to hit.

This answers the question TASK-44 has been stuck on since 2026-08-01. Every prior instrument counted edges and needed a human to vouch that a touch happened; this one asks the application. A ret that moves only while your finger is on the reader is the answer.

It brackets each query with the interrupt count, so the call's own edge is in a separate column from spontaneous ones — the 1444-event trap. If the own column accounts for everything, the sensor is not talking to you and you will see it immediately.

If ret never moves, try qualify_capture (10/4) next: the part may only report finger state during a capture rather than as a standing query.

Then, in order

  1. RAM-only enrol and identify. 11/6 load_empty_db → 11/9 set_active_fingerprint_set (set id at +12) → 11/0 begin_enrol → 11/1 enrol per capture → 11/2 end_enrol → 11/3 identify. Nothing persists yet, and nothing here can block.
  2. Persistence. Target 2 only, through a listener. See the safety note.
  3. souveraine-fpd. The daemon. TASK-44 §"Where it plugs in".

Safety, and it is narrow

The application's only persistence is qsee_fts_*, and the call graph says only targets 2 and 12 can reach it. Targets 10 and 11 cannot, so neither can block on a listener.

  • Safe on the daily driver: all of target 10, all of target 11.
  • Not on the daily driver: target 2 (fs) and target 12's remove_file — these can leave TZ parked, and a parked TZ blocks every QSEECOM caller until a reboot, not just yours. Target 5 is 19 production-test commands with a 529-byte payload and the build manifest lists prodtestlib and sensor_settings; treat it as the destructive group. Both want the spare.

delete_template and load_empty_db are harmless while nothing persists. They become destructive the moment target 2 works — wire the guard before the listener, not after.

Also landed

  • Five fingerprint tools were phone-only and are now in Pixel3Arch/tools/: fp-arm.py, fp-bringup.py, fp-go.py, fp-load.py, fp-sweep.py. They had lived only in ~ on the device since 2026-08-01 and a reprovision would have taken them. The three already tracked still hash-match the phone.
  • References cloned to Pixel3Arch/references/biometrics/ (gitignored): fprintd, libfprint with wrobelda/goodix-qsee fetched as a branch, sailfish-fpd-community, biometryd, qsee-supplicant, goodix-fp-spi-linux, both wrobelda kernel series, Google's own fpc1020_platform_tee.c and sdm845-b1c1-fingerprint.dtsi, and the extracted TA and HAL.
  • There is no API to design — fprintd, gazed, sailfish-fpd and biometryd are the same interface four times. TASK-44 maps every call onto a TA command.
  • The boot-chain trio (katana / sdm845-payloads / QHEEStub) is a separate strand: Pixel3Arch/docs/secure-world-references.md. blueline's hyp is Google-signed not QTI-signed, so QHEEStub's precondition holds, but qtestsign only works where firmware secure boot is off — so EL2 is per-boot over USB, never persistent. bootxbl is the piece worth having now; it turns a broken boot chain from a brick into a recovery.

Traps recorded today

  • Do not blind-dump /sys/bus/nvmem/devices/qfprom0/nvmem on a live phone. Did it, and cdc_ncm transmit-queue watchdogs and a dead tether followed. Possibly coincident with the known stale-usb0 hijack — not separable after the fact, and not worth separating. The fuse question belongs in EDL, on a device that is not the daily driver.
  • A call graph that loses jump-table case blocks reports no SPI anywhere. That is how the bug announces itself; the corrected graph resolves qsee_spi_* for exactly the sensor commands. Recorded in the protocol doc because the next session will rebuild this graph.
  • llvm-objdump 22 has no -b binary. Use aarch64-linux-gnu-objdump -D -b binary -m aarch64.

Open, and honest about it

  • Attribution — the one measurement above. Needs a finger.
  • Whether enrolment demands a Gatekeeper-signed hw_auth_token (target 3). It would return an error rather than block, so it costs a result, not a reboot.
  • linux-firmware carries no fingerprint TA on sdm845, sm8250 or sm8150. TAs are per-device extracts, so this can be enabled on a phone whose vendor image you hold and cannot be packaged for anyone else. Say so out loud rather than discovering it at release.