8000 Isolated Processes 17: Implement executor to run syscalls in remote process by marti4d · Pull Request #217 · rust-minidump/minidump-writer · GitHub
[go: up one dir, main page]

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions crates/linux/process-backend/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ pub enum ProcessReaderKind {
pub enum Error {
#[error("there was a failure making a direct syscall")]
Local(#[source] local::Error),
#[error("the remote executor returned an error")]
Executor(#[source] remote::executor::Error),
#[error("buffer was too small to contain the result")]
BufferTooSmall,
}
269 changes: 269 additions & 0 deletions crates/linux/process-backend/src/remote/executor/handler.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,269 @@
use super as executor;
use super::remote;
use crate::{ProcessReaderKind, regs::*, wrapper::Stat};
use executor::{Error, Executor, Result};
use remote::wire;
use wire::{CStrWithNull, HandlesRequests};

impl HandlesRequests for &mut Executor<'_> {
fn GetPid<'args, 'output>(self, _args: ()) -> Result<libc::pid_t>
where
Self: 'output,
{
Ok(self.local_backend.pid())
}

fn ProcessReaderReadAt<'args, 'output>(
self,
args: wire::ProcessReaderReadAtArgs,
) -> Result<&'output [u8]>
where
Self: 'output,
{
let scratch_buf = borrow_with_limit(self.scratch_buf, args.requested_len);

let bytes_read = self
.local_backend
.process_reader()
.read_at(args.address, scratch_buf)
.map_err(Error::Local)?;

Ok(&scratch_buf[0..bytes_read])
}

fn StopProcess<'args, 'output>(self, _args: ()) -> Result<()>
where
Self: 'output,
{
self.local_backend.stop_process().map_err(Error::Local)
}

fn ContinueProcess<'args, 'output>(self, _args: ()) -> Result<()>
where
Self: 'output,
{
self.local_backend.continue_process().map_err(Error::Local)
}

fn SuspendThread<'args, 'output>(self, tid: libc::pid_t) -> Result<()>
where
Self: 'output,
{
self.local_backend.suspend_thread(tid).map_err(Error::Local)
}

fn ResumeThread<'args, 'output>(self, tid: libc::pid_t) -> Result<()>
where
Self: 'output,
{
self.local_backend.resume_thread(tid).map_err(Error::Local)
}

fn MappedModuleMemoryReaderOpen<'args, 'output>(
self,
args: wire::MappedModuleMemoryReaderOpenArgs,
) -> Result<usize>
where
Self: 'output,
{
let reader = self
.local_backend
.map_module_into_memory(&args.path, args.offset)
.map_err(Error::Local)?;
self.mapped_module_memory_readers
.assign_slot(reader)
.ok_or(Error::MappedModuleMemoryReaderSlotsExhausted)
}

fn MappedModuleMemoryReaderReadAt<'args, 'output>(
self,
args: wire::MappedModuleMemoryReaderReadAtArgs,
) -> Result<&'output [u8]>
where
Self: 'output,
{
let reader = self
.mapped_module_memory_readers
.get_slot_mut(args.handle)
.ok_or(Error::EmptyMappedModuleMemoryReaderSlotRequested)?;
reader
.read_at(args.offset, args.requested_len)
.map_err(Error::Local)
}

fn MappedModuleMemoryReaderLen<'args, 'output>(self, handle: usize) -> Result<usize>
where
Self: 'output,
{
let reader = self
.mapped_module_memory_readers
.get_slot_mut(handle)
.ok_or(Error::EmptyMappedModuleMemoryReaderSlotRequested)?;
Ok(reader.len())
}

fn MappedModuleMemoryReaderClose<'args, 'output>(self, handle: usize) -> Result<()>
where
Self: 'output,
{
let _reader = self
.mapped_module_memory_readers
.free_slot(handle)
.ok_or(Error::EmptyMappedModuleMemoryReaderSlotRequested)?;
Ok(())
}

fn StatFile<'args, 'output>(self, path: CStrWithNull<'_>) -> Result<Stat>
where
Self: 'output,
{
self.local_backend.stat_file(&path).map_err(Error::Local)
}

fn FileReaderOpen<'args, 'output>(self, path: CStrWithNull<'_>) -> Result<usize>
where
Self: 'output,
{
let reader = self.local_backend.read_file(&path).map_err(Error::Local)?;
self.file_readers
.assign_slot(reader)
.ok_or(Error::FileReaderSlotsExhausted)
}

fn FileReaderRead<'args, 'output>(self, args: wire::FileReaderArgs) -> Result<&'output [u8]>
where
Self: 'output,
{
let scratch_buf = borrow_with_limit(self.scratch_buf, args.requested_len);

let reader = self
.file_readers
.get_slot_mut(args.handle)
.ok_or(Error::EmptyFileSlotRequested)?;

let bytes_read = reader.read(scratch_buf).map_err(Error::Local)?;

Ok(&scratch_buf[0..bytes_read])
}

fn FileReaderClose<'args, 'output>(self, handle: usize) -> Result<()>
where
Self: 'output,
{
let _reader = self
.file_readers
.free_slot(handle)
.ok_or(Error::EmptyFileSlotRequested)?;
Ok(())
}

fn DirReaderOpen<'args, 'output>(self, path: CStrWithNull<'_>) -> Result<usize>
where
Self: 'output,
{
let reader = self.local_backend.read_dir(&path).map_err(Error::Local)?;
self.dir_readers
.assign_slot(reader)
.ok_or(Error::DirReaderSlotsExhausted)
}

fn DirReaderRead<'args, 'output>(self, handle: usize) -> Result<Option<&'output [u8]>>
where
Self: 'output,
{
let reader = self
.dir_readers
.get_slot_mut(handle)
.ok_or(Error::EmptyDirSlotRequested)?;

reader.read_next_name().map_err(Error::Local)
}

fn DirReaderClose<'args, 'output>(self, handle: usize) -> Result<()>
where
Self: 'output,
{
let _reader = self
.dir_readers
.free_slot(handle)
.ok_or(Error::EmptyDirSlotRequested)?;
Ok(())
}

fn ReadLink<'args, 'output>(self, args: wire::ReadLinkArgs<'_>) -> Result<&'output [u8]>
where
Self: 'output,
{
let scratch_buf = borrow_with_limit(self.scratch_buf, args.requested_len);

let bytes_read = self
.local_backend
.read_link(&args.path, scratch_buf)
.map_err(Error::Local)?;

Ok(&scratch_buf[0..bytes_read])
}

fn GetGenRegs<'args, 'output>(self, tid: libc::pid_t) -> Result<GenRegs>
where
Self: 'output,
{
self.local_backend.get_gen_regs(tid).map_err(Error::Local)
}

fn GetFpRegs<'args, 'output>(self, tid: libc::pid_t) -> Result<FpRegs>
where
Self: 'output,
{
self.local_backend.get_fp_regs(tid).map_err(Error::Local)
}

#[cfg(target_arch = "x86")]
fn GetFpxRegs<'args, 'output>(self, tid: libc::pid_t) -> Result<FpxRegs>
where
Self: 'output,
{
self.local_backend.get_fpx_regs(tid).map_err(Error::Local)
}

#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
fn PtracePeekUser<'args, 'output>(self, addr: usize) -> Result<[u8; crate::PTRACE_DATA_LEN]>
where
Self: 'output,
{
self.local_backend
.ptrace_peekuser(addr)
.map_err(Error::Local)
}

fn ForceProcessReaderKind<'args, 'output>(self, kind: ProcessReaderKind) -> Result<()>
where
Self: 'output,
{
self.local_backend
.force_process_reader_kind(kind)
.map_err(Error::Local)
}

#[cfg(feature = "testing")]
fn FailOneSyscallWith<'args, 'output>(self, errno: core::ffi::c_int) -> Result<()>
where
Self: 'output,
{
self.local_backend.fail_one_syscall_with(errno);
Ok(())
}

fn Quit<'args, 'output>(self, _args: ()) -> Result<()>
where
Self: 'output,
{
self.quit = true;
Ok(())
}
Comment on lines +9 to +263
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Add a blank line between each function

}

fn borrow_with_limit(buf: &mut [u8], limit: usize) -> &mut [u8] {
let len = usize::min(buf.len(), limit);
&mut buf[0..len]
}
8BD0
60 changes: 60 additions & 0 deletions crates/linux/process-backend/src/remote/executor/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
use super as remote;
use crate::local;
use remote::{transport, wire};
use resources::Pool;

pub use resources::Resources;

pub mod resources;

mod handler;

pub type Result<T> = core::result::Result<T, Error>;

pub fn run<T: transport::Executor>(
pid: libc::pid_t,
mut transport: T,
resources: Resources<'_>,
) -> core::result::Result<(), transport::ExecutorError> {
let mut executor = Executor {
local_backend: local::Backend::new(pid),
quit: false,
file_readers: Pool::new(resources.file_readers),
dir_readers: Pool::new(resources.dir_readers),
mapped_module_memory_readers: Pool::new(resources.mapped_module_memory_readers),
scratch_buf: resources.scratch_buf,
};

while !executor.quit {
wire::serve_request(&mut transport, &mut executor)?;
}

Ok(())
}

struct Executor<'a> {
local_backend: local::Backend,
quit: bool,
file_readers: Pool<'a, resources::FileReader>,
dir_readers: Pool<'a, resources::DirReader>,
mapped_module_memory_readers: Pool<'a, resources::MappedModuleMemoryReader>,
scratch_buf: &'a mut [u8],
}

#[derive(Debug, thiserror::Error, serde::Deserialize, serde::Serialize)]
pub enum Error {
#[error("an error was returned by a local syscall")]
Local(#[source] local::Error),
#[error("ran out of slots for a new MappedModuleMemoryReader")]
MappedModuleMemoryReaderSlotsExhausted,
#[error("requested an empty MappedModuleMemoryReader slot")]
EmptyMappedModuleMemoryReaderSlotRequested,
#[error("ran out of slots for a new FileReader")]
FileReaderSlotsExhausted,
#[error("requested an empty file slot")]
EmptyFileSlotRequested,
#[error("ran out of slots for a new DirReader")]
DirReaderSlotsExhausted,
#[error("requested an empty directory slot")]
EmptyDirSlotRequested,
}
Loading
Loading
0