Clarify the UTS names in `/proc/version`

This commit is contained in:
Ruihan Li 2025-12-11 13:46:46 +08:00 committed by Jianfeng Jiang
parent 0cfc539608
commit d299cf4db4
5 changed files with 70 additions and 81 deletions

View File

@ -12,7 +12,7 @@ use crate::{
procfs::template::{FileOps, ProcFileBuilder},
utils::{Inode, mkmod},
},
net::UtsNamespace,
net::uts_ns::UtsName,
prelude::*,
};
@ -35,14 +35,12 @@ impl FileOps for VersionFileOps {
fn read_at(&self, offset: usize, writer: &mut VmWriter) -> Result<usize> {
let mut printer = VmPrinter::new_skip(writer, offset);
// Get UTS namespace information from the init namespace
let uts_name = UtsNamespace::get_init_singleton().uts_name();
// Get information from `UtsName`.
let sysname = UtsName::SYSNAME;
let release = UtsName::RELEASE;
let version = UtsName::VERSION;
let sysname = uts_name.sysname()?;
let release = uts_name.release()?;
let version = uts_name.version()?;
// Get info from compile environment variables
// Get information from compile-time environment variables.
let compile_by = option_env!("OSDK_BUILD_USERNAME").unwrap_or("unknown");
let compile_host = option_env!("OSDK_BUILD_HOSTNAME").unwrap_or("unknown");
let compiler = option_env!("OSDK_BUILD_RUSTC").unwrap_or("unknown");

View File

@ -2,9 +2,7 @@
pub mod iface;
pub mod socket;
mod uts_ns;
pub use uts_ns::UtsNamespace;
pub mod uts_ns;
pub fn init() {
iface::init();

View File

@ -16,40 +16,18 @@ pub struct UtsNamespace {
}
impl UtsNamespace {
/// Returns the Linux machine name for the current architecture.
const fn machine_name() -> &'static [u8] {
#[cfg(target_arch = "x86_64")]
return b"x86_64";
#[cfg(target_arch = "riscv64")]
return b"riscv64";
#[cfg(target_arch = "loongarch64")]
return b"loongarch64";
#[cfg(target_arch = "aarch64")]
return b"aarch64";
#[cfg(not(any(
target_arch = "x86_64",
target_arch = "riscv64",
target_arch = "loongarch64",
target_arch = "aarch64"
)))]
compile_error!("Unsupported architecture for UTS namespace machine name");
}
/// Returns a reference to the singleton initial UTS namespace.
pub fn get_init_singleton() -> &'static Arc<UtsNamespace> {
static INIT: Once<Arc<UtsNamespace>> = Once::new();
INIT.call_once(|| {
// We intentionally report Linux-like UTS values instead of Asterinas' real
// name and version. These spoofed values satisfy glibc, which inspects
// uname fields (sysname, release, version, etc.) and expects Linux-compatible data.
let version_str = option_env!("OSDK_BUILD_TIMESTAMP").unwrap_or("unknown");
let uts_name = UtsName {
sysname: padded(b"Linux"),
nodename: padded(b"WHITLEY"),
release: padded(b"5.13.0"),
version: padded(version_str.as_bytes()),
machine: padded(Self::machine_name()),
sysname: padded(UtsName::SYSNAME.as_bytes()),
// Reference: <https://elixir.bootlin.com/linux/v6.16/source/init/Kconfig#L408>.
nodename: padded(b"(none)"),
release: padded(UtsName::RELEASE.as_bytes()),
version: padded(UtsName::VERSION.as_bytes()),
machine: padded(UtsName::MACHINE.as_bytes()),
// Reference: <https://elixir.bootlin.com/linux/v6.16/source/include/linux/uts.h#L17>.
domainname: padded(b"(none)"),
};
@ -119,46 +97,6 @@ impl UtsNamespace {
}
}
const UTS_FIELD_LEN: usize = 65;
#[derive(Debug, Clone, Copy, Pod)]
#[repr(C)]
pub struct UtsName {
sysname: [u8; UTS_FIELD_LEN],
nodename: [u8; UTS_FIELD_LEN],
release: [u8; UTS_FIELD_LEN],
version: [u8; UTS_FIELD_LEN],
machine: [u8; UTS_FIELD_LEN],
domainname: [u8; UTS_FIELD_LEN],
}
impl UtsName {
/// Returns the system name as UTF-8 string.
pub fn sysname(&self) -> Result<&str> {
Self::cstr_bytes_to_str(&self.sysname)
}
/// Returns the release name as UTF-8 string.
pub fn release(&self) -> Result<&str> {
Self::cstr_bytes_to_str(&self.release)
}
/// Returns the version name as UTF-8 string.
pub fn version(&self) -> Result<&str> {
Self::cstr_bytes_to_str(&self.version)
}
/// Converts a C string bytes to a UTF-8 string.
fn cstr_bytes_to_str(cstr_bytes: &[u8]) -> Result<&str> {
CStr::from_bytes_until_nul(cstr_bytes)
.map_err(|_| Error::with_message(Errno::EINVAL, "not a null-terminated C string"))
.and_then(|cstr| {
cstr.to_str()
.map_err(|_| Error::with_message(Errno::EINVAL, "not a UTF-8 string"))
})
}
}
fn copy_uts_field_from_user(addr: Vaddr, len: u32, ctx: &Context) -> Result<[u8; UTS_FIELD_LEN]> {
if len.cast_signed() < 0 {
return_errno_with_message!(Errno::EINVAL, "the buffer length cannot be negative");
@ -184,3 +122,58 @@ fn copy_uts_field_from_user(addr: Vaddr, len: u32, ctx: &Context) -> Result<[u8;
Ok(buffer)
}
const UTS_FIELD_LEN: usize = 65;
#[derive(Debug, Clone, Copy, Pod)]
#[repr(C)]
pub struct UtsName {
sysname: [u8; UTS_FIELD_LEN],
nodename: [u8; UTS_FIELD_LEN],
release: [u8; UTS_FIELD_LEN],
version: [u8; UTS_FIELD_LEN],
machine: [u8; UTS_FIELD_LEN],
domainname: [u8; UTS_FIELD_LEN],
}
impl UtsName {
// Note that the following names remain constant across all UTS namespaces. They are immutable,
// meaning the user space cannot change them. They are stored in the UTS namespace for ease of
// implementing related system calls.
//
// In addition, we intentionally report Linux-like UTS values instead of Asterinas' real name
// and version. These spoofed values satisfy glibc, which inspects uname fields (sysname,
// release, version, etc.) and expects Linux-compatible data.
/// The system name.
pub const SYSNAME: &str = "Linux";
/// The release name.
pub const RELEASE: &str = "5.13.0";
/// The version name.
pub const VERSION: &str = {
if let Some(version) = option_env!("OSDK_BUILD_TIMESTAMP") {
version
} else {
"unknown"
}
};
/// The machine name.
pub const MACHINE: &str = {
cfg_if::cfg_if! {
if #[cfg(target_arch = "x86_64")] {
"x86_64"
} else if #[cfg(target_arch = "riscv64")] {
"riscv64"
} else if #[cfg(target_arch = "loongarch64")] {
"loongarch64"
} else if #[cfg(target_arch = "aarch64")] {
"aarch64"
} else {
compile_error!("unsupported target")
}
}
};
}

View File

@ -4,7 +4,7 @@ use spin::Once;
use crate::{
fs::path::MountNamespace,
net::UtsNamespace,
net::uts_ns::UtsNamespace,
prelude::*,
process::{CloneFlags, UserNamespace, posix_thread::PosixThread},
};

View File

@ -12,7 +12,7 @@
use crate::{
fs::{file_table::FileDesc, path::MountNamespace},
net::UtsNamespace,
net::uts_ns::UtsNamespace,
prelude::*,
process::{
CloneFlags, ContextSetNsAdminApi, NsProxy, NsProxyBuilder, PidFile,