Add syscall sethostname

This commit is contained in:
jiangjianfeng 2025-09-18 09:40:51 +00:00 committed by Tate, Hongliang Tian
parent 66356e133d
commit 87091aa19c
9 changed files with 75 additions and 11 deletions

View File

@ -190,7 +190,7 @@ provided by Linux on x86-64 architecture.
| 167 | swapon | ❌ | |
| 168 | swapoff | ❌ | |
| 169 | reboot | ❌ | |
| 170 | sethostname | | |
| 170 | sethostname | | |
| 171 | setdomainname | ❌ | |
| 172 | iopl | ❌ | |
| 173 | ioperm | ❌ | |

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: MPL-2.0
use ostd::sync::RwMutexReadGuard;
use spin::Once;
use crate::{
@ -10,7 +11,7 @@ use crate::{
/// The UTS namespace.
pub struct UtsNamespace {
uts_name: UtsName,
uts_name: RwMutex<UtsName>,
owner: Arc<UserNamespace>,
}
@ -34,7 +35,10 @@ impl UtsNamespace {
let owner = UserNamespace::get_init_singleton().clone();
Arc::new(Self { uts_name, owner })
Arc::new(Self {
uts_name: RwMutex::new(uts_name),
owner,
})
})
}
@ -46,7 +50,7 @@ impl UtsNamespace {
) -> Result<Arc<Self>> {
owner.check_cap(CapSet::SYS_ADMIN, posix_thread)?;
Ok(Arc::new(Self {
uts_name: self.uts_name,
uts_name: RwMutex::new(*self.uts_name.read()),
owner,
}))
}
@ -56,9 +60,25 @@ impl UtsNamespace {
&self.owner
}
/// Returns the UTS name.
pub fn uts_name(&self) -> &UtsName {
&self.uts_name
/// Returns a read-only lock guard for accessing the UTS name.
pub fn uts_name(&self) -> RwMutexReadGuard<'_, UtsName> {
self.uts_name.read()
}
/// Sets a new hostname for the UTS namespace.
///
/// This method will fail with `EPERM` if the caller does not have the SYS_ADMIN capability
/// in the owner user namespace.
pub fn set_hostname(&self, addr: Vaddr, len: usize, ctx: &Context) -> Result<()> {
self.owner.check_cap(CapSet::SYS_ADMIN, ctx.posix_thread)?;
let new_host_name = copy_uts_field_from_user(addr, len as _, ctx)?;
debug!(
"set host name: {:?}",
CStr::from_bytes_until_nul(new_host_name.as_bytes()).unwrap()
);
self.uts_name.write().nodename = new_host_name;
Ok(())
}
}
@ -74,3 +94,29 @@ pub struct UtsName {
machine: [u8; UTS_FIELD_LEN],
domainname: [u8; UTS_FIELD_LEN],
}
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");
}
let user_space = ctx.user_space();
let mut reader = user_space.reader(addr, len as usize)?;
// UTS fields represent C strings, which must be nul-terminated.
// Therefore, the user-provided buffer length cannot exceed `UTS_FIELD_LEN - 1`
// to ensure space for the terminating nul byte.
if reader.remain() > UTS_FIELD_LEN - 1 {
return_errno_with_message!(Errno::EINVAL, "the UTS name is too long");
}
let mut buffer = [0u8; UTS_FIELD_LEN];
// Partial reads are acceptable,
// but an error is returned if no bytes can be read successfully.
if let Err((err, 0)) = reader.read_fallible(&mut VmWriter::from(buffer.as_mut_slice())) {
return Err(err.into());
}
Ok(buffer)
}

View File

