starnix_modules_syscalls/
misc.rs1use fidl_fuchsia_buildinfo as buildinfo;
6use fuchsia_component::client::connect_to_protocol_sync;
7use starnix_core::arch::{ARCH_NAME, ARCH_NAME32};
8use starnix_core::mm::{MemoryAccessor, MemoryAccessorExt, PAGE_SIZE};
9use starnix_core::security;
10use starnix_core::task::CurrentTask;
11use starnix_core::vfs::FsString;
12use starnix_logging::{log_error, track_stub};
13
14use starnix_syscalls::decls::SyscallDecl;
15use starnix_syscalls::{SUCCESS, SyscallResult};
16use starnix_types::user_buffer::MAX_RW_COUNT;
17use starnix_uapi::auth::{CAP_SYS_ADMIN, CAP_SYS_MODULE};
18use starnix_uapi::errors::Errno;
19use starnix_uapi::personality::PersonalityFlags;
20use starnix_uapi::user_address::{MultiArchUserRef, UserAddress, UserCString, UserRef};
21use starnix_uapi::version::KERNEL_RELEASE;
22use starnix_uapi::{
23 EFAULT, GRND_NONBLOCK, GRND_RANDOM, c_char, errno, error, from_status_like_fdio, uapi, utsname,
24};
25
26uapi::check_arch_independent_layout! {
27 utsname {
28 sysname,
29 nodename,
30 release,
31 version,
32 machine,
33 domainname,
34 }
35}
36
37pub fn do_uname(current_task: &CurrentTask, result: &mut utsname) -> Result<(), Errno> {
38 fn init_array(fixed: &mut [c_char; 65], init: &[u8]) {
39 let len = init.len();
40 #[allow(
41 clippy::undocumented_unsafe_blocks,
42 reason = "Force documented unsafe blocks in Starnix"
43 )]
44 fixed[..len].copy_from_slice(zerocopy::transmute_ref!(init))
45 }
46
47 init_array(&mut result.sysname, b"Linux");
48 if current_task.thread_group().read().personality.contains(PersonalityFlags::UNAME26) {
49 init_array(&mut result.release, b"2.6.40-starnix");
50 } else {
51 init_array(&mut result.release, KERNEL_RELEASE.as_bytes());
52 }
53
54 let version = current_task.kernel().build_version.get_or_try_init(|| {
55 let proxy =
56 connect_to_protocol_sync::<buildinfo::ProviderMarker>().map_err(|_| errno!(ENOENT))?;
57 let buildinfo = proxy.get_build_info(zx::MonotonicInstant::INFINITE).map_err(|e| {
58 log_error!("FIDL error getting build info: {e}");
59 errno!(EIO)
60 })?;
61 Ok(buildinfo.version.unwrap_or_else(|| "starnix".to_string()))
62 })?;
63
64 init_array(&mut result.version, version.as_bytes());
65
66 let personality = current_task.thread_group().read().personality;
67 let machine = if personality.execution_domain() == (uapi::PER_LINUX32 as u32) {
68 ARCH_NAME32
69 } else {
70 ARCH_NAME
71 };
72 init_array(&mut result.machine, machine);
73
74 {
75 let task_state = current_task.read();
77 let uts_ns = task_state.uts_ns.read();
78 init_array(&mut result.nodename, uts_ns.hostname.as_slice());
79 init_array(&mut result.domainname, uts_ns.domainname.as_slice());
80 }
81 Ok(())
82}
83
84pub fn sys_uname(current_task: &CurrentTask, name: UserRef<utsname>) -> Result<(), Errno> {
85 let mut result = utsname {
86 sysname: [0; 65],
87 nodename: [0; 65],
88 release: [0; 65],
89 version: [0; 65],
90 machine: [0; 65],
91 domainname: [0; 65],
92 };
93 do_uname(current_task, &mut result)?;
94 current_task.write_object(name, &result)?;
95 Ok(())
96}
97
98pub fn sys_sysinfo(
99 current_task: &CurrentTask,
100 info: MultiArchUserRef<uapi::sysinfo, uapi::arch32::sysinfo>,
101) -> Result<(), Errno> {
102 let page_size = zx::system_get_page_size();
103 let total_ram_pages = zx::system_get_physmem() / (page_size as u64);
104 let num_procs = current_task.kernel().pids.read().len();
105
106 track_stub!(TODO("https://fxbug.dev/297374270"), "compute system load");
107 let loads = [0; 3];
108
109 track_stub!(TODO("https://fxbug.dev/322874530"), "compute actual free ram usage");
110 let freeram = total_ram_pages / 8;
111
112 let result = uapi::sysinfo {
113 uptime: (zx::MonotonicInstant::get() - zx::MonotonicInstant::ZERO).into_seconds(),
114 loads,
115 totalram: total_ram_pages,
116 freeram,
117 procs: num_procs.try_into().map_err(|_| errno!(EINVAL))?,
118 mem_unit: page_size,
119 ..Default::default()
120 };
121
122 current_task.write_multi_arch_object(info, result)?;
123 Ok(())
124}
125
126fn read_name(current_task: &CurrentTask, name: UserCString, len: u64) -> Result<FsString, Errno> {
128 const MAX_LEN: usize = 64;
129 let len = len as usize;
130
131 if len > MAX_LEN {
132 return error!(EINVAL);
133 }
134
135 let mut name = current_task.read_c_string_to_vec(name, MAX_LEN)?;
137
138 if len < name.len() {
140 name.truncate(len);
141 }
142 Ok(name)
143}
144
145pub fn sys_sethostname(
146 current_task: &CurrentTask,
147 hostname: UserCString,
148 len: u64,
149) -> Result<SyscallResult, Errno> {
150 security::check_task_capable(current_task, CAP_SYS_ADMIN)?;
151
152 let hostname = read_name(current_task, hostname, len)?;
153
154 let task_state = current_task.read();
155 let mut uts_ns = task_state.uts_ns.write();
156 uts_ns.hostname = hostname;
157
158 Ok(SUCCESS)
159}
160
161pub fn sys_setdomainname(
162 current_task: &CurrentTask,
163 domainname: UserCString,
164 len: u64,
165) -> Result<SyscallResult, Errno> {
166 security::check_task_capable(current_task, CAP_SYS_ADMIN)?;
167
168 let domainname = read_name(current_task, domainname, len)?;
169
170 let task_state = current_task.read();
171 let mut uts_ns = task_state.uts_ns.write();
172 uts_ns.domainname = domainname;
173
174 Ok(SUCCESS)
175}
176
177pub fn sys_getrandom(
178 current_task: &CurrentTask,
179 start_addr: UserAddress,
180 size: usize,
181 flags: u32,
182) -> Result<usize, Errno> {
183 if flags & !(GRND_RANDOM | GRND_NONBLOCK) != 0 {
184 return error!(EINVAL);
185 }
186
187 let mut bytes_written = 0;
190 let mut bounce_buffer = vec![0u8; std::cmp::min(*PAGE_SIZE as usize, size)];
191
192 let bytes_to_write = std::cmp::min(size, *MAX_RW_COUNT);
193
194 while bytes_written < bytes_to_write {
195 let chunk_start = start_addr.saturating_add(bytes_written);
196 let chunk_len = std::cmp::min(*PAGE_SIZE as usize, size - bytes_written);
197
198 let chunk = &mut bounce_buffer[..chunk_len];
199 starnix_crypto::cprng_draw(chunk);
200 match current_task.write_memory_partial(chunk_start, chunk) {
201 Ok(n) => {
202 bytes_written += n;
203
204 if n < chunk_len {
206 break;
207 }
208 }
209
210 Err(e) if e.code.error_code() == EFAULT && bytes_written > 0 => break,
213 Err(e) => return Err(e),
214 }
215 }
216
217 Ok(bytes_written)
218}
219
220pub fn sys_sched_yield(_current_task: &CurrentTask) -> Result<(), Errno> {
221 let status = unsafe { zx::sys::zx_thread_legacy_yield(0) };
223 zx::Status::ok(status).map_err(|status| from_status_like_fdio!(status))
224}
225
226pub fn sys_unknown(
227 current_task: &CurrentTask,
228 syscall_number: u64,
229) -> Result<SyscallResult, Errno> {
230 let decl = SyscallDecl::from_number(syscall_number, current_task.thread_state.arch_width());
231 track_stub!(TODO("https://fxbug.dev/322874143"), decl.name(), syscall_number);
232
233 error!(ENOSYS)
235}
236
237pub fn sys_personality(current_task: &CurrentTask, persona: u32) -> Result<SyscallResult, Errno> {
238 let mut state = current_task.task.thread_group().write();
239 let previous_value = state.personality.update_from_syscall(persona);
240 Ok(previous_value.into())
241}
242
243pub fn sys_delete_module(
244 current_task: &CurrentTask,
245 user_name: UserCString,
246 _flags: u32,
247) -> Result<SyscallResult, Errno> {
248 security::check_task_capable(current_task, CAP_SYS_MODULE)?;
249 const MODULE_NAME_LEN: usize = 64 - std::mem::size_of::<u64>();
251 let _name = current_task.read_c_string_to_vec(user_name, MODULE_NAME_LEN)?;
252 error!(ENOENT)
254}
255
256#[cfg(target_arch = "aarch64")]
258mod arch32 {
259 pub use super::{sys_sysinfo as sys_arch32_sysinfo, sys_uname as sys_arch32_uname};
260}
261
262#[cfg(target_arch = "aarch64")]
263pub use arch32::*;