Commit graph fingerprintd/README.md
Author SHA1 Message Date
2da03d1595 readme
Some checks failed
package / package (push) Has been cancelled
2026-09-05 19:58:09 +02:00
ba882ee47b Learning off by default: it makes matching worse on this hardware
Jorijn asked for the control that settles it -- a fresh template, tested with
learning off -- and ran it twice.

  fresh template, 0 folds     30/30, two consecutive blocks of fifteen
  same lineage, 40 folds      12/15
  same lineage, 185 folds     total failure, 108 consecutive rejections

Every one of those measured with learning switched off during the measurement
itself, so nothing moved underneath the numbers, and the fresh-template result is
replicated back to back. Three points, monotonic in fold count.

The mechanism has been visible since the 185-fold collapse: the frames one press
contributes are near-duplicates of a single image from one finger position, so
folding them spends the template's ninety-six slots on that position and evicts
the diversity a twenty-sample enrolment put there. Stock's updates are spread
across many separate presses hours apart, which is where diversity actually comes
from.

And there is nothing on the other side of the scale. A plain enrolment measures
thirty out of thirty, so learning has no headroom to improve anything, and it has
never once been observed to raise a rate under conditions worth defending -- the
run that once looked like proof was confounded by a freshly wiped sensor and a
user learning the technique, both of which Jorijn identified himself while the
numbers were still climbing.

The code stays behind --learn=1. The finding is about this trustlet's algorithm,
not about the idea.
2026-09-05 02:11:43 +02:00
c5fc3afc77 Add fplearn.sh, because a cumulative measurement is a protocol not three commands
Learning rewrites the template on every matched press, so run two is not a
repeat of run one and an A/B against a moving template is not an A/B. The order
is the measurement:

  enrol   a fresh template at 20 samples with no position prompts, which is also
          the outstanding replication of the best result this lane has seen
  base    learning off: the clean number for that template, and the only figure
          comparable to every rate already recorded
  trend   learning on, three times: the rate should climb, with the container
          size as an independent witness that it is the template moving

A rate that climbs while the body grows is learning. A rate that moves while the
body does not is noise, and the daemon's own learn: lines say which. Run one of
the trend is not evidence that learning helped; it starts on the template the
baseline ended on.

One limit the script states rather than letting someone discover it: learning
only fires on a press that matched, so a template that never matches never
improves. That is why the protocol re-enrols instead of building on a template
already measured at 0 of 10.
2026-09-03 17:46:33 +02:00
82ceae988e README: what real use taught about the verify loop, and the revert 2026-09-02 23:19:24 +02:00
1368b2f474 README: it works end to end through fprintd's own clients 2026-09-02 22:29:59 +02:00
93692c9505 Add the cross-build sysroot recipe, verified on the device
packaging/make-sysroot.sh populates a minimal Alpine aarch64 rootfs with
apk-tools-static, so a cross build needs no root, no qemu and no phone. Adapted
from imsd's, plus glib-dev for the bus layer that is coming.

Building against a real Alpine sysroot means the binary links dynamically
against the phone's own musl and libc++ -- libc++, libc++abi, libunwind and
libgcc_s are all already on pmOS. The harness this daemon replaces had to be
built -static, but only because it was built with the host's glibc toolchain;
that constraint was never about the target.

The pipeline is proven end to end rather than assumed: the cross-built binary
runs on the phone, and all five core suites pass there too -- on the real
hardware, not just under qemu-aarch64. That matters for modules that are almost
entirely little-endian field packing and offset arithmetic.
2026-09-02 17:34:27 +02:00
1a54b5480c README: the core is complete 2026-09-02 17:22:51 +02:00
1d26852a6b Initial commit: the gpfile wire format, pinned by two real containers
fingerprintd will own the FP6's fingerprint sensor: the rail, the QTEE session,
the storage callbacks QTEE makes back into the normal world, and
net.reactivated.Fprint so pam_fprintd and the desktop need no changes. None of
that runs yet. What is here is the first core module and the machinery around
it.

Fingerprintd:Sfs is the gpfile listener's frame -- the callback that carries
47 of 66 storage requests during an enrolment. It is parse, reply and root
mapping only: no file I/O, no TEE, no allocation of the shared buffer. The
daemon shell supplies those, which is what lets every byte-level decision be
tested on a dev box with no phone.

The module exists mainly to hold one fact. READ answers at req+0x00c and WRITE
reads its payload from req+0x110, because the frame is a union: a WRITE still
needs its path while the payload is copied out, so it sits past the 256-byte
path field, while a READ has consumed the path and packs its reply over it.
Conflating them is wrong in both directions with the same symptom -- the
container does not round-trip, QTEE's HMAC check fails, and the file is
unlinked as tampered on the next session.

So the tests do not assert the constants against themselves. They load two real
containers off the phone -- one written correctly, one written with the offsets
conflated -- and re-derive the bug: the broken one opens with ASCII path text
rather than a binary HMAC, that text is the group name from character 8 because
the read offset is 8 bytes into the path field, and the real container sits
exactly 0x104 further in. Then a write-store-read round trip must be the
identity, and the same round trip through a single offset must not be.

O_TRUNC gets a static_assert of its own. QTEE writes a container as
write(0,4096), write(4096,N), write(0,4096), so truncating on open leaves 4096
bytes where a 258850-byte template belongs; it unlinks a file it means to
shorten rather than relying on the opener.

Verified by mutation: conflating the offsets, making DataOffset return the read
offset for writes, and setting O_TRUNC each fail the suite.
2026-09-02 16:02:46 +02:00