fingerprintd/packaging
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Jorijn van der Graaf 41e86f84f4 Delete a finger's template, not just its name
FF_CMD_TA_REMOVE, recovered the way AUTHENTICATE was: read the stub, read the
handler. The 0x2006 stub at 0xa15c is a bare `ldp w0, w1, [payload]`, so the
request is two u32s -- gid at +0, fid at +4 -- and the 0x2000 dispatcher
validates no length. Walking the jump table reproduces authenticate at 0xa180,
which is the address already on record, so the table read is sound.

Three preconditions, all the trustlet's own. The gid must be the ACTIVE group
(it compares against device+0x30, the field SET_ACTIVE_GROUP writes). The fid
must be non-zero: zero is not "remove all", it is an error the trustlet logs
and refuses. And the fid must be among the loaded templates, because it
removes by the SLOT INDEX it finds, not by id.

It persists: on a hit the trustlet formats ff_template_<gid>_<slot>.bin and
calls ff_file_delete, which arrives on our gpfile listener as an unlink -- so
this only works with the store served writable.

Proven harmlessly first. --probe-remove sends one command with no map
involvement, and a fid the group does not hold answers rc=-2 with the real
template untouched -- which is what established that both words are read where
we send them, before anything was deleted.

Then for real, through fprintd-delete: both 347202-byte containers and their
.bak companions unlinked, templates loaded 1 -> 0, and a re-enrolment
afterwards completed 20 stages with SAVE_DATA rc=0, so the store is consistent
after a removal rather than merely emptier.

The ordering the transcript shows is worth keeping: the group index is
rewritten and the RPMB anti-rollback counter bumped BEFORE each unlink. That
is precisely why an orderly removal leaves a valid store where restoring an
older container leaves a tampered one -- the counter has already moved past
it.

The delete reply now waits for the worker, because only that thread invokes
the trustlet and fprintd's Delete methods are synchronous. Names are dropped
before templates on purpose: a template that survives a failed removal is a
slot leak, while a name that survives a successful one keeps offering a finger
that can no longer match.
2026-09-05 04:27:14 +02:00
..
20-focal64.manifest A verify nobody answered is not a failure, and the trustlet is not ours to ship 2026-09-05 04:01:06 +02:00
80-fingerprintd.preset Package the daemon, so a fingerprint survives a reflash 2026-09-05 02:52:01 +02:00
APKBUILD Delete a finger's template, not just its name 2026-09-05 04:27:14 +02:00
build-package.sh Package the daemon, so a fingerprint survives a reflash 2026-09-05 02:52:01 +02:00
deploy-dev.sh Package the daemon, so a fingerprint survives a reflash 2026-09-05 02:52:01 +02:00
fingerprintd.json Package the daemon, so a fingerprint survives a reflash 2026-09-05 02:52:01 +02:00
fingerprintd.modules-load.conf Package the daemon, so a fingerprint survives a reflash 2026-09-05 02:52:01 +02:00
fingerprintd.service A verify nobody answered is not a failure, and the trustlet is not ours to ship 2026-09-05 04:01:06 +02:00
fingerprintd.tmpfiles.conf Package the daemon, so a fingerprint survives a reflash 2026-09-05 02:52:01 +02:00
fpenrol.sh fpenrol.sh: no enrolment ever received the position guidance this script claims 2026-09-03 17:44:35 +02:00
fplearn.sh fplearn.sh: a wipe leaves learning off too 2026-09-05 02:07:26 +02:00
fptrial.sh Hold, do not tap -- and stop spending the verdict on a frame that cannot carry it 2026-09-05 00:17:13 +02:00
make-bin-tarball.sh A verify nobody answered is not a failure, and the trustlet is not ours to ship 2026-09-05 04:01:06 +02:00
make-libqcomtee.sh Reach QTEE: credentials, client env and the app loader, with no QCBOR 2026-09-02 18:02:28 +02:00
make-sysroot.sh Add the cross-build sysroot recipe, verified on the device 2026-09-02 17:34:27 +02:00
mnt-persist.mount Package the daemon, so a fingerprint survives a reflash 2026-09-05 02:52:01 +02:00
net.reactivated.Fprint.conf Become a daemon: a held session, a worker, and net.reactivated.Fprint 2026-09-02 22:10:51 +02:00
net.reactivated.fprint.device.policy Package the daemon, so a fingerprint survives a reflash 2026-09-05 02:52:01 +02:00
net.reactivated.Fprint.service Package the daemon, so a fingerprint survives a reflash 2026-09-05 02:52:01 +02:00
README.config.md Package the daemon, so a fingerprint survives a reflash 2026-09-05 02:52:01 +02:00

fingerprintd.json — where it comes from, and why this exact file

The trustlet gates its config file on common.configuration_uuid and silently falls back to built-in defaults on a mismatch, so the file is not decorative: SYNC_CONFIG returning 0 is what makes the whole init chain run.

This copy is generated, not hand-written. Its source is fp6fpcfg.py in the fp6 bring-up repo, which builds it from the captured stock configuration dump (journal/fingerprint/captures/2026-08-25-focal64-effective-config-from-stock.txt):

utilities/fp6fpcfg.py --daemon --verbose > packaging/fingerprintd.json

sha256 begins b205c756914a66f1.

Why the --verbose variant

--verbose here is the trustlet's own log level, not the daemon's. It is shipped because it is the file every accuracy number was measured on — 30/30 held presses, zero false accepts, 36-330 ms to a verdict — and the TA's log level cannot be raised again by a runtime SYNC_CONFIG, so a session that needs the matcher's own lines has to have started with it.

--daemon alone produces the same file with trustlet logging off (sha256 6c4503e628406424, four diagnosis.* keys differ and nothing else). It is plausibly the better shipping default and it is untested: no rate in the journal was measured on it. Switching is a measurement, not an edit.

The two policy keys

  • common.max_authentication_rescan_times: 0 — at the stock budget a wrong finger never yields a terminal frame, so a PAM client waits forever for the verify-no-match it needs.
  • trustlet.enable_trusted_enrollment: false — skips the challenge compare and the hw_auth_token HMAC verify. pmOS has no Gatekeeper to issue a token and nothing on pmOS verifies one.