kernel: the give paths take the lock, and a give confines afresh after a death
Three holes from the real-AMD audit, one shared root: the delegation flag-day added paths that touch the broker table and the IOMMU records without the big kernel lock, and a loan-return rule whose re-delegation skipped confinement. - device_enumerate walked the table with no lock. The table stopped being a static array in the bounds track — reserve() regrows it through realloc on every boot — so an unlocked reader can be mid-copy out of a slice that device_register on another core has already freed and reused, or pair a fresh count with a stale slice. Each chunk is now snapshotted under the lock; the copy to the user stays outside it. - system_spawn's give ran entirely unlocked — the comment claiming "the lock has not been dropped" was false (spawnProcessSupervised takes and releases it internally). The ownership pre-check now only spares creating a doomed child; the give itself re-checks, confines and moves in one lock hold, and a give that fails after the spawn kills the child rather than leaving it running without the hardware it was spawned for. - A re-delegated device after a driver death was never re-confined. Death tears the domain down before the loan returns to the lender, so the next give found no active record, reassign no-op'd, and the respawned driver ran the device with a V=0 device-table entry and no domain — silently unconfined, the exact fail-open the fail-closed claim was built to remove. Both give paths now share one body (giveDeviceLocked): check first, confine afresh when no record is active — refusing with ECONFINE like the claim — and move last, when nothing can fail. The iommu test drives the death-and-respawn sequence directly; with the old reassign-only behaviour its two confinement checks fail, with this change the suite is 118/118.
This commit is contained in:
@@ -1491,6 +1491,33 @@ fn iommuTest() void {
|
||||
check("and the previous holder no longer owns it", iommu.confinementOwner(device_id) != me);
|
||||
iommu.releaseAllOwnedBy(me + 1000);
|
||||
check("the new holder's death tears the domain down", iommu.confinementOwner(device_id) == null);
|
||||
|
||||
// The restart hole. A driver's death returns its device to the lender with the
|
||||
// domain torn down (asserted just above) — so the NEXT delegation of the same
|
||||
// device finds no active confinement record, and the transfer path's bare
|
||||
// `reassign` no-ops: the respawned driver would run the device with a V=0
|
||||
// device-table entry and no domain, silently unconfined. The give path must
|
||||
// confine afresh in that case, exactly as a first claim would.
|
||||
check("the lender holds the returned device", claimOk(device_id, me));
|
||||
const driver: u32 = me + 2000;
|
||||
check("delegating it confines it to the receiver", process.giveDeviceLocked(device_id, me, driver) == 0);
|
||||
check("the give's confinement names the receiver", iommu.confinementOwner(device_id) == driver);
|
||||
// The receiver dies: confinement torn down first, then the broker loans the
|
||||
// device back to the lender — the same order releaseTaskResourcesLocked runs.
|
||||
iommu.releaseAllOwnedBy(driver);
|
||||
devices_broker.releaseAllOwnedBy(driver);
|
||||
check("death returns the loan to the lender", devices_broker.ownerOf(device_id) == me);
|
||||
check("and leaves the device unconfined", iommu.confinementOwner(device_id) == null);
|
||||
// The regression this guards: re-delegation after that death.
|
||||
const respawned: u32 = me + 3000;
|
||||
check("re-delegation after the death succeeds", process.giveDeviceLocked(device_id, me, respawned) == 0);
|
||||
check(
|
||||
"and the respawned driver's device is confined, not silently naked",
|
||||
iommu.confinementOwner(device_id) == respawned,
|
||||
);
|
||||
iommu.releaseAllOwnedBy(respawned);
|
||||
devices_broker.releaseAllOwnedBy(respawned);
|
||||
_ = devices_broker.unclaim(device_id, me);
|
||||
}
|
||||
|
||||
log("DANOS-IOMMU: enabled base=0x{x} domains active\n", .{pinfo.iommu_base});
|
||||
|
||||
Reference in New Issue
Block a user