commit
6dccd948c5
|
@ -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");
|
static FONT_ITALIC: &'static [u8] = include_bytes!("../../../res/fonts/DejaVuSansMono-Oblique.ttf");
|
||||||
|
|
||||||
/// A display
|
/// 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 struct Display {
|
||||||
pub width: usize,
|
pub width: usize,
|
||||||
pub height: usize,
|
pub height: usize,
|
||||||
|
|
|
@ -93,9 +93,9 @@ pub fn cpu_count() -> usize {
|
||||||
pub extern fn userspace_init() {
|
pub extern fn userspace_init() {
|
||||||
assert_eq!(syscall::chdir(b"initfs:bin"), Ok(0));
|
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:", syscall::flag::O_RDONLY).map(FileHandle::into), Ok(0));
|
||||||
assert_eq!(syscall::open(b"debug:", 0).map(FileHandle::into), Ok(1));
|
assert_eq!(syscall::open(b"debug:", syscall::flag::O_WRONLY).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_WRONLY).map(FileHandle::into), Ok(2));
|
||||||
|
|
||||||
syscall::exec(b"initfs:bin/init", &[]).expect("failed to execute initfs:init");
|
syscall::exec(b"initfs:bin/init", &[]).expect("failed to execute initfs:init");
|
||||||
|
|
||||||
|
|
|
@ -224,14 +224,6 @@ impl Scheme for UserScheme {
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mkdir(&self, path: &[u8], mode: u16, _uid: u32, _gid: u32) -> Result<usize> {
|
|
||||||
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<usize> {
|
fn chmod(&self, path: &[u8], mode: u16, _uid: u32, _gid: u32) -> Result<usize> {
|
||||||
let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?;
|
let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?;
|
||||||
let address = inner.capture(path)?;
|
let address = inner.capture(path)?;
|
||||||
|
|
|
@ -49,7 +49,7 @@ pub fn file_op_mut_slice(a: usize, fd: FileHandle, slice: &mut [u8]) -> Result<u
|
||||||
|
|
||||||
/// Change the current working directory
|
/// Change the current working directory
|
||||||
pub fn chdir(path: &[u8]) -> Result<usize> {
|
pub fn chdir(path: &[u8]) -> Result<usize> {
|
||||||
let fd = open(path, 0)?;
|
let fd = open(path, syscall::flag::O_RDONLY | syscall::flag::O_DIRECTORY)?;
|
||||||
let mut stat = Stat::default();
|
let mut stat = Stat::default();
|
||||||
let stat_res = file_op_mut_slice(syscall::number::SYS_FSTAT, fd, &mut stat);
|
let stat_res = file_op_mut_slice(syscall::number::SYS_FSTAT, fd, &mut stat);
|
||||||
let _ = close(fd);
|
let _ = close(fd);
|
||||||
|
@ -144,28 +144,6 @@ pub fn pipe2(fds: &mut [usize], flags: usize) -> Result<usize> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// mkdir syscall
|
|
||||||
pub fn mkdir(path: &[u8], mode: u16) -> Result<usize> {
|
|
||||||
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
|
/// chmod syscall
|
||||||
pub fn chmod(path: &[u8], mode: u16) -> Result<usize> {
|
pub fn chmod(path: &[u8], mode: u16) -> Result<usize> {
|
||||||
let (path_canon, uid, gid, scheme_ns) = {
|
let (path_canon, uid, gid, scheme_ns) = {
|
||||||
|
|
|
@ -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_CLASS_PATH => match a {
|
||||||
SYS_OPEN => open(validate_slice(b as *const u8, c)?, d).map(FileHandle::into),
|
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_CHMOD => chmod(validate_slice(b as *const u8, c)?, d as u16),
|
||||||
SYS_RMDIR => rmdir(validate_slice(b as *const u8, c)?),
|
SYS_RMDIR => rmdir(validate_slice(b as *const u8, c)?),
|
||||||
SYS_UNLINK => unlink(validate_slice(b as *const u8, c)?),
|
SYS_UNLINK => unlink(validate_slice(b as *const u8, c)?),
|
||||||
|
|
|
@ -468,7 +468,7 @@ pub fn exec(path: &[u8], arg_ptrs: &[[usize; 2]]) -> Result<usize> {
|
||||||
(context.euid, context.egid, context.canonicalize(path))
|
(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();
|
let mut stat = Stat::default();
|
||||||
syscall::file_op_mut_slice(syscall::number::SYS_FSTAT, file, &mut stat)?;
|
syscall::file_op_mut_slice(syscall::number::SYS_FSTAT, file, &mut stat)?;
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ pub use self::syscall::error::*;
|
||||||
pub use self::syscall::flag::*;
|
pub use self::syscall::flag::*;
|
||||||
pub use self::syscall::{
|
pub use self::syscall::{
|
||||||
clock_gettime, clone, execve as exec, exit, futex, getpid, kill, nanosleep, setregid, setreuid, waitpid,
|
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
|
read, write, fcntl, fpath, fstat, fsync, ftruncate, lseek, close
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
172
programs/contain/src/chroot.rs
Normal file
172
programs/contain/src/chroot.rs
Normal file
|
@ -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<String> {
|
||||||
|
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<usize> {
|
||||||
|
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<usize> {
|
||||||
|
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<usize> {
|
||||||
|
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<usize> {
|
||||||
|
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<usize> {
|
||||||
|
syscall::dup(old_id, buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read(&self, id: usize, buf: &mut [u8]) -> Result<usize> {
|
||||||
|
syscall::read(id, buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write(&self, id: usize, buf: &[u8]) -> Result<usize> {
|
||||||
|
syscall::write(id, buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn seek(&self, id: usize, pos: usize, whence: usize) -> Result<usize> {
|
||||||
|
syscall::lseek(id, pos as isize, whence)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fcntl(&self, id: usize, cmd: usize, arg: usize) -> Result<usize> {
|
||||||
|
syscall::fcntl(id, cmd, arg)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fevent(&self, _id: usize, _flags: usize) -> Result<usize> {
|
||||||
|
//TODO
|
||||||
|
Err(Error::new(EBADF))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fmap(&self, _id: usize, _offset: usize, _size: usize) -> Result<usize> {
|
||||||
|
//TODO
|
||||||
|
Err(Error::new(EBADF))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fpath(&self, id: usize, buf: &mut [u8]) -> Result<usize> {
|
||||||
|
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<usize> {
|
||||||
|
syscall::fstat(id, stat)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fstatvfs(&self, id: usize, stat: &mut StatVfs) -> Result<usize> {
|
||||||
|
syscall::fstatvfs(id, stat)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fsync(&self, id: usize) -> Result<usize> {
|
||||||
|
syscall::fsync(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ftruncate(&self, id: usize, len: usize) -> Result<usize> {
|
||||||
|
syscall::ftruncate(id, len)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn close(&self, id: usize) -> Result<usize> {
|
||||||
|
syscall::close(id)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,17 +1,31 @@
|
||||||
extern crate syscall;
|
extern crate syscall;
|
||||||
|
|
||||||
|
use syscall::scheme::Scheme;
|
||||||
|
|
||||||
|
use std::{env, fs, thread};
|
||||||
use std::os::unix::process::CommandExt;
|
use std::os::unix::process::CommandExt;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
|
use self::chroot::ChrootScheme;
|
||||||
|
|
||||||
|
mod chroot;
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
let names = [
|
let mut args = env::args().skip(1);
|
||||||
"file",
|
|
||||||
|
let root_opt = args.next();
|
||||||
|
|
||||||
|
let cmd = args.next().unwrap_or("sh".to_string());
|
||||||
|
|
||||||
|
let mut names = vec![
|
||||||
"rand",
|
"rand",
|
||||||
"tcp",
|
"tcp",
|
||||||
"udp"
|
"udp"
|
||||||
];
|
];
|
||||||
|
|
||||||
let command = "sh";
|
if root_opt.is_none() {
|
||||||
|
names.push("file");
|
||||||
|
}
|
||||||
|
|
||||||
let mut name_ptrs = Vec::new();
|
let mut name_ptrs = Vec::new();
|
||||||
for name in names.iter() {
|
for name in names.iter() {
|
||||||
|
@ -20,15 +34,43 @@ pub fn main() {
|
||||||
|
|
||||||
let new_ns = syscall::mkns(&name_ptrs).unwrap();
|
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() };
|
let pid = unsafe { syscall::clone(0).unwrap() };
|
||||||
if pid == 0 {
|
if pid == 0 {
|
||||||
syscall::setrens(new_ns, new_ns).unwrap();
|
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 {
|
} else {
|
||||||
let mut status = 0;
|
let mut status = 0;
|
||||||
syscall::waitpid(pid, &mut status, 0).unwrap();
|
syscall::waitpid(pid, &mut status, 0).unwrap();
|
||||||
|
|
2
rust
2
rust
|
@ -1 +1 @@
|
||||||
Subproject commit 6733074c847767fd3e0425fcefb73226bde1f6a1
|
Subproject commit d73d32f58d477ca1562e3fc0e966efc88e81409e
|
|
@ -1 +1 @@
|
||||||
Subproject commit dcaf5c76be265bbfa5013cf131f14fa79680a634
|
Subproject commit 25fe6d382641184b447645d6a784316652eaed95
|
2
syscall
2
syscall
|
@ -1 +1 @@
|
||||||
Subproject commit 2835586ee671b0777ef1a98ced9237269c472941
|
Subproject commit 1908eea7e91142a058ae99c06edb2a9dd7efd692
|
Loading…
Reference in a new issue