From 51e0657d496651fbbc73b34d85f949206491197a Mon Sep 17 00:00:00 2001 From: edef Date: Fri, 29 Jul 2022 22:20:08 +0000 Subject: ripple/minitrace: strictly verify fd arguments Change-Id: I9210105171314d036dc12a1b36ce01aaeeb2466d --- ripple/minitrace/src/main.rs | 90 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 70 insertions(+), 20 deletions(-) diff --git a/ripple/minitrace/src/main.rs b/ripple/minitrace/src/main.rs index 6d5dbc5..4735603 100644 --- a/ripple/minitrace/src/main.rs +++ b/ripple/minitrace/src/main.rs @@ -19,6 +19,7 @@ use { convert::TryInto, env, ffi::CString, + fmt::{self, Debug}, fs::File, io::{self, BufRead, Seek, SeekFrom}, os::unix::process::CommandExt, @@ -26,9 +27,6 @@ use { }, }; -#[cfg(test)] -use std::fmt::{self, Debug}; - // TODO(edef): consider implementing this in terms of TID? // tgids are a strict subset of tids #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -316,8 +314,6 @@ impl SyscallArg for *mut u8 { } } -type FileDesc = i32; - type SigAction = (); type SysInfo = (); type Tms = (); @@ -342,7 +338,7 @@ define_syscalls! { fn read(fd: FileDesc, buf: *mut u8, count: usize) -> i64 = 0; fn write(fd: FileDesc, buf: *const u8, count: usize) -> i64 = 1; fn close(fd: FileDesc) -> i64 = 3; - fn mmap(addr: u64, len: u64, prot: ProtFlags, flags: MapFlags, fd: FileDesc, off: u64) -> i64 = 9; + fn mmap(addr: u64, len: u64, prot: ProtFlags, flags: MapFlags, fd: Option, off: u64) -> i64 = 9; fn mprotect(addr: u64, len: usize, prot: ProtFlags) -> i64 = 10; fn brk(brk: u64) -> i64 = 12; fn rt_sigaction(sig: Signal, act: *const SigAction, oact: *mut SigAction, sigsetsize: usize) -> i64 = 13; @@ -356,8 +352,8 @@ define_syscalls! { fn arch_prctl(option: ArchOption, arg2: u64) -> i64 = 158; fn set_tid_address(tidptr: *mut i32) -> i64 = 218; fn exit_group(error_code: i32) -> i64 = 231; - fn openat(dfd: FileDesc, filename: CString, flags: OpenFlags, mode: FileMode) -> i64 = 257; - fn newfstatat(dfd: FileDesc, filename: CString, statbuf: *mut Stat, flags: AtFlags) -> i64 = 262; + fn openat(dfd: DirFd, filename: CString, flags: OpenFlags, mode: FileMode) -> i64 = 257; + fn newfstatat(dfd: DirFd, filename: CString, statbuf: *mut Stat, flags: AtFlags) -> i64 = 262; fn set_robust_list(head: *mut RobustListHead, len: usize) -> i64 = 273; fn prlimit64(pid: i32, resource: ResourceLimit, new_rlim: *const RLimit64, old_rlim: *mut RLimit64) -> i64 = 302; fn getrandom(ubuf: *mut u8, len: usize, flags: GrndFlags) -> i64 = 318; @@ -468,11 +464,15 @@ fn check_syscall(entry: &SyscallEntry) -> bool { if addr % 4096 != 0 { return false; } - if fd == !0 { - return flags.contains(MapFlags::ANONYMOUS); - } else { - return flags.intersection(MapFlags::PRIVATE | MapFlags::ANONYMOUS) - == MapFlags::PRIVATE; + + match fd { + None => { + return flags.contains(MapFlags::ANONYMOUS); + } + Some(_) => { + return flags.intersection(MapFlags::PRIVATE | MapFlags::ANONYMOUS) + == MapFlags::PRIVATE; + } } } SyscallEntry::mprotect { addr, len, prot: _ } => { @@ -509,11 +509,11 @@ fn check_syscall(entry: &SyscallEntry) -> bool { flags, mode: _, } => { - if dfd != AT_FDCWD { + if dfd != DirFd::Cwd { return false; } - println!("openat(AT_FDCWD, {filename:?}, {flags:?}, ..)"); + println!("openat({dfd:?}, {filename:?}, {flags:?}, ..)"); } SyscallEntry::newfstatat { dfd, @@ -526,11 +526,8 @@ fn check_syscall(entry: &SyscallEntry) -> bool { // empty path without AT_EMPTY_PATH return false; } - (AT_FDCWD, _) => { - println!("newfstatat(AT_FDCWD, {filename:?}, .., {flags:?})"); - } - (_, b"") if dfd >= 0 => { - println!("newfstatat({dfd}, {filename:?}, .., {flags:?})"); + (DirFd::Cwd, _) | (_, b"") => { + println!("newfstatat({dfd:?}, {filename:?}, .., {flags:?})"); } _ => { return false; @@ -642,3 +639,56 @@ syscall_enums! { SEGV = 11 => SIGSEGV, } } + +#[derive(Clone, Copy, Eq, PartialEq)] +struct FileDesc(i32); + +impl Debug for FileDesc { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.0) + } +} + +impl SyscallArg for FileDesc { + fn try_from_reg(reg: u64) -> Option { + Some(match i32::try_from_reg(reg)? { + fd @ 0..=i32::MAX => FileDesc(fd), + _ => return None, + }) + } +} + +impl SyscallArg for Option { + fn try_from_reg(reg: u64) -> Option { + Some(match i32::try_from_reg(reg)? { + -1 => None, + fd @ 0..=i32::MAX => Some(FileDesc(fd)), + _ => return None, + }) + } +} + +#[derive(Clone, Copy, Eq, PartialEq)] +enum DirFd { + Cwd, + Fd(FileDesc), +} + +impl Debug for DirFd { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + DirFd::Cwd => write!(f, "AT_FDCWD"), + DirFd::Fd(FileDesc(fd)) => write!(f, "{fd}"), + } + } +} + +impl SyscallArg for DirFd { + fn try_from_reg(reg: u64) -> Option { + Some(match i32::try_from_reg(reg)? { + AT_FDCWD => Self::Cwd, + fd @ 0..=i32::MAX => DirFd::Fd(FileDesc(fd)), + _ => return None, + }) + } +} -- cgit 1.4.1