Update to support i686
This commit is contained in:
33
Cargo.lock
generated
33
Cargo.lock
generated
@@ -7,8 +7,7 @@ name = "acid"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"redox_syscall 0.2.12 (git+https://gitlab.redox-os.org/redox-os/syscall.git)",
|
||||
"strace",
|
||||
"redox_syscall",
|
||||
"x86",
|
||||
]
|
||||
|
||||
@@ -26,45 +25,27 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.126"
|
||||
version = "0.2.132"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
|
||||
checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5"
|
||||
|
||||
[[package]]
|
||||
name = "raw-cpuid"
|
||||
version = "10.3.0"
|
||||
version = "10.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "738bc47119e3eeccc7e94c4a506901aea5e7b4944ecd0829cbebf4af04ceda12"
|
||||
checksum = "6aa2540135b6a94f74c7bc90ad4b794f822026a894f3d7bcd185c100d13d4ad6"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ae183fc1b06c149f0c1793e1eb447c8b04bfe46d48e9e48bfb8d2d7ed64ecf0"
|
||||
version = "0.3.2"
|
||||
source = "git+https://gitlab.redox-os.org/redox-os/syscall.git#7eb24a17cef4e8f4617d20925a86a31dd1b777ea"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.12"
|
||||
source = "git+https://gitlab.redox-os.org/redox-os/syscall.git#30f29c32952343412bb6c36c9fda136d26e9431f"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strace"
|
||||
version = "0.1.0"
|
||||
source = "git+https://gitlab.redox-os.org/redox-os/strace-redox#59425e43bc4284325054bf3ba6ea357d3403ca22"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"redox_syscall 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "x86"
|
||||
version = "0.47.0"
|
||||
|
||||
@@ -1,253 +0,0 @@
|
||||
// TODO: This is no longer implemented by the kernel. Should it be moved to resist?
|
||||
|
||||
use syscall::data::{Map, Packet};
|
||||
use syscall::error::{Error, Result, EFAULT, EINVAL};
|
||||
use syscall::flag::{CloneFlags, MapFlags, O_CREAT, O_RDONLY, O_RDWR, O_CLOEXEC, WaitFlags};
|
||||
use syscall::scheme::SchemeMut;
|
||||
|
||||
// Start of code copied from syscall.
|
||||
use std::convert::Infallible;
|
||||
|
||||
use syscall::{
|
||||
clone,
|
||||
close,
|
||||
EIO,
|
||||
exit,
|
||||
pipe2,
|
||||
read,
|
||||
write,
|
||||
};
|
||||
|
||||
#[must_use = "Daemon::ready must be called"]
|
||||
pub struct Daemon {
|
||||
write_pipe: usize,
|
||||
}
|
||||
|
||||
impl Daemon {
|
||||
pub fn new<F: FnOnce(Daemon) -> Infallible>(f: F) -> Result<u8> {
|
||||
let mut pipes = [0; 2];
|
||||
pipe2(&mut pipes, 0)?;
|
||||
|
||||
let [read_pipe, write_pipe] = pipes;
|
||||
|
||||
let result = unsafe { libc::fork() };
|
||||
|
||||
if result == 0 {
|
||||
let _ = close(read_pipe);
|
||||
|
||||
f(Daemon {
|
||||
write_pipe,
|
||||
});
|
||||
// TODO: Replace Infallible with the never type once it is stabilized.
|
||||
unreachable!();
|
||||
} else if result > 0 {
|
||||
let _ = close(write_pipe);
|
||||
|
||||
let mut data = [0];
|
||||
let res = read(read_pipe, &mut data);
|
||||
let _ = close(read_pipe);
|
||||
|
||||
if res? == 1 {
|
||||
//exit(data[0] as usize)?;
|
||||
//unreachable!();
|
||||
Ok(data[0])
|
||||
} else {
|
||||
Err(Error::new(EIO))
|
||||
}
|
||||
} else {
|
||||
return Err(Error::new(std::io::Error::last_os_error().raw_os_error().unwrap_or(EINVAL)));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ready(self) -> Result<()> {
|
||||
let res = write(self.write_pipe, &[0]);
|
||||
let _ = close(self.write_pipe);
|
||||
|
||||
if res? == 1 {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::new(EIO))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// End of code copied from syscall
|
||||
|
||||
struct TestScheme(bool);
|
||||
|
||||
impl SchemeMut for TestScheme {
|
||||
fn open(&mut self, _path: &str, _flags: usize, _uid: u32, _gid: u32) -> Result<usize> { Ok(0) }
|
||||
fn close(&mut self, _id: usize) -> Result<usize> { Ok(0) }
|
||||
fn fmap(&mut self, id: usize, map: &Map) -> Result<usize> {
|
||||
if map.size != PAGE_SIZE { return Err(Error::new(EINVAL)); }
|
||||
|
||||
let addr = unsafe { syscall::fmap(!0, &Map { offset: 0, size: PAGE_SIZE, flags: MapFlags::MAP_SHARED | MapFlags::PROT_WRITE, address: 0 })? };
|
||||
if self.0 { unsafe { (addr as *mut u8).write(42); } }
|
||||
|
||||
Ok(addr)
|
||||
}
|
||||
}
|
||||
|
||||
const SCHEME_NAME: &str = "acid_clone_grant_using_fmap";
|
||||
const PAGE_SIZE: usize = 4096;
|
||||
|
||||
fn inner(readonly: bool) -> Result<()> {
|
||||
println!("Testing - {}", if readonly { "readonly" } else { "writable" });
|
||||
Daemon::new(move |daemon: Daemon| -> std::convert::Infallible {
|
||||
let e = |r| {
|
||||
match r {
|
||||
Ok(t) => t,
|
||||
Err(e) => {
|
||||
eprintln!("error in clone_grant_using_fmap daemon: {}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let socket = e(syscall::open(format!(":{}{}", SCHEME_NAME, readonly), O_CREAT | O_RDWR | O_CLOEXEC));
|
||||
|
||||
daemon.ready();
|
||||
|
||||
let mut packet = Packet::default();
|
||||
let mut scheme = TestScheme(readonly);
|
||||
|
||||
loop {
|
||||
if e(syscall::read(socket, &mut packet)) == 0 { break };
|
||||
scheme.handle(&mut packet);
|
||||
if e(syscall::write(socket, &packet)) == 0 { break }
|
||||
}
|
||||
let _ = syscall::close(socket);
|
||||
|
||||
std::process::exit(0);
|
||||
})?;
|
||||
println!("Started scheme daemon");
|
||||
let fd = syscall::open(format!("{}{}:", SCHEME_NAME, readonly), O_CLOEXEC | O_RDONLY)?;
|
||||
|
||||
let ptr = unsafe { syscall::fmap(fd, &Map { offset: 0, size: PAGE_SIZE, flags: MapFlags::MAP_PRIVATE | MapFlags::PROT_READ | MapFlags::PROT_WRITE, address: 0 })? as *mut u8 };
|
||||
|
||||
println!("Obtained pointer {:p}", ptr);
|
||||
|
||||
// TODO: Prevent optimizations which may cancel out this type of checking. Volatile will most
|
||||
// likely be adequate.
|
||||
|
||||
if !readonly {
|
||||
unsafe {
|
||||
ptr.write_volatile(0x42);
|
||||
}
|
||||
}
|
||||
|
||||
let pid;
|
||||
unsafe {
|
||||
pid = libc::fork() as usize;
|
||||
|
||||
assert_ne!(pid, (-1_isize) as usize);
|
||||
|
||||
println!("Fork was successful, for the {} process", if pid == 0 { "child" } else { "parent" });
|
||||
|
||||
if pid == 0 {
|
||||
println!("Child process: checking...");
|
||||
|
||||
// We are the child process. Hopefully relibc copied the grant properly and without
|
||||
// aliasing.
|
||||
if readonly {
|
||||
assert_eq!(ptr.read_volatile(), 42);
|
||||
} else {
|
||||
assert_eq!(ptr.read_volatile(), 0);
|
||||
ptr.write_volatile(0x43);
|
||||
assert_eq!(ptr.read_volatile(), 0x43);
|
||||
}
|
||||
println!("Child process: obtained correct page");
|
||||
std::process::exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
println!("Waiting...");
|
||||
syscall::waitpid(pid, &mut 0, WaitFlags::empty())?;
|
||||
|
||||
unsafe { assert_eq!(ptr.read_volatile(), if readonly { 42 } else { 0x42 }); }
|
||||
|
||||
println!("It worked!");
|
||||
|
||||
let _ = unsafe { syscall::funmap(ptr as usize, PAGE_SIZE) };
|
||||
|
||||
syscall::unlink(format!(":{}{}", SCHEME_NAME, readonly))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn clone_grant_using_fmap() -> Result<(), String> {
|
||||
inner(false).map_err(|e| e.to_string())?;
|
||||
inner(true).map_err(|e| e.to_string())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
struct Perms { r: bool, w: bool, x: bool, b: bool }
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
struct Mapping {
|
||||
addr: usize,
|
||||
len: usize,
|
||||
offset: usize,
|
||||
perms: Perms,
|
||||
}
|
||||
fn read_addr_space() -> Result<Box<[Mapping]>, String> {
|
||||
use std::fs::File;
|
||||
use std::io::{BufReader, prelude::*};
|
||||
|
||||
let mut mappings = Vec::new();
|
||||
|
||||
let mut buf = vec! [0_u8; 4096];
|
||||
let mut file = File::open("thisproc:current/addrspace").map_err(|err| format!("failed to open current address space: {}", err))?;
|
||||
|
||||
loop {
|
||||
const RECORD_SIZE: usize = 4 * std::mem::size_of::<usize>();
|
||||
let read = file.read(&mut buf).map_err(|err| format!("failed to read from address space: {}", err))? / RECORD_SIZE;
|
||||
|
||||
for chunks in buf[..read].array_chunks::<RECORD_SIZE>() {
|
||||
let mut nums = chunks.array_chunks::<{std::mem::size_of::<usize>()}>().copied().map(usize::from_ne_bytes);
|
||||
|
||||
mappings.push(Mapping {
|
||||
addr: nums.next().unwrap(),
|
||||
len: nums.next().unwrap(),
|
||||
perms: {
|
||||
let raw = nums.next().unwrap();
|
||||
let flags = MapFlags::from_bits(raw & !0x8000_0000).unwrap();
|
||||
|
||||
Perms {
|
||||
r: true,
|
||||
w: flags.contains(MapFlags::PROT_WRITE),
|
||||
x: flags.contains(MapFlags::PROT_EXEC),
|
||||
b: raw & 0x8000_0000 != 0,
|
||||
}
|
||||
},
|
||||
offset: nums.next().unwrap(),
|
||||
});
|
||||
}
|
||||
|
||||
if read < buf.len() { break }
|
||||
}
|
||||
|
||||
Ok(mappings.into_boxed_slice())
|
||||
}
|
||||
|
||||
// Exec is harder and more unreliable to check, but kernel debug looks good enough for now.
|
||||
pub fn check_clone_leak() -> Result<(), String> {
|
||||
// TODO: Check sigaction?
|
||||
|
||||
let prev_addr_space = read_addr_space()?;
|
||||
|
||||
let prev_number = syscall::open("memory:", 0).map_err(|_| format!("failed to open dummy file descriptor 1st time"))?;
|
||||
let _ = syscall::close(prev_number);
|
||||
|
||||
unsafe { libc::fork(); }
|
||||
|
||||
let next_addr_space = read_addr_space()?;
|
||||
|
||||
let next_number = syscall::open("memory:", 0).map_err(|_| format!("failed to open dummy file descriptor 2nd time"))?;
|
||||
let _ = syscall::close(next_number);
|
||||
|
||||
assert_eq!(prev_number, next_number, "file descriptor leak");
|
||||
assert_eq!(prev_addr_space, next_addr_space);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
16
src/main.rs
16
src/main.rs
@@ -1,8 +1,6 @@
|
||||
//!Acid testing program
|
||||
#![feature(array_chunks, core_intrinsics, thread_local)]
|
||||
|
||||
mod clone_grant_using_fmap;
|
||||
|
||||
const PAGE_SIZE: usize = 4096;
|
||||
|
||||
fn e<T, E: ToString>(error: Result<T, E>) -> Result<T, String> {
|
||||
@@ -208,7 +206,7 @@ fn thread_test() -> Result<(), String> {
|
||||
static mut TBSS_TEST_ZERO: usize = 0;
|
||||
/// Test of non-zero values in thread data.
|
||||
#[thread_local]
|
||||
static mut TDATA_TEST_NONZERO: usize = 0xFFFFFFFFFFFFFFFF;
|
||||
static mut TDATA_TEST_NONZERO: usize = usize::max_value();
|
||||
|
||||
fn tls_test() -> Result<(), String> {
|
||||
use std::thread;
|
||||
@@ -218,9 +216,9 @@ fn tls_test() -> Result<(), String> {
|
||||
assert_eq!(TBSS_TEST_ZERO, 0);
|
||||
TBSS_TEST_ZERO += 1;
|
||||
assert_eq!(TBSS_TEST_ZERO, 1);
|
||||
assert_eq!(TDATA_TEST_NONZERO, 0xFFFFFFFFFFFFFFFF);
|
||||
assert_eq!(TDATA_TEST_NONZERO, usize::max_value());
|
||||
TDATA_TEST_NONZERO -= 1;
|
||||
assert_eq!(TDATA_TEST_NONZERO, 0xFFFFFFFFFFFFFFFE);
|
||||
assert_eq!(TDATA_TEST_NONZERO, usize::max_value() - 1);
|
||||
}
|
||||
}).join().unwrap();
|
||||
|
||||
@@ -228,16 +226,14 @@ fn tls_test() -> Result<(), String> {
|
||||
assert_eq!(TBSS_TEST_ZERO, 0);
|
||||
TBSS_TEST_ZERO += 1;
|
||||
assert_eq!(TBSS_TEST_ZERO, 1);
|
||||
assert_eq!(TDATA_TEST_NONZERO, 0xFFFFFFFFFFFFFFFF);
|
||||
assert_eq!(TDATA_TEST_NONZERO, usize::max_value());
|
||||
TDATA_TEST_NONZERO -= 1;
|
||||
assert_eq!(TDATA_TEST_NONZERO, 0xFFFFFFFFFFFFFFFE);
|
||||
assert_eq!(TDATA_TEST_NONZERO, usize::max_value() - 1);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
use self::clone_grant_using_fmap::*;
|
||||
|
||||
fn main() {
|
||||
use std::collections::BTreeMap;
|
||||
use std::{env, process};
|
||||
@@ -251,8 +247,6 @@ fn main() {
|
||||
tests.insert("tcp_fin", tcp_fin_test);
|
||||
tests.insert("thread", thread_test);
|
||||
tests.insert("tls", tls_test);
|
||||
tests.insert("clone_grant_using_fmap", clone_grant_using_fmap);
|
||||
tests.insert("check_clone_leak", check_clone_leak);
|
||||
|
||||
let mut ran_test = false;
|
||||
for arg in env::args().skip(1) {
|
||||
|
||||
Reference in New Issue
Block a user