Implement the RPMB write path, which was never there
An enrolment collected all ten samples and then SAVE_DATA answered -5. The cause was not the sensor or the storage framing: ServeRpmb only ever implemented Op::Read. A write fell through the branch with rc still -1 and was refused, whatever --rpmb-write said. QTEE could not commit the anti-rollback record, so it rolled the transaction back -- after it had already rewritten the group's index container on disk. The write sequence is per chunk: the data frames out, a Result Read Request out, the result frame back. A remainder is refused rather than partially committed, and a non-zero device result aborts instead of continuing into further chunks, because at that point the counter state is not what we think it is. The refusal was not the only failure. Two assumptions were wrong and both are recorded in the journal: --group-path does NOT isolate the group directory. The writes went to the Android group, the one holding the working template, not to a new group derived from the namespace path. Isolation has to come from pointing the SFS root at a separate tree, not from the namespace key. And the rolled-back transaction left the index rewritten, so QTEE rejected it and the template became unreachable -- ENUMERATE 0, and repeated unlink attempts refused only because the mount had been switched back to read-only. Restoring the index from the pre-enrolment backup brought it back: templates loaded 1. The RPMB counter never moved, which is why restoring an older index worked at all. Had the write path been implemented, it would have.
This commit is contained in:
parent
bdd5de21b3
commit
cc079cd1f8
1 changed files with 37 additions and 0 deletions
|
|
@ -499,6 +499,43 @@ void ServeRpmb(std::span<std::byte> sb) {
|
||||||
// collects nblocks * 512 back.
|
// collects nblocks * 512 back.
|
||||||
if (SecurityProtocolRetry(fd, false, frames, rp::FrameSize) == 0)
|
if (SecurityProtocolRetry(fd, false, frames, rp::FrameSize) == 0)
|
||||||
rc = SecurityProtocolRetry(fd, true, frames, total);
|
rc = SecurityProtocolRetry(fd, true, frames, total);
|
||||||
|
} else {
|
||||||
|
// The authenticated write sequence, per chunk: the data frames out, a
|
||||||
|
// Result Read Request out, the result frame back.
|
||||||
|
//
|
||||||
|
// A remainder is refused rather than partially committed. The
|
||||||
|
// reference silently drops one, which would leave the store
|
||||||
|
// inconsistent with a counter that cannot be moved back.
|
||||||
|
auto plan = rp::PlanChunks(req->nblocks, req->blocksPerOp);
|
||||||
|
if (!plan.exact) {
|
||||||
|
std::println(" rpmb: {} blocks is not a whole number of {}-block chunks"
|
||||||
|
" -- refusing", req->nblocks, req->blocksPerOp);
|
||||||
|
} else {
|
||||||
|
std::array<std::byte, rp::FrameSize> rrq{};
|
||||||
|
rp::BuildResultReadRequest(rrq);
|
||||||
|
std::array<std::byte, rp::FrameSize> result{};
|
||||||
|
rc = 0;
|
||||||
|
for (std::uint32_t k = 0; k < plan.chunks && rc == 0; k++) {
|
||||||
|
std::byte* chunk = frames + static_cast<std::size_t>(k)
|
||||||
|
* req->blocksPerOp * rp::FrameSize;
|
||||||
|
std::uint32_t bytes = req->blocksPerOp
|
||||||
|
* static_cast<std::uint32_t>(rp::FrameSize);
|
||||||
|
if (SecurityProtocolRetry(fd, false, chunk, bytes) != 0 ||
|
||||||
|
SecurityProtocolRetry(fd, false, rrq.data(), rp::FrameSize) != 0 ||
|
||||||
|
SecurityProtocolRetry(fd, true, result.data(), rp::FrameSize) != 0) {
|
||||||
|
rc = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
std::uint16_t res = rp::ResultOf(result);
|
||||||
|
std::println(" rpmb write chunk {}/{}: result=0x{:04x} ({}) counter={}",
|
||||||
|
k + 1, plan.chunks, res, rp::ResultString(res),
|
||||||
|
rp::WriteCounterOf(result));
|
||||||
|
// Anything non-zero aborts rather than continuing into further
|
||||||
|
// chunks: the device rejected the frame and the counter state
|
||||||
|
// is not what we think it is.
|
||||||
|
if (res != rp::ResultOk) rc = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
::close(fd);
|
::close(fd);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue