Merge pull request #760 from redox-os/chroot

Chroot
This commit is contained in:
Jeremy Soller 2016-11-25 20:56:47 -07:00 committed by GitHub
commit 6dccd948c5
12 changed files with 229 additions and 56 deletions

View file

@ -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,

View file

@ -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");

View file

@ -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)?;

View file

@ -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) = {

View file

@ -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)?),

View file

@ -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)?;

View file

@ -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
}; };

View 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)
}
}

View file

@ -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

@ -1 +1 @@
Subproject commit 6733074c847767fd3e0425fcefb73226bde1f6a1 Subproject commit d73d32f58d477ca1562e3fc0e966efc88e81409e

@ -1 +1 @@
Subproject commit dcaf5c76be265bbfa5013cf131f14fa79680a634 Subproject commit 25fe6d382641184b447645d6a784316652eaed95

@ -1 +1 @@
Subproject commit 2835586ee671b0777ef1a98ced9237269c472941 Subproject commit 1908eea7e91142a058ae99c06edb2a9dd7efd692