Skip to content

Commit

Permalink
Implement more functions.
Browse files Browse the repository at this point in the history
Implement more functions:
 - fileno, fseek
 - several more __*_chk functions
 - madvise, mlock, mlock2, munlock, msync
  • Loading branch information
sunfishcode committed Oct 4, 2023
1 parent 4e43981 commit 99ba028
Show file tree
Hide file tree
Showing 5 changed files with 365 additions and 120 deletions.
111 changes: 108 additions & 3 deletions c-gull/src/printf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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.

Expand All @@ -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();
Expand All @@ -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)
}

// <https://refspecs.linuxbase.org/LSB_4.0.0/LSB-Core-generic/LSB-Core-generic/libc---sprintf-chk-1.html>
#[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
}

// <https://refspecs.linuxbase.org/LSB_4.0.0/LSB-Core-generic/LSB-Core-generic/libc---fprintf-chk-1.html>
#[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)
}

// <https://refspecs.linuxbase.org/LSB_4.0.0/LSB-Core-generic/LSB-Core-generic/libc---vfprintf-chk-1.html>
#[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() };
Expand Down
2 changes: 1 addition & 1 deletion c-scape/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ mod math;
mod mem;

#[cfg(not(target_os = "wasi"))]
mod mmap;
mod mm;

mod net;

Expand Down
58 changes: 56 additions & 2 deletions c-scape/src/mem/chk.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
//! `__*_chk` functions.

use libc::{c_char, c_void, size_t};
use libc::{c_char, c_int, c_void, size_t};

// <https://refspecs.linuxbase.org/LSB_4.0.0/LSB-Core-generic/LSB-Core-generic/libc---chk-fail-1.html>
#[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",
Expand All @@ -28,6 +28,42 @@ unsafe extern "C" fn __memcpy_chk(
libc::memcpy(dest, src, len)
}

// <http://refspecs.linux-foundation.org/LSB_4.0.0/LSB-Core-generic/LSB-Core-generic/libc---memset-chk-1.html>
#[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)
}

// <https://refspecs.linuxbase.org/LSB_4.0.0/LSB-Core-generic/LSB-Core-generic/libc---strcat-chk-1.html>
#[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()
}

// <https://refspecs.linuxbase.org/LSB_4.0.0/LSB-Core-generic/LSB-Core-generic/libc---strncpy-chk-1.html>
#[no_mangle]
unsafe extern "C" fn __strncpy_chk(
Expand All @@ -42,3 +78,21 @@ unsafe extern "C" fn __strncpy_chk(

libc::strncpy(dest, src, len)
}

// <https://refspecs.linuxbase.org/LSB_4.0.0/LSB-Core-generic/LSB-Core-generic/libc---fgets-chk-1.html>
#[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())
}
Loading

0 comments on commit 99ba028

Please sign in to comment.