Serve QTEE's storage: the enrolled template loads
The whole storage path now works from the daemon. On the phone, against the
real store:
listener 0x7000 sb=516096 -> result=0 REGISTERED
listener 0x2000 sb=25600 -> result=0 REGISTERED
SET_ACTIVE_GROUP gid=60 path='/data/vendor_de/0/fpdata'
gpfile READ .../1lPrxAL0vXRvWPeDkW2c off=4096 len=252114
...
CMD 0x2005 -> result=0 rc=1
templates loaded: 1
QTEE read a 252114-byte enrolled template through our gpfile listener, verified
it, and loaded it. Since QTEE unlinks any container whose keyed integrity tag
fails, a load is proof the framing is right -- the read/write offset split, the
container chunking, and the RPMB anti-rollback read that has to succeed before
QTEE will trust any of it.
RPMB is served too: SECURITY PROTOCOL IN/OUT against the RPMB well-known LUN,
retrying the unit attention the LUN raises once after a reset. Writes are
refused unless asked for, because they advance a counter that cannot be moved
back, and key programming is refused unconditionally.
The store was served READ-ONLY throughout, which is the point. A listener that
serves bytes at the wrong offset does not merely fail: QTEE deletes the
container it cannot verify, and that is an enrolled fingerprint gone. Read-only
makes a wrong build harmless, so it is the default and writing is opt-in.
Two ordering facts, both of which produce -2 with no storage read at all --
indistinguishable from a broken listener:
* a template reload needs the device init chain to have run FIRST, because
that chain allocates the per-slot array the reload writes through;
* SET_ACTIVE_GROUP's second field is a NAMESPACE path, not a filesystem one
and not the gid again. The trustlet hashes it into the group's directory
name, so it has to match what the store was written under.
Also: a positive rc is not an error code. ENUMERATE returns the template count
there, and running that through the error table printed "unknown" for a good
answer.
This commit is contained in:
parent
6c4622afff
commit
03023284ba
3 changed files with 432 additions and 7 deletions
|
|
@ -253,7 +253,27 @@ export namespace fingerprintd::ta {
|
|||
// "templates with gid(%u != %u) hasn't been loaded." and returning -200 on
|
||||
// a mismatch. So the two only have to agree with each other — the value
|
||||
// itself is the caller's to choose.
|
||||
//
|
||||
// Its payload is {u32 gid; char path[]} and the path is NOT a filesystem
|
||||
// path we control: the trustlet hashes it into the SFS group's directory
|
||||
// name, so it is a namespace key and it has to match whatever the store
|
||||
// was written under. The store on this device was written by the Android
|
||||
// stack under its data directory, and every group in it derives from that
|
||||
// string. Passing anything else resolves a different group, finds nothing
|
||||
// and answers -2 -- with no storage read at all, which reads like a
|
||||
// listener failure and is not one.
|
||||
inline constexpr std::size_t SetActiveGroupGidOff = 0;
|
||||
inline constexpr std::size_t SetActiveGroupPathOff = 4;
|
||||
inline constexpr std::string_view GroupNamespacePath = "/data/vendor_de/0/fpdata";
|
||||
|
||||
inline std::vector<std::byte> BuildSetActiveGroup(
|
||||
std::uint32_t gid, std::string_view path = GroupNamespacePath) {
|
||||
std::vector<std::byte> out(SetActiveGroupPathOff + path.size() + 1, std::byte{0});
|
||||
detail::StoreU32(out, SetActiveGroupGidOff, gid);
|
||||
for (std::size_t i = 0; i < path.size(); i++)
|
||||
out[SetActiveGroupPathOff + i] = static_cast<std::byte>(path[i]);
|
||||
return out;
|
||||
}
|
||||
|
||||
// ---- The request/response envelope ------------------------------------
|
||||
//
|
||||
|
|
|
|||
Loading…
Reference in a new issue