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:
@@ -0,0 +1,182 @@
|
||||
diff --git a/drivers/pcid/src/scheme.rs b/drivers/pcid/src/scheme.rs
|
||||
index bb9f39a3..06be6267 100644
|
||||
--- a/drivers/pcid/src/scheme.rs
|
||||
+++ b/drivers/pcid/src/scheme.rs
|
||||
@@ -1,11 +1,11 @@
|
||||
-use std::collections::{BTreeMap, VecDeque};
|
||||
+use std::collections::{BTreeMap, HashMap, VecDeque};
|
||||
|
||||
use pci_types::{ConfigRegionAccess, PciAddress};
|
||||
use redox_scheme::scheme::SchemeSync;
|
||||
use redox_scheme::{CallerCtx, OpenResult};
|
||||
use scheme_utils::HandleMap;
|
||||
use syscall::dirent::{DirEntry, DirentBuf, DirentKind};
|
||||
-use syscall::error::{Error, Result, EACCES, EBADF, EINVAL, EIO, EISDIR, ENOENT, ENOTDIR};
|
||||
+use syscall::error::{Error, Result, EACCES, EBADF, EINVAL, EIO, EISDIR, ENOENT, ENOTDIR, EALREADY};
|
||||
use syscall::flag::{MODE_CHR, MODE_DIR, O_DIRECTORY, O_STAT};
|
||||
use syscall::schemev2::NewFdFlags;
|
||||
use syscall::ENOLCK;
|
||||
@@ -16,6 +16,8 @@ pub struct PciScheme {
|
||||
handles: HandleMap<HandleWrapper>,
|
||||
pub pcie: Pcie,
|
||||
pub tree: BTreeMap<PciAddress, crate::Func>,
|
||||
+ /// Maps device address string (e.g. "0000:00:14.0") to owning PID
|
||||
+ binds: HashMap<String, u32>,
|
||||
}
|
||||
enum Handle {
|
||||
TopLevel { entries: Vec<String> },
|
||||
@@ -23,6 +25,12 @@ enum Handle {
|
||||
Device,
|
||||
Channel { addr: PciAddress, st: ChannelState },
|
||||
SchemeRoot,
|
||||
+ /// Represents an open handle to a device's bind endpoint
|
||||
+ Bind { addr: PciAddress },
|
||||
+ /// Uevent surface for hotplug consumers. Opening uevent returns an object
|
||||
+ /// from which device add/remove events can be read. Since pcid currently
|
||||
+ /// only scans at startup, this surface is ready for hotplug polling consumers.
|
||||
+ Uevent,
|
||||
}
|
||||
struct HandleWrapper {
|
||||
inner: Handle,
|
||||
@@ -30,14 +38,13 @@ struct HandleWrapper {
|
||||
}
|
||||
impl Handle {
|
||||
fn is_file(&self) -> bool {
|
||||
- matches!(self, Self::Access | Self::Channel { .. })
|
||||
+ matches!(self, Self::Access | Self::Channel { .. } | Self::Bind { .. } | Self::Uevent)
|
||||
}
|
||||
fn is_dir(&self) -> bool {
|
||||
!self.is_file()
|
||||
}
|
||||
- // TODO: capability rather than root
|
||||
fn requires_root(&self) -> bool {
|
||||
- matches!(self, Self::Access | Self::Channel { .. })
|
||||
+ matches!(self, Self::Access | Self::Channel { .. } | Self::Bind { .. })
|
||||
}
|
||||
fn is_scheme_root(&self) -> bool {
|
||||
matches!(self, Self::SchemeRoot)
|
||||
@@ -49,7 +56,7 @@ enum ChannelState {
|
||||
AwaitingResponseRead(VecDeque<u8>),
|
||||
}
|
||||
|
||||
-const DEVICE_CONTENTS: &[&str] = &["channel"];
|
||||
+const DEVICE_CONTENTS: &[&str] = &["channel", "bind"];
|
||||
|
||||
impl PciScheme {
|
||||
pub fn access(&mut self) -> usize {
|
||||
@@ -88,22 +95,25 @@ impl SchemeSync for PciScheme {
|
||||
let path = path.trim_matches('/');
|
||||
|
||||
let handle = if path.is_empty() {
|
||||
- Handle::TopLevel {
|
||||
- entries: self
|
||||
- .tree
|
||||
- .iter()
|
||||
- // FIXME remove replacement of : once the old scheme format is no longer supported.
|
||||
- .map(|(addr, _)| format!("{}", addr).replace(':', "--"))
|
||||
- .collect::<Vec<_>>(),
|
||||
- }
|
||||
+ let mut entries: Vec<String> = self
|
||||
+ .tree
|
||||
+ .iter()
|
||||
+ // FIXME remove replacement of : once the old scheme format is no longer supported.
|
||||
+ .map(|(addr, _)| format!("{}", addr).replace(':', "--"))
|
||||
+ .collect();
|
||||
+ entries.push(String::from("uevent"));
|
||||
+ entries.push(String::from("access"));
|
||||
+ Handle::TopLevel { entries }
|
||||
} else if path == "access" {
|
||||
Handle::Access
|
||||
+ } else if path == "uevent" {
|
||||
+ Handle::Uevent
|
||||
} else {
|
||||
let idx = path.find('/').unwrap_or(path.len());
|
||||
let (addr_str, after) = path.split_at(idx);
|
||||
let addr = parse_pci_addr(addr_str).ok_or(Error::new(ENOENT))?;
|
||||
|
||||
- self.parse_after_pci_addr(addr, after)?
|
||||
+ self.parse_after_pci_addr(addr, after, ctx)?
|
||||
};
|
||||
|
||||
let stat = flags & O_STAT != 0;
|
||||
@@ -132,7 +142,8 @@ impl SchemeSync for PciScheme {
|
||||
let (len, mode) = match handle.inner {
|
||||
Handle::TopLevel { ref entries } => (entries.len(), MODE_DIR | 0o755),
|
||||
Handle::Device => (DEVICE_CONTENTS.len(), MODE_DIR | 0o755),
|
||||
- Handle::Access | Handle::Channel { .. } => (0, MODE_CHR | 0o600),
|
||||
+ Handle::Access | Handle::Channel { .. } | Handle::Bind { .. } => (0, MODE_CHR | 0o600),
|
||||
+ Handle::Uevent => (0, MODE_CHR | 0o644),
|
||||
Handle::SchemeRoot => return Err(Error::new(EBADF)),
|
||||
};
|
||||
stat.st_size = len as u64;
|
||||
@@ -160,7 +171,13 @@ impl SchemeSync for PciScheme {
|
||||
addr: _,
|
||||
ref mut st,
|
||||
} => Self::read_channel(st, buf),
|
||||
- Handle::SchemeRoot => Err(Error::new(EBADF)),
|
||||
+ Handle::Uevent => {
|
||||
+ // Uevent surface is ready for hotplug polling consumers.
|
||||
+ // pcid currently only scans at startup, so return empty (EAGAIN would indicate no data available).
|
||||
+ // Consumers can poll and re-read to check for new events.
|
||||
+ Ok(0)
|
||||
+ }
|
||||
+ Handle::SchemeRoot | Handle::Bind { .. } => Err(Error::new(EBADF)),
|
||||
_ => Err(Error::new(EBADF)),
|
||||
}
|
||||
}
|
||||
@@ -193,7 +210,7 @@ impl SchemeSync for PciScheme {
|
||||
return Ok(buf);
|
||||
}
|
||||
Handle::Device => DEVICE_CONTENTS,
|
||||
- Handle::Access | Handle::Channel { .. } => return Err(Error::new(ENOTDIR)),
|
||||
+ Handle::Access | Handle::Channel { .. } | Handle::Bind { .. } | Handle::Uevent => return Err(Error::new(ENOTDIR)),
|
||||
Handle::SchemeRoot => return Err(Error::new(EBADF)),
|
||||
};
|
||||
|
||||
@@ -316,6 +333,16 @@ impl SchemeSync for PciScheme {
|
||||
func.enabled = false;
|
||||
}
|
||||
}
|
||||
+ Some(HandleWrapper {
|
||||
+ inner: Handle::Bind { addr },
|
||||
+ ..
|
||||
+ }) => {
|
||||
+ let addr_str = format!("{}", addr);
|
||||
+ if let Some(&owner_pid) = self.binds.get(&addr_str) {
|
||||
+ log::info!("pcid: device {} unbound by pid {}", addr_str, owner_pid);
|
||||
+ }
|
||||
+ self.binds.remove(&addr_str);
|
||||
+ }
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
@@ -327,9 +354,10 @@ impl PciScheme {
|
||||
handles: HandleMap::new(),
|
||||
pcie,
|
||||
tree: BTreeMap::new(),
|
||||
+ binds: HashMap::new(),
|
||||
}
|
||||
}
|
||||
- fn parse_after_pci_addr(&mut self, addr: PciAddress, after: &str) -> Result<Handle> {
|
||||
+ fn parse_after_pci_addr(&mut self, addr: PciAddress, after: &str, ctx: &CallerCtx) -> Result<Handle> {
|
||||
if after.chars().next().map_or(false, |c| c != '/') {
|
||||
return Err(Error::new(ENOENT));
|
||||
}
|
||||
@@ -356,6 +384,17 @@ impl PciScheme {
|
||||
st: ChannelState::AwaitingData,
|
||||
}
|
||||
}
|
||||
+ "bind" => {
|
||||
+ let addr_str = format!("{}", addr);
|
||||
+ if let Some(&owner_pid) = self.binds.get(&addr_str) {
|
||||
+ log::info!("pcid: device {} already bound by pid {}", addr_str, owner_pid);
|
||||
+ return Err(Error::new(EALREADY));
|
||||
+ }
|
||||
+ let caller_pid = ctx.pid;
|
||||
+ self.binds.insert(addr_str.clone(), caller_pid);
|
||||
+ log::info!("pcid: device {} bound by pid {}", addr_str, caller_pid);
|
||||
+ Handle::Bind { addr }
|
||||
+ }
|
||||
_ => return Err(Error::new(ENOENT)),
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user