@ -117,6 +117,7 @@ use super::{
setfsuid::sys_setfsuid,
setgid::sys_setgid,
setgroups::sys_setgroups,
sethostname::sys_sethostname,
setitimer::{sys_getitimer, sys_setitimer},
setns::sys_setns,
setpgid::sys_setpgid,
@ -283,6 +284,7 @@ impl_syscall_nums_and_dispatch_fn! {
SYS_GETGROUPS = 158 => sys_getgroups(args[..2]);
SYS_SETGROUPS = 159 => sys_setgroups(args[..2]);
SYS_NEWUNAME = 160 => sys_uname(args[..1]);
SYS_SETHOSTNAME = 161 => sys_sethostname(args[..2]);
SYS_GETRUSAGE = 165 => sys_getrusage(args[..2]);
SYS_UMASK = 166 => sys_umask(args[..1]);
SYS_PRCTL = 167 => sys_prctl(args[..5]);

View File

@ -117,6 +117,7 @@ use super::{
setfsuid::sys_setfsuid,
setgid::sys_setgid,
setgroups::sys_setgroups,
sethostname::sys_sethostname,
setitimer::{sys_getitimer, sys_setitimer},
setns::sys_setns,
setpgid::sys_setpgid,
@ -283,6 +284,7 @@ impl_syscall_nums_and_dispatch_fn! {
SYS_GETGROUPS = 158 => sys_getgroups(args[..2]);
SYS_SETGROUPS = 159 => sys_setgroups(args[..2]);
SYS_NEWUNAME = 160 => sys_uname(args[..1]);
SYS_SETHOSTNAME = 161 => sys_sethostname(args[..2]);
SYS_GETRLIMIT = 163 => sys_getrlimit(args[..2]);
SYS_SETRLIMIT = 164 => sys_setrlimit(args[..2]);
SYS_GETRUSAGE = 165 => sys_getrusage(args[..2]);

View File

@ -128,6 +128,7 @@ use super::{
setfsuid::sys_setfsuid,
setgid::sys_setgid,
setgroups::sys_setgroups,
sethostname::sys_sethostname,
setitimer::{sys_getitimer, sys_setitimer},
setns::sys_setns,
setpgid::sys_setpgid,
@ -306,7 +307,8 @@ impl_syscall_nums_and_dispatch_fn! {
SYS_CHROOT = 161 => sys_chroot(args[..1]);
SYS_SYNC = 162 => sys_sync(args[..0]);
SYS_MOUNT = 165 => sys_mount(args[..5]);
SYS_UMOUNT2 = 166 => sys_umount(args[..2]);
SYS_UMOUNT2 = 166 => sys_umount(args[..2]);
SYS_SETHOSTNAME = 170 => sys_sethostname(args[..2]);
SYS_GETTID = 186 => sys_gettid(args[..0]);
SYS_SETXATTR = 188 => sys_setxattr(args[..5]);
SYS_LSETXATTR = 189 => sys_lsetxattr(args[..5]);

View File

@ -144,6 +144,7 @@ mod setfsgid;
mod setfsuid;
mod setgid;
mod setgroups;
mod sethostname;
mod setitimer;
mod setns;
mod setpgid;

View File

@ -0,0 +1,10 @@
// SPDX-License-Identifier: MPL-2.0
use crate::{prelude::*, syscall::SyscallReturn};
pub fn sys_sethostname(addr: Vaddr, len: usize, ctx: &Context) -> Result<SyscallReturn> {
let ns_proxy_ref = ctx.thread_local.borrow_ns_proxy();
let ns_proxy = ns_proxy_ref.unwrap();
ns_proxy.uts_ns().set_hostname(addr, len, ctx)?;
Ok(SyscallReturn::Return(0))
}

View File

@ -6,6 +6,6 @@ pub fn sys_uname(old_uname_addr: Vaddr, ctx: &Context) -> Result<SyscallReturn>
debug!("old uname addr = 0x{:x}", old_uname_addr);
let ns_proxy = ctx.thread_local.borrow_ns_proxy();
let uts_name = ns_proxy.unwrap().uts_ns().uts_name();
ctx.user_space().write_val(old_uname_addr, uts_name)?;
ctx.user_space().write_val(old_uname_addr, &*uts_name)?;
Ok(SyscallReturn::Return(0))
}

View File

@ -1379,8 +1379,9 @@ setgroups02
# setgroups03
# setgroups03_16
# sethostname01
# sethostname02
sethostname01
sethostname02
# TODO: Drop capabilities on UID changes, so that sethostname() will fail with EPERM.
# sethostname03
# setitimer01