A verify nobody answered is not a failure, and the trustlet is not ours to ship
Two things the packaging left behind.
A verify that ran its 600-frame budget without the sensor being touched was
reported to the client as verify-unknown-error. Nothing had gone wrong: nobody
had pressed. It cost three verifications during packaging, each reading as a
broken daemon. fprintd's contract is that a verify runs until the client stops
it, so the frame cap bounds one trustlet scan session rather than the user's
patience, and a window with no press simply runs again. Verified across the
rollover: 600 frames untouched, "still waiting", then a press matching on its
first contact frame in 44 ms.
Presses that happen and never reach a verdict now report verify-retry-scan --
a bad scan, which fprintd has a word for, and not the matcher saying no.
The cost is that an unanswered verify polls every ~200 ms for as long as the
client holds it. The cure is measured and available -- gpio75 is silent at
idle and bursts on contact -- but it would make the IRQ the only way a press
is ever noticed, deleting the poll under every rate this daemon has been
measured at. Noted where the loop waits, not done.
And the trustlet: focal64.mbn is a proprietary OEM-signed blob, so the package
ships a fp6-vendor-blobs manifest fragment instead, the same mechanism
soc-fairphone-fp6-audio uses for the amp config. It needed a new directive
there -- a QTEE image is an ELF header file plus one payload per program
header, not one file -- and reassembly on the phone reproduces the image QTEE
has accepted since August, byte for byte.
2026-09-05 04:01:06 +02:00
|
|
|
# FocalTech FT9391 trustlet (proprietary, OEM-signed) - reassembled from the
|
|
|
|
|
# stock modem partition on-device instead of being shipped (fp6 repo
|
|
|
|
|
# journal/blobs/, journal/fingerprint/). It is the matcher: every pixel the
|
|
|
|
|
# sensor produces stays inside it, and no part of the daemon can substitute
|
|
|
|
|
# for it. QTEE's signature gate is fused OEM root, measured 2026-09-03, so
|
|
|
|
|
# there is no version of this that is our own code.
|
|
|
|
|
#
|
|
|
|
|
# Not one file: image/focal64.mdt plus focal64.b00..b08, placed at each ELF
|
0.2.4: the trustlet comes from the active slot, unpinned, and a refusal says why
0.2.3's manifest pinned the sha256 of one Android build's focal64
(16.82.0, the build the dev phone runs). Fairphone re-signs the trustlet
every release, so that pin matched exactly one of the six builds seen,
and two of two field reports had no sensor: one user on 16.100.0 edited
the manifest by hand, another ended up with a file QTEE refuses.
The manifest now carries '-' instead of a hash and depends on
fp6-vendor-blobs 1-r3, which tries the active slot first and verifies the
image's structure; QTEE's signature check is the gate it always was (one
flipped byte -> ERROR_ELF_SIGNATURE_ERROR, measured 2026-09-03 and again
today).
post-install reassembles the trustlet right away, so 'apk add' no longer
needs a boot for it. post-upgrade re-derives it from the active slot,
which replaces a hand-placed or wrongly pinned file, and then restarts
the daemon -- a plain restart, so a daemon that exited on a refused
trustlet comes back up on the re-derived one.
loadFromBuffer failures name the loader's verdict. The field's first
report was a bare result=12; it now reads ERROR_ELF_SIGNATURE_ERROR with
what to do about it. Probed on the phone with this build: a one-byte
tampered image and 100000 random bytes both print it, the pristine image
loads, and the suites pass 8/8.
2026-09-11 13:04:35 +02:00
|
|
|
# segment's p_offset. The extractor tries the ACTIVE slot first (its TZ is
|
|
|
|
|
# the one running) and the other slot as fallback.
|
|
|
|
|
#
|
|
|
|
|
# No sha256 pin ('-'): Fairphone re-signs this trustlet every Android
|
|
|
|
|
# release, so a whole-image hash matches exactly one build - six builds, six
|
|
|
|
|
# hashes, one trustlet - and the pin 0.2.3 shipped (16.82.0's) left every
|
|
|
|
|
# unit on another build without a sensor (two of two field reports,
|
|
|
|
|
# 2026-09-11). The extractor verifies the structure; QTEE verifies the
|
|
|
|
|
# signature and refuses a damaged or foreign image (one flipped byte ->
|
|
|
|
|
# ERROR_ELF_SIGNATURE_ERROR, measured 2026-09-03), and the daemon names that
|
|
|
|
|
# verdict in its log.
|
|
|
|
|
mbn modem_a,modem_b image focal64 /usr/lib/firmware/focal64.mbn -
|