79 lines
3.3 KiB
Markdown
79 lines
3.3 KiB
Markdown
|
|
# fingerprintd
|
||
|
|
|
||
|
|
Fingerprint daemon for the Fairphone 6 (`milos`, SM7635) on mainline Linux.
|
||
|
|
|
||
|
|
## Why a daemon
|
||
|
|
|
||
|
|
The sensor is a FocalTech FT9391 on a TrustZone-owned SPI bus. `spi@a88000` is
|
||
|
|
`disabled` in both the mainline and the stock Android device tree, and the pads
|
||
|
|
are XPU-protected — touching them from the normal world is an instant SError
|
||
|
|
reboot. Every pixel the sensor produces stays inside the TEE: capture,
|
||
|
|
preprocessing, the classifier, enrolment and matching all run in the `focal64`
|
||
|
|
trustlet, which reports a matched finger id and nothing else. A libfprint-style
|
||
|
|
driver cannot exist on this device.
|
||
|
|
|
||
|
|
So the normal world's job is narrower than usual, and none of it is per-request
|
||
|
|
work:
|
||
|
|
|
||
|
|
* **Power the sensor.** Rail on gpio29, reset on gpio74, interrupt on gpio75 —
|
||
|
|
the same division of labour the downstream driver uses. One sensor reset buys
|
||
|
|
exactly one trustlet init, so whatever powers the sensor must also hold the
|
||
|
|
session open.
|
||
|
|
* **Be QTEE's filesystem.** QTEE cannot reach storage. When the trustlet saves
|
||
|
|
or loads a template it calls back into the normal world through the `gpfile`
|
||
|
|
(0x7000) and RPMB (0x2000) listeners, and expects them served. QTEE does the
|
||
|
|
crypto and the anti-rollback; this side moves opaque bytes and performs the
|
||
|
|
authenticated RPMB transactions against the UFS device.
|
||
|
|
* **Speak a biometrics API.** The daemon owns `net.reactivated.Fprint`, so
|
||
|
|
`pam_fprintd`, the Plasma fingerprint KCM and `fprintd-enroll(1)` work
|
||
|
|
against it unmodified.
|
||
|
|
|
||
|
|
A listener registration is held for as long as the process lives and QTEE's
|
||
|
|
listener table is global to the boot, so this has to be one long-lived process
|
||
|
|
rather than a tool spawned per request.
|
||
|
|
|
||
|
|
## Layout
|
||
|
|
|
||
|
|
```
|
||
|
|
interfaces/ Fingerprintd{,-Sfs}.cppm the core: pure C++ modules
|
||
|
|
implementations/main.cpp the daemon shell
|
||
|
|
tests/ one suite per core module
|
||
|
|
```
|
||
|
|
|
||
|
|
`fingerprintd-core` is a static library with no GLib, no libqcomtee and no
|
||
|
|
system headers. Everything in it is a wire format or a state machine that was
|
||
|
|
recovered by reverse-engineering, so all of it is pinned by tests that run on a
|
||
|
|
dev box with no phone, no TEE and no sensor. The daemon shell holds everything
|
||
|
|
that touches hardware.
|
||
|
|
|
||
|
|
## Build
|
||
|
|
|
||
|
|
```sh
|
||
|
|
crafter-build # bin/fingerprintd-<target>-<march>/fingerprintd
|
||
|
|
crafter-build test # the unit suites
|
||
|
|
```
|
||
|
|
|
||
|
|
Cross-compiling for the phone:
|
||
|
|
|
||
|
|
```sh
|
||
|
|
crafter-build -- --target=aarch64-alpine-linux-musl \
|
||
|
|
--sysroot=<alpine-aarch64-sysroot> --march=armv8-a --mtune=generic
|
||
|
|
crafter-build test --target=aarch64-alpine-linux-musl
|
||
|
|
```
|
||
|
|
|
||
|
|
## Status
|
||
|
|
|
||
|
|
Early. The core is being ported one wire format at a time out of the research
|
||
|
|
harness that first made the sensor work (`utilities/fpta.c` in the fp6 repo),
|
||
|
|
each piece landing with tests before the next starts. `Fingerprintd:Sfs` — the
|
||
|
|
gpfile frame — is done. The daemon itself does not run yet.
|
||
|
|
|
||
|
|
The working reference enrols a finger, keeps it across a reboot, and matches it
|
||
|
|
with zero false accepts; the port exists to turn that into a service rather
|
||
|
|
than to rediscover it.
|
||
|
|
|
||
|
|
## Runtime dependencies, not carried here
|
||
|
|
|
||
|
|
The `focal64` trustlet is proprietary and is **not** in this repo. It is
|
||
|
|
extracted from the device's own stock Android partition on first boot by the
|
||
|
|
`fp6-vendor-blobs` mechanism, the same way the audio firmware is.
|