diff --git a/drivers/vesad/src/display.rs b/drivers/vesad/src/display.rs index 2d5f24e..829d6ba 100644 --- a/drivers/vesad/src/display.rs +++ b/drivers/vesad/src/display.rs @@ -22,16 +22,6 @@ static FONT_BOLD_ITALIC: &'static [u8] = include_bytes!("../../../res/fonts/Deja static FONT_ITALIC: &'static [u8] = include_bytes!("../../../res/fonts/DejaVuSansMono-Oblique.ttf"); /// A display -#[cfg(not(feature="rusttype"))] -pub struct Display { - pub width: usize, - pub height: usize, - pub onscreen: &'static mut [u32], - pub offscreen: &'static mut [u32] -} - -/// A display -#[cfg(feature="rusttype")] pub struct Display { pub width: usize, pub height: usize, diff --git a/kernel/lib.rs b/kernel/lib.rs index bda4da9..0c52084 100644 --- a/kernel/lib.rs +++ b/kernel/lib.rs @@ -93,9 +93,9 @@ pub fn cpu_count() -> usize { pub extern fn userspace_init() { assert_eq!(syscall::chdir(b"initfs:bin"), Ok(0)); - assert_eq!(syscall::open(b"debug:", 0).map(FileHandle::into), Ok(0)); - assert_eq!(syscall::open(b"debug:", 0).map(FileHandle::into), Ok(1)); - assert_eq!(syscall::open(b"debug:", 0).map(FileHandle::into), Ok(2)); + assert_eq!(syscall::open(b"debug:", syscall::flag::O_RDONLY).map(FileHandle::into), Ok(0)); + assert_eq!(syscall::open(b"debug:", syscall::flag::O_WRONLY).map(FileHandle::into), Ok(1)); + assert_eq!(syscall::open(b"debug:", syscall::flag::O_WRONLY).map(FileHandle::into), Ok(2)); syscall::exec(b"initfs:bin/init", &[]).expect("failed to execute initfs:init"); diff --git a/kernel/scheme/user.rs b/kernel/scheme/user.rs index b7355bb..589a8c9 100644 --- a/kernel/scheme/user.rs +++ b/kernel/scheme/user.rs @@ -224,14 +224,6 @@ impl Scheme for UserScheme { result } - fn mkdir(&self, path: &[u8], mode: u16, _uid: u32, _gid: u32) -> Result { - let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?; - let address = inner.capture(path)?; - let result = inner.call(SYS_MKDIR, address, path.len(), mode as usize); - let _ = inner.release(address); - result - } - fn chmod(&self, path: &[u8], mode: u16, _uid: u32, _gid: u32) -> Result { let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?; let address = inner.capture(path)?; diff --git a/kernel/syscall/fs.rs b/kernel/syscall/fs.rs index 30bd291..6f6a698 100644 --- a/kernel/syscall/fs.rs +++ b/kernel/syscall/fs.rs @@ -49,7 +49,7 @@ pub fn file_op_mut_slice(a: usize, fd: FileHandle, slice: &mut [u8]) -> Result Result { - let fd = open(path, 0)?; + let fd = open(path, syscall::flag::O_RDONLY | syscall::flag::O_DIRECTORY)?; let mut stat = Stat::default(); let stat_res = file_op_mut_slice(syscall::number::SYS_FSTAT, fd, &mut stat); let _ = close(fd); @@ -144,28 +144,6 @@ pub fn pipe2(fds: &mut [usize], flags: usize) -> Result { } } -/// mkdir syscall -pub fn mkdir(path: &[u8], mode: u16) -> Result { - let (path_canon, uid, gid, scheme_ns) = { - let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; - let context = context_lock.read(); - (context.canonicalize(path), context.euid, context.egid, context.ens) - }; - - let mut parts = path_canon.splitn(2, |&b| b == b':'); - let scheme_name_opt = parts.next(); - let reference_opt = parts.next(); - - let scheme_name = scheme_name_opt.ok_or(Error::new(ENODEV))?; - let scheme = { - let schemes = scheme::schemes(); - let (_scheme_id, scheme) = schemes.get_name(scheme_ns, scheme_name).ok_or(Error::new(ENODEV))?; - scheme.clone() - }; - scheme.mkdir(reference_opt.unwrap_or(b""), mode, uid, gid) -} - /// chmod syscall pub fn chmod(path: &[u8], mode: u16) -> Result { let (path_canon, uid, gid, scheme_ns) = { diff --git a/kernel/syscall/mod.rs b/kernel/syscall/mod.rs index f197f84..69e53ec 100644 --- a/kernel/syscall/mod.rs +++ b/kernel/syscall/mod.rs @@ -61,7 +61,6 @@ pub extern fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize }, SYS_CLASS_PATH => match a { SYS_OPEN => open(validate_slice(b as *const u8, c)?, d).map(FileHandle::into), - SYS_MKDIR => mkdir(validate_slice(b as *const u8, c)?, d as u16), SYS_CHMOD => chmod(validate_slice(b as *const u8, c)?, d as u16), SYS_RMDIR => rmdir(validate_slice(b as *const u8, c)?), SYS_UNLINK => unlink(validate_slice(b as *const u8, c)?), diff --git a/kernel/syscall/process.rs b/kernel/syscall/process.rs index 9c1c69a..f6b4b1e 100644 --- a/kernel/syscall/process.rs +++ b/kernel/syscall/process.rs @@ -468,7 +468,7 @@ pub fn exec(path: &[u8], arg_ptrs: &[[usize; 2]]) -> Result { (context.euid, context.egid, context.canonicalize(path)) }; - let file = syscall::open(&canonical, 0)?; + let file = syscall::open(&canonical, syscall::flag::O_RDONLY)?; let mut stat = Stat::default(); syscall::file_op_mut_slice(syscall::number::SYS_FSTAT, file, &mut stat)?; diff --git a/libstd/libc/src/syscall.rs b/libstd/libc/src/syscall.rs index 7f44357..6a97833 100644 --- a/libstd/libc/src/syscall.rs +++ b/libstd/libc/src/syscall.rs @@ -9,7 +9,7 @@ pub use self::syscall::error::*; pub use self::syscall::flag::*; pub use self::syscall::{ clock_gettime, clone, execve as exec, exit, futex, getpid, kill, nanosleep, setregid, setreuid, waitpid, - chdir, chmod, getcwd, open, mkdir, rmdir, unlink, dup, pipe2, + chdir, chmod, getcwd, open, rmdir, unlink, dup, pipe2, read, write, fcntl, fpath, fstat, fsync, ftruncate, lseek, close }; diff --git a/programs/contain/src/chroot.rs b/programs/contain/src/chroot.rs new file mode 100644 index 0000000..edce9ea --- /dev/null +++ b/programs/contain/src/chroot.rs @@ -0,0 +1,172 @@ +use syscall; +use syscall::data::{Stat, StatVfs}; +use syscall::error::{Error, EBADF, EINVAL, EPERM, Result}; +use syscall::scheme::Scheme; + +use std::str; +use std::path::PathBuf; + +pub struct ChrootScheme { + root: PathBuf +} + +impl ChrootScheme { + pub fn new(root: PathBuf) -> ChrootScheme { + ChrootScheme { + root: root + } + } + + fn translate(&self, path: &[u8]) -> Result { + let path = str::from_utf8(path).or(Err(Error::new(EINVAL)))?; + let mut translated = self.root.clone(); + translated.push(path.trim_left_matches('/')); + if translated.starts_with(&self.root) { + translated.into_os_string().into_string().or(Err(Error::new(EINVAL))) + } else { + println!("escaped chroot"); + Err(Error::new(EPERM)) + } + } +} + +impl Scheme for ChrootScheme { + fn open(&self, path: &[u8], flags: usize, uid: u32, gid: u32) -> Result { + if uid != 0 { + syscall::setreuid(0, uid as usize)?; + } + if gid != 0 { + syscall::setregid(0, gid as usize)?; + } + let res = syscall::open(&self.translate(path)?, flags); + if uid != 0 { + syscall::setreuid(0, 0).unwrap(); + } + if gid != 0 { + syscall::setregid(0, 0).unwrap(); + } + res + } + + fn chmod(&self, path: &[u8], mode: u16, uid: u32, gid: u32) -> Result { + if uid != 0 { + syscall::setreuid(0, uid as usize)?; + } + if gid != 0 { + syscall::setregid(0, gid as usize)?; + } + let res = syscall::chmod(&self.translate(path)?, mode as usize); + if uid != 0 { + syscall::setreuid(0, 0).unwrap(); + } + if gid != 0 { + syscall::setregid(0, 0).unwrap(); + } + res + } + + fn rmdir(&self, path: &[u8], uid: u32, gid: u32) -> Result { + if uid != 0 { + syscall::setreuid(0, uid as usize)?; + } + if gid != 0 { + syscall::setregid(0, gid as usize)?; + } + let res = syscall::rmdir(&self.translate(path)?); + if uid != 0 { + syscall::setreuid(0, 0).unwrap(); + } + if gid != 0 { + syscall::setregid(0, 0).unwrap(); + } + res + } + + fn unlink(&self, path: &[u8], uid: u32, gid: u32) -> Result { + if uid != 0 { + syscall::setreuid(0, uid as usize)?; + } + if gid != 0 { + syscall::setregid(0, gid as usize)?; + } + let res = syscall::unlink(&self.translate(path)?); + if uid != 0 { + syscall::setreuid(0, 0).unwrap(); + } + if gid != 0 { + syscall::setregid(0, 0).unwrap(); + } + res + } + + /* Resource operations */ + fn dup(&self, old_id: usize, buf: &[u8]) -> Result { + syscall::dup(old_id, buf) + } + + fn read(&self, id: usize, buf: &mut [u8]) -> Result { + syscall::read(id, buf) + } + + fn write(&self, id: usize, buf: &[u8]) -> Result { + syscall::write(id, buf) + } + + fn seek(&self, id: usize, pos: usize, whence: usize) -> Result { + syscall::lseek(id, pos as isize, whence) + } + + fn fcntl(&self, id: usize, cmd: usize, arg: usize) -> Result { + syscall::fcntl(id, cmd, arg) + } + + fn fevent(&self, _id: usize, _flags: usize) -> Result { + //TODO + Err(Error::new(EBADF)) + } + + fn fmap(&self, _id: usize, _offset: usize, _size: usize) -> Result { + //TODO + Err(Error::new(EBADF)) + } + + fn fpath(&self, id: usize, buf: &mut [u8]) -> Result { + let count = syscall::fpath(id, buf)?; + + let translated = { + let path = str::from_utf8(&buf[.. count]).or(Err(Error::new(EINVAL)))?; + let translated = path.to_string().replace(self.root.to_str().ok_or(Error::new(EINVAL))?, ""); + format!("file:{}", translated.trim_left_matches('/')) + }; + + let path = translated.as_bytes(); + + let mut i = 0; + while i < buf.len() && i < path.len() { + buf[i] = path[i]; + i += 1; + } + + Ok(i) + } + + fn fstat(&self, id: usize, stat: &mut Stat) -> Result { + syscall::fstat(id, stat) + } + + fn fstatvfs(&self, id: usize, stat: &mut StatVfs) -> Result { + syscall::fstatvfs(id, stat) + } + + fn fsync(&self, id: usize) -> Result { + syscall::fsync(id) + } + + fn ftruncate(&self, id: usize, len: usize) -> Result { + syscall::ftruncate(id, len) + } + + fn close(&self, id: usize) -> Result { + syscall::close(id) + } +} diff --git a/programs/contain/src/main.rs b/programs/contain/src/main.rs index 0a14eca..8e22e23 100644 --- a/programs/contain/src/main.rs +++ b/programs/contain/src/main.rs @@ -1,17 +1,31 @@ extern crate syscall; +use syscall::scheme::Scheme; + +use std::{env, fs, thread}; use std::os::unix::process::CommandExt; use std::process::Command; +use self::chroot::ChrootScheme; + +mod chroot; + pub fn main() { - let names = [ - "file", + let mut args = env::args().skip(1); + + let root_opt = args.next(); + + let cmd = args.next().unwrap_or("sh".to_string()); + + let mut names = vec![ "rand", "tcp", "udp" ]; - let command = "sh"; + if root_opt.is_none() { + names.push("file"); + } let mut name_ptrs = Vec::new(); for name in names.iter() { @@ -20,15 +34,43 @@ pub fn main() { let new_ns = syscall::mkns(&name_ptrs).unwrap(); + let root_thread = if let Some(root) = root_opt { + Some(thread::spawn(move || { + syscall::setrens(-1isize as usize, new_ns).unwrap(); + let scheme_fd = syscall::open(":file", syscall::O_CREAT | syscall::O_RDWR | syscall::O_CLOEXEC).unwrap(); + syscall::setrens(-1isize as usize, syscall::getns().unwrap()).unwrap(); + + let chroot_scheme = ChrootScheme::new(fs::canonicalize(root).unwrap()); + loop { + let mut packet = syscall::Packet::default(); + if syscall::read(scheme_fd, &mut packet).unwrap() == 0 { + break; + } + chroot_scheme.handle(&mut packet); + syscall::write(scheme_fd, &packet).unwrap(); + } + + let _ = syscall::close(scheme_fd); + })) + } else { + None + }; + let pid = unsafe { syscall::clone(0).unwrap() }; if pid == 0 { syscall::setrens(new_ns, new_ns).unwrap(); - println!("Container {}: enter: {}", new_ns, command); + println!("Container {}: enter: {}", new_ns, cmd); - let err = Command::new(command).exec(); + let mut command = Command::new(&cmd); + for arg in args { + command.arg(&arg); + } + command.current_dir("/"); - panic!("contain: failed to launch {}: {}", command, err); + let err = command.exec(); + + panic!("contain: failed to launch {}: {}", cmd, err); } else { let mut status = 0; syscall::waitpid(pid, &mut status, 0).unwrap(); diff --git a/rust b/rust index 6733074..d73d32f 160000 --- a/rust +++ b/rust @@ -1 +1 @@ -Subproject commit 6733074c847767fd3e0425fcefb73226bde1f6a1 +Subproject commit d73d32f58d477ca1562e3fc0e966efc88e81409e diff --git a/schemes/redoxfs b/schemes/redoxfs index dcaf5c7..25fe6d3 160000 --- a/schemes/redoxfs +++ b/schemes/redoxfs @@ -1 +1 @@ -Subproject commit dcaf5c76be265bbfa5013cf131f14fa79680a634 +Subproject commit 25fe6d382641184b447645d6a784316652eaed95 diff --git a/syscall b/syscall index 2835586..1908eea 160000 --- a/syscall +++ b/syscall @@ -1 +1 @@ -Subproject commit 2835586ee671b0777ef1a98ced9237269c472941 +Subproject commit 1908eea7e91142a058ae99c06edb2a9dd7efd692