From 5697ac0f8420ede05ded8489a35d978d883d6118 Mon Sep 17 00:00:00 2001 From: jD91mZM2 <me@krake.one> Date: Mon, 23 Jul 2018 11:26:18 +0200 Subject: [PATCH] Fix stat stack corruption and link test --- src/arpainet/src/lib.rs | 4 +-- src/platform/src/lib.rs | 35 +------------------- src/platform/src/linux/mod.rs | 15 +-------- src/platform/src/redox/mod.rs | 1 - src/platform/src/types.rs | 55 ++++++++++++++++++++++++++++++- src/signal/src/lib.rs | 5 ++- src/sys_socket/src/lib.rs | 14 ++++---- src/sys_stat/src/lib.rs | 14 +++++--- src/sys_utsname/src/lib.rs | 16 ++++----- tests/.gitignore | 2 +- tests/Makefile | 4 +-- tests/expected/unistd/stat.stderr | 0 tests/expected/unistd/stat.stdout | 4 +++ tests/unistd/link.c | 44 +++++++++++++++++++++++-- tests/unistd/stat.c | 19 +++++++++++ tests/unistd/unlink.c | 8 ----- 16 files changed, 152 insertions(+), 88 deletions(-) create mode 100644 tests/expected/unistd/stat.stderr create mode 100644 tests/expected/unistd/stat.stdout create mode 100644 tests/unistd/stat.c delete mode 100644 tests/unistd/unlink.c diff --git a/src/arpainet/src/lib.rs b/src/arpainet/src/lib.rs index b30372d9e..3ef6a8cf9 100644 --- a/src/arpainet/src/lib.rs +++ b/src/arpainet/src/lib.rs @@ -14,9 +14,9 @@ extern crate sys_socket; use core::str::FromStr; use core::{mem, ptr, slice, str}; use errno::*; -pub use netinet::in_h::*; +use netinet::in_h::in_addr; use platform::types::*; -use platform::{c_str, socklen_t, AF_INET}; +use platform::c_str; #[no_mangle] pub extern "C" fn htonl(hostlong: u32) -> u32 { diff --git a/src/platform/src/lib.rs b/src/platform/src/lib.rs index e1119e820..21088f099 100644 --- a/src/platform/src/lib.rs +++ b/src/platform/src/lib.rs @@ -36,46 +36,13 @@ mod sys; pub mod types; use alloc::Vec; -use core::{fmt, mem, ptr}; +use core::{fmt, ptr}; use types::*; #[global_allocator] static ALLOCATOR: Allocator = Allocator; -pub const AF_INET: c_int = 2; -pub const SOCK_STREAM: c_int = 1; -pub const SOCK_DGRAM: c_int = 2; -pub const SOCK_NONBLOCK: c_int = 0o4000; -pub const SOCK_CLOEXEC: c_int = 0o2000000; - -pub const SIG_BLOCK: c_int = 0; -pub const SIG_UNBLOCK: c_int = 1; -pub const SIG_SETMASK: c_int = 2; - -pub type in_addr_t = [u8; 4]; -pub type in_port_t = u16; -pub type sa_family_t = u16; -pub type socklen_t = u32; - -#[repr(C)] -pub struct sockaddr { - pub sa_family: sa_family_t, - pub data: [c_char; 14], -} - -#[repr(C)] -pub struct sigaction { - pub sa_handler: extern "C" fn(c_int), - pub sa_flags: c_ulong, - pub sa_restorer: unsafe extern "C" fn(), - pub sa_mask: sigset_t -} - -const NSIG: usize = 64; - -pub type sigset_t = [c_ulong; NSIG / (8 * mem::size_of::<c_ulong>())]; - //TODO #[thread_local] #[allow(non_upper_case_globals)] #[no_mangle] diff --git a/src/platform/src/linux/mod.rs b/src/platform/src/linux/mod.rs index 187ea1929..93750dbd8 100644 --- a/src/platform/src/linux/mod.rs +++ b/src/platform/src/linux/mod.rs @@ -1,26 +1,13 @@ use core::{mem, ptr}; +use errno; use types::*; -use *; const AT_FDCWD: c_int = -100; const AT_EMPTY_PATH: c_int = 0x1000; const AT_REMOVEDIR: c_int = 0x200; const AT_SYMLINK_NOFOLLOW: c_int = 0x100; -// Also in sys_utsname. Has to be both because cbindgen -const UTSLENGTH: usize = 65; - -#[repr(C)] -pub struct utsname { - pub sysname: [c_char; UTSLENGTH], - pub nodename: [c_char; UTSLENGTH], - pub release: [c_char; UTSLENGTH], - pub version: [c_char; UTSLENGTH], - pub machine: [c_char; UTSLENGTH], - pub domainname: [c_char; UTSLENGTH], -} - fn e(sys: usize) -> usize { if (sys as isize) < 0 && (sys as isize) >= -256 { unsafe { diff --git a/src/platform/src/redox/mod.rs b/src/platform/src/redox/mod.rs index 8ac654c37..1ed15c0c0 100644 --- a/src/platform/src/redox/mod.rs +++ b/src/platform/src/redox/mod.rs @@ -10,7 +10,6 @@ use syscall::flag::*; use syscall::{self, Result}; use types::*; -use *; #[thread_local] static mut SIG_HANDLER: Option<extern "C" fn(c_int)> = None; diff --git a/src/platform/src/types.rs b/src/platform/src/types.rs index e77751123..3299c4356 100644 --- a/src/platform/src/types.rs +++ b/src/platform/src/types.rs @@ -1,3 +1,5 @@ +use core::mem; + #[cfg(target_os = "redox")] use syscall::data::TimeSpec as redox_timespec; // Use repr(u8) as LLVM expects `void*` to be the same as `i8*` to help enable @@ -96,8 +98,59 @@ pub struct stat { pub st_rdev: dev_t, pub st_size: off_t, pub st_blksize: blksize_t, + pub st_blocks: blkcnt_t, + pub st_atim: time_t, pub st_mtim: time_t, pub st_ctim: time_t, - pub st_blocks: blkcnt_t, + + // Compared to glibc, our struct is for some reason 48 bytes too small. + // Accessing atime works, so clearly the struct isn't incorrect... + // This works. + pub _pad: [u8; 48] +} + +pub const AF_INET: c_int = 2; +pub const SOCK_STREAM: c_int = 1; +pub const SOCK_DGRAM: c_int = 2; +pub const SOCK_NONBLOCK: c_int = 0o4000; +pub const SOCK_CLOEXEC: c_int = 0o2000000; + +pub const SIG_BLOCK: c_int = 0; +pub const SIG_UNBLOCK: c_int = 1; +pub const SIG_SETMASK: c_int = 2; + +pub type in_addr_t = [u8; 4]; +pub type in_port_t = u16; +pub type sa_family_t = u16; +pub type socklen_t = u32; + +#[repr(C)] +pub struct sockaddr { + pub sa_family: sa_family_t, + pub data: [c_char; 14], +} + +#[repr(C)] +pub struct sigaction { + pub sa_handler: extern "C" fn(c_int), + pub sa_flags: c_ulong, + pub sa_restorer: unsafe extern "C" fn(), + pub sa_mask: sigset_t +} + +const NSIG: usize = 64; + +pub type sigset_t = [c_ulong; NSIG / (8 * mem::size_of::<c_ulong>())]; + +const UTSLENGTH: usize = 65; + +#[repr(C)] +pub struct utsname { + pub sysname: [c_char; UTSLENGTH], + pub nodename: [c_char; UTSLENGTH], + pub release: [c_char; UTSLENGTH], + pub version: [c_char; UTSLENGTH], + pub machine: [c_char; UTSLENGTH], + pub domainname: [c_char; UTSLENGTH], } diff --git a/src/signal/src/lib.rs b/src/signal/src/lib.rs index 833181a0b..ee6f23d16 100644 --- a/src/signal/src/lib.rs +++ b/src/signal/src/lib.rs @@ -36,7 +36,6 @@ pub use sys::*; use core::{mem, ptr}; use platform::types::*; -use platform::sigset_t; #[no_mangle] pub extern "C" fn kill(pid: pid_t, sig: c_int) -> c_int { @@ -59,11 +58,11 @@ pub unsafe extern "C" fn sigaction(sig: c_int, act: *const sigaction, oact: *mut let ptr = if !act.is_null() { _sigaction = Some((*act).clone()); _sigaction.as_mut().unwrap().sa_flags |= SA_RESTORER as c_ulong; - _sigaction.as_mut().unwrap() as *mut _ as *mut platform::sigaction + _sigaction.as_mut().unwrap() as *mut _ as *mut platform::types::sigaction } else { ptr::null_mut() }; - platform::sigaction(sig, ptr, oact as *mut platform::sigaction) + platform::sigaction(sig, ptr, oact as *mut platform::types::sigaction) } // #[no_mangle] diff --git a/src/sys_socket/src/lib.rs b/src/sys_socket/src/lib.rs index b8fa277e5..505bd5d50 100644 --- a/src/sys_socket/src/lib.rs +++ b/src/sys_socket/src/lib.rs @@ -28,7 +28,7 @@ pub unsafe extern "C" fn accept( address: *mut sockaddr, address_len: *mut socklen_t, ) -> c_int { - platform::accept(socket, address as *mut platform::sockaddr, address_len) + platform::accept(socket, address as *mut platform::types::sockaddr, address_len) } #[no_mangle] @@ -37,7 +37,7 @@ pub unsafe extern "C" fn bind( address: *const sockaddr, address_len: socklen_t, ) -> c_int { - platform::bind(socket, address as *const platform::sockaddr, address_len) + platform::bind(socket, address as *const platform::types::sockaddr, address_len) } #[no_mangle] @@ -46,7 +46,7 @@ pub unsafe extern "C" fn connect( address: *const sockaddr, address_len: socklen_t, ) -> c_int { - platform::connect(socket, address as *const platform::sockaddr, address_len) + platform::connect(socket, address as *const platform::types::sockaddr, address_len) } #[no_mangle] @@ -55,7 +55,7 @@ pub unsafe extern "C" fn getpeername( address: *mut sockaddr, address_len: *mut socklen_t, ) -> c_int { - platform::getpeername(socket, address as *mut platform::sockaddr, address_len) + platform::getpeername(socket, address as *mut platform::types::sockaddr, address_len) } #[no_mangle] @@ -64,7 +64,7 @@ pub unsafe extern "C" fn getsockname( address: *mut sockaddr, address_len: *mut socklen_t, ) -> c_int { - platform::getsockname(socket, address as *mut platform::sockaddr, address_len) + platform::getsockname(socket, address as *mut platform::types::sockaddr, address_len) } #[no_mangle] @@ -114,7 +114,7 @@ pub unsafe extern "C" fn recvfrom( buffer, length, flags, - address as *mut platform::sockaddr, + address as *mut platform::types::sockaddr, address_len, ) } @@ -143,7 +143,7 @@ pub unsafe extern "C" fn sendto( message, length, flags, - dest_addr as *const platform::sockaddr, + dest_addr as *const platform::types::sockaddr, dest_len, ) } diff --git a/src/sys_stat/src/lib.rs b/src/sys_stat/src/lib.rs index b8f67ef89..2303f8d2a 100644 --- a/src/sys_stat/src/lib.rs +++ b/src/sys_stat/src/lib.rs @@ -6,7 +6,7 @@ extern crate platform; use platform::types::*; -pub const S_IFMT: c_int = 0o0170000; +pub const S_IFMT: c_int = 0o0170000; pub const S_IFBLK: c_int = 0o060000; pub const S_IFCHR: c_int = 0o020000; pub const S_IFIFO: c_int = 0o010000; @@ -43,10 +43,16 @@ pub struct stat { pub st_rdev: dev_t, pub st_size: off_t, pub st_blksize: blksize_t, - pub st_atime: time_t, - pub st_mtime: time_t, - pub st_ctime: time_t, pub st_blocks: blkcnt_t, + + pub st_atim: time_t, + pub st_mtim: time_t, + pub st_ctim: time_t, + + // Compared to glibc, our struct is for some reason 48 bytes too small. + // Accessing atime works, so clearly the struct isn't incorrect... + // This works. + pub _pad: [u8; 48] } #[no_mangle] diff --git a/src/sys_utsname/src/lib.rs b/src/sys_utsname/src/lib.rs index 06363566c..ae6c16f4b 100644 --- a/src/sys_utsname/src/lib.rs +++ b/src/sys_utsname/src/lib.rs @@ -8,22 +8,22 @@ mod inner { use self::platform::types::*; - const LENGTH: usize = 65; + const UTSLENGTH: usize = 65; #[no_mangle] #[repr(C)] pub struct utsname { - pub sysname: [c_char; LENGTH], - pub nodename: [c_char; LENGTH], - pub release: [c_char; LENGTH], - pub version: [c_char; LENGTH], - pub machine: [c_char; LENGTH], - pub domainname: [c_char; LENGTH], + pub sysname: [c_char; UTSLENGTH], + pub nodename: [c_char; UTSLENGTH], + pub release: [c_char; UTSLENGTH], + pub version: [c_char; UTSLENGTH], + pub machine: [c_char; UTSLENGTH], + pub domainname: [c_char; UTSLENGTH], } #[no_mangle] pub unsafe extern "C" fn uname(uts: *mut utsname) -> c_int { - platform::uname(uts as *mut platform::utsname) + platform::uname(uts as *mut platform::types::utsname) } } #[cfg(target_os = "linux")] diff --git a/tests/.gitignore b/tests/.gitignore index e14391eda..c2a99bc5d 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -56,6 +56,7 @@ unistd/getopt unistd/pipe unistd/rmdir unistd/sleep +unistd/stat unistd/write waitpid wchar/mbrtowc @@ -70,4 +71,3 @@ unistd/gethostname unistd/getid unistd/link unistd/setid -unistd/unlink diff --git a/tests/Makefile b/tests/Makefile index c631eeb95..3f3f2bbe0 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -55,6 +55,7 @@ EXPECT_BINS=\ unistd/pipe \ unistd/rmdir \ unistd/sleep \ + unistd/stat \ unistd/write \ waitpid \ wchar/mbrtowc \ @@ -72,8 +73,7 @@ BINS=\ unistd/gethostname \ unistd/getid \ unistd/link \ - unistd/setid \ - unistd/unlink + unistd/setid all: $(BINS) diff --git a/tests/expected/unistd/stat.stderr b/tests/expected/unistd/stat.stderr new file mode 100644 index 000000000..e69de29bb diff --git a/tests/expected/unistd/stat.stdout b/tests/expected/unistd/stat.stdout new file mode 100644 index 000000000..74f3a92e9 --- /dev/null +++ b/tests/expected/unistd/stat.stdout @@ -0,0 +1,4 @@ +144 +st_mode: 33188 +st_size: 383 +st_blksize: 4096 diff --git a/tests/unistd/link.c b/tests/unistd/link.c index a6cf06b6e..a39286106 100644 --- a/tests/unistd/link.c +++ b/tests/unistd/link.c @@ -1,8 +1,46 @@ +#include <errno.h> #include <stdio.h> +#include <sys/stat.h> #include <unistd.h> int main(int argc, char** argv) { - link("./link.c", "./link.out"); - perror("link"); - return 0; + printf("%ld\n", sizeof(struct stat)); + + struct stat buf; + + // Stat for the inode + if (stat("unistd/link.c", &buf)) { + perror("stat"); + return 1; + } + unsigned long inode = buf.st_ino; + printf("%ld\n", inode); + + // Create the link + if (link("unistd/link.c", "link.out")) { + perror("link"); + return 1; + } + + // Make sure inodes match + if (stat("link.out", &buf)) { + perror("stat"); + } + printf("%ld\n", inode); + printf("%ld\n", buf.st_ino); + if (inode != buf.st_ino) { + puts("Created file is not a link."); + printf("unistd/link.c inode: %ld\n", inode); + printf("link.out inode: %ld\n", buf.st_ino); + } + + // Remove link + if (unlink("link.out")) { + perror("unlink"); + return 1; + } + if (!stat("link.out", &buf) || errno != ENOENT) { + perror("stat"); + return 1; + } } diff --git a/tests/unistd/stat.c b/tests/unistd/stat.c new file mode 100644 index 000000000..19236f7de --- /dev/null +++ b/tests/unistd/stat.c @@ -0,0 +1,19 @@ +#include <errno.h> +#include <stdio.h> +#include <sys/stat.h> +#include <unistd.h> + +int main() { + printf("%ld\n", sizeof(struct stat)); + + struct stat buf; + + if (stat("unistd/stat.c", &buf)) { + perror("stat"); + return 1; + } + + printf("st_mode: %u\n", buf.st_mode); + printf("st_size: %lu\n", buf.st_size); + printf("st_blksize: %lu\n", buf.st_blksize); +} diff --git a/tests/unistd/unlink.c b/tests/unistd/unlink.c deleted file mode 100644 index e8bbb517b..000000000 --- a/tests/unistd/unlink.c +++ /dev/null @@ -1,8 +0,0 @@ -#include <unistd.h> -#include <stdio.h> - -int main(int argc, char** argv) { - link("./unlink.c", "./unlink.out"); - perror("unlink"); - return 0; -} -- GitLab