From 9e9c90618c764255e468b4ea4019f945d18cf784 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Tue, 3 Oct 2023 08:05:48 -0700 Subject: [PATCH] Implement more functions. Implement more functions: - fileno, fseek - several more __*_chk functions - madvise, mlock, mlock2, munlock, msync --- c-gull/src/printf.rs | 111 +++++++++++++++++++++- c-scape/src/lib.rs | 2 +- c-scape/src/mem/chk.rs | 58 +++++++++++- c-scape/src/mm/mod.rs | 205 ++++++++++++++++++++++++++++++++++++++++ c-scape/src/mmap/mod.rs | 114 ---------------------- 5 files changed, 370 insertions(+), 120 deletions(-) create mode 100644 c-scape/src/mm/mod.rs delete mode 100644 c-scape/src/mmap/mod.rs diff --git a/c-gull/src/printf.rs b/c-gull/src/printf.rs index 632e881..ac981fe 100644 --- a/c-gull/src/printf.rs +++ b/c-gull/src/printf.rs @@ -11,7 +11,7 @@ //! [has differences with glibc]: https://docs.rs/printf-compat/0.1.1/printf_compat/output/fn.fmt_write.html#differences use errno::{set_errno, Errno}; -use libc::{c_char, c_int, c_uchar, c_void, size_t}; +use libc::{c_char, c_int, c_long, c_uchar, c_void, size_t}; use printf_compat::{format, output}; use rustix::fd::{FromRawFd, IntoRawFd}; use std::cmp::min; @@ -250,6 +250,49 @@ unsafe extern "C" fn fgets(s: *mut c_char, size: c_int, file: *mut c_void) -> *m } } +#[no_mangle] +unsafe extern "C" fn fileno(file: *mut c_void) -> c_int { + //libc!(libc::fileno(file)); + + if file == stdin { + 0 + } else if file == stdout { + 1 + } else if file == stderr { + 2 + } else { + unimplemented!("fileno with a file other than stdio") + } +} + +#[no_mangle] +unsafe extern "C" fn fseek(file: *mut c_void, offset: c_long, whence: c_int) -> c_int { + //libc!(libc::fseek(file, offset, whence)); + + let r = if file == stdin { + libc::lseek(0, offset, whence) + } else if file == stdout { + match rust_stdout().flush() { + Ok(()) => {} + Err(err) => { + set_errno(Errno(err.raw_os_error().unwrap_or(libc::EIO))); + return -1; + } + } + libc::lseek(1, offset, whence) + } else if file == stderr { + libc::lseek(2, offset, whence) + } else { + unimplemented!("fileno with a file other than stdio") + }; + + if r == -1 { + -1 + } else { + 0 + } +} + // `__*_chk` functions that have to live in c-gull because they depend on // C functions not in the libc crate, due to `VaList` being unstable. @@ -272,7 +315,7 @@ unsafe extern "C" fn __snprintf_chk( } if flag > 0 { - unimplemented!("__USE_FORTIFY_LEVEL > 1"); + unimplemented!("__USE_FORTIFY_LEVEL > 0"); } let va_list = args.as_va_list(); @@ -294,12 +337,74 @@ unsafe extern "C" fn __vsnprintf_chk( } if flag > 0 { - unimplemented!("__USE_FORTIFY_LEVEL > 1"); + unimplemented!("__USE_FORTIFY_LEVEL > 0"); } vsnprintf(ptr, len, fmt, va_list) } +// +#[no_mangle] +unsafe extern "C" fn __sprintf_chk( + ptr: *mut c_char, + flag: c_int, + strlen: size_t, + format: *const c_char, + mut args: ... +) -> c_int { + if flag > 0 { + unimplemented!("__USE_FORTIFY_LEVEL > 0"); + } + + if strlen == 0 { + __chk_fail(); + } + + // We can't check `sprintf` up front, so do a `vsnprintf` and check the + // results. + let va_list = args.as_va_list(); + let n = vsnprintf(ptr, strlen, format, va_list); + if n >= 0 && n as size_t >= strlen { + __chk_fail(); + } + n +} + +// +#[no_mangle] +unsafe extern "C" fn __fprintf_chk( + file: *mut c_void, + flag: c_int, + fmt: *const c_char, + mut args: ... +) -> c_int { + if flag > 0 { + unimplemented!("__USE_FORTIFY_LEVEL > 0"); + } + + // Our `printf` uses `printf_compat` which doesn't support `%n`. + + let va_list = args.as_va_list(); + vfprintf(file, fmt, va_list) +} + +// +#[no_mangle] +unsafe extern "C" fn __vfprintf_chk( + file: *mut c_void, + flag: c_int, + fmt: *const c_char, + va_list: VaList, +) -> c_int { + if flag > 0 { + unimplemented!("__USE_FORTIFY_LEVEL > 0"); + } + + // Our `printf` uses `printf_compat` which doesn't support `%n`. + + vfprintf(file, fmt, va_list) +} + #[no_mangle] #[allow(non_upper_case_globals)] static mut stdin: *mut c_void = unsafe { THE_STDIN.as_mut_ptr().cast() }; diff --git a/c-scape/src/lib.rs b/c-scape/src/lib.rs index 71be40f..3b256fa 100644 --- a/c-scape/src/lib.rs +++ b/c-scape/src/lib.rs @@ -55,7 +55,7 @@ mod math; mod mem; #[cfg(not(target_os = "wasi"))] -mod mmap; +mod mm; mod net; diff --git a/c-scape/src/mem/chk.rs b/c-scape/src/mem/chk.rs index 25053be..486b448 100644 --- a/c-scape/src/mem/chk.rs +++ b/c-scape/src/mem/chk.rs @@ -1,10 +1,10 @@ //! `__*_chk` functions. -use libc::{c_char, c_void, size_t}; +use libc::{c_char, c_int, c_void, size_t}; // #[no_mangle] -unsafe extern "C" fn __chk_fail() { +unsafe extern "C" fn __chk_fail() -> ! { rustix::io::write( rustix::stdio::stderr(), b"A buffer overflow has been detected.\n", @@ -28,6 +28,42 @@ unsafe extern "C" fn __memcpy_chk( libc::memcpy(dest, src, len) } +// +#[no_mangle] +unsafe extern "C" fn __memset_chk( + dest: *mut c_void, + c: c_int, + len: size_t, + destlen: size_t, +) -> *mut c_void { + if destlen < len { + __chk_fail(); + } + + libc::memset(dest, c, len) +} + +// +#[no_mangle] +unsafe extern "C" fn __strcat_chk( + dest: *mut c_char, + src: *const c_char, + destlen: size_t, +) -> *mut c_char { + let dest_strlen = libc::strlen(dest); + let src_strlen = libc::strlen(src); + + if let Some(sum) = dest_strlen.checked_add(src_strlen) { + if let Some(sum) = sum.checked_add(1) { + if sum <= destlen { + return libc::strcat(dest, src); + } + } + } + + __chk_fail() +} + // #[no_mangle] unsafe extern "C" fn __strncpy_chk( @@ -42,3 +78,21 @@ unsafe extern "C" fn __strncpy_chk( libc::strncpy(dest, src, len) } + +// +#[no_mangle] +unsafe extern "C" fn __fgets_chk( + s: *mut c_char, + size: size_t, + strsize: c_int, + stream: *mut c_void, +) -> *mut c_char { + if strsize < 0 { + __chk_fail(); + } + if strsize as size_t > size { + __chk_fail(); + } + + libc::fgets(s, strsize, stream.cast()) +} diff --git a/c-scape/src/mm/mod.rs b/c-scape/src/mm/mod.rs new file mode 100644 index 0000000..d9b9674 --- /dev/null +++ b/c-scape/src/mm/mod.rs @@ -0,0 +1,205 @@ +use rustix::fd::BorrowedFd; +use rustix::mm::{MapFlags, MprotectFlags, MremapFlags, ProtFlags}; + +use core::ffi::c_void; +use errno::{set_errno, Errno}; +use libc::{c_int, c_uint, off64_t, off_t, size_t}; + +use crate::convert_res; + +#[no_mangle] +unsafe extern "C" fn mmap( + addr: *mut c_void, + length: size_t, + prot: c_int, + flags: c_int, + fd: c_int, + offset: off_t, +) -> *mut c_void { + libc!(libc::mmap(addr, length, prot, flags, fd, offset)); + + mmap64(addr, length, prot, flags, fd, offset as off64_t) +} + +#[no_mangle] +unsafe extern "C" fn mmap64( + addr: *mut c_void, + length: size_t, + prot: c_int, + flags: c_int, + fd: c_int, + offset: off64_t, +) -> *mut c_void { + libc!(libc::mmap64(addr, length, prot, flags, fd, offset)); + + let anon = flags & libc::MAP_ANONYMOUS == libc::MAP_ANONYMOUS; + let prot = ProtFlags::from_bits(prot as _).unwrap(); + let flags = MapFlags::from_bits((flags & !libc::MAP_ANONYMOUS) as _).unwrap(); + match convert_res(if anon { + rustix::mm::mmap_anonymous(addr, length, prot, flags) + } else { + rustix::mm::mmap( + addr, + length, + prot, + flags, + BorrowedFd::borrow_raw(fd), + offset as _, + ) + }) { + Some(ptr) => ptr, + None => libc::MAP_FAILED, + } +} + +#[no_mangle] +unsafe extern "C" fn munmap(ptr: *mut c_void, len: size_t) -> c_int { + libc!(libc::munmap(ptr, len)); + + match convert_res(rustix::mm::munmap(ptr, len)) { + Some(()) => 0, + None => -1, + } +} + +#[no_mangle] +unsafe extern "C" fn mremap( + old_address: *mut c_void, + old_size: size_t, + new_size: size_t, + flags: c_int, + mut args: ... +) -> *mut c_void { + if (flags & libc::MREMAP_FIXED) == libc::MREMAP_FIXED { + let new_address = args.arg::<*mut c_void>(); + libc!(libc::mremap( + old_address, + old_size, + new_size, + flags, + new_address + )); + + let flags = flags & !libc::MREMAP_FIXED; + let flags = MremapFlags::from_bits(flags as _).unwrap(); + match convert_res(rustix::mm::mremap_fixed( + old_address, + old_size, + new_size, + flags, + new_address, + )) { + Some(new_address) => new_address, + None => libc::MAP_FAILED, + } + } else { + libc!(libc::mremap(old_address, old_size, new_size, flags)); + + let flags = MremapFlags::from_bits(flags as _).unwrap(); + match convert_res(rustix::mm::mremap(old_address, old_size, new_size, flags)) { + Some(new_address) => new_address, + None => libc::MAP_FAILED, + } + } +} + +#[no_mangle] +unsafe extern "C" fn mprotect(addr: *mut c_void, length: size_t, prot: c_int) -> c_int { + libc!(libc::mprotect(addr, length, prot)); + + let prot = MprotectFlags::from_bits(prot as _).unwrap(); + match convert_res(rustix::mm::mprotect(addr, length, prot)) { + Some(()) => 0, + None => -1, + } +} + +#[no_mangle] +unsafe extern "C" fn madvise(addr: *mut c_void, length: size_t, advice: c_int) -> c_int { + libc!(libc::madvise(addr, length, advice)); + + use rustix::mm::Advice; + + let advice = match advice { + libc::MADV_NORMAL => Advice::Normal, + libc::MADV_SEQUENTIAL => Advice::Sequential, + libc::MADV_RANDOM => Advice::Random, + libc::MADV_WILLNEED => Advice::WillNeed, + libc::MADV_DONTNEED => Advice::LinuxDontNeed, + libc::MADV_FREE => Advice::LinuxFree, + libc::MADV_REMOVE => Advice::LinuxRemove, + libc::MADV_DONTFORK => Advice::LinuxDontFork, + libc::MADV_DOFORK => Advice::LinuxDoFork, + libc::MADV_HWPOISON => Advice::LinuxHwPoison, + #[cfg(not(any( + target_arch = "mips", + target_arch = "mips32r6", + target_arch = "mips64", + target_arch = "mips64r6" + )))] + libc::MADV_SOFT_OFFLINE => Advice::LinuxSoftOffline, + libc::MADV_MERGEABLE => Advice::LinuxMergeable, + libc::MADV_UNMERGEABLE => Advice::LinuxUnmergeable, + libc::MADV_HUGEPAGE => Advice::LinuxHugepage, + libc::MADV_NOHUGEPAGE => Advice::LinuxNoHugepage, + libc::MADV_DONTDUMP => Advice::LinuxDontDump, + libc::MADV_DODUMP => Advice::LinuxDoDump, + libc::MADV_WIPEONFORK => Advice::LinuxWipeOnFork, + libc::MADV_KEEPONFORK => Advice::LinuxKeepOnFork, + libc::MADV_COLD => Advice::LinuxCold, + libc::MADV_PAGEOUT => Advice::LinuxPageOut, + libc::MADV_POPULATE_READ => Advice::LinuxPopulateRead, + libc::MADV_POPULATE_WRITE => Advice::LinuxPopulateWrite, + libc::MADV_DONTNEED_LOCKED => Advice::LinuxDontneedLocked, + _ => { + set_errno(Errno(libc::EINVAL)); + return -1; + } + }; + match convert_res(rustix::mm::madvise(addr, length, advice)) { + Some(()) => 0, + None => -1, + } +} + +#[no_mangle] +unsafe extern "C" fn mlock(addr: *mut c_void, len: size_t) -> c_int { + libc!(libc::mlock(addr, len)); + + match convert_res(rustix::mm::mlock(addr as *mut c_void, len)) { + Some(()) => 0, + None => -1, + } +} + +#[no_mangle] +unsafe extern "C" fn mlock2(addr: *const c_void, len: size_t, flags: c_uint) -> c_int { + libc!(libc::mlock2(addr, len, flags)); + + let flags = rustix::mm::MlockFlags::from_bits_retain(flags); + match convert_res(rustix::mm::mlock_with(addr as *mut c_void, len, flags)) { + Some(()) => 0, + None => -1, + } +} + +#[no_mangle] +unsafe extern "C" fn munlock(addr: *const c_void, len: size_t) -> c_int { + libc!(libc::munlock(addr, len)); + + match convert_res(rustix::mm::munlock(addr as *mut c_void, len)) { + Some(()) => 0, + None => -1, + } +} + +#[no_mangle] +unsafe extern "C" fn msync(addr: *mut c_void, len: size_t, flags: c_int) -> c_int { + libc!(libc::msync(addr, len, flags)); + + let flags = rustix::mm::MsyncFlags::from_bits_retain(flags as _); + match convert_res(rustix::mm::msync(addr, len, flags)) { + Some(()) => 0, + None => -1, + } +} diff --git a/c-scape/src/mmap/mod.rs b/c-scape/src/mmap/mod.rs deleted file mode 100644 index 4952ee7..0000000 --- a/c-scape/src/mmap/mod.rs +++ /dev/null @@ -1,114 +0,0 @@ -use rustix::fd::BorrowedFd; -use rustix::mm::{MapFlags, MprotectFlags, MremapFlags, ProtFlags}; - -use core::ffi::c_void; -use libc::{c_int, off64_t, off_t}; - -use crate::convert_res; - -#[no_mangle] -unsafe extern "C" fn mmap( - addr: *mut c_void, - length: usize, - prot: c_int, - flags: c_int, - fd: c_int, - offset: off_t, -) -> *mut c_void { - libc!(libc::mmap(addr, length, prot, flags, fd, offset)); - - mmap64(addr, length, prot, flags, fd, offset as off64_t) -} - -#[no_mangle] -unsafe extern "C" fn mmap64( - addr: *mut c_void, - length: usize, - prot: c_int, - flags: c_int, - fd: c_int, - offset: off64_t, -) -> *mut c_void { - libc!(libc::mmap64(addr, length, prot, flags, fd, offset)); - - let anon = flags & libc::MAP_ANONYMOUS == libc::MAP_ANONYMOUS; - let prot = ProtFlags::from_bits(prot as _).unwrap(); - let flags = MapFlags::from_bits((flags & !libc::MAP_ANONYMOUS) as _).unwrap(); - match convert_res(if anon { - rustix::mm::mmap_anonymous(addr, length, prot, flags) - } else { - rustix::mm::mmap( - addr, - length, - prot, - flags, - BorrowedFd::borrow_raw(fd), - offset as _, - ) - }) { - Some(ptr) => ptr, - None => libc::MAP_FAILED, - } -} - -#[no_mangle] -unsafe extern "C" fn munmap(ptr: *mut c_void, len: usize) -> c_int { - libc!(libc::munmap(ptr, len)); - - match convert_res(rustix::mm::munmap(ptr, len)) { - Some(()) => 0, - None => -1, - } -} - -#[no_mangle] -unsafe extern "C" fn mremap( - old_address: *mut c_void, - old_size: usize, - new_size: usize, - flags: c_int, - mut args: ... -) -> *mut c_void { - if (flags & libc::MREMAP_FIXED) == libc::MREMAP_FIXED { - let new_address = args.arg::<*mut c_void>(); - libc!(libc::mremap( - old_address, - old_size, - new_size, - flags, - new_address - )); - - let flags = flags & !libc::MREMAP_FIXED; - let flags = MremapFlags::from_bits(flags as _).unwrap(); - match convert_res(rustix::mm::mremap_fixed( - old_address, - old_size, - new_size, - flags, - new_address, - )) { - Some(new_address) => new_address, - None => libc::MAP_FAILED, - } - } else { - libc!(libc::mremap(old_address, old_size, new_size, flags)); - - let flags = MremapFlags::from_bits(flags as _).unwrap(); - match convert_res(rustix::mm::mremap(old_address, old_size, new_size, flags)) { - Some(new_address) => new_address, - None => libc::MAP_FAILED, - } - } -} - -#[no_mangle] -unsafe extern "C" fn mprotect(addr: *mut c_void, length: usize, prot: c_int) -> c_int { - libc!(libc::mprotect(addr, length, prot)); - - let prot = MprotectFlags::from_bits(prot as _).unwrap(); - match convert_res(rustix::mm::mprotect(addr, length, prot)) { - Some(()) => 0, - None => -1, - } -}