unlock/patch: preserve SCSI sense across the bridge; init aborts on dead bus; slow-retry first patch failure
Audit fixes (v1.1.0..HEAD regressions in the unlock migration + adaptive patch
speed):
- unlock_bridge ScsiAdapter: libfreemkv's transport returns Err on ANY non-zero
SCSI status (a normal CHECK CONDITION), not only transport faults. The adapter
was collapsing every such Err to { status: 0xFF, sense: None }, which discarded
the parsed sense and defeated the AACS handshake's ILLEGAL_REQUEST wedge guard
(so it kept hammering the drive — hard-rule #2) and inverted its
transport-vs-rejection diagnosis. Now reconstruct status + the 32-byte sense
buffer (sense_key@2, asc@12, ascq@13) and only emit 0xFF/None for a genuine
transport fault.
- Drive::init: a genuine transport fault during the drive-prep unlock means the
bus is dead — propagate it (the v1.1.0 invariant) instead of silently
swallowing it via `if let Ok`. Other errors (no matching unlocker) still fall
through to stock mode. SET CD SPEED max now runs only when the bus is alive.
- disc::patch: on the first read failure in a range, drop to slow recovery speed
and RE-ATTEMPT the same position at slow speed before marking it. A
single-sector range's first failing sector was being marked from a MAX-speed
read it never got to recover.
- docs: lib.rs architecture diagram (handshake → host_certs) and README (stale
pluggable-unlock-seam / register-unlocker / crates.io / docs.rs references).
This commit is contained in:
+25
-5
@@ -44,11 +44,31 @@ impl fu::scsi::ScsiTransport for ScsiAdapter<'_> {
|
||||
bytes_transferred: r.bytes_transferred,
|
||||
sense: r.sense,
|
||||
}),
|
||||
// libfreemkv's transport returns Err only on a transport-layer fault.
|
||||
Err(_) => Err(fu::scsi::ScsiError {
|
||||
status: 0xFF,
|
||||
sense: None,
|
||||
}),
|
||||
// libfreemkv's transport returns Err for ANY non-zero SCSI status —
|
||||
// i.e. a normal drive CHECK CONDITION (ILLEGAL_REQUEST, etc.), NOT
|
||||
// only a transport-layer fault. Preserve the real status AND the
|
||||
// parsed sense across the seam: the AACS handshake's wedge guard
|
||||
// bails on an ILLEGAL_REQUEST sense (so it stops hammering the drive),
|
||||
// and its diagnosis distinguishes a cert rejection from a dead bus by
|
||||
// the same status/sense. Collapsing everything to 0xFF/None defeated
|
||||
// both. Reconstruct the 32-byte sense buffer at the offsets the
|
||||
// unlock crate reads (sense_key@2 low-nibble, asc@12, ascq@13); a
|
||||
// genuine transport fault (status 0xFF, no sense) maps through
|
||||
// unchanged.
|
||||
Err(e) => {
|
||||
let (status, sense) = crate::drive::extract_scsi_context(&e);
|
||||
let sense_buf = sense.map(|s| {
|
||||
let mut b = [0u8; 32];
|
||||
b[2] = s.sense_key & 0x0F;
|
||||
b[12] = s.asc;
|
||||
b[13] = s.ascq;
|
||||
b
|
||||
});
|
||||
Err(fu::scsi::ScsiError {
|
||||
status,
|
||||
sense: sense_buf,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user