feat: build system transition to release fork + archive hardening
Release fork infrastructure: - REDBEAR_RELEASE=0.1.1 with offline enforcement (fetch/distclean/unfetch blocked) - 195 BLAKE3-verified source archives in standard format - Atomic provisioning via provision-release.sh (staging + .complete sentry) - 5-phase improvement plan: restore format auto-detection, source tree validation (validate-source-trees.py), archive-map.json, REPO_BINARY fallback Archive normalization: - Removed 87 duplicate/unversioned archives from shared pool - Regenerated all archives in consistent format with source/ + recipe.toml - BLAKE3SUMS and manifest.json generated from stable tarball set Patch management: - verify-patches.sh: pre-sync dry-run report (OK/REVERSED/CONFLICT) - 121 upstream-absorbed patches moved to absorbed/ directories - 43 active patches verified clean against rebased sources - Stress test: base updated to upstream HEAD, relibc reset and patched Compilation fixes: - relibc: Vec imports in redox-rt (proc.rs, lib.rs, sys.rs) - relibc: unsafe from_raw_parts in mod.rs (2024 edition) - fetch.rs: rev comparison handles short/full hash prefixes - kibi recipe: corrected rev mismatch New scripts: restore-sources.sh, provision-release.sh, verify-sources-archived.sh, check-upstream-releases.sh, validate-source-trees.py, verify-patches.sh, repair-archive-format.sh, generate-manifest.py Documentation: AGENTS.md, README.md, local/AGENTS.md updated for release fork model
This commit is contained in:
@@ -1,169 +0,0 @@
|
||||
# P2-pcid-cfg-access.patch
|
||||
#
|
||||
# PCI config access error handling: replace unwrap()/expect()/assert!() with
|
||||
# proper error returns and graceful fallbacks in PCI configuration space access
|
||||
# (both I/O port fallback and ECAM/DTB paths).
|
||||
#
|
||||
# Covers:
|
||||
# - pcid/cfg_access/fallback.rs: I/O port rights error logging, offset overflow returns
|
||||
# - pcid/cfg_access/mod.rs: DTB property access with proper error propagation,
|
||||
# bus-range validation, interrupt-map phandle/property fallbacks
|
||||
#
|
||||
diff --git a/drivers/pcid/src/cfg_access/fallback.rs b/drivers/pcid/src/cfg_access/fallback.rs
|
||||
index 671d17f7..ea8f69f8 100644
|
||||
--- a/drivers/pcid/src/cfg_access/fallback.rs
|
||||
+++ b/drivers/pcid/src/cfg_access/fallback.rs
|
||||
@@ -33,7 +33,12 @@ impl Pci {
|
||||
"PCI: couldn't find or access PCIe extended configuration, \
|
||||
and thus falling back to PCI 3.0 io ports"
|
||||
);
|
||||
- common::acquire_port_io_rights().expect("pcid: failed to get IO port rights");
|
||||
+ common::acquire_port_io_rights()
|
||||
+ .map_err(|err| {
|
||||
+ log::error!("pcid: failed to get IO port rights: {err}");
|
||||
+ err
|
||||
+ })
|
||||
+ .expect("pcid: IO port rights required for PCI 3.0 fallback");
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -61,8 +66,9 @@ impl ConfigRegionAccess for Pci {
|
||||
|
||||
Self::set_iopl();
|
||||
|
||||
- let offset =
|
||||
- u8::try_from(offset).expect("offset too large for PCI 3.0 configuration space");
|
||||
+ let Ok(offset) = u8::try_from(offset) else {
|
||||
+ return 0xFFFFFFFF;
|
||||
+ };
|
||||
let address = Self::address(address, offset);
|
||||
|
||||
Pio::<u32>::new(0xCF8).write(address);
|
||||
@@ -74,8 +80,9 @@ impl ConfigRegionAccess for Pci {
|
||||
|
||||
Self::set_iopl();
|
||||
|
||||
- let offset =
|
||||
- u8::try_from(offset).expect("offset too large for PCI 3.0 configuration space");
|
||||
+ let Ok(offset) = u8::try_from(offset) else {
|
||||
+ return;
|
||||
+ };
|
||||
let address = Self::address(address, offset);
|
||||
|
||||
Pio::<u32>::new(0xCF8).write(address);
|
||||
diff --git a/drivers/pcid/src/cfg_access/mod.rs b/drivers/pcid/src/cfg_access/mod.rs
|
||||
index c2552448..0fe215a6 100644
|
||||
--- a/drivers/pcid/src/cfg_access/mod.rs
|
||||
+++ b/drivers/pcid/src/cfg_access/mod.rs
|
||||
@@ -38,42 +38,57 @@ fn locate_ecam_dtb<T>(
|
||||
)
|
||||
})?;
|
||||
|
||||
- let address = node.reg().unwrap().next().unwrap().starting_address as u64;
|
||||
+ let mut reg = node.reg().ok_or_else(|| {
|
||||
+ io::Error::new(io::ErrorKind::NotFound, "pci-host-ecam-generic missing 'reg' property")
|
||||
+ })?;
|
||||
+ let address = reg.next().ok_or_else(|| {
|
||||
+ io::Error::new(io::ErrorKind::NotFound, "pci-host-ecam-generic 'reg' has no entries")
|
||||
+ })?.starting_address as u64;
|
||||
|
||||
- let bus_range = node.property("bus-range").unwrap();
|
||||
- assert_eq!(bus_range.value.len(), 8);
|
||||
- let start_bus = u32::from_be_bytes(<[u8; 4]>::try_from(&bus_range.value[0..4]).unwrap());
|
||||
- let end_bus = u32::from_be_bytes(<[u8; 4]>::try_from(&bus_range.value[4..8]).unwrap());
|
||||
+ let bus_range = node.property("bus-range").ok_or_else(|| {
|
||||
+ io::Error::new(io::ErrorKind::NotFound, "pci-host-ecam-generic missing 'bus-range' property")
|
||||
+ })?;
|
||||
+ if bus_range.value.len() != 8 {
|
||||
+ return Err(io::Error::new(io::ErrorKind::InvalidData, "pci-host-ecam-generic 'bus-range' not 8 bytes"));
|
||||
+ }
|
||||
+ let start_bus = u32::from_be_bytes(<[u8; 4]>::try_from(&bus_range.value[0..4]).map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "bus-range start parse failed"))?);
|
||||
+ let end_bus = u32::from_be_bytes(<[u8; 4]>::try_from(&bus_range.value[4..8]).map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "bus-range end parse failed"))?);
|
||||
|
||||
- // address-cells == 3, size-cells == 2, interrupt-cells == 1
|
||||
- let mut interrupt_map_data = node
|
||||
- .property("interrupt-map")
|
||||
- .unwrap()
|
||||
+ let interrupt_map_prop = node.property("interrupt-map").ok_or_else(|| {
|
||||
+ io::Error::new(io::ErrorKind::NotFound, "pci-host-ecam-generic missing 'interrupt-map' property")
|
||||
+ })?;
|
||||
+ let mut interrupt_map_data = interrupt_map_prop
|
||||
.value
|
||||
.chunks_exact(4)
|
||||
- .map(|x| u32::from_be_bytes(<[u8; 4]>::try_from(x).unwrap()));
|
||||
+ .map(|x| u32::from_be_bytes(<[u8; 4]>::try_from(x).unwrap_or([0, 0, 0, 0])));
|
||||
let mut interrupt_map = Vec::<InterruptMap>::new();
|
||||
while let Ok([addr1, addr2, addr3, int1, phandle]) = interrupt_map_data.next_chunk::<5>() {
|
||||
- let parent = dt.find_phandle(phandle).unwrap();
|
||||
- let parent_address_cells = u32::from_be_bytes(
|
||||
- parent.property("#address-cells").unwrap().value[..4]
|
||||
- .try_into()
|
||||
- .unwrap(),
|
||||
- );
|
||||
+ let Some(parent) = dt.find_phandle(phandle) else {
|
||||
+ log::warn!("pcid: DTB interrupt-map references phandle {phandle} not found, skipping");
|
||||
+ continue;
|
||||
+ };
|
||||
+ let parent_address_cells = match parent.property("#address-cells") {
|
||||
+ Some(prop) => u32::from_be_bytes(
|
||||
+ prop.value[..4]
|
||||
+ .try_into()
|
||||
+ .unwrap_or([0, 0, 0, 0]),
|
||||
+ ),
|
||||
+ None => 0,
|
||||
+ };
|
||||
match parent_address_cells {
|
||||
0 => {}
|
||||
1 => {
|
||||
- assert_eq!(interrupt_map_data.next().unwrap(), 0);
|
||||
+ let _ = interrupt_map_data.next();
|
||||
}
|
||||
2 => {
|
||||
- assert_eq!(interrupt_map_data.next_chunk::<2>().unwrap(), [0, 0]);
|
||||
+ let _ = interrupt_map_data.next_chunk::<2>();
|
||||
}
|
||||
3 => {
|
||||
- assert_eq!(interrupt_map_data.next_chunk::<3>().unwrap(), [0, 0, 0]);
|
||||
+ let _ = interrupt_map_data.next_chunk::<3>();
|
||||
}
|
||||
_ => break,
|
||||
};
|
||||
- let parent_interrupt_cells = parent.interrupt_cells().unwrap();
|
||||
+ let parent_interrupt_cells = parent.interrupt_cells().unwrap_or(1);
|
||||
let parent_interrupt = match parent_interrupt_cells {
|
||||
1 if let Some(a) = interrupt_map_data.next() => [a, 0, 0],
|
||||
2 if let Ok([a, b]) = interrupt_map_data.next_chunk::<2>() => [a, b, 0],
|
||||
@@ -94,8 +109,8 @@ fn locate_ecam_dtb<T>(
|
||||
let mut cells = interrupt_mask_node
|
||||
.value
|
||||
.chunks_exact(4)
|
||||
- .map(|x| u32::from_be_bytes(<[u8; 4]>::try_from(x).unwrap()));
|
||||
- cells.next_chunk::<4>().unwrap().to_owned()
|
||||
+ .map(|x| u32::from_be_bytes(<[u8; 4]>::try_from(x).unwrap_or([0, 0, 0, 0])));
|
||||
+ cells.next_chunk::<4>().unwrap_or([u32::MAX, u32::MAX, u32::MAX, u32::MAX]).to_owned()
|
||||
} else {
|
||||
[u32::MAX, u32::MAX, u32::MAX, u32::MAX]
|
||||
};
|
||||
@@ -104,8 +119,8 @@ fn locate_ecam_dtb<T>(
|
||||
PcieAllocs(&[PcieAlloc {
|
||||
base_addr: address,
|
||||
seg_group_num: 0,
|
||||
- start_bus: start_bus.try_into().unwrap(),
|
||||
- end_bus: end_bus.try_into().unwrap(),
|
||||
+ start_bus: start_bus.try_into().map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "start_bus overflow"))?,
|
||||
+ end_bus: end_bus.try_into().map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "end_bus overflow"))?,
|
||||
_rsvd: [0; 4],
|
||||
}]),
|
||||
interrupt_map,
|
||||
@@ -165,7 +180,10 @@ impl Mcfg {
|
||||
// crashing. `as_encoded_bytes()` returns some superset
|
||||
// of ASCII, so directly comparing it with an ASCII name
|
||||
// is fine.
|
||||
- let table_filename = table_path.file_name().unwrap().as_encoded_bytes();
|
||||
+ let table_filename = match table_path.file_name() {
|
||||
+ Some(name) => name.as_encoded_bytes(),
|
||||
+ None => continue,
|
||||
+ };
|
||||
if table_filename.get(0..4) == Some(&MCFG_NAME) {
|
||||
let bytes = fs::read(table_path)?.into_boxed_slice();
|
||||
match Mcfg::parse(&*bytes) {
|
||||
Reference in New Issue
Block a user