base: apply Red Bear patches on latest upstream/main

251 files: init, acpid, ipcd, netcfg, ihdgd, virtio-gpud, scheme-utils,
inputd, block driver, ptyd, ramfs, randd, initfs bootstrap, path deps,
version +rb0.3.1, author attribution
This commit is contained in:
Red Bear OS
2026-07-11 11:39:24 +03:00
parent 1b17b3fc24
commit bd595851e2
251 changed files with 24641 additions and 5993 deletions
+39 -49
View File
@@ -6,11 +6,10 @@ use core::str::FromStr;
use hashbrown::HashMap;
use redox_scheme::Socket;
use libredox::protocol::O_CLOEXEC;
use syscall::data::{GlobalSchemes, KernelSchemeInfo};
use syscall::flag::{O_DIRECTORY, O_RDONLY, O_STAT};
use syscall::CallFlags;
use syscall::{Error, EINTR};
use syscall::data::{GlobalSchemes, KernelSchemeInfo};
use syscall::flag::{O_CLOEXEC, O_RDONLY, O_STAT};
use syscall::{EINTR, Error};
use redox_rt::proc::*;
@@ -27,7 +26,7 @@ impl log::Log for Logger {
let line = record.line().unwrap_or(0);
let level = record.level();
let msg = record.args();
let _ = syscall::write(
let _ = libredox::call::write(
1,
alloc::format!("[{file}:{line} {level}] {msg}\n").as_bytes(),
);
@@ -54,8 +53,6 @@ pub fn main() -> ! {
FdGuard::new(*(base_ptr as *const usize))
};
let cur_context_idx = scheme_creation_cap.as_raw_fd() + 1;
let mut kernel_schemes = KernelSchemeMap::new(kernel_scheme_infos);
let auth = kernel_schemes
@@ -63,8 +60,8 @@ pub fn main() -> ! {
.remove(&GlobalSchemes::Proc)
.expect("failed to get proc fd");
let this_thr_fd = syscall::dup_into(auth.as_raw_fd(), cur_context_idx, b"cur-context")
.map(FdGuard::new)
let this_thr_fd = auth
.dup(b"cur-context")
.expect("failed to open open_via_dup")
.to_upper()
.unwrap();
@@ -73,13 +70,13 @@ pub fn main() -> ! {
let mut env_bytes = [0_u8; 4096];
let mut envs = {
let fd = FdGuard::new(
redox_rt::sys::openat(
libredox::call::openat(
kernel_schemes
.get(GlobalSchemes::Sys)
.expect("failed to get sys fd")
.as_raw_fd(),
"env",
O_RDONLY | O_CLOEXEC,
(O_RDONLY | O_CLOEXEC) as i32,
0,
)
.expect("bootstrap: failed to open env"),
@@ -208,16 +205,12 @@ pub fn main() -> ! {
// from this point, this_thr_fd is no longer valid
const CWD: &[u8] = b"/scheme/initfs";
let initfs_root_fd = initns_fd
.openat_into_upper("/scheme/initfs", O_DIRECTORY, 0)
.expect("failed to open initfs root fd");
let cwd_fd = initfs_root_fd
.openat_into_upper("", O_STAT, 0)
.expect("failed to open cwd fd");
let filetable_binary_fd = init_thr_fd
.dup_into_upper(b"filetable-binary")
.expect("faild to create filetable-binary fd");
let cwd_fd = FdGuard::new(
libredox::call::openat(initns_fd.as_raw_fd(), "/scheme/initfs", O_STAT as i32, 0)
.expect("failed to open cwd fd"),
)
.to_upper()
.unwrap();
let extrainfo = ExtraInfo {
cwd: Some(CWD),
sigprocmask: 0,
@@ -227,18 +220,18 @@ pub fn main() -> ! {
proc_fd: init_proc_fd.as_raw_fd(),
ns_fd: Some(initns_fd.take()),
cwd_fd: Some(cwd_fd.as_raw_fd()),
filetable_fd: Some(filetable_binary_fd.as_raw_fd()),
same_process: true,
};
let exe_path = "/scheme/initfs/bin/init";
let exe_reference = "bin/init";
let path = "/scheme/initfs/bin/init";
let image_file = initfs_root_fd
.openat_into_upper(exe_reference, O_RDONLY | O_CLOEXEC, 0)
.expect("failed to open init");
let image_file = FdGuard::new(
libredox::call::openat(extrainfo.ns_fd.unwrap(), path, (O_RDONLY | O_CLOEXEC) as i32, 0)
.expect("failed to open init"),
)
.to_upper()
.unwrap();
drop(initfs_root_fd);
let exe_path = alloc::format!("/scheme/initfs{}", path);
let FexecResult::Interp {
path: interp_path,
@@ -253,33 +246,26 @@ pub fn main() -> ! {
&extrainfo,
None,
)
.ok()
.flatten()
.map_err(|e| {
let _ = libredox::call::write(1, alloc::format!("fexec_impl failed: {}\n", e).as_bytes());
e
})
.expect("failed to execute init");
// According to elf(5), PT_INTERP requires that the interpreter path be
// null-terminated. Violating this should therefore give the "format error" ENOEXEC.
let interp_cstr = CStr::from_bytes_with_nul(&interp_path).expect("interpreter not valid C str");
let interp_path = interp_cstr.to_str().expect("interpreter not UTF-8");
let root_fd = FdGuard::new(
redox_rt::sys::openat_into_upper(
let interp_file = FdGuard::new(
libredox::call::openat(
extrainfo.ns_fd.unwrap(), // initns, not initfs!
interp_path,
O_RDONLY | O_CLOEXEC,
interp_cstr.to_str().expect("interpreter not UTF-8"),
(O_RDONLY | O_CLOEXEC) as i32,
0,
)
.expect("failed to open root fd"),
.expect("failed to open dynamic linker"),
)
.to_upper()
.unwrap();
let redox_path = redox_path::RedoxPath::from_absolute(interp_path)
.expect("interpreter path is not a Scheme-rooted path");
let (_, reference) = redox_path
.as_parts()
.expect("redox_path is not scheme root path");
let interp_file = root_fd
.openat_into_upper(reference.as_ref(), O_RDONLY | O_CLOEXEC, 0)
.expect("failed to open dynamic linker");
fexec_impl(
interp_file,
@@ -306,13 +292,13 @@ pub(crate) fn spawn(
inner: impl FnOnce(FdGuard, Socket, FdGuard, KernelSchemeMap) -> !,
) -> (FdGuard, FdGuard, KernelSchemeMap, FdGuard) {
let read = FdGuard::new(
redox_rt::sys::openat(
libredox::call::openat(
kernel_schemes
.get(GlobalSchemes::Pipe)
.expect("failed to get pipe fd")
.as_raw_fd(),
"",
O_CLOEXEC,
O_CLOEXEC as i32,
0,
)
.expect("failed to open sync read pipe"),
@@ -320,7 +306,7 @@ pub(crate) fn spawn(
// The write pipe will not inherit O_CLOEXEC, but is closed by the daemon later.
let write = FdGuard::new(
redox_rt::sys::dup(read.as_raw_fd(), b"write").expect("failed to open sync write pipe"),
libredox::call::dup(read.as_raw_fd(), b"write").expect("failed to open sync write pipe"),
);
match fork_impl(&ForkArgs::Init {
@@ -332,11 +318,15 @@ pub(crate) fn spawn(
}
// Continue serving the scheme as the child.
Ok(0) => {
let _ = libredox::call::write(1, b"SP:0\n");
drop(read);
let _ = libredox::call::write(1, b"SP:1\n");
let socket = Socket::create_inner(scheme_creation_cap.as_raw_fd(), nonblock)
.expect("failed to open proc scheme socket");
let _ = libredox::call::write(1, b"SP:2\n");
drop(scheme_creation_cap);
let _ = libredox::call::write(1, b"SP:3\n");
inner(write, socket, auth, kernel_schemes)
}
@@ -352,7 +342,7 @@ pub(crate) fn spawn(
)
};
loop {
match redox_rt::sys::sys_call_ro(
match syscall::call_ro(
read.as_raw_fd(),
fd_bytes,
CallFlags::FD | CallFlags::FD_UPPER,
+82 -24
View File
@@ -6,15 +6,16 @@ use core::str;
use alloc::string::String;
use hashbrown::HashMap;
use redox_initfs::{InitFs, Inode, InodeDir, InodeKind, InodeStruct};
use redox_initfs::{InitFs, Inode, InodeDir, InodeKind, InodeStruct, types::Timespec};
use redox_rt::proc::FdGuard;
use redox_scheme::{
scheme::{SchemeState, SchemeSync},
CallerCtx, OpenResult, RequestKind,
scheme::{SchemeState, SchemeSync},
};
use redox_scheme::{SignalBehavior, Socket};
use syscall::PAGE_SIZE;
use syscall::data::Stat;
use syscall::dirent::DirEntry;
use syscall::dirent::DirentBuf;
@@ -22,7 +23,6 @@ use syscall::dirent::DirentKind;
use syscall::error::*;
use syscall::flag::*;
use syscall::schemev2::NewFdFlags;
use syscall::PAGE_SIZE;
enum Handle {
Node(Node),
@@ -135,7 +135,7 @@ impl SchemeSync for InitFsScheme {
// filter out double slashes (e.g. /usr//bin/...)
.filter(|c| !c.is_empty());
let mut current_inode = self.fs.root_inode();
let mut current_inode = InitFs::ROOT_INODE;
while let Some(component) = components.next() {
match component {
@@ -315,6 +315,8 @@ impl SchemeSync for InitFsScheme {
fn fstat(&mut self, id: usize, stat: &mut Stat, _ctx: &CallerCtx) -> Result<()> {
let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?.as_node()?;
let Timespec { sec, nsec } = self.fs.image_creation_time();
let inode = Self::get_inode(&self.fs, handle.inode)?;
stat.st_ino = inode.id();
@@ -329,10 +331,10 @@ impl SchemeSync for InitFsScheme {
stat.st_gid = 0;
stat.st_size = u64::try_from(inode_len(inode)?).unwrap_or(u64::MAX);
stat.st_ctime = 0;
stat.st_ctime_nsec = 0;
stat.st_mtime = 0;
stat.st_mtime_nsec = 0;
stat.st_ctime = sec.get();
stat.st_ctime_nsec = nsec.get();
stat.st_mtime = sec.get();
stat.st_mtime_nsec = nsec.get();
Ok(())
}
@@ -391,9 +393,9 @@ pub fn run(bytes: &'static [u8], sync_pipe: FdGuard, socket: Socket) -> ! {
let cap_fd = socket
.create_this_scheme_fd(0, new_id, 0, 0)
.expect("failed to issue initfs root fd");
let _ = redox_rt::sys::sys_call_wo(
let _ = syscall::call_rw(
sync_pipe.as_raw_fd(),
&cap_fd.to_ne_bytes(),
&mut cap_fd.to_ne_bytes(),
CallFlags::FD,
&[],
);
@@ -444,21 +446,72 @@ pub unsafe extern "C" fn redox_write_v1(fd: usize, ptr: *const u8, len: usize) -
})) as isize
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn redox_openat_v1(
fd: usize,
buf: *const u8,
path_len: usize,
flags: u32,
fcntl_flags: u32,
) -> isize {
let path = unsafe { core::slice::from_raw_parts(buf, path_len) };
let path_str = match core::str::from_utf8(path) {
Ok(s) => s,
Err(_) => return -(syscall::EINVAL as isize),
};
Error::mux(syscall::openat(fd, path_str, flags as usize, fcntl_flags as usize)) as isize
}
#[unsafe(no_mangle)]
pub unsafe fn redox_dup_v1(fd: usize, buf: *const u8, len: usize) -> isize {
Error::mux(redox_rt::sys::dup(fd, unsafe {
Error::mux(syscall::dup(fd, unsafe {
core::slice::from_raw_parts(buf, len)
})) as isize
}
#[unsafe(no_mangle)]
pub unsafe fn redox_fcntl_v0(fd: usize, cmd: usize, arg: usize) -> isize {
Error::mux(redox_rt::sys::fcntl(fd, cmd, arg)) as isize
pub extern "C" fn redox_close_v1(fd: usize) -> isize {
Error::mux(syscall::close(fd)) as isize
}
#[unsafe(no_mangle)]
pub extern "C" fn redox_close_v1(fd: usize) -> isize {
Error::mux(redox_rt::sys::close(fd)) as isize
pub extern "C" fn redox_fcntl_v0(fd: usize, cmd: usize, arg: usize) -> isize {
Error::mux(syscall::fcntl(fd, cmd, arg)) as isize
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn redox_strerror_v1(
dst: *mut u8,
dst_len: *mut usize,
error: u32,
) -> isize {
let msg = match error {
x if x == syscall::EPERM as u32 => "Operation not permitted",
x if x == syscall::ENOENT as u32 => "No such file or directory",
x if x == syscall::EINTR as u32 => "Interrupted system call",
x if x == syscall::EIO as u32 => "I/O error",
x if x == syscall::EBADF as u32 => "Bad file descriptor",
x if x == syscall::EAGAIN as u32 => "Resource temporarily unavailable",
x if x == syscall::ENOMEM as u32 => "Cannot allocate memory",
x if x == syscall::EACCES as u32 => "Permission denied",
x if x == syscall::EFAULT as u32 => "Bad address",
x if x == syscall::EBUSY as u32 => "Device or resource busy",
x if x == syscall::EEXIST as u32 => "File exists",
x if x == syscall::ENOTDIR as u32 => "Not a directory",
x if x == syscall::EISDIR as u32 => "Is a directory",
x if x == syscall::EINVAL as u32 => "Invalid argument",
x if x == syscall::ENOSYS as u32 => "Function not implemented",
x if x == syscall::ENOTEMPTY as u32 => "Directory not empty",
_ => "Unknown error",
};
let msg_bytes = msg.as_bytes();
unsafe {
let avail = *dst_len;
let copy_len = avail.min(msg_bytes.len());
core::ptr::copy_nonoverlapping(msg_bytes.as_ptr(), dst, copy_len);
*dst_len = copy_len;
copy_len as isize
}
}
#[unsafe(no_mangle)]
@@ -471,15 +524,20 @@ pub unsafe extern "C" fn redox_sys_call_v0(
metadata_len: usize,
) -> isize {
let flags = CallFlags::from_bits_retain(flags);
let read = flags.contains(syscall::CallFlags::READ);
let write = flags.contains(syscall::CallFlags::WRITE);
let payload = unsafe { core::slice::from_raw_parts_mut(payload, payload_len) };
let metadata = unsafe { core::slice::from_raw_parts(metadata, metadata_len) };
Error::mux(match (read, write) {
(true, true) => redox_rt::sys::sys_call_rw(fd, payload, flags, metadata),
(true, false) => redox_rt::sys::sys_call_ro(fd, payload, flags, metadata),
(false, true) => redox_rt::sys::sys_call_wo(fd, payload, flags, metadata),
(false, false) => redox_rt::sys::sys_call(fd, payload, flags, metadata),
}) as isize
let result = if flags.contains(CallFlags::READ) {
let payload = unsafe { core::slice::from_raw_parts_mut(payload, payload_len) };
if flags.contains(CallFlags::WRITE) {
syscall::call_rw(fd, payload, flags, metadata)
} else {
syscall::call_ro(fd, payload, flags, metadata)
}
} else {
let payload = unsafe { core::slice::from_raw_parts(payload, payload_len) };
syscall::call_wo(fd, payload, flags, metadata)
};
Error::mux(result) as isize
}
+101 -150
View File
@@ -10,14 +10,14 @@ use libredox::protocol::{NsDup, NsPermissions};
use log::{error, warn};
use redox_path::RedoxPath;
use redox_path::RedoxScheme;
use redox_rt::proc::{FdGuard, FdGuardUpper};
use redox_rt::proc::FdGuard;
use redox_scheme::{
scheme::{SchemeState, SchemeSync},
CallerCtx, OpenResult, RequestKind, Response, SendFdRequest, SignalBehavior, Socket,
scheme::{SchemeState, SchemeSync},
};
use syscall::dirent::{DirEntry, DirentBuf, DirentKind};
use syscall::Stat;
use syscall::{error::*, schemev2::NewFdFlags, CallFlags, FobtainFdFlags};
use syscall::dirent::{DirEntry, DirentBuf, DirentKind};
use syscall::{CallFlags, FobtainFdFlags, error::*, schemev2::NewFdFlags};
#[derive(Debug, Clone)]
struct Namespace {
@@ -92,7 +92,6 @@ impl SchemeRegister {
enum Handle {
Access(NamespaceAccess),
Register(SchemeRegister),
OtherScheme { name: String, fd: Rc<FdGuard> },
List(NamespaceAccess),
}
@@ -101,7 +100,7 @@ pub struct NamespaceScheme<'sock> {
handles: HashMap<usize, Handle>,
root_namespace: Namespace,
next_id: usize,
scheme_creation_cap: Rc<FdGuardUpper>,
scheme_creation_cap: FdGuard,
}
const HIGH_PERMISSIONS: NsPermissions = NsPermissions::SCHEME_CREATE;
@@ -110,14 +109,14 @@ impl<'sock> NamespaceScheme<'sock> {
pub fn new(
socket: &'sock Socket,
schemes: HashMap<String, Arc<FdGuard>>,
scheme_creation_cap: FdGuardUpper,
scheme_creation_cap: FdGuard,
) -> Self {
Self {
socket,
handles: HashMap::new(),
root_namespace: Namespace { schemes },
next_id: 0,
scheme_creation_cap: Rc::new(scheme_creation_cap),
scheme_creation_cap,
}
}
@@ -138,55 +137,23 @@ impl<'sock> NamespaceScheme<'sock> {
}
fn open_namespace_resource(
&mut self,
&self,
ns_access: &NamespaceAccess,
redox_path: RedoxPath<'_>,
reference: &str,
_flags: usize,
_fcntl_flags: u32,
_ctx: &CallerCtx,
) -> Result<usize> {
let (_scheme, reference) = redox_path.as_parts().ok_or(Error::new(EINVAL))?;
match reference.as_ref() {
match reference {
"scheme-creation-cap" => {
if !ns_access.has_permission(NsPermissions::SCHEME_CREATE) {
error!("Permission denied to get scheme creation capability");
return Err(Error::new(EACCES));
}
let new_id = self.next_id;
self.next_id += 1;
self.handles.insert(new_id, Handle::List(ns_access.clone()));
let resource_id = self.next_id;
self.next_id += 1;
let dup_fd = self.scheme_creation_cap.dup(&[])?;
self.handles.insert(
resource_id,
Handle::OtherScheme {
name: redox_path.to_string(),
fd: Rc::new(dup_fd),
},
);
Ok(resource_id)
}
"" => {
if !ns_access.has_permission(NsPermissions::LIST) {
error!("Permission denied to list schemes in namespace root");
return Err(Error::new(EACCES));
}
let new_id = self.next_id;
self.next_id += 1;
self.handles.insert(new_id, Handle::List(ns_access.clone()));
Ok(new_id)
Ok(libredox::call::dup(self.scheme_creation_cap.as_raw_fd(), &[])?)
}
_ => {
error!("Unknown special reference: {}", reference.as_ref());
error!("Unknown special reference: {}", reference);
return Err(Error::new(EINVAL));
}
}
@@ -196,19 +163,24 @@ impl<'sock> NamespaceScheme<'sock> {
&self,
ns: &Namespace,
scheme: &str,
reference: &str,
flags: usize,
_ctx: &CallerCtx,
) -> Result<FdGuard> {
fcntl_flags: u32,
ctx: &CallerCtx,
) -> Result<usize> {
let Some(cap_fd) = ns.get_scheme_fd(scheme) else {
log::info!("Scheme {:?} not found in namespace", scheme);
return Err(Error::new(ENODEV));
};
if flags & syscall::O_DIRECTORY == 0 {
return Err(Error::new(EISDIR));
}
let scheme_fd = syscall::openat(
cap_fd.as_raw_fd(),
reference,
flags,
fcntl_flags as usize,
)?;
cap_fd.dup(&[])
Ok(scheme_fd)
}
fn fork_namespace(&mut self, namespace: Rc<RefCell<Namespace>>, names: &[u8]) -> Result<usize> {
@@ -237,10 +209,6 @@ impl<'sock> NamespaceScheme<'sock> {
self.next_id += 1;
Ok(next_id)
}
fn on_close(&mut self, id: usize) {
let _ = self.handles.remove(&id);
}
}
impl<'sock> SchemeSync for NamespaceScheme<'sock> {
@@ -252,83 +220,55 @@ impl<'sock> SchemeSync for NamespaceScheme<'sock> {
fcntl_flags: u32,
ctx: &CallerCtx,
) -> Result<OpenResult> {
let handle = self.handles.get(&fd).cloned().ok_or_else(|| {
error!("Handle with ID {} not found", fd);
Error::new(ENOENT)
})?;
match handle {
Handle::Access(ns_access) => {
let redox_path = RedoxPath::from_absolute(path).ok_or(Error::new(EINVAL))?;
let (scheme, _reference) = redox_path.as_parts().ok_or(Error::new(EINVAL))?;
match scheme.as_ref() {
"namespace" | "" => {
let new_id = self.open_namespace_resource(
&ns_access,
redox_path,
flags,
fcntl_flags,
ctx,
)?;
Ok(OpenResult::ThisScheme {
number: new_id,
flags: NewFdFlags::empty(),
})
}
_ => {
let res_fd = self.open_scheme_resource(
&ns_access.namespace.borrow(),
scheme.as_ref(),
flags,
ctx,
)?;
Ok(OpenResult::OtherScheme { fd: res_fd.take() })
}
}
}
Handle::List(ns_access) => {
if path.is_empty() || path == "." {
let new_id = self.next_id;
self.next_id += 1;
self.handles.insert(new_id, Handle::List(ns_access.clone()));
Ok(OpenResult::ThisScheme {
number: new_id,
flags: NewFdFlags::empty(),
})
} else {
error!("Cannot open a path under List handle: {}", path);
Err(Error::new(EINVAL))
}
}
Handle::OtherScheme {
name: saved_path_str,
fd: target_fd,
} => {
let saved_path =
RedoxPath::from_absolute(&saved_path_str).ok_or(Error::new(syscall::EPROTO))?;
let (_scheme, reference) =
saved_path.as_parts().ok_or(Error::new(syscall::EPROTO))?;
if reference.as_ref() == path {
Ok(OpenResult::OtherScheme {
fd: target_fd.dup(&[])?.take(),
})
} else {
error!(
"Resource path mismatch: expected {}, got {}",
reference.as_ref(),
path,
);
Err(Error::new(EINVAL))
}
}
_ => {
error!("Handle {} is not accessible for openat", fd);
Err(Error::new(EBADF))
let ns_access = {
let handle = self.handles.get(&fd);
match handle {
Some(Handle::Access(access)) => Some(access),
_ => None,
}
}
.ok_or_else(|| {
error!("Namespace with ID {} not found", fd);
Error::new(ENOENT)
})?;
let redox_path = RedoxPath::from_absolute(path).ok_or(Error::new(EINVAL))?;
let (scheme, reference) = redox_path.as_parts().ok_or(Error::new(EINVAL))?;
let res_fd = match scheme.as_ref() {
"namespace" => self.open_namespace_resource(
ns_access,
reference.as_ref(),
flags,
fcntl_flags,
ctx,
)?,
"" => {
if !ns_access.has_permission(NsPermissions::LIST) {
error!("Permission denied to list schemes in namespace {}", fd);
return Err(Error::new(EACCES));
}
let new_id = self.next_id;
self.next_id += 1;
self.handles.insert(new_id, Handle::List(ns_access.clone()));
return Ok(OpenResult::ThisScheme {
number: new_id,
flags: NewFdFlags::empty(),
});
}
_ => self.open_scheme_resource(
&ns_access.namespace.borrow(),
scheme.as_ref(),
reference.as_ref(),
flags,
fcntl_flags,
ctx,
)?,
};
Ok(OpenResult::OtherScheme { fd: res_fd })
}
fn dup(&mut self, id: usize, buf: &[u8], _ctx: &CallerCtx) -> Result<OpenResult> {
@@ -346,6 +286,7 @@ impl<'sock> SchemeSync for NamespaceScheme<'sock> {
let new_id = match kind {
NsDup::ForkNs => {
let ns = ns_access.namespace.clone();
let _ = ns_access;
self.fork_namespace(ns, payload)?
}
NsDup::ShrinkPermissions => self.shrink_permissions(
@@ -383,7 +324,7 @@ impl<'sock> SchemeSync for NamespaceScheme<'sock> {
})
}
fn unlinkat(&mut self, fd: usize, path: &str, _flags: usize, _ctx: &CallerCtx) -> Result<()> {
fn unlinkat(&mut self, fd: usize, path: &str, flags: usize, ctx: &CallerCtx) -> Result<()> {
let ns_access = self.get_ns_access(fd).ok_or_else(|| {
error!("Namespace with ID {} not found", fd);
Error::new(ENOENT)
@@ -392,20 +333,31 @@ impl<'sock> SchemeSync for NamespaceScheme<'sock> {
let redox_path = RedoxPath::from_absolute(path).ok_or(Error::new(EINVAL))?;
let (scheme, reference) = redox_path.as_parts().ok_or(Error::new(EINVAL))?;
if !reference.as_ref().is_empty() {
return Err(Error::new(EXDEV));
}
if !ns_access.has_permission(NsPermissions::DELETE) {
error!("Permission denied to remove scheme for namespace {}", fd);
return Err(Error::new(EACCES));
}
match ns.remove_scheme(scheme.as_ref()) {
Some(_) => Ok(()),
None => {
error!("Scheme {} not found in namespace", scheme);
Err(Error::new(ENODEV))
if reference.as_ref().is_empty() {
if !ns_access.has_permission(NsPermissions::DELETE) {
error!("Permission denied to remove scheme for namespace {}", fd);
return Err(Error::new(EACCES));
}
match ns.remove_scheme(scheme.as_ref()) {
Some(_) => return Ok(()),
None => {
error!("Scheme {} not found in namespace", scheme);
return Err(Error::new(ENODEV));
}
}
}
let Some(cap_fd) = ns.get_scheme_fd(scheme.as_ref()) else {
error!("Scheme {} not found in namespace", scheme);
return Err(Error::new(ENODEV));
};
syscall::unlinkat(cap_fd.as_raw_fd(), reference, flags)?;
Ok(())
}
fn on_close(&mut self, id: usize) {
self.handles.remove(&id);
}
fn on_sendfd(&mut self, sendfd_request: &SendFdRequest) -> Result<usize> {
@@ -433,7 +385,7 @@ impl<'sock> SchemeSync for NamespaceScheme<'sock> {
}
let mut new_fd = usize::MAX;
if let Err(e) = sendfd_request.obtain_fd(
self.socket,
&self.socket,
FobtainFdFlags::UPPER_TBL,
core::slice::from_mut(&mut new_fd),
) {
@@ -468,11 +420,12 @@ impl<'sock> SchemeSync for NamespaceScheme<'sock> {
}
if let Err(err) = buf.entry(DirEntry {
kind: DirentKind::Unspecified,
name: name,
name: &name.clone(),
inode: 0,
next_opaque_id: i as u64 + 1,
}) {
if err.errno == EINVAL && i > opaque_offset {
// POSIX allows partial result of getdents
break;
} else {
return Err(err);
@@ -485,7 +438,7 @@ impl<'sock> SchemeSync for NamespaceScheme<'sock> {
fn fstat(&mut self, id: usize, stat: &mut Stat, _ctx: &CallerCtx) -> Result<()> {
let resource_stat = match self.handles.get(&id).ok_or(Error::new(EBADF))? {
Handle::List(_) | Handle::OtherScheme { .. } => Stat {
Handle::List(_) => Stat {
st_mode: 0o444 | syscall::MODE_DIR,
st_uid: 0,
st_gid: 0,
@@ -547,9 +500,6 @@ pub fn run(
schemes: HashMap<String, Arc<FdGuard>>,
scheme_creation_cap: FdGuard,
) -> ! {
let scheme_creation_cap = scheme_creation_cap
.to_upper()
.expect("Failed to move scheme creation cap into upper");
let mut state = SchemeState::new();
let mut scheme = NamespaceScheme::new(&socket, schemes, scheme_creation_cap);
@@ -561,7 +511,7 @@ pub fn run(
.socket
.create_this_scheme_fd(0, new_id, 0, 0)
.expect("nsmgr: failed to create namespace fd");
let _ = redox_rt::sys::sys_call_wo(
let _ = syscall::call_wo(
sync_pipe.as_raw_fd(),
&cap_fd.to_ne_bytes(),
CallFlags::FD,
@@ -599,6 +549,7 @@ pub fn run(
break;
}
}
_ => (),
}
}
+24 -7
View File
@@ -1,6 +1,7 @@
#![no_std]
#![no_main]
#![feature(abort_immediate, never_type)]
#![allow(internal_features)]
#![feature(core_intrinsics, str_from_raw_parts, never_type)]
#[cfg(target_arch = "aarch64")]
#[path = "aarch64.rs"]
@@ -38,18 +39,34 @@ use syscall::flag::MapFlags;
fn panic_handler(info: &core::panic::PanicInfo) -> ! {
use core::fmt::Write;
struct Writer;
// Try fd 1 first (opened in start()). If that fails, open a fresh debug handle.
struct Writer {
fd: usize,
}
impl Write for Writer {
fn write_str(&mut self, s: &str) -> core::fmt::Result {
syscall::write(1, s.as_bytes())
.map_err(|_| core::fmt::Error)
.map(|_| ())
// Try writing to our fd. If it fails and we're on fd 1,
// attempt to open a fresh debug handle.
if libredox::call::write(self.fd, s.as_bytes()).is_ok() {
return Ok(());
}
if self.fd == 1 {
let debug_root =
syscall::UPPER_FDTBL_TAG + syscall::data::GlobalSchemes::Debug as usize;
if let Ok(new_fd) =
libredox::call::openat(debug_root, "", syscall::O_WRONLY as i32, 0)
{
self.fd = new_fd;
let _ = libredox::call::write(self.fd, s.as_bytes());
}
}
Ok(()) // Always succeed so writeln! continues formatting
}
}
let _ = writeln!(&mut Writer, "{}", info);
core::process::abort_immediate();
let _ = writeln!(Writer { fd: 1 }, "{}", info);
core::intrinsics::abort();
}
const HEAP_OFF: usize = arch::USERMODE_END / 2;
+28 -21
View File
@@ -46,15 +46,20 @@ enum VirtualId {
}
pub fn run(write_fd: FdGuard, socket: Socket, auth: FdGuard, event: FdGuard) -> ! {
let _ = libredox::call::write(1, b"PM:0\n");
// TODO?
let socket_ident = socket.inner().raw();
let _ = libredox::call::write(1, b"PM:1\n");
let queue = RawEventQueue::new(event.as_raw_fd()).expect("failed to create event queue");
let _ = libredox::call::write(1, b"PM:2\n");
drop(event);
let _ = libredox::call::write(1, b"PM:3\n");
queue
.subscribe(socket.inner().raw(), socket_ident, EventFlags::EVENT_READ)
.expect("failed to listen to scheme socket events");
let _ = libredox::call::write(1, b"PM:4\n");
let mut scheme = ProcScheme::new(auth, &queue);
@@ -63,9 +68,10 @@ pub fn run(write_fd: FdGuard, socket: Socket, auth: FdGuard, event: FdGuard) ->
let cap_fd = socket
.create_this_scheme_fd(0, new_id, 0, 0)
.expect("failed to issue procmgr root fd");
let _ = libredox::call::write(1, b"PM:5\n");
log::debug!("process manager started");
let _ = redox_rt::sys::sys_call_wo(
let _ = syscall::call_wo(
write_fd.as_raw_fd(),
&cap_fd.to_ne_bytes(),
CallFlags::FD,
@@ -549,7 +555,8 @@ enum WaitpidTarget {
struct RawEventQueue(FdGuard);
impl RawEventQueue {
pub fn new(cap_fd: usize) -> Result<Self> {
redox_rt::sys::openat(cap_fd, "", O_CREAT, 0)
libredox::call::openat(cap_fd, "", O_CREAT as i32, 0)
.map_err(Into::into)
.map(FdGuard::new)
.map(Self)
}
@@ -725,7 +732,10 @@ impl<'a> ProcScheme<'a> {
sig_pctl: None, // TODO
rtqs: Vec::new(),
}));
if let Err(err) = new_process.borrow_mut().sync_kernel_attrs(&self.auth) {
if let Err(err) = new_process
.borrow_mut()
.sync_kernel_attrs(&self.auth)
{
log::warn!("Failed to set kernel attrs when forking: {err}");
}
@@ -1065,27 +1075,25 @@ impl<'a> ProcScheme<'a> {
// FIXME remove this ProcCall variant
ProcCall::Setrens => Response::ready_err(EINVAL, op),
ProcCall::SetProcPriority => {
let target_pid = NonZeroUsize::new(metadata[1] as usize)
.map_or(fd_pid, |n| ProcessId(n.get()));
let target_pid = NonZeroUsize::new(metadata[1] as usize).map_or(fd_pid, |n| ProcessId(n.get()));
let new_prio = metadata[2] as u32;
Ready(Response::new(
self.on_setprocprio(fd_pid, target_pid, new_prio)
.map(|()| 0),
op,
self.on_setprocprio(fd_pid, target_pid, new_prio).map(|()| 0),
op
))
}
},
ProcCall::GetProcPriority => {
let target_pid = NonZeroUsize::new(metadata[1] as usize)
.map_or(fd_pid, |n| ProcessId(n.get()));
Ready(Response::new(
self.on_getprocprio(fd_pid, target_pid)
.map(|prio| prio as usize),
self.on_getprocprio(fd_pid, target_pid).map(|prio| prio as usize),
op,
))
}
},
}
}
Handle::Ps(_) => Response::ready_err(EOPNOTSUPP, op),
@@ -2541,8 +2549,8 @@ impl<'a> ProcScheme<'a> {
// Useful for debugging memory leaks.
log::trace!("NEXT FD: {}", {
let nextfd = redox_rt::sys::dup(0, &[]).unwrap();
let _ = redox_rt::sys::close(nextfd);
let nextfd = libredox::call::dup(0, &[]).unwrap();
let _ = libredox::call::close(nextfd);
nextfd
});
log::trace!("{} processes", self.processes.len());
@@ -2565,12 +2573,7 @@ impl<'a> ProcScheme<'a> {
return Err(Error::new(EINVAL));
}
let caller_euid = self
.processes
.get(&caller_pid)
.ok_or(Error::new(ESRCH))?
.borrow()
.euid;
let caller_euid = self.processes.get(&caller_pid).ok_or(Error::new(ESRCH))?.borrow().euid;
let target_rc = self.processes.get(&target_pid).ok_or(Error::new(ESRCH))?;
let mut target = target_rc.borrow_mut();
@@ -2587,7 +2590,11 @@ impl<'a> ProcScheme<'a> {
Ok(())
}
fn on_getprocprio(&self, caller_pid: ProcessId, target_pid: ProcessId) -> Result<u32> {
fn on_getprocprio(
&self,
caller_pid: ProcessId,
target_pid: ProcessId,
) -> Result<u32> {
let target_rc = self.processes.get(&target_pid).ok_or(Error::new(ESRCH))?;
Ok(target_rc.borrow().prio)
}
+21 -9
View File
@@ -2,13 +2,10 @@ use syscall::flag::MapFlags;
mod offsets {
unsafe extern "C" {
// text (R-X)
static __text_start: u8;
static __text_end: u8;
// rodata (R--)
static __rodata_start: u8;
static __rodata_end: u8;
// data+bss (RW-)
static __data_start: u8;
static __bss_end: u8;
}
@@ -38,42 +35,56 @@ mod offsets {
}
}
fn dbg(msg: &[u8]) {
let _ = libredox::call::write(1, msg);
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn start() -> ! {
// Remap self, from the previous RWX
let (text_start, text_end) = offsets::text();
let (rodata_start, rodata_end) = offsets::rodata();
let (data_start, data_end) = offsets::data_and_bss();
// NOTE: Assuming the debug scheme root fd is always placed at this position
let debug_fd = syscall::UPPER_FDTBL_TAG + syscall::data::GlobalSchemes::Debug as usize;
let _ = syscall::openat_into(debug_fd, 0, "", syscall::O_RDONLY, 0); // stdin
let _ = syscall::openat_into(debug_fd, 1, "", syscall::O_WRONLY, 0); // stdout
let _ = syscall::openat_into(debug_fd, 2, "", syscall::O_WRONLY, 0); // stderr
let _ = libredox::call::openat(debug_fd, "", syscall::O_RDONLY as i32, 0);
let _ = libredox::call::openat(debug_fd, "", syscall::O_WRONLY as i32, 0);
let _ = libredox::call::openat(debug_fd, "", syscall::O_WRONLY as i32, 0);
dbg(b"BS:0\n");
unsafe {
let _ = syscall::mprotect(4096, 4096, MapFlags::PROT_READ | MapFlags::MAP_PRIVATE)
.expect("mprotect failed for initfs header page");
dbg(b"BS:1\n");
let _ = syscall::mprotect(
text_start,
text_end - text_start,
MapFlags::PROT_READ | MapFlags::PROT_EXEC | MapFlags::MAP_PRIVATE,
)
.expect("mprotect failed for .text");
dbg(b"BS:2\n");
let _ = syscall::mprotect(
rodata_start,
rodata_end - rodata_start,
MapFlags::PROT_READ | MapFlags::MAP_PRIVATE,
)
.expect("mprotect failed for .rodata");
dbg(b"BS:3\n");
let _ = syscall::mprotect(
data_start,
data_end - data_start,
MapFlags::PROT_READ | MapFlags::PROT_WRITE | MapFlags::MAP_PRIVATE,
)
.expect("mprotect failed for .data/.bss");
dbg(b"BS:4\n");
let _ = syscall::mprotect(
data_end,
crate::arch::STACK_START - data_end,
@@ -82,5 +93,6 @@ pub unsafe extern "C" fn start() -> ! {
.expect("mprotect failed for rest of memory");
}
dbg(b"BS:5\n");
crate::exec::main();
}