From 86a9f26dae6337a5914d6813d37066a3bd0155fe Mon Sep 17 00:00:00 2001 From: Thomas de Zeeuw Date: Mon, 22 Dec 2025 18:42:42 +0100 Subject: [PATCH 1/3] Add a shim for uname systemcall --- src/shims/unix/env.rs | 59 +++++++++++++++++++++++++++++-- src/shims/unix/foreign_items.rs | 10 ++++++ tests/pass-dep/libc/libc-uname.rs | 30 ++++++++++++++++ 3 files changed, 96 insertions(+), 3 deletions(-) create mode 100644 tests/pass-dep/libc/libc-uname.rs diff --git a/src/shims/unix/env.rs b/src/shims/unix/env.rs index 41bf70c346..852f5d3d7b 100644 --- a/src/shims/unix/env.rs +++ b/src/shims/unix/env.rs @@ -1,6 +1,6 @@ -use std::env; -use std::ffi::{OsStr, OsString}; -use std::io::ErrorKind; +use std::ffi::{CStr, OsStr, OsString}; +use std::io::{self, ErrorKind}; +use std::{env, slice}; use rustc_abi::{FieldIdx, Size}; use rustc_data_structures::fx::FxHashMap; @@ -272,6 +272,59 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { interp_ok(Scalar::from_u32(this.get_current_tid())) } + fn uname(&mut self, uname: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> { + let this = self.eval_context_mut(); + this.assert_target_os_is_unix("uname"); + + let uname_ptr = this.read_pointer(uname)?; + if this.ptr_is_null(uname_ptr)? { + return this.set_last_error_and_return_i32(LibcError("EFAULT")); + } + + let mut uname_buf = unsafe { std::mem::zeroed() }; + if this.machine.communicate() { + let result = unsafe { libc::uname(&mut uname_buf) }; + if result != 0 { + let err = this.io_error_to_errnum(io::Error::last_os_error())?; + this.set_last_error(err)?; + return interp_ok(Scalar::from_i32(result)); + } + } else { + fn write_slice(dst: &mut [i8], src: &[u8]) { + dst[..src.len()].copy_from_slice(unsafe { + slice::from_raw_parts(src.as_ptr().cast(), src.len()) + }); + } + write_slice(uname_buf.sysname.as_mut_slice(), b"Linux"); + write_slice(uname_buf.nodename.as_mut_slice(), b"Miri"); + write_slice(uname_buf.release.as_mut_slice(), b"6.18.1-arch1-2"); + write_slice( + uname_buf.version.as_mut_slice(), + b"#1 SMP PREEMPT_DYNAMIC Sat, 13 Dec 2025 18:23:21 +0000", + ); + write_slice(uname_buf.machine.as_mut_slice(), b"x86_64"); + write_slice(uname_buf.domainname.as_mut_slice(), b"(none)"); + } + + let uname = this.deref_pointer_as(uname, this.libc_ty_layout("utsname"))?; + let values = [ + ("sysname", uname_buf.sysname.as_ptr()), + ("nodename", uname_buf.nodename.as_ptr()), + ("release", uname_buf.release.as_ptr()), + ("version", uname_buf.version.as_ptr()), + ("machine", uname_buf.machine.as_ptr()), + ("domainname", uname_buf.domainname.as_ptr()), + ]; + for (name, value) in values { + let value = unsafe { CStr::from_ptr(value) }.to_bytes(); + let field = this.project_field_named(&uname, name)?; + let size = field.layout().layout.size().bytes(); + let (written, _) = this.write_c_str(value, field.ptr(), size)?; + assert!(written); // All values should fit. + } + interp_ok(Scalar::from_i32(0)) + } + /// The Apple-specific `int pthread_threadid_np(pthread_t thread, uint64_t *thread_id)`, which /// allows querying the ID for arbitrary threads, identified by their pthread_t. /// diff --git a/src/shims/unix/foreign_items.rs b/src/shims/unix/foreign_items.rs index 64b8376ff4..430a4f0430 100644 --- a/src/shims/unix/foreign_items.rs +++ b/src/shims/unix/foreign_items.rs @@ -172,6 +172,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let result = this.getpid()?; this.write_scalar(result, dest)?; } + "uname" => { + let [uname] = this.check_shim_sig( + shim_sig!(extern "C" fn(*mut _) -> i32), + link_name, + abi, + args, + )?; + let result = this.uname(uname)?; + this.write_scalar(result, dest)?; + } "sysconf" => { let [val] = this.check_shim_sig( shim_sig!(extern "C" fn(i32) -> isize), diff --git a/tests/pass-dep/libc/libc-uname.rs b/tests/pass-dep/libc/libc-uname.rs new file mode 100644 index 0000000000..23fc7781f0 --- /dev/null +++ b/tests/pass-dep/libc/libc-uname.rs @@ -0,0 +1,30 @@ +use std::ffi::CStr; +use std::{io, ptr}; + +fn main() { + test_ok(); + test_null_ptr(); +} + +fn test_ok() { + // SAFETY: all zeros for `utsname` is valid. + let mut uname: libc::utsname = unsafe { std::mem::zeroed() }; + let result = unsafe { libc::uname(&mut uname) }; + if result != 0 { + panic!("failed to call uname"); + } + + // These values are only correct when running isolated. + assert_eq!(unsafe { CStr::from_ptr(&uname.sysname as *const _) }, c"Linux"); + assert_eq!(unsafe { CStr::from_ptr(&uname.nodename as *const _) }, c"Miri"); + assert_eq!(unsafe { CStr::from_ptr(&uname.release as *const _) }, c"6.18.1-arch1-2"); + assert_eq!(unsafe { CStr::from_ptr(&uname.version as *const _) }, c"#1 SMP PREEMPT_DYNAMIC Sat, 13 Dec 2025 18:23:21 +0000"); + assert_eq!(unsafe { CStr::from_ptr(&uname.machine as *const _) }, c"x86_64"); + assert_eq!(unsafe { CStr::from_ptr(&uname.domainname as *const _) }, c"(none)"); +} + +fn test_null_ptr() { + let result = unsafe { libc::uname(ptr::null_mut()) }; + assert_eq!(result, -1); + assert_eq!(io::Error::last_os_error().raw_os_error(), Some(libc::EFAULT)); +} From c8999eb73e710c6f0141c9d4882581349030c408 Mon Sep 17 00:00:00 2001 From: Thomas de Zeeuw Date: Mon, 22 Dec 2025 18:54:48 +0100 Subject: [PATCH 2/3] Add cfg attributes for domainname Seems like most the BSD family (FreeBSD, OpenBSD, NetBSD, macOS) doesn't have this fields, only Linux. --- src/shims/unix/env.rs | 2 ++ tests/pass-dep/libc/libc-uname.rs | 6 +++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/shims/unix/env.rs b/src/shims/unix/env.rs index 852f5d3d7b..971449d944 100644 --- a/src/shims/unix/env.rs +++ b/src/shims/unix/env.rs @@ -303,6 +303,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { b"#1 SMP PREEMPT_DYNAMIC Sat, 13 Dec 2025 18:23:21 +0000", ); write_slice(uname_buf.machine.as_mut_slice(), b"x86_64"); + #[cfg(any(target_os = "linux", target_os = "android"))] write_slice(uname_buf.domainname.as_mut_slice(), b"(none)"); } @@ -313,6 +314,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ("release", uname_buf.release.as_ptr()), ("version", uname_buf.version.as_ptr()), ("machine", uname_buf.machine.as_ptr()), + #[cfg(any(target_os = "linux", target_os = "android"))] ("domainname", uname_buf.domainname.as_ptr()), ]; for (name, value) in values { diff --git a/tests/pass-dep/libc/libc-uname.rs b/tests/pass-dep/libc/libc-uname.rs index 23fc7781f0..53390eafea 100644 --- a/tests/pass-dep/libc/libc-uname.rs +++ b/tests/pass-dep/libc/libc-uname.rs @@ -18,8 +18,12 @@ fn test_ok() { assert_eq!(unsafe { CStr::from_ptr(&uname.sysname as *const _) }, c"Linux"); assert_eq!(unsafe { CStr::from_ptr(&uname.nodename as *const _) }, c"Miri"); assert_eq!(unsafe { CStr::from_ptr(&uname.release as *const _) }, c"6.18.1-arch1-2"); - assert_eq!(unsafe { CStr::from_ptr(&uname.version as *const _) }, c"#1 SMP PREEMPT_DYNAMIC Sat, 13 Dec 2025 18:23:21 +0000"); + assert_eq!( + unsafe { CStr::from_ptr(&uname.version as *const _) }, + c"#1 SMP PREEMPT_DYNAMIC Sat, 13 Dec 2025 18:23:21 +0000" + ); assert_eq!(unsafe { CStr::from_ptr(&uname.machine as *const _) }, c"x86_64"); + #[cfg(any(target_os = "linux", target_os = "android"))] assert_eq!(unsafe { CStr::from_ptr(&uname.domainname as *const _) }, c"(none)"); } From afba9c9e7d4e30af2989aad201546bfa3411ca1b Mon Sep 17 00:00:00 2001 From: Thomas de Zeeuw Date: Mon, 22 Dec 2025 18:58:23 +0100 Subject: [PATCH 3/3] Fix type issue x86_64 uses i8, aarch64 seems to use u8. --- src/shims/unix/env.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/unix/env.rs b/src/shims/unix/env.rs index 971449d944..3dd0bc9cc0 100644 --- a/src/shims/unix/env.rs +++ b/src/shims/unix/env.rs @@ -290,7 +290,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { return interp_ok(Scalar::from_i32(result)); } } else { - fn write_slice(dst: &mut [i8], src: &[u8]) { + fn write_slice(dst: &mut [libc::c_char], src: &[u8]) { dst[..src.len()].copy_from_slice(unsafe { slice::from_raw_parts(src.as_ptr().cast(), src.len()) });