1use crate::execution::execute_task;
6use crate::mm::{DumpPolicy, MemoryAccessor, MemoryAccessorExt, PAGE_SIZE};
7use crate::ptrace::{
8 PR_SET_PTRACER_ANY, PR_SET_PTRACER_ANY_ARCH32, PtraceAllowedPtracers, PtraceAttachType,
9 PtraceOptions, ptrace_attach, ptrace_dispatch, ptrace_traceme,
10};
11use crate::security;
12use crate::signals::syscalls::RUsagePtr;
13use crate::task::{
14 CurrentTask, ExitStatus, NormalPriority, SchedulingPolicy, SeccompAction, SeccompStateValue,
15 SyslogAccess, Task, ThreadGroup, max_priority_for_sched_policy, min_priority_for_sched_policy,
16};
17use crate::vfs::{
18 FdNumber, FileHandle, MountNamespaceFile, PidFdFileObject, UserBuffersOutputBuffer,
19 VecOutputBuffer,
20};
21use starnix_logging::{log_error, log_info, log_trace, track_stub};
22use starnix_syscalls::SyscallResult;
23use starnix_task_command::TaskCommand;
24use starnix_types::time::timeval_from_duration;
25use starnix_uapi::auth::{
26 CAP_SETGID, CAP_SETPCAP, CAP_SETUID, CAP_SYS_ADMIN, CAP_SYS_NICE, CAP_SYS_RESOURCE,
27 CAP_SYS_TTY_CONFIG, Capabilities, Credentials, PTRACE_MODE_READ_REALCREDS, SecureBits,
28};
29use starnix_uapi::errors::{ENAMETOOLONG, Errno};
30use starnix_uapi::kcmp::KcmpResource;
31use starnix_uapi::open_flags::OpenFlags;
32use starnix_uapi::resource_limits::Resource;
33use starnix_uapi::signals::{Signal, UncheckedSignal};
34use starnix_uapi::syslog::SyslogAction;
35use starnix_uapi::user_address::{
36 ArchSpecific, MappingMultiArchUserRef, MultiArchUserRef, UserAddress, UserCString,
37 UserCStringPtr, UserRef,
38};
39use starnix_uapi::{
40 __user_cap_data_struct, __user_cap_header_struct, _LINUX_CAPABILITY_VERSION_1,
41 _LINUX_CAPABILITY_VERSION_2, _LINUX_CAPABILITY_VERSION_3, AT_EMPTY_PATH, AT_SYMLINK_NOFOLLOW,
42 BPF_MAXINSNS, CLONE_ARGS_SIZE_VER0, CLONE_ARGS_SIZE_VER1, CLONE_ARGS_SIZE_VER2, CLONE_FILES,
43 CLONE_FS, CLONE_NEWNS, CLONE_NEWUTS, CLONE_SETTLS, CLONE_VFORK, NGROUPS_MAX, PR_CAP_AMBIENT,
44 PR_CAP_AMBIENT_CLEAR_ALL, PR_CAP_AMBIENT_IS_SET, PR_CAP_AMBIENT_LOWER, PR_CAP_AMBIENT_RAISE,
45 PR_CAPBSET_DROP, PR_CAPBSET_READ, PR_GET_CHILD_SUBREAPER, PR_GET_DUMPABLE, PR_GET_KEEPCAPS,
46 PR_GET_NAME, PR_GET_NO_NEW_PRIVS, PR_GET_SECCOMP, PR_GET_SECUREBITS, PR_GET_TIMERSLACK,
47 PR_SET_CHILD_SUBREAPER, PR_SET_DUMPABLE, PR_SET_KEEPCAPS, PR_SET_NAME, PR_SET_NO_NEW_PRIVS,
48 PR_SET_PDEATHSIG, PR_SET_PTRACER, PR_SET_SECCOMP, PR_SET_SECUREBITS, PR_SET_TIMERSLACK,
49 PR_SET_VMA, PR_SET_VMA_ANON_NAME, PRIO_PROCESS, PTRACE_ATTACH, PTRACE_SEIZE, PTRACE_TRACEME,
50 RUSAGE_CHILDREN, SCHED_RESET_ON_FORK, SECCOMP_FILTER_FLAG_LOG,
51 SECCOMP_FILTER_FLAG_NEW_LISTENER, SECCOMP_FILTER_FLAG_SPEC_ALLOW, SECCOMP_FILTER_FLAG_TSYNC,
52 SECCOMP_FILTER_FLAG_TSYNC_ESRCH, SECCOMP_GET_ACTION_AVAIL, SECCOMP_GET_NOTIF_SIZES,
53 SECCOMP_MODE_FILTER, SECCOMP_MODE_STRICT, SECCOMP_SET_MODE_FILTER, SECCOMP_SET_MODE_STRICT,
54 c_char, c_int, clone_args, errno, error, gid_t, pid_t, rlimit, rusage, sched_param,
55 sock_filter, uapi, uid_t,
56};
57use static_assertions::const_assert;
58use std::cmp;
59use std::ffi::CString;
60use std::sync::{Arc, LazyLock};
61use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
62
63#[cfg(target_arch = "aarch64")]
64use starnix_uapi::{PR_GET_TAGGED_ADDR_CTRL, PR_SET_TAGGED_ADDR_CTRL, PR_TAGGED_ADDR_ENABLE};
65
66pub type SockFProgPtr =
67 MappingMultiArchUserRef<SockFProg, uapi::sock_fprog, uapi::arch32::sock_fprog>;
68pub type SockFilterPtr = MultiArchUserRef<uapi::sock_filter, uapi::arch32::sock_filter>;
69
70pub struct SockFProg {
71 pub len: u32,
72 pub filter: SockFilterPtr,
73}
74
75uapi::arch_map_data! {
76 BidiTryFrom<SockFProg, sock_fprog> {
77 len = len;
78 filter = filter;
79 }
80}
81
82uapi::check_arch_independent_layout! {
83 sched_param {
84 sched_priority,
85 }
86}
87
88pub fn do_clone(current_task: &mut CurrentTask, args: &clone_args) -> Result<pid_t, Errno> {
89 security::check_task_create_access(current_task)?;
90
91 let child_exit_signal = if args.exit_signal == 0 {
92 None
93 } else {
94 Some(Signal::try_from(UncheckedSignal::new(args.exit_signal))?)
95 };
96
97 let mut new_task = current_task.clone_task(
98 args.flags,
99 child_exit_signal,
100 UserRef::<pid_t>::new(UserAddress::from(args.parent_tid)),
101 UserRef::<pid_t>::new(UserAddress::from(args.child_tid)),
102 UserRef::<FdNumber>::new(UserAddress::from(args.pidfd)),
103 )?;
104
105 new_task.thread_state.registers.set_return_register(0);
108 let (trace_kind, ptrace_state) = current_task.get_ptrace_core_state_for_clone(args);
109
110 if args.stack != 0 {
111 new_task
115 .thread_state
116 .registers
117 .set_stack_pointer_register(args.stack.wrapping_add(args.stack_size));
118 }
119
120 if args.flags & (CLONE_SETTLS as u64) != 0 {
121 new_task.thread_state.registers.set_thread_pointer_register(args.tls);
122 }
123
124 let tid = new_task.task.tid.id;
125 let task_ref = Arc::downgrade(&new_task.task);
126 execute_task(new_task, |_| Ok(()), |_| {}, ptrace_state)?;
127
128 current_task.ptrace_event(trace_kind, tid as u64);
129
130 if args.flags & (CLONE_VFORK as u64) != 0 {
131 current_task.wait_for_execve(task_ref)?;
132 current_task.ptrace_event(PtraceOptions::TRACEVFORKDONE, tid as u64);
133 }
134
135 Ok(tid)
136}
137
138pub fn sys_clone3(
139 current_task: &mut CurrentTask,
140 user_clone_args: UserRef<clone_args>,
141 user_clone_args_size: usize,
142) -> Result<pid_t, Errno> {
143 if !(user_clone_args_size == CLONE_ARGS_SIZE_VER0 as usize
145 || user_clone_args_size == CLONE_ARGS_SIZE_VER1 as usize
146 || user_clone_args_size == CLONE_ARGS_SIZE_VER2 as usize)
147 {
148 return error!(EINVAL);
149 }
150
151 const_assert!(std::mem::size_of::<clone_args>() == CLONE_ARGS_SIZE_VER2 as usize);
153
154 let clone_args = current_task.read_object_partial(user_clone_args, user_clone_args_size)?;
155 do_clone(current_task, &clone_args)
156}
157
158fn read_c_string_vector(
159 mm: &CurrentTask,
160 user_vector: UserCStringPtr,
161 elem_limit: usize,
162 vec_limit: usize,
163) -> Result<(Vec<CString>, usize), Errno> {
164 let mut user_current = user_vector;
165 let mut vector: Vec<CString> = vec![];
166 let mut vec_size: usize = 0;
167 loop {
168 let user_string = mm.read_multi_arch_ptr(user_current)?;
169 if user_string.is_null() {
170 break;
171 }
172 let string = mm
173 .read_c_string_to_vec(user_string, elem_limit)
174 .map_err(|e| if e.code == ENAMETOOLONG { errno!(E2BIG) } else { e })?;
175 let cstring = CString::new(string).map_err(|_| errno!(EINVAL))?;
176 vec_size =
177 vec_size.checked_add(cstring.as_bytes_with_nul().len()).ok_or_else(|| errno!(E2BIG))?;
178 if vec_size > vec_limit {
179 return error!(E2BIG);
180 }
181 vector.push(cstring);
182 user_current = user_current.next()?;
183 }
184 Ok((vector, vec_size))
185}
186
187pub fn sys_execve(
188 current_task: &mut CurrentTask,
189 user_path: UserCString,
190 user_argv: UserCStringPtr,
191 user_environ: UserCStringPtr,
192) -> Result<(), Errno> {
193 sys_execveat(current_task, FdNumber::AT_FDCWD, user_path, user_argv, user_environ, 0)
194}
195
196pub fn sys_execveat(
197 current_task: &mut CurrentTask,
198 dir_fd: FdNumber,
199 user_path: UserCString,
200 user_argv: UserCStringPtr,
201 user_environ: UserCStringPtr,
202 flags: u32,
203) -> Result<(), Errno> {
204 if flags & !(AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW) != 0 {
205 return error!(EINVAL);
206 }
207
208 const PAGE_LIMIT: usize = 32;
211 let page_limit_size: usize = PAGE_LIMIT * *PAGE_SIZE as usize;
212 let rlimit = current_task.thread_group().get_rlimit(Resource::STACK);
213 let stack_limit = rlimit / 4;
214 let argv_env_limit = cmp::max(page_limit_size, stack_limit as usize);
215
216 let (argv, argv_size) = if user_argv.is_null() {
219 (Vec::new(), 0)
220 } else {
221 read_c_string_vector(current_task, user_argv, page_limit_size, argv_env_limit)?
222 };
223
224 let (environ, _) = if user_environ.is_null() {
225 (Vec::new(), 0)
226 } else {
227 read_c_string_vector(
228 current_task,
229 user_environ,
230 page_limit_size,
231 argv_env_limit - argv_size,
232 )?
233 };
234
235 let path = ¤t_task.read_path(user_path)?;
236
237 log_trace!(argv:?, environ:?, flags:?; "execveat({dir_fd}, {path})");
238
239 let mut open_flags = OpenFlags::empty();
240
241 if flags & AT_SYMLINK_NOFOLLOW != 0 {
242 open_flags |= OpenFlags::NOFOLLOW;
243 }
244
245 if path.is_empty() && flags & AT_EMPTY_PATH == 0 {
246 return error!(ENOENT);
248 }
249
250 let executable = current_task.open_file_for_exec(dir_fd, path.as_ref(), open_flags)?;
251
252 let path = if dir_fd == FdNumber::AT_FDCWD {
255 path.to_vec()
258 } else {
259 match path.first() {
264 Some(b'/') => {
265 path.to_vec()
267 }
268 Some(_) => {
269 let mut new_path = format!("/dev/fd/{}/", dir_fd.raw()).into_bytes();
271 new_path.append(&mut path.to_vec());
272 new_path
273 }
274 None => format!("/dev/fd/{}", dir_fd.raw()).into_bytes(),
276 }
277 };
278
279 let path = CString::new(path).map_err(|_| errno!(EINVAL))?;
280
281 current_task.exec(executable, path, argv, environ)?;
282 Ok(())
283}
284
285pub fn sys_getcpu(
286 current_task: &CurrentTask,
287 cpu_out: UserRef<u32>,
288 node_out: UserRef<u32>,
289) -> Result<(), Errno> {
290 if !cpu_out.is_null() {
293 let thread_stats = current_task
294 .running_state()
295 .thread
296 .get()
297 .expect("current thread is never None when executing")
298 .thread
299 .stats()
300 .map_err(|e| errno!(EINVAL, format!("getting thread stats failed {e:?}")))?;
301 current_task.write_object(cpu_out, &thread_stats.last_scheduled_cpu)?;
302 }
303 if !node_out.is_null() {
304 track_stub!(TODO("https://fxbug.dev/325643815"), "getcpu() numa node");
307 current_task.write_object(node_out, &0)?;
308 }
309 Ok(())
310}
311
312pub fn sys_getpid(current_task: &CurrentTask) -> Result<pid_t, Errno> {
313 Ok(current_task.get_pid())
314}
315
316pub fn sys_gettid(current_task: &CurrentTask) -> Result<pid_t, Errno> {
317 Ok(current_task.get_tid())
318}
319
320pub fn sys_getppid(current_task: &CurrentTask) -> Result<pid_t, Errno> {
321 Ok(current_task.thread_group().read().get_ppid())
322}
323
324fn get_task_or_current(current_task: &CurrentTask, pid: pid_t) -> Result<Arc<Task>, Errno> {
325 if pid == 0 { Ok(current_task.task.clone()) } else { current_task.get_task(pid) }
326}
327
328pub fn sys_getsid(current_task: &CurrentTask, pid: pid_t) -> Result<pid_t, Errno> {
329 let target_task = get_task_or_current(current_task, pid)?;
330 if pid != 0 {
331 security::check_task_getsid(current_task, &target_task)?;
332 }
333 let sid = target_task.thread_group().read().process_group.session.leader.id;
334 Ok(sid)
335}
336
337pub fn sys_getpgid(current_task: &CurrentTask, pid: pid_t) -> Result<pid_t, Errno> {
338 let task = get_task_or_current(current_task, pid)?;
339
340 security::check_getpgid_access(current_task, &task)?;
341 let pgid = task.thread_group().read().process_group.leader.id;
342 Ok(pgid)
343}
344
345pub fn sys_setpgid(current_task: &CurrentTask, pid: pid_t, pgid: pid_t) -> Result<(), Errno> {
346 if pgid < 0 {
347 return error!(EINVAL);
348 }
349 let task = get_task_or_current(current_task, pid)?;
350 let pgid = if pgid == 0 {
351 task.pid.clone()
352 } else {
353 current_task.kernel().pids.get(pgid).map_err(|_| errno!(EPERM))?
354 };
355
356 current_task.thread_group().setpgid(current_task, &task, &pgid)
357}
358
359impl CurrentTask {
360 fn is_euid_friendly_with(&self, target_task: &Task) -> bool {
370 let self_creds = self.current_creds();
371 let target_creds = target_task.real_creds();
372 self_creds.euid == target_creds.uid || self_creds.euid == target_creds.euid
373 }
374}
375
376fn new_uid_allowed(current_task: &CurrentTask, uid: uid_t) -> bool {
380 let current_creds = current_task.current_creds();
381 uid == current_creds.uid
382 || uid == current_creds.euid
383 || uid == current_creds.saved_uid
384 || security::is_task_capable_noaudit(current_task, CAP_SETUID)
385}
386
387fn new_gid_allowed(current_task: &CurrentTask, gid: gid_t) -> bool {
388 let current_creds = current_task.current_creds();
389 gid == current_creds.gid
390 || gid == current_creds.egid
391 || gid == current_creds.saved_gid
392 || security::is_task_capable_noaudit(current_task, CAP_SETGID)
393}
394
395pub fn sys_getuid(current_task: &CurrentTask) -> Result<uid_t, Errno> {
396 Ok(current_task.current_creds().uid)
397}
398
399pub fn sys_getgid(current_task: &CurrentTask) -> Result<gid_t, Errno> {
400 Ok(current_task.current_creds().gid)
401}
402
403pub fn sys_setuid(current_task: &CurrentTask, uid: uid_t) -> Result<(), Errno> {
404 if uid == uid_t::MAX {
405 return error!(EINVAL);
406 }
407 if !new_uid_allowed(¤t_task, uid) {
408 return error!(EPERM);
409 }
410
411 let prev = current_task.current_creds();
412 let mut creds = Credentials::clone(&prev);
413 creds.euid = uid;
414 creds.fsuid = uid;
415 if security::is_task_capable_noaudit(current_task, CAP_SETUID) {
416 creds.uid = uid;
417 creds.saved_uid = uid;
418 }
419
420 creds.update_capabilities(&prev);
421 std::mem::drop(prev);
422 current_task.set_creds(creds);
423 Ok(())
424}
425
426pub fn sys_setgid(current_task: &CurrentTask, gid: gid_t) -> Result<(), Errno> {
427 if gid == gid_t::MAX {
428 return error!(EINVAL);
429 }
430 if !new_gid_allowed(¤t_task, gid) {
431 return error!(EPERM);
432 }
433
434 let mut creds = Credentials::clone(¤t_task.current_creds());
435 creds.egid = gid;
436 creds.fsgid = gid;
437 if security::is_task_capable_noaudit(current_task, CAP_SETGID) {
438 creds.gid = gid;
439 creds.saved_gid = gid;
440 }
441 current_task.set_creds(creds);
442 Ok(())
443}
444
445pub fn sys_geteuid(current_task: &CurrentTask) -> Result<uid_t, Errno> {
446 Ok(current_task.current_creds().euid)
447}
448
449pub fn sys_getegid(current_task: &CurrentTask) -> Result<gid_t, Errno> {
450 Ok(current_task.current_creds().egid)
451}
452
453pub fn sys_setfsuid(current_task: &CurrentTask, fsuid: uid_t) -> Result<uid_t, Errno> {
454 let prev = current_task.current_creds();
455 let prev_fsuid = prev.fsuid;
456 if fsuid != u32::MAX && new_uid_allowed(¤t_task, fsuid) {
457 let mut creds = Credentials::clone(&prev);
458 creds.fsuid = fsuid;
459 creds.update_capabilities(&prev);
460 std::mem::drop(prev);
461 current_task.set_creds(creds);
462 }
463
464 Ok(prev_fsuid)
465}
466
467pub fn sys_setfsgid(current_task: &CurrentTask, fsgid: gid_t) -> Result<gid_t, Errno> {
468 let prev = current_task.current_creds();
469 let prev_fsgid = prev.fsgid;
470
471 if fsgid != u32::MAX && new_gid_allowed(¤t_task, fsgid) {
472 let mut creds = Credentials::clone(&prev);
473 creds.fsgid = fsgid;
474 creds.update_capabilities(&prev);
475 std::mem::drop(prev);
476 current_task.set_creds(creds);
477 }
478
479 Ok(prev_fsgid)
480}
481
482pub fn sys_getresuid(
483 current_task: &CurrentTask,
484 ruid_addr: UserRef<uid_t>,
485 euid_addr: UserRef<uid_t>,
486 suid_addr: UserRef<uid_t>,
487) -> Result<(), Errno> {
488 let creds = current_task.current_creds();
489 current_task.write_object(ruid_addr, &creds.uid)?;
490 current_task.write_object(euid_addr, &creds.euid)?;
491 current_task.write_object(suid_addr, &creds.saved_uid)?;
492 Ok(())
493}
494
495pub fn sys_getresgid(
496 current_task: &CurrentTask,
497 rgid_addr: UserRef<gid_t>,
498 egid_addr: UserRef<gid_t>,
499 sgid_addr: UserRef<gid_t>,
500) -> Result<(), Errno> {
501 let creds = current_task.current_creds();
502 current_task.write_object(rgid_addr, &creds.gid)?;
503 current_task.write_object(egid_addr, &creds.egid)?;
504 current_task.write_object(sgid_addr, &creds.saved_gid)?;
505 Ok(())
506}
507
508pub fn sys_setreuid(current_task: &CurrentTask, ruid: uid_t, euid: uid_t) -> Result<(), Errno> {
509 let validate_ruid = |uid: uid_t| {
513 let creds = current_task.current_creds();
514 uid == u32::MAX
515 || uid == creds.uid
516 || uid == creds.euid
517 || security::is_task_capable_noaudit(current_task, CAP_SETUID)
518 };
519 let validate_euid = |uid: uid_t| {
520 let creds = current_task.current_creds();
521 uid == u32::MAX
522 || uid == creds.uid
523 || uid == creds.euid
524 || uid == creds.saved_uid
525 || security::is_task_capable_noaudit(current_task, CAP_SETUID)
526 };
527 if !validate_ruid(ruid) || !validate_euid(euid) {
528 return error!(EPERM);
529 }
530
531 let prev = current_task.current_creds();
532 let mut creds = Credentials::clone(&prev);
533 let is_ruid_set = ruid != u32::MAX;
534 if is_ruid_set {
535 creds.uid = ruid;
536 }
537 let is_euid_set = euid != u32::MAX;
538 if is_euid_set {
539 creds.euid = euid;
540 creds.fsuid = euid;
541 }
542
543 if is_ruid_set || (is_euid_set && euid != prev.uid) {
547 creds.saved_uid = creds.euid;
548 }
549
550 creds.update_capabilities(&prev);
551 std::mem::drop(prev);
552 current_task.set_creds(creds);
553 Ok(())
554}
555
556pub fn sys_setregid(current_task: &CurrentTask, rgid: gid_t, egid: gid_t) -> Result<(), Errno> {
557 let validate_rgid = |gid: gid_t| {
559 let creds = current_task.current_creds();
560 gid == u32::MAX
561 || gid == creds.gid
562 || gid == creds.egid
563 || security::is_task_capable_noaudit(current_task, CAP_SETGID)
564 };
565 let validate_egid = |gid: gid_t| {
566 let creds = current_task.current_creds();
567 gid == u32::MAX
568 || gid == creds.gid
569 || gid == creds.egid
570 || gid == creds.saved_gid
571 || security::is_task_capable_noaudit(current_task, CAP_SETGID)
572 };
573 if !validate_rgid(rgid) || !validate_egid(egid) {
574 return error!(EPERM);
575 }
576
577 let mut creds = Credentials::clone(¤t_task.current_creds());
578 let previous_rgid = creds.gid;
579 let is_rgid_set = rgid != u32::MAX;
580 if is_rgid_set {
581 creds.gid = rgid;
582 }
583 let is_egid_set = egid != u32::MAX;
584 if is_egid_set {
585 creds.egid = egid;
586 creds.fsgid = egid;
587 }
588
589 if is_rgid_set || (is_egid_set && egid != previous_rgid) {
593 creds.saved_gid = creds.egid;
594 }
595
596 current_task.set_creds(creds);
597 Ok(())
598}
599
600pub fn sys_setresuid(
601 current_task: &CurrentTask,
602 ruid: uid_t,
603 euid: uid_t,
604 suid: uid_t,
605) -> Result<(), Errno> {
606 let allowed = |uid| uid == u32::MAX || new_uid_allowed(¤t_task, uid);
607 if !allowed(ruid) || !allowed(euid) || !allowed(suid) {
608 return error!(EPERM);
609 }
610
611 let prev = current_task.current_creds();
612 let mut creds = Credentials::clone(&prev);
613 if ruid != u32::MAX {
614 creds.uid = ruid;
615 }
616 if euid != u32::MAX {
617 creds.euid = euid;
618 creds.fsuid = euid;
619 }
620 if suid != u32::MAX {
621 creds.saved_uid = suid;
622 }
623 creds.update_capabilities(&prev);
624 std::mem::drop(prev);
625 current_task.set_creds(creds);
626 Ok(())
627}
628
629pub fn sys_setresgid(
630 current_task: &CurrentTask,
631 rgid: gid_t,
632 egid: gid_t,
633 sgid: gid_t,
634) -> Result<(), Errno> {
635 let allowed = |gid| gid == u32::MAX || new_gid_allowed(¤t_task, gid);
636 if !allowed(rgid) || !allowed(egid) || !allowed(sgid) {
637 return error!(EPERM);
638 }
639
640 let mut creds = Credentials::clone(¤t_task.current_creds());
641 if rgid != u32::MAX {
642 creds.gid = rgid;
643 }
644 if egid != u32::MAX {
645 creds.egid = egid;
646 creds.fsgid = egid;
647 }
648 if sgid != u32::MAX {
649 creds.saved_gid = sgid;
650 }
651 current_task.set_creds(creds);
652 Ok(())
653}
654
655pub fn sys_exit(current_task: &CurrentTask, code: i32) -> Result<(), Errno> {
656 current_task.write().set_exit_status_if_not_already(ExitStatus::Exit(code as u8));
659 Ok(())
660}
661
662pub fn sys_exit_group(current_task: &mut CurrentTask, code: i32) -> Result<(), Errno> {
663 current_task.kill_thread_group(ExitStatus::Exit(code as u8));
664 Ok(())
665}
666
667pub fn sys_sched_getscheduler(current_task: &CurrentTask, pid: pid_t) -> Result<u32, Errno> {
668 if pid < 0 {
669 return error!(EINVAL);
670 }
671
672 let target_task = get_task_or_current(current_task, pid)?;
673 security::check_task_getscheduler_access(current_task, target_task.as_ref())?;
674 let current_scheduler_state = target_task.read().scheduler_state;
675 Ok(current_scheduler_state.policy_for_sched_getscheduler())
676}
677
678pub fn sys_sched_setscheduler(
679 current_task: &CurrentTask,
680 pid: pid_t,
681 policy: u32,
682 param: UserRef<sched_param>,
683) -> Result<(), Errno> {
684 if pid < 0 || param.is_null() {
686 return error!(EINVAL);
687 }
688
689 let target_task = get_task_or_current(current_task, pid)?;
690
691 let reset_on_fork = policy & SCHED_RESET_ON_FORK != 0;
692
693 let policy = SchedulingPolicy::try_from(policy & !SCHED_RESET_ON_FORK)?;
694 let realtime_priority =
695 policy.realtime_priority_from(current_task.read_object(param)?.sched_priority)?;
696
697 let current_state = target_task.read().scheduler_state;
699
700 let euid_friendly = current_task.is_euid_friendly_with(&target_task);
702 let strengthening = current_state.realtime_priority < realtime_priority;
703 let rlimited = strengthening
704 && realtime_priority.exceeds(target_task.thread_group().get_rlimit(Resource::RTPRIO));
705 let clearing_reset_on_fork = current_state.reset_on_fork && !reset_on_fork;
706 let caught_in_idle_trap = current_state.policy == SchedulingPolicy::Idle
707 && policy != SchedulingPolicy::Idle
708 && current_state
709 .normal_priority
710 .exceeds(target_task.thread_group().get_rlimit(Resource::NICE));
711 if !euid_friendly || rlimited || clearing_reset_on_fork || caught_in_idle_trap {
712 security::check_task_capable(current_task, CAP_SYS_NICE)?;
713 }
714
715 security::check_task_setscheduler_access(current_task, &target_task)?;
716
717 target_task.set_scheduler_policy_priority_and_reset_on_fork(
719 policy,
720 realtime_priority,
721 reset_on_fork,
722 )?;
723
724 Ok(())
725}
726
727const CPU_SET_SIZE: usize = 128;
728
729#[repr(C)]
730#[derive(Debug, Copy, Clone, IntoBytes, FromBytes, KnownLayout, Immutable)]
731pub struct CpuSet {
732 bits: [u8; CPU_SET_SIZE],
733}
734
735impl Default for CpuSet {
736 fn default() -> Self {
737 Self { bits: [0; CPU_SET_SIZE] }
738 }
739}
740
741fn check_cpu_set_alignment(current_task: &CurrentTask, cpusetsize: u32) -> Result<(), Errno> {
742 let alignment = if current_task.is_arch32() { 4 } else { 8 };
743 if cpusetsize < alignment || cpusetsize % alignment != 0 {
744 return error!(EINVAL);
745 }
746 Ok(())
747}
748
749fn get_default_cpu_set() -> CpuSet {
750 let mut result = CpuSet::default();
751 let mut cpus_count = zx::system_get_num_cpus();
752 let cpus_count_max = (CPU_SET_SIZE * 8) as u32;
753 if cpus_count > cpus_count_max {
754 log_error!("cpus_count={cpus_count}, greater than the {cpus_count_max} max supported.");
755 cpus_count = cpus_count_max;
756 }
757 let mut index = 0;
758 while cpus_count > 0 {
759 let count = std::cmp::min(cpus_count, 8);
760 let (shl, overflow) = 1_u8.overflowing_shl(count);
761 let mask = if overflow { u8::MAX } else { shl - 1 };
762 result.bits[index] = mask;
763 index += 1;
764 cpus_count -= count;
765 }
766 result
767}
768
769pub fn sys_sched_getaffinity(
770 current_task: &CurrentTask,
771 pid: pid_t,
772 cpusetsize: u32,
773 user_mask: UserAddress,
774) -> Result<usize, Errno> {
775 if pid < 0 {
776 return error!(EINVAL);
777 }
778
779 check_cpu_set_alignment(current_task, cpusetsize)?;
780
781 let target_task = get_task_or_current(current_task, pid)?;
782 security::check_task_getscheduler_access(current_task, &target_task)?;
783
784 let mask = get_default_cpu_set();
786 let mask_size = std::cmp::min(cpusetsize as usize, CPU_SET_SIZE);
787 current_task.write_memory(user_mask, &mask.bits[..mask_size])?;
788 track_stub!(TODO("https://fxbug.dev/322874659"), "sched_getaffinity");
789 Ok(mask_size)
790}
791
792pub fn sys_sched_setaffinity(
793 current_task: &CurrentTask,
794 pid: pid_t,
795 cpusetsize: u32,
796 user_mask: UserAddress,
797) -> Result<(), Errno> {
798 if pid < 0 {
799 return error!(EINVAL);
800 }
801 let target_task = get_task_or_current(current_task, pid)?;
802
803 check_cpu_set_alignment(current_task, cpusetsize)?;
804
805 let mask_size = std::cmp::min(cpusetsize as usize, CPU_SET_SIZE);
806 let mut mask = CpuSet::default();
807 current_task.read_memory_to_slice(user_mask, &mut mask.bits[..mask_size])?;
808
809 let max_mask = get_default_cpu_set();
811 let mut has_valid_cpu_in_mask = false;
812 for (l1, l2) in std::iter::zip(max_mask.bits, mask.bits) {
813 has_valid_cpu_in_mask = has_valid_cpu_in_mask || (l1 & l2 > 0);
814 }
815 if !has_valid_cpu_in_mask {
816 return error!(EINVAL);
817 }
818
819 if !current_task.is_euid_friendly_with(&target_task) {
820 security::check_task_capable(current_task, CAP_SYS_NICE)?;
821 }
822
823 security::check_task_setscheduler_access(current_task, &target_task)?;
824
825 track_stub!(TODO("https://fxbug.dev/322874889"), "sched_setaffinity");
828 Ok(())
829}
830
831pub fn sys_sched_getparam(
832 current_task: &CurrentTask,
833 pid: pid_t,
834 param: UserRef<sched_param>,
835) -> Result<(), Errno> {
836 if pid < 0 || param.is_null() {
837 return error!(EINVAL);
838 }
839
840 let target_task = get_task_or_current(current_task, pid)?;
841 let param_value = target_task.read().scheduler_state.get_sched_param();
842 current_task.write_object(param, ¶m_value)?;
843 Ok(())
844}
845
846pub fn sys_sched_setparam(
847 current_task: &CurrentTask,
848 pid: pid_t,
849 param: UserRef<sched_param>,
850) -> Result<(), Errno> {
851 if pid < 0 || param.is_null() {
853 return error!(EINVAL);
854 }
855 let target_task = get_task_or_current(current_task, pid)?;
856
857 let current_state = target_task.read().scheduler_state;
859
860 let realtime_priority = current_state
861 .policy
862 .realtime_priority_from(current_task.read_object(param)?.sched_priority)?;
863
864 let euid_friendly = current_task.is_euid_friendly_with(&target_task);
866 let strengthening = current_state.realtime_priority < realtime_priority;
867 let rlimited = strengthening
868 && realtime_priority.exceeds(target_task.thread_group().get_rlimit(Resource::RTPRIO));
869 if !euid_friendly || rlimited {
870 security::check_task_capable(current_task, CAP_SYS_NICE)?;
871 }
872
873 security::check_task_setscheduler_access(current_task, &target_task)?;
874
875 target_task.set_scheduler_priority(realtime_priority)?;
877
878 Ok(())
879}
880
881pub fn sys_sched_get_priority_min(_ctx: &CurrentTask, policy: u32) -> Result<u8, Errno> {
882 min_priority_for_sched_policy(policy)
883}
884
885pub fn sys_sched_get_priority_max(_ctx: &CurrentTask, policy: u32) -> Result<u8, Errno> {
886 max_priority_for_sched_policy(policy)
887}
888
889pub fn sys_ioprio_set(
890 _current_task: &mut CurrentTask,
891 _which: i32,
892 _who: i32,
893 _ioprio: i32,
894) -> Result<(), Errno> {
895 track_stub!(TODO("https://fxbug.dev/297591758"), "ioprio_set()");
896 error!(ENOSYS)
897}
898
899pub fn sys_prctl(
900 current_task: &mut CurrentTask,
901 option: u32,
902 arg2: u64,
903 arg3: u64,
904 arg4: u64,
905 arg5: u64,
906) -> Result<SyscallResult, Errno> {
907 match option {
908 PR_SET_VMA => {
909 if arg2 != PR_SET_VMA_ANON_NAME as u64 {
910 track_stub!(TODO("https://fxbug.dev/322874826"), "prctl PR_SET_VMA", arg2);
911 return error!(ENOSYS);
912 }
913 let addr = UserAddress::from(arg3);
914 let length = arg4 as usize;
915 let name_addr = UserAddress::from(arg5);
916 let name = if name_addr.is_null() {
917 None
918 } else {
919 let name = UserCString::new(current_task, UserAddress::from(arg5));
920 let name = current_task.read_c_string_to_vec(name, 256).map_err(|e| {
921 if e.code == ENAMETOOLONG { errno!(EINVAL) } else { e }
923 })?;
924 if name.iter().any(|b| {
926 matches!(b,
927 0..=0x1f |
928 0x7f..=0xff |
929 b'\\' | b'`' | b'$' | b'[' | b']'
930 )
931 }) {
932 return error!(EINVAL);
933 }
934 Some(name)
935 };
936 current_task.mm()?.set_mapping_name(addr, length, name)?;
937 Ok(().into())
938 }
939 PR_SET_DUMPABLE => {
940 let mm = current_task.mm()?;
941 let mut dumpable = mm.dumpable.lock();
942 *dumpable = if arg2 == 1 { DumpPolicy::User } else { DumpPolicy::Disable };
943 Ok(().into())
944 }
945 PR_GET_DUMPABLE => {
946 let mm = current_task.mm()?;
947 let dumpable = mm.dumpable.lock();
948 Ok(match *dumpable {
949 DumpPolicy::Disable => 0.into(),
950 DumpPolicy::User => 1.into(),
951 })
952 }
953 PR_SET_PDEATHSIG => {
954 track_stub!(TODO("https://fxbug.dev/322874397"), "PR_SET_PDEATHSIG");
955 Ok(().into())
956 }
957 PR_SET_NAME => {
958 let addr = UserAddress::from(arg2);
959 let name = TaskCommand::new(¤t_task.read_memory_to_array::<16>(addr)?);
960 current_task.set_command_name(name);
961 if current_task.tid == current_task.pid {
962 current_task.thread_group.sync_syscall_log_level();
963 }
964 Ok(0.into())
965 }
966 PR_GET_NAME => {
967 let addr = UserAddress::from(arg2);
968 let name = current_task.command().prctl_name();
969 current_task.write_memory(addr, &name[..])?;
970 Ok(().into())
971 }
972 PR_SET_PTRACER => {
973 let allowed_ptracers = if arg2 == PR_SET_PTRACER_ANY
974 || (current_task.is_arch32() && arg2 == PR_SET_PTRACER_ANY_ARCH32)
975 {
976 PtraceAllowedPtracers::Any
977 } else if arg2 == 0 {
978 PtraceAllowedPtracers::None
979 } else {
980 let task = current_task.get_task(arg2 as i32).map_err(|_| errno!(EINVAL))?;
981 PtraceAllowedPtracers::Some(task.pid.clone())
982 };
983 current_task.thread_group().write().allowed_ptracers = allowed_ptracers;
984 Ok(().into())
985 }
986 PR_GET_KEEPCAPS => {
987 Ok(current_task.current_creds().securebits.contains(SecureBits::KEEP_CAPS).into())
988 }
989 PR_SET_KEEPCAPS => {
990 if arg2 != 0 && arg2 != 1 {
991 return error!(EINVAL);
992 }
993 let mut creds = Credentials::clone(¤t_task.current_creds());
994 let mut securebits = creds.securebits;
995 securebits.set(SecureBits::KEEP_CAPS, arg2 != 0);
996 creds.set_securebits(securebits)?;
997 current_task.set_creds(creds);
998 Ok(().into())
999 }
1000 PR_SET_NO_NEW_PRIVS => {
1001 if arg2 != 1 || arg3 != 0 || arg4 != 0 || arg5 != 0 {
1003 return error!(EINVAL);
1004 }
1005 current_task.write().enable_no_new_privs();
1006 Ok(().into())
1007 }
1008 PR_GET_NO_NEW_PRIVS => {
1009 if arg2 != 0 || arg3 != 0 || arg4 != 0 {
1011 return error!(EINVAL);
1012 }
1013 Ok(current_task.read().no_new_privs().into())
1014 }
1015 PR_GET_SECCOMP => {
1016 if current_task.seccomp_filter_state.get() == SeccompStateValue::None {
1017 Ok(0.into())
1018 } else {
1019 Ok(2.into())
1020 }
1021 }
1022 PR_SET_SECCOMP => {
1023 if arg2 == SECCOMP_MODE_STRICT as u64 {
1024 return sys_seccomp(current_task, SECCOMP_SET_MODE_STRICT, 0, UserAddress::NULL);
1025 } else if arg2 == SECCOMP_MODE_FILTER as u64 {
1026 return sys_seccomp(current_task, SECCOMP_SET_MODE_FILTER, 0, arg3.into());
1027 }
1028 Ok(().into())
1029 }
1030 PR_GET_CHILD_SUBREAPER => {
1031 let addr = UserAddress::from(arg2);
1032 #[allow(clippy::bool_to_int_with_if)]
1033 let value: i32 =
1034 if current_task.thread_group().read().is_child_subreaper { 1 } else { 0 };
1035 current_task.write_object(addr.into(), &value)?;
1036 Ok(().into())
1037 }
1038 PR_SET_CHILD_SUBREAPER => {
1039 current_task.thread_group().write().is_child_subreaper = arg2 != 0;
1040 Ok(().into())
1041 }
1042 PR_GET_SECUREBITS => Ok(current_task.current_creds().securebits.bits().into()),
1043 PR_SET_SECUREBITS => {
1044 security::check_task_capable(current_task, CAP_SETPCAP)?;
1045
1046 let securebits = SecureBits::from_bits(arg2 as u32).ok_or_else(|| {
1047 track_stub!(TODO("https://fxbug.dev/322875244"), "PR_SET_SECUREBITS", arg2);
1048 errno!(ENOSYS)
1049 })?;
1050
1051 let mut creds = Credentials::clone(¤t_task.current_creds());
1052 creds.set_securebits(securebits)?;
1053 current_task.set_creds(creds);
1054 Ok(().into())
1055 }
1056 PR_CAPBSET_READ => {
1057 let cap = Capabilities::try_from(arg2)?;
1058 Ok(current_task.current_creds().cap_bounding.contains(cap).into())
1059 }
1060 PR_CAPBSET_DROP => {
1061 let mut creds = Credentials::clone(¤t_task.current_creds());
1062 security::check_task_capable(current_task, CAP_SETPCAP)?;
1063
1064 creds.cap_bounding.remove(Capabilities::try_from(arg2)?);
1065 current_task.set_creds(creds);
1066 Ok(().into())
1067 }
1068 PR_CAP_AMBIENT => {
1069 let operation = arg2 as u32;
1070 let capability_arg = Capabilities::try_from(arg3)?;
1071 if arg4 != 0 || arg5 != 0 {
1072 return error!(EINVAL);
1073 }
1074
1075 match operation {
1078 PR_CAP_AMBIENT_RAISE => {
1079 let mut creds = Credentials::clone(¤t_task.current_creds());
1080 if !(creds.cap_permitted.contains(capability_arg)
1081 && creds.cap_inheritable.contains(capability_arg))
1082 {
1083 return error!(EPERM);
1084 }
1085 if creds.securebits.contains(SecureBits::NO_CAP_AMBIENT_RAISE) {
1086 return error!(EPERM);
1087 }
1088
1089 creds.cap_ambient.insert(capability_arg);
1090 current_task.set_creds(creds);
1091 Ok(().into())
1092 }
1093 PR_CAP_AMBIENT_LOWER => {
1094 let mut creds = Credentials::clone(¤t_task.current_creds());
1095 creds.cap_ambient.remove(capability_arg);
1096 current_task.set_creds(creds);
1097 Ok(().into())
1098 }
1099 PR_CAP_AMBIENT_IS_SET => {
1100 Ok(current_task.current_creds().cap_ambient.contains(capability_arg).into())
1101 }
1102 PR_CAP_AMBIENT_CLEAR_ALL => {
1103 if arg3 != 0 {
1104 return error!(EINVAL);
1105 }
1106
1107 let mut creds = Credentials::clone(¤t_task.current_creds());
1108 creds.cap_ambient = Capabilities::empty();
1109 current_task.set_creds(creds);
1110 Ok(().into())
1111 }
1112 _ => error!(EINVAL),
1113 }
1114 }
1115 PR_SET_TIMERSLACK => {
1116 current_task.write().set_timerslack_ns(arg2);
1117 Ok(().into())
1118 }
1119 PR_GET_TIMERSLACK => Ok(current_task.read().timerslack_ns.into()),
1120 #[cfg(target_arch = "aarch64")]
1121 PR_GET_TAGGED_ADDR_CTRL => {
1122 track_stub!(TODO("https://fxbug.dev/408554469"), "PR_GET_TAGGED_ADDR_CTRL");
1123 Ok(0.into())
1124 }
1125 #[cfg(target_arch = "aarch64")]
1126 PR_SET_TAGGED_ADDR_CTRL => match u32::try_from(arg2).map_err(|_| errno!(EINVAL))? {
1127 0 => Ok(().into()),
1129 PR_TAGGED_ADDR_ENABLE => {
1130 track_stub!(TODO("https://fxbug.dev/408554469"), "PR_TAGGED_ADDR_ENABLE");
1131 error!(EINVAL)
1132 }
1133 unknown_mode => {
1134 track_stub!(
1135 TODO("https://fxbug.dev/408554469"),
1136 "PR_SET_TAGGED_ADDR_CTRL unknown mode",
1137 unknown_mode,
1138 );
1139 error!(EINVAL)
1140 }
1141 },
1142 _ => {
1143 track_stub!(TODO("https://fxbug.dev/322874733"), "prctl fallthrough", option);
1144 error!(ENOSYS)
1145 }
1146 }
1147}
1148
1149pub fn sys_ptrace(
1150 current_task: &mut CurrentTask,
1151 request: u32,
1152 pid: pid_t,
1153 addr: UserAddress,
1154 data: UserAddress,
1155) -> Result<SyscallResult, Errno> {
1156 if request == PTRACE_TRACEME {
1157 return ptrace_traceme(current_task);
1158 }
1159 let pid = current_task.kernel().pids.get(pid)?;
1160 match request {
1161 PTRACE_ATTACH => ptrace_attach(current_task, &pid, PtraceAttachType::Attach, data),
1162 PTRACE_SEIZE => ptrace_attach(current_task, &pid, PtraceAttachType::Seize, data),
1163 _ => ptrace_dispatch(current_task, request, &pid, addr, data),
1164 }
1165}
1166
1167pub fn sys_set_tid_address(
1168 current_task: &CurrentTask,
1169 user_tid: UserRef<pid_t>,
1170) -> Result<pid_t, Errno> {
1171 current_task.write().clear_child_tid = user_tid;
1172 Ok(current_task.get_tid())
1173}
1174
1175pub fn sys_getrusage(
1176 current_task: &CurrentTask,
1177 who: i32,
1178 user_usage: RUsagePtr,
1179) -> Result<(), Errno> {
1180 const RUSAGE_SELF: i32 = starnix_uapi::uapi::RUSAGE_SELF as i32;
1181 const RUSAGE_THREAD: i32 = starnix_uapi::uapi::RUSAGE_THREAD as i32;
1182 track_stub!(TODO("https://fxbug.dev/297370242"), "real rusage");
1183 let time_stats = match who {
1184 RUSAGE_CHILDREN => current_task.task.thread_group().read().children_time_stats,
1185 RUSAGE_SELF => current_task.task.thread_group().time_stats(),
1186 RUSAGE_THREAD => current_task.task.time_stats(),
1187 _ => return error!(EINVAL),
1188 };
1189
1190 let usage = rusage {
1191 ru_utime: timeval_from_duration(time_stats.user_time),
1192 ru_stime: timeval_from_duration(time_stats.system_time),
1193 ..rusage::default()
1194 };
1195 current_task.write_multi_arch_object(user_usage, usage)?;
1196
1197 Ok(())
1198}
1199
1200type PrLimitRef = MultiArchUserRef<uapi::rlimit, uapi::arch32::rlimit>;
1201
1202pub fn sys_getrlimit(
1203 current_task: &CurrentTask,
1204 resource: u32,
1205 user_rlimit: PrLimitRef,
1206) -> Result<(), Errno> {
1207 do_prlimit64(current_task, 0, resource, PrLimitRef::null(current_task), user_rlimit)
1208}
1209
1210pub fn sys_setrlimit(
1211 current_task: &CurrentTask,
1212 resource: u32,
1213 user_rlimit: PrLimitRef,
1214) -> Result<(), Errno> {
1215 do_prlimit64(current_task, 0, resource, user_rlimit, PrLimitRef::null(current_task))
1216}
1217
1218pub fn sys_prlimit64(
1219 current_task: &CurrentTask,
1220 pid: pid_t,
1221 user_resource: u32,
1222 new_limit_ref: UserRef<uapi::rlimit>,
1223 old_limit_ref: UserRef<uapi::rlimit>,
1224) -> Result<(), Errno> {
1225 do_prlimit64::<uapi::rlimit>(
1226 current_task,
1227 pid,
1228 user_resource,
1229 new_limit_ref.into(),
1230 old_limit_ref.into(),
1231 )
1232}
1233
1234pub fn do_prlimit64<T>(
1235 current_task: &CurrentTask,
1236 pid: pid_t,
1237 user_resource: u32,
1238 new_limit_ref: MultiArchUserRef<uapi::rlimit, T>,
1239 old_limit_ref: MultiArchUserRef<uapi::rlimit, T>,
1240) -> Result<(), Errno>
1241where
1242 T: FromBytes + IntoBytes + Immutable + From<uapi::rlimit> + Into<uapi::rlimit>,
1243{
1244 let target_task = get_task_or_current(current_task, pid)?;
1245
1246 if current_task.get_pid() != target_task.get_pid() {
1250 let self_creds = current_task.current_creds();
1251 let target_creds = target_task.real_creds();
1252 if self_creds.uid != target_creds.uid
1253 || self_creds.euid != target_creds.euid
1254 || self_creds.saved_uid != target_creds.saved_uid
1255 || self_creds.gid != target_creds.gid
1256 || self_creds.egid != target_creds.egid
1257 || self_creds.saved_gid != target_creds.saved_gid
1258 {
1259 security::check_task_capable(current_task, CAP_SYS_RESOURCE)?;
1260 }
1261 security::task_prlimit(
1262 current_task,
1263 &target_task,
1264 !old_limit_ref.is_null(),
1265 !new_limit_ref.is_null(),
1266 )?;
1267 }
1268
1269 let resource = Resource::from_raw(user_resource)?;
1270
1271 let old_limit = match resource {
1272 Resource::STACK => {
1274 if !new_limit_ref.is_null() {
1275 track_stub!(
1276 TODO("https://fxbug.dev/322874791"),
1277 "prlimit64 cannot set RLIMIT_STACK"
1278 );
1279 }
1280 let mm = target_task.mm()?;
1284 let mm_state = mm.state.read();
1285 let stack_size = mm_state.stack_size as u64;
1286 rlimit { rlim_cur: stack_size, rlim_max: stack_size }
1287 }
1288 _ => {
1289 let new_limit = if new_limit_ref.is_null() {
1290 None
1291 } else {
1292 let new_limit = current_task.read_multi_arch_object(new_limit_ref)?;
1293 if new_limit.rlim_cur > new_limit.rlim_max {
1294 return error!(EINVAL);
1295 }
1296 Some(new_limit)
1297 };
1298 ThreadGroup::adjust_rlimits(current_task, &target_task, resource, new_limit)?
1299 }
1300 };
1301 if !old_limit_ref.is_null() {
1302 current_task.write_multi_arch_object(old_limit_ref, old_limit)?;
1303 }
1304 Ok(())
1305}
1306
1307pub fn sys_quotactl(
1308 _current_task: &CurrentTask,
1309 _cmd: i32,
1310 _special: UserRef<c_char>,
1311 _id: i32,
1312 _addr: UserRef<c_char>,
1313) -> Result<SyscallResult, Errno> {
1314 track_stub!(TODO("https://fxbug.dev/297302197"), "quotacl()");
1315 error!(ENOSYS)
1316}
1317
1318pub fn sys_capget(
1319 current_task: &CurrentTask,
1320 user_header: UserRef<__user_cap_header_struct>,
1321 user_data: UserRef<__user_cap_data_struct>,
1322) -> Result<(), Errno> {
1323 let mut header = current_task.read_object(user_header)?;
1324 let is_version_valid =
1325 [_LINUX_CAPABILITY_VERSION_1, _LINUX_CAPABILITY_VERSION_2, _LINUX_CAPABILITY_VERSION_3]
1326 .contains(&header.version);
1327 if !is_version_valid {
1328 header.version = _LINUX_CAPABILITY_VERSION_3;
1329 current_task.write_object(user_header, &header)?;
1330 }
1331 if user_data.is_null() {
1332 return Ok(());
1333 }
1334 if !is_version_valid || header.pid < 0 {
1335 return error!(EINVAL);
1336 }
1337
1338 let target_task = get_task_or_current(current_task, header.pid)?;
1339
1340 security::check_getcap_access(current_task, &target_task)?;
1341
1342 let (permitted, effective, inheritable) = {
1343 let creds = &target_task.real_creds();
1344 (creds.cap_permitted, creds.cap_effective, creds.cap_inheritable)
1345 };
1346
1347 match header.version {
1348 _LINUX_CAPABILITY_VERSION_1 => {
1349 let data: [__user_cap_data_struct; 1] = [__user_cap_data_struct {
1350 effective: effective.as_abi_v1(),
1351 inheritable: inheritable.as_abi_v1(),
1352 permitted: permitted.as_abi_v1(),
1353 }];
1354 current_task.write_objects(user_data, &data)?;
1355 }
1356 _LINUX_CAPABILITY_VERSION_2 | _LINUX_CAPABILITY_VERSION_3 => {
1357 let (permitted, effective, inheritable) =
1359 (permitted.as_abi_v3(), effective.as_abi_v3(), inheritable.as_abi_v3());
1360 let data: [__user_cap_data_struct; 2] = [
1361 __user_cap_data_struct {
1362 effective: effective.0,
1363 inheritable: inheritable.0,
1364 permitted: permitted.0,
1365 },
1366 __user_cap_data_struct {
1367 effective: effective.1,
1368 inheritable: inheritable.1,
1369 permitted: permitted.1,
1370 },
1371 ];
1372 current_task.write_objects(user_data, &data)?;
1373 }
1374 _ => {
1375 unreachable!("already returned if Linux capability version is not valid")
1376 }
1377 }
1378 Ok(())
1379}
1380
1381pub fn sys_capset(
1382 current_task: &CurrentTask,
1383 user_header: UserRef<__user_cap_header_struct>,
1384 user_data: UserRef<__user_cap_data_struct>,
1385) -> Result<(), Errno> {
1386 let mut header = current_task.read_object(user_header)?;
1387 let is_version_valid =
1388 [_LINUX_CAPABILITY_VERSION_1, _LINUX_CAPABILITY_VERSION_2, _LINUX_CAPABILITY_VERSION_3]
1389 .contains(&header.version);
1390 if !is_version_valid {
1391 header.version = _LINUX_CAPABILITY_VERSION_3;
1392 current_task.write_object(user_header, &header)?;
1393 return error!(EINVAL);
1394 }
1395 if header.pid != 0 && header.pid != current_task.tid.id {
1396 return error!(EPERM);
1397 }
1398
1399 let (new_permitted, new_effective, new_inheritable) = match header.version {
1400 _LINUX_CAPABILITY_VERSION_1 => {
1401 let data = current_task.read_object(user_data)?;
1402 (
1403 Capabilities::from_abi_v1(data.permitted),
1404 Capabilities::from_abi_v1(data.effective),
1405 Capabilities::from_abi_v1(data.inheritable),
1406 )
1407 }
1408 _LINUX_CAPABILITY_VERSION_2 | _LINUX_CAPABILITY_VERSION_3 => {
1409 let data =
1410 current_task.read_objects_to_array::<__user_cap_data_struct, 2>(user_data)?;
1411 (
1412 Capabilities::from_abi_v3((data[0].permitted, data[1].permitted)),
1413 Capabilities::from_abi_v3((data[0].effective, data[1].effective)),
1414 Capabilities::from_abi_v3((data[0].inheritable, data[1].inheritable)),
1415 )
1416 }
1417 _ => {
1418 unreachable!("already returned if Linux capability version is not valid")
1419 }
1420 };
1421
1422 let mut creds = Credentials::clone(¤t_task.current_creds());
1424 {
1425 log_trace!(
1426 "Capabilities({{permitted={:?} from {:?}, effective={:?} from {:?}, inheritable={:?} from {:?}}}, bounding={:?})",
1427 new_permitted,
1428 creds.cap_permitted,
1429 new_effective,
1430 creds.cap_effective,
1431 new_inheritable,
1432 creds.cap_inheritable,
1433 creds.cap_bounding
1434 );
1435 if !creds.cap_inheritable.union(creds.cap_permitted).contains(new_inheritable) {
1436 security::check_task_capable(current_task, CAP_SETPCAP)?;
1437 }
1438
1439 if !creds.cap_inheritable.union(creds.cap_bounding).contains(new_inheritable) {
1440 return error!(EPERM);
1441 }
1442 if !creds.cap_permitted.contains(new_permitted) {
1443 return error!(EPERM);
1444 }
1445 if !new_permitted.contains(new_effective) {
1446 return error!(EPERM);
1447 }
1448 }
1449 let target_task = get_task_or_current(current_task, header.pid)?;
1450
1451 security::check_setcap_access(current_task, &target_task)?;
1452
1453 creds.cap_permitted = new_permitted;
1454 creds.cap_effective = new_effective;
1455 creds.cap_inheritable = new_inheritable;
1456 creds.cap_ambient = new_permitted & new_inheritable & creds.cap_ambient;
1457 current_task.set_creds(creds);
1458 Ok(())
1459}
1460
1461pub fn sys_seccomp(
1462 current_task: &mut CurrentTask,
1463 operation: u32,
1464 flags: u32,
1465 args: UserAddress,
1466) -> Result<SyscallResult, Errno> {
1467 match operation {
1468 SECCOMP_SET_MODE_STRICT => {
1469 if flags != 0 || args != UserAddress::NULL {
1470 return error!(EINVAL);
1471 }
1472 current_task.set_seccomp_state(SeccompStateValue::Strict)?;
1473 Ok(().into())
1474 }
1475 SECCOMP_SET_MODE_FILTER => {
1476 if flags
1477 & (SECCOMP_FILTER_FLAG_LOG
1478 | SECCOMP_FILTER_FLAG_NEW_LISTENER
1479 | SECCOMP_FILTER_FLAG_SPEC_ALLOW
1480 | SECCOMP_FILTER_FLAG_TSYNC
1481 | SECCOMP_FILTER_FLAG_TSYNC_ESRCH)
1482 != flags
1483 {
1484 return error!(EINVAL);
1485 }
1486 if (flags & SECCOMP_FILTER_FLAG_TSYNC == 0)
1487 && (flags & SECCOMP_FILTER_FLAG_TSYNC_ESRCH != 0)
1488 {
1489 return error!(EINVAL);
1490 }
1491 if (flags & SECCOMP_FILTER_FLAG_NEW_LISTENER != 0)
1492 && (flags & SECCOMP_FILTER_FLAG_TSYNC != 0)
1493 && (flags & SECCOMP_FILTER_FLAG_TSYNC_ESRCH == 0)
1494 {
1495 return error!(EINVAL);
1496 }
1497 let fprog =
1498 current_task.read_multi_arch_object(SockFProgPtr::new(current_task, args))?;
1499 if fprog.len > BPF_MAXINSNS || fprog.len == 0 {
1500 return error!(EINVAL);
1501 }
1502 let code: Vec<sock_filter> =
1503 current_task.read_multi_arch_objects_to_vec(fprog.filter, fprog.len as usize)?;
1504
1505 if !current_task.read().no_new_privs() {
1506 security::check_task_capable(current_task, CAP_SYS_ADMIN)
1507 .map_err(|_| errno!(EACCES))?;
1508 }
1509 current_task.add_seccomp_filter(code, flags)
1510 }
1511 SECCOMP_GET_ACTION_AVAIL => {
1512 if flags != 0 || args.is_null() {
1513 return error!(EINVAL);
1514 }
1515 let action: u32 = current_task.read_object(UserRef::new(args))?;
1516 SeccompAction::is_action_available(action)
1517 }
1518 SECCOMP_GET_NOTIF_SIZES => {
1519 if flags != 0 {
1520 return error!(EINVAL);
1521 }
1522 track_stub!(TODO("https://fxbug.dev/322874791"), "SECCOMP_GET_NOTIF_SIZES");
1523 error!(ENOSYS)
1524 }
1525 _ => {
1526 track_stub!(TODO("https://fxbug.dev/322874916"), "seccomp fallthrough", operation);
1527 error!(EINVAL)
1528 }
1529 }
1530}
1531
1532pub fn sys_setgroups(
1533 current_task: &CurrentTask,
1534 size: usize,
1535 groups_addr: UserAddress,
1536) -> Result<(), Errno> {
1537 if size > NGROUPS_MAX as usize {
1538 return error!(EINVAL);
1539 }
1540 let groups = current_task.read_objects_to_vec::<gid_t>(groups_addr.into(), size)?;
1541 security::check_task_capable(current_task, CAP_SETGID)?;
1542 let mut creds = Credentials::clone(¤t_task.current_creds());
1543 creds.groups = groups;
1544 current_task.set_creds(creds);
1545 Ok(())
1546}
1547
1548pub fn sys_getgroups(
1549 current_task: &CurrentTask,
1550 size: usize,
1551 groups_addr: UserAddress,
1552) -> Result<usize, Errno> {
1553 if size > NGROUPS_MAX as usize {
1554 return error!(EINVAL);
1555 }
1556 let creds = current_task.current_creds();
1557 if size != 0 {
1558 if size < creds.groups.len() {
1559 return error!(EINVAL);
1560 }
1561 current_task.write_memory(groups_addr, creds.groups.as_slice().as_bytes())?;
1562 }
1563 Ok(creds.groups.len())
1564}
1565
1566pub fn sys_setsid(current_task: &CurrentTask) -> Result<pid_t, Errno> {
1567 current_task.thread_group().setsid()?;
1568 Ok(current_task.get_pid())
1569}
1570
1571pub fn sys_getpriority(current_task: &CurrentTask, which: u32, who: i32) -> Result<u8, Errno> {
1575 match which {
1576 PRIO_PROCESS => {}
1577 _ => return error!(EINVAL),
1579 }
1580 track_stub!(TODO("https://fxbug.dev/322893809"), "getpriority permissions");
1581 let target_task = get_task_or_current(current_task, who)?;
1582 let state = target_task.read();
1583 Ok(state.scheduler_state.normal_priority.raw_priority())
1584}
1585
1586pub fn sys_setpriority(
1591 current_task: &CurrentTask,
1592 which: u32,
1593 who: i32,
1594 priority: i32,
1595) -> Result<(), Errno> {
1596 match which {
1598 PRIO_PROCESS => {}
1599 _ => return error!(EINVAL),
1601 }
1602
1603 let target_task = get_task_or_current(current_task, who)?;
1604
1605 let normal_priority = NormalPriority::from_setpriority_syscall(priority);
1606
1607 let current_state = target_task.read().scheduler_state;
1609
1610 let euid_friendly = current_task.is_euid_friendly_with(&target_task);
1612 let strengthening = current_state.normal_priority < normal_priority;
1613 let rlimited = strengthening
1614 && normal_priority.exceeds(target_task.thread_group().get_rlimit(Resource::NICE));
1615 if !euid_friendly {
1616 security::check_task_capable(current_task, CAP_SYS_NICE)?;
1617 } else if rlimited {
1618 security::check_task_capable(current_task, CAP_SYS_NICE).map_err(|_| errno!(EACCES))?;
1619 }
1620
1621 security::check_task_setnice_access(current_task, &target_task)?;
1622
1623 target_task.set_scheduler_nice(normal_priority)?;
1625
1626 Ok(())
1627}
1628
1629pub fn sys_setns(current_task: &CurrentTask, ns_fd: FdNumber, ns_type: c_int) -> Result<(), Errno> {
1630 let file_handle = current_task.files().get(ns_fd)?;
1631
1632 security::check_task_capable(current_task, CAP_SYS_ADMIN)?;
1636
1637 if let Some(mount_ns) = file_handle.downcast_file::<MountNamespaceFile>() {
1638 if !(ns_type == 0 || ns_type == CLONE_NEWNS as i32) {
1639 log_trace!("invalid type");
1640 return error!(EINVAL);
1641 }
1642
1643 track_stub!(TODO("https://fxbug.dev/297312091"), "setns CLONE_FS limitations");
1644 current_task.fs().set_namespace(mount_ns.0.clone())?;
1645 return Ok(());
1646 }
1647
1648 if let Some(_pidfd) = file_handle.downcast_file::<PidFdFileObject>() {
1649 track_stub!(TODO("https://fxbug.dev/297312844"), "setns w/ pidfd");
1650 return error!(ENOSYS);
1651 }
1652
1653 track_stub!(TODO("https://fxbug.dev/322893829"), "unknown ns file for setns, see logs");
1654 log_info!("ns_fd was not a supported namespace file: {}", file_handle.ops_type_name());
1655 error!(EINVAL)
1656}
1657
1658pub fn sys_unshare(current_task: &CurrentTask, flags: u32) -> Result<(), Errno> {
1659 const IMPLEMENTED_FLAGS: u32 = CLONE_FILES | CLONE_FS | CLONE_NEWNS | CLONE_NEWUTS;
1660 if flags & !IMPLEMENTED_FLAGS != 0 {
1661 track_stub!(TODO("https://fxbug.dev/322893372"), "unshare", flags & !IMPLEMENTED_FLAGS);
1662 return error!(EINVAL);
1663 }
1664
1665 if (flags & CLONE_FILES) != 0 {
1666 current_task.running_state().unshare_files(current_task);
1667 }
1668
1669 if (flags & CLONE_FS) != 0 {
1670 current_task.unshare_fs();
1671 }
1672
1673 if (flags & CLONE_NEWNS) != 0 {
1674 security::check_task_capable(current_task, CAP_SYS_ADMIN)?;
1675 current_task.fs().unshare_namespace();
1676 }
1677
1678 if (flags & CLONE_NEWUTS) != 0 {
1679 security::check_task_capable(current_task, CAP_SYS_ADMIN)?;
1680 let mut task_state = current_task.write();
1682 let new_uts_ns = task_state.uts_ns.read().clone();
1683 task_state.uts_ns = Arc::new(new_uts_ns.into());
1684 }
1685
1686 Ok(())
1687}
1688
1689pub fn sys_swapon(
1690 current_task: &CurrentTask,
1691 user_path: UserCString,
1692 _flags: i32,
1693) -> Result<(), Errno> {
1694 const MAX_SWAPFILES: usize = 32; security::check_task_capable(current_task, CAP_SYS_ADMIN)?;
1697
1698 track_stub!(TODO("https://fxbug.dev/322893905"), "swapon validate flags");
1699
1700 let path = current_task.read_path(user_path)?;
1701 let file = current_task.open_file(path.as_ref(), OpenFlags::RDWR)?;
1702
1703 let node = file.node();
1704 let mode = node.info().mode;
1705 if !mode.is_reg() && !mode.is_blk() {
1706 return error!(EINVAL);
1707 }
1708
1709 const MAGIC_OFFSET: usize = 0xff6;
1714 let swap_magic = b"SWAPSPACE2";
1715 let mut buffer = VecOutputBuffer::new(swap_magic.len());
1716 if file.read_at(current_task, MAGIC_OFFSET, &mut buffer)? != swap_magic.len()
1717 || buffer.data() != swap_magic
1718 {
1719 return error!(EINVAL);
1720 }
1721
1722 let mut swap_files = current_task.kernel().swap_files.lock();
1723 for swap_node in swap_files.iter() {
1724 if Arc::ptr_eq(swap_node, node) {
1725 return error!(EBUSY);
1726 }
1727 }
1728 if swap_files.len() >= MAX_SWAPFILES {
1729 return error!(EPERM);
1730 }
1731 swap_files.push(node.clone());
1732 Ok(())
1733}
1734
1735pub fn sys_swapoff(current_task: &CurrentTask, user_path: UserCString) -> Result<(), Errno> {
1736 security::check_task_capable(current_task, CAP_SYS_ADMIN)?;
1737
1738 let path = current_task.read_path(user_path)?;
1739 let file = current_task.open_file(path.as_ref(), OpenFlags::RDWR)?;
1740 let node = file.node();
1741
1742 let mut swap_files = current_task.kernel().swap_files.lock();
1743 let original_length = swap_files.len();
1744 swap_files.retain(|swap_node| !Arc::ptr_eq(swap_node, node));
1745 if swap_files.len() == original_length {
1746 return error!(EINVAL);
1747 }
1748 Ok(())
1749}
1750
1751#[derive(Default, Debug, IntoBytes, KnownLayout, FromBytes, Immutable)]
1752#[repr(C)]
1753struct KcmpParams {
1754 mask: usize,
1755 shuffle: usize,
1756}
1757
1758static KCMP_PARAMS: LazyLock<KcmpParams> = LazyLock::new(|| {
1759 let mut params = KcmpParams::default();
1760 starnix_crypto::cprng_draw(params.as_mut_bytes());
1761 params.shuffle |= 1;
1763 params
1764});
1765
1766fn obfuscate_value(value: usize) -> usize {
1767 let KcmpParams { mask, shuffle } = *KCMP_PARAMS;
1768 (value ^ mask).wrapping_mul(shuffle)
1769}
1770
1771fn obfuscate_ptr<T>(ptr: *const T) -> usize {
1772 obfuscate_value(ptr as usize)
1773}
1774
1775fn obfuscate_arc<T>(arc: &Arc<T>) -> usize {
1776 obfuscate_ptr(Arc::as_ptr(arc))
1777}
1778
1779pub fn sys_kcmp(
1780 current_task: &CurrentTask,
1781 pid1: pid_t,
1782 pid2: pid_t,
1783 resource_type: u32,
1784 index1: u64,
1785 index2: u64,
1786) -> Result<u32, Errno> {
1787 let task1 = current_task.get_task(pid1)?;
1788 let task2 = current_task.get_task(pid2)?;
1789
1790 current_task.check_ptrace_access_mode(PTRACE_MODE_READ_REALCREDS, &task1)?;
1791 current_task.check_ptrace_access_mode(PTRACE_MODE_READ_REALCREDS, &task2)?;
1792
1793 let resource_type = KcmpResource::from_raw(resource_type)?;
1794
1795 fn encode_ordering(value: cmp::Ordering) -> u32 {
1803 match value {
1804 cmp::Ordering::Equal => 0,
1805 cmp::Ordering::Less => 1,
1806 cmp::Ordering::Greater => 2,
1807 }
1808 }
1809
1810 match resource_type {
1811 KcmpResource::FILE => {
1812 fn get_file(task: &Task, index: u64) -> Result<FileHandle, Errno> {
1813 task.files()?.get_allowing_opath(FdNumber::from_raw(
1816 index.try_into().map_err(|_| errno!(EBADF))?,
1817 ))
1818 }
1819 let file1 = get_file(&task1, index1)?;
1820 let file2 = get_file(&task2, index2)?;
1821 Ok(encode_ordering(obfuscate_arc(&file1).cmp(&obfuscate_arc(&file2))))
1822 }
1823 KcmpResource::FILES => {
1824 let files1 = task1.files()?.id();
1825 let files2 = task2.files()?.id();
1826 Ok(encode_ordering(obfuscate_value(files1.raw()).cmp(&obfuscate_value(files2.raw()))))
1827 }
1828 KcmpResource::FS => {
1829 let fs1 = task1.running_state()?.fs();
1830 let fs2 = task2.running_state()?.fs();
1831 Ok(encode_ordering(obfuscate_arc(&fs1).cmp(&obfuscate_arc(&fs2))))
1832 }
1833 KcmpResource::SIGHAND => Ok(encode_ordering(
1834 obfuscate_arc(&task1.thread_group().signal_actions)
1835 .cmp(&obfuscate_arc(&task2.thread_group().signal_actions)),
1836 )),
1837 KcmpResource::VM => {
1838 Ok(encode_ordering(obfuscate_arc(&task1.mm()?).cmp(&obfuscate_arc(&task2.mm()?))))
1839 }
1840 _ => error!(EINVAL),
1841 }
1842}
1843
1844pub fn sys_syslog(
1845 current_task: &CurrentTask,
1846 action_type: i32,
1847 address: UserAddress,
1848 length: i32,
1849) -> Result<i32, Errno> {
1850 let action = SyslogAction::try_from(action_type)?;
1851 let syslog =
1852 current_task.kernel().syslog.access(¤t_task, SyslogAccess::Syscall(action))?;
1853 match action {
1854 SyslogAction::Read => {
1855 if address.is_null() || length < 0 {
1856 return error!(EINVAL);
1857 }
1858 let mut output_buffer =
1859 UserBuffersOutputBuffer::unified_new_at(current_task, address, length as usize)?;
1860 syslog.blocking_read(current_task, &mut output_buffer)
1861 }
1862 SyslogAction::ReadAll => {
1863 if address.is_null() || length < 0 {
1864 return error!(EINVAL);
1865 }
1866 let mut output_buffer =
1867 UserBuffersOutputBuffer::unified_new_at(current_task, address, length as usize)?;
1868 syslog.read_all(current_task.kernel(), &mut output_buffer)
1869 }
1870 SyslogAction::SizeUnread => syslog.size_unread(),
1871 SyslogAction::SizeBuffer => syslog.size_buffer(),
1872 SyslogAction::Close | SyslogAction::Open => Ok(0),
1873 SyslogAction::ReadClear => {
1874 track_stub!(TODO("https://fxbug.dev/322894145"), "syslog: read clear");
1875 Ok(0)
1876 }
1877 SyslogAction::Clear => {
1878 track_stub!(TODO("https://fxbug.dev/322893673"), "syslog: clear");
1879 Ok(0)
1880 }
1881 SyslogAction::ConsoleOff => {
1882 track_stub!(TODO("https://fxbug.dev/322894399"), "syslog: console off");
1883 Ok(0)
1884 }
1885 SyslogAction::ConsoleOn => {
1886 track_stub!(TODO("https://fxbug.dev/322894106"), "syslog: console on");
1887 Ok(0)
1888 }
1889 SyslogAction::ConsoleLevel => {
1890 if length <= 0 || length >= 8 {
1891 return error!(EINVAL);
1892 }
1893 track_stub!(TODO("https://fxbug.dev/322894199"), "syslog: console level");
1894 Ok(0)
1895 }
1896 }
1897}
1898
1899pub fn sys_vhangup(current_task: &CurrentTask) -> Result<(), Errno> {
1900 security::check_task_capable(current_task, CAP_SYS_TTY_CONFIG)?;
1901 track_stub!(TODO("https://fxbug.dev/324079257"), "vhangup");
1902 Ok(())
1903}
1904
1905#[cfg(target_arch = "aarch64")]
1907mod arch32 {
1908 pub use super::{
1909 sys_execve as sys_arch32_execve, sys_execveat as sys_arch32_execveat,
1910 sys_getegid as sys_arch32_getegid32, sys_geteuid as sys_arch32_geteuid32,
1911 sys_getgid as sys_arch32_getgid32, sys_getgroups as sys_arch32_getgroups32,
1912 sys_getpgid as sys_arch32_getpgid, sys_getppid as sys_arch32_getppid,
1913 sys_getpriority as sys_arch32_getpriority, sys_getresgid as sys_arch32_getresgid32,
1914 sys_getresuid as sys_arch32_getresuid32, sys_getrlimit as sys_arch32_ugetrlimit,
1915 sys_getrusage as sys_arch32_getrusage, sys_getuid as sys_arch32_getuid32,
1916 sys_ioprio_set as sys_arch32_ioprio_set, sys_ptrace as sys_arch32_ptrace,
1917 sys_quotactl as sys_arch32_quotactl,
1918 sys_sched_get_priority_max as sys_arch32_sched_get_priority_max,
1919 sys_sched_get_priority_min as sys_arch32_sched_get_priority_min,
1920 sys_sched_getaffinity as sys_arch32_sched_getaffinity,
1921 sys_sched_getparam as sys_arch32_sched_getparam,
1922 sys_sched_setaffinity as sys_arch32_sched_setaffinity,
1923 sys_sched_setparam as sys_arch32_sched_setparam,
1924 sys_sched_setscheduler as sys_arch32_sched_setscheduler, sys_seccomp as sys_arch32_seccomp,
1925 sys_setfsgid as sys_arch32_setfsgid, sys_setfsgid as sys_arch32_setfsgid32,
1926 sys_setfsuid as sys_arch32_setfsuid, sys_setfsuid as sys_arch32_setfsuid32,
1927 sys_setgid as sys_arch32_setgid32, sys_setgroups as sys_arch32_setgroups32,
1928 sys_setns as sys_arch32_setns, sys_setpgid as sys_arch32_setpgid,
1929 sys_setpriority as sys_arch32_setpriority, sys_setregid as sys_arch32_setregid32,
1930 sys_setresgid as sys_arch32_setresgid32, sys_setresuid as sys_arch32_setresuid32,
1931 sys_setreuid as sys_arch32_setreuid32, sys_setreuid as sys_arch32_setreuid,
1932 sys_setrlimit as sys_arch32_setrlimit, sys_setsid as sys_arch32_setsid,
1933 sys_syslog as sys_arch32_syslog, sys_unshare as sys_arch32_unshare,
1934 };
1935}
1936
1937#[cfg(target_arch = "aarch64")]
1938pub use arch32::*;
1939
1940#[cfg(test)]
1941mod tests {
1942 use super::*;
1943 use crate::mm::syscalls::sys_munmap;
1944 use crate::testing::{AutoReleasableTask, map_memory, spawn_kernel_and_run};
1945 use starnix_syscalls::SUCCESS;
1946 use starnix_task_command::TaskCommand;
1947 use starnix_uapi::auth::Credentials;
1948 use starnix_uapi::{SCHED_FIFO, SCHED_NORMAL};
1949 use std::ffi::CString;
1950
1951 #[::fuchsia::test]
1952 async fn test_prctl_set_vma_anon_name() {
1953 spawn_kernel_and_run(async |current_task| {
1954 let mapped_address = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
1955 let name_addr = (mapped_address + 128u64).unwrap();
1956 let name = "test-name\0";
1957 current_task.write_memory(name_addr, name.as_bytes()).expect("failed to write name");
1958 sys_prctl(
1959 current_task,
1960 PR_SET_VMA,
1961 PR_SET_VMA_ANON_NAME as u64,
1962 mapped_address.ptr() as u64,
1963 32,
1964 name_addr.ptr() as u64,
1965 )
1966 .expect("failed to set name");
1967 assert_eq!(
1968 "test-name",
1969 current_task
1970 .mm()
1971 .unwrap()
1972 .get_mapping_name((mapped_address + 24u64).unwrap())
1973 .expect("failed to get address")
1974 .unwrap()
1975 .to_string(),
1976 );
1977
1978 sys_munmap(¤t_task, mapped_address, *PAGE_SIZE as usize)
1979 .expect("failed to unmap memory");
1980 assert_eq!(
1981 error!(EFAULT),
1982 current_task.mm().unwrap().get_mapping_name((mapped_address + 24u64).unwrap())
1983 );
1984 })
1985 .await;
1986 }
1987
1988 #[::fuchsia::test]
1989 async fn test_set_vma_name_special_chars() {
1990 spawn_kernel_and_run(async |current_task| {
1991 let name_addr = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
1992
1993 let mapping_addr = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
1994
1995 for c in 1..255 {
1996 let vma_name = CString::new([c]).unwrap();
1997 current_task.write_memory(name_addr, vma_name.as_bytes_with_nul()).unwrap();
1998
1999 let result = sys_prctl(
2000 current_task,
2001 PR_SET_VMA,
2002 PR_SET_VMA_ANON_NAME as u64,
2003 mapping_addr.ptr() as u64,
2004 *PAGE_SIZE,
2005 name_addr.ptr() as u64,
2006 );
2007
2008 if c > 0x1f
2009 && c < 0x7f
2010 && c != b'\\'
2011 && c != b'`'
2012 && c != b'$'
2013 && c != b'['
2014 && c != b']'
2015 {
2016 assert_eq!(result, Ok(SUCCESS));
2017 } else {
2018 assert_eq!(result, error!(EINVAL));
2019 }
2020 }
2021 })
2022 .await;
2023 }
2024
2025 #[::fuchsia::test]
2026 async fn test_set_vma_name_long() {
2027 spawn_kernel_and_run(async |current_task| {
2028 let name_addr = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
2029
2030 let mapping_addr = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
2031
2032 let name_too_long = CString::new(vec![b'a'; 256]).unwrap();
2033
2034 current_task.write_memory(name_addr, name_too_long.as_bytes_with_nul()).unwrap();
2035
2036 assert_eq!(
2037 sys_prctl(
2038 current_task,
2039 PR_SET_VMA,
2040 PR_SET_VMA_ANON_NAME as u64,
2041 mapping_addr.ptr() as u64,
2042 *PAGE_SIZE,
2043 name_addr.ptr() as u64,
2044 ),
2045 error!(EINVAL)
2046 );
2047
2048 let name_just_long_enough = CString::new(vec![b'a'; 255]).unwrap();
2049
2050 current_task
2051 .write_memory(name_addr, name_just_long_enough.as_bytes_with_nul())
2052 .unwrap();
2053
2054 assert_eq!(
2055 sys_prctl(
2056 current_task,
2057 PR_SET_VMA,
2058 PR_SET_VMA_ANON_NAME as u64,
2059 mapping_addr.ptr() as u64,
2060 *PAGE_SIZE,
2061 name_addr.ptr() as u64,
2062 ),
2063 Ok(SUCCESS)
2064 );
2065 })
2066 .await;
2067 }
2068
2069 #[::fuchsia::test]
2070 async fn test_set_vma_name_misaligned() {
2071 spawn_kernel_and_run(async |current_task| {
2072 let name_addr = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
2073
2074 let mapping_addr = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
2075
2076 let name = CString::new("name").unwrap();
2077 current_task.write_memory(name_addr, name.as_bytes_with_nul()).unwrap();
2078
2079 assert_eq!(
2081 sys_prctl(
2082 current_task,
2083 PR_SET_VMA,
2084 PR_SET_VMA_ANON_NAME as u64,
2085 1 + mapping_addr.ptr() as u64,
2086 *PAGE_SIZE - 1,
2087 name_addr.ptr() as u64,
2088 ),
2089 error!(EINVAL)
2090 );
2091
2092 assert_eq!(
2094 sys_prctl(
2095 current_task,
2096 PR_SET_VMA,
2097 PR_SET_VMA_ANON_NAME as u64,
2098 mapping_addr.ptr() as u64,
2099 *PAGE_SIZE - 1,
2100 name_addr.ptr() as u64,
2101 ),
2102 Ok(SUCCESS)
2103 );
2104 })
2105 .await;
2106 }
2107
2108 #[::fuchsia::test]
2109 async fn test_prctl_get_set_dumpable() {
2110 spawn_kernel_and_run(async |current_task| {
2111 sys_prctl(current_task, PR_GET_DUMPABLE, 0, 0, 0, 0).expect("failed to get dumpable");
2112
2113 sys_prctl(current_task, PR_SET_DUMPABLE, 1, 0, 0, 0).expect("failed to set dumpable");
2114 sys_prctl(current_task, PR_GET_DUMPABLE, 0, 0, 0, 0).expect("failed to get dumpable");
2115
2116 sys_prctl(current_task, PR_SET_DUMPABLE, 2, 0, 0, 0).expect("failed to set dumpable");
2118 sys_prctl(current_task, PR_GET_DUMPABLE, 0, 0, 0, 0).expect("failed to get dumpable");
2119 })
2120 .await;
2121 }
2122
2123 #[::fuchsia::test]
2124 async fn test_sys_getsid() {
2125 spawn_kernel_and_run(async |current_task| {
2126 let kernel = current_task.kernel();
2127 assert_eq!(
2128 current_task.get_tid(),
2129 sys_getsid(¤t_task, 0).expect("failed to get sid")
2130 );
2131
2132 let second_task = crate::execution::create_init_child_process(
2133 &kernel.weak_self.upgrade().unwrap(),
2134 TaskCommand::new(b"second task"),
2135 Credentials::with_ids(0, 0),
2136 None,
2137 )
2138 .expect("failed to create second task");
2139 let second_current = AutoReleasableTask::from(second_task);
2140
2141 assert_eq!(
2142 second_current.get_tid(),
2143 sys_getsid(¤t_task, second_current.get_tid()).expect("failed to get sid")
2144 );
2145 })
2146 .await;
2147 }
2148
2149 #[::fuchsia::test]
2150 async fn test_get_affinity_size() {
2151 spawn_kernel_and_run(async |current_task| {
2152 let mapped_address = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
2153 let pid = current_task.get_pid();
2154 assert_eq!(sys_sched_getaffinity(¤t_task, pid, 16, mapped_address), Ok(16));
2155 assert_eq!(
2156 sys_sched_getaffinity(¤t_task, pid, 1024, mapped_address),
2157 Ok(std::mem::size_of::<CpuSet>())
2158 );
2159 assert_eq!(
2160 sys_sched_getaffinity(¤t_task, pid, 1, mapped_address),
2161 error!(EINVAL)
2162 );
2163 assert_eq!(
2164 sys_sched_getaffinity(¤t_task, pid, 9, mapped_address),
2165 error!(EINVAL)
2166 );
2167 })
2168 .await;
2169 }
2170
2171 #[::fuchsia::test]
2172 async fn test_set_affinity_size() {
2173 spawn_kernel_and_run(async |current_task| {
2174 let mapped_address = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
2175 current_task.write_memory(mapped_address, &[0xffu8]).expect("failed to cpumask");
2176 let pid = current_task.get_pid();
2177 assert_eq!(
2178 sys_sched_setaffinity(¤t_task, pid, *PAGE_SIZE as u32, mapped_address),
2179 Ok(())
2180 );
2181 assert_eq!(
2182 sys_sched_setaffinity(¤t_task, pid, 1, mapped_address),
2183 error!(EINVAL)
2184 );
2185 })
2186 .await;
2187 }
2188
2189 #[::fuchsia::test]
2190 async fn test_task_name() {
2191 spawn_kernel_and_run(async |current_task| {
2192 let mapped_address = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
2193 let name = "my-task-name\0";
2194 current_task
2195 .write_memory(mapped_address, name.as_bytes())
2196 .expect("failed to write name");
2197
2198 let result =
2199 sys_prctl(current_task, PR_SET_NAME, mapped_address.ptr() as u64, 0, 0, 0).unwrap();
2200 assert_eq!(SUCCESS, result);
2201
2202 let mapped_address = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
2203 let result =
2204 sys_prctl(current_task, PR_GET_NAME, mapped_address.ptr() as u64, 0, 0, 0).unwrap();
2205 assert_eq!(SUCCESS, result);
2206
2207 let name_length = name.len();
2208
2209 let out_name = current_task.read_memory_to_vec(mapped_address, name_length).unwrap();
2210 assert_eq!(name.as_bytes(), &out_name);
2211 })
2212 .await;
2213 }
2214
2215 #[::fuchsia::test]
2216 async fn test_sched_get_priority_min_max() {
2217 spawn_kernel_and_run(async |current_task| {
2218 let non_rt_min = sys_sched_get_priority_min(¤t_task, SCHED_NORMAL).unwrap();
2219 assert_eq!(non_rt_min, 0);
2220 let non_rt_max = sys_sched_get_priority_max(¤t_task, SCHED_NORMAL).unwrap();
2221 assert_eq!(non_rt_max, 0);
2222
2223 let rt_min = sys_sched_get_priority_min(¤t_task, SCHED_FIFO).unwrap();
2224 assert_eq!(rt_min, 1);
2225 let rt_max = sys_sched_get_priority_max(¤t_task, SCHED_FIFO).unwrap();
2226 assert_eq!(rt_max, 99);
2227
2228 let min_bad_policy_error =
2229 sys_sched_get_priority_min(¤t_task, u32::MAX).unwrap_err();
2230 assert_eq!(min_bad_policy_error, errno!(EINVAL));
2231
2232 let max_bad_policy_error =
2233 sys_sched_get_priority_max(¤t_task, u32::MAX).unwrap_err();
2234 assert_eq!(max_bad_policy_error, errno!(EINVAL));
2235 })
2236 .await;
2237 }
2238
2239 #[::fuchsia::test]
2240 async fn test_sched_setscheduler() {
2241 spawn_kernel_and_run(async |current_task| {
2242 current_task
2243 .thread_group()
2244 .limits
2245 .lock()
2246 .set(Resource::RTPRIO, rlimit { rlim_cur: 255, rlim_max: 255 });
2247
2248 let scheduler = sys_sched_getscheduler(¤t_task, 0).unwrap();
2249 assert_eq!(scheduler, SCHED_NORMAL, "tasks should have normal scheduler by default");
2250
2251 let mapped_address = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
2252 let requested_params = sched_param { sched_priority: 15 };
2253 current_task.write_object(mapped_address.into(), &requested_params).unwrap();
2254
2255 sys_sched_setscheduler(¤t_task, 0, SCHED_FIFO, mapped_address.into()).unwrap();
2256
2257 let new_scheduler = sys_sched_getscheduler(¤t_task, 0).unwrap();
2258 assert_eq!(new_scheduler, SCHED_FIFO, "task should have been assigned fifo scheduler");
2259
2260 let mapped_address = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
2261 sys_sched_getparam(¤t_task, 0, mapped_address.into()).expect("sched_getparam");
2262 let param_value: sched_param =
2263 current_task.read_object(mapped_address.into()).expect("read_object");
2264 assert_eq!(param_value.sched_priority, 15);
2265 })
2266 .await;
2267 }
2268
2269 #[::fuchsia::test]
2270 async fn test_sched_getparam() {
2271 spawn_kernel_and_run(async |current_task| {
2272 let mapped_address = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
2273 sys_sched_getparam(¤t_task, 0, mapped_address.into()).expect("sched_getparam");
2274 let param_value: sched_param =
2275 current_task.read_object(mapped_address.into()).expect("read_object");
2276 assert_eq!(param_value.sched_priority, 0);
2277 })
2278 .await;
2279 }
2280
2281 #[::fuchsia::test]
2282 async fn test_setuid() {
2283 spawn_kernel_and_run(async |current_task| {
2284 current_task.set_creds(Credentials::with_ids(0, 0));
2286 sys_setuid(¤t_task, 42).expect("setuid");
2287 let mut creds = Credentials::clone(¤t_task.current_creds());
2288 assert_eq!(creds.euid, 42);
2289 assert_eq!(creds.uid, 42);
2290 assert_eq!(creds.saved_uid, 42);
2291
2292 creds.cap_effective.remove(CAP_SETUID);
2294 current_task.set_creds(creds);
2295
2296 assert_eq!(sys_setuid(¤t_task, 0), error!(EPERM));
2298 assert_eq!(sys_setuid(¤t_task, 43), error!(EPERM));
2299
2300 sys_setuid(¤t_task, 42).expect("setuid");
2301 assert_eq!(current_task.current_creds().euid, 42);
2302 assert_eq!(current_task.current_creds().uid, 42);
2303 assert_eq!(current_task.current_creds().saved_uid, 42);
2304
2305 let mut creds = Credentials::clone(¤t_task.current_creds());
2307 creds.uid = 41;
2308 creds.euid = 42;
2309 creds.saved_uid = 43;
2310 current_task.set_creds(creds);
2311
2312 sys_setuid(¤t_task, 41).expect("setuid");
2313 assert_eq!(current_task.current_creds().euid, 41);
2314 assert_eq!(current_task.current_creds().uid, 41);
2315 assert_eq!(current_task.current_creds().saved_uid, 43);
2316
2317 let mut creds = Credentials::clone(¤t_task.current_creds());
2318 creds.uid = 41;
2319 creds.euid = 42;
2320 creds.saved_uid = 43;
2321 current_task.set_creds(creds);
2322
2323 sys_setuid(¤t_task, 43).expect("setuid");
2324 assert_eq!(current_task.current_creds().euid, 43);
2325 assert_eq!(current_task.current_creds().uid, 41);
2326 assert_eq!(current_task.current_creds().saved_uid, 43);
2327 })
2328 .await;
2329 }
2330
2331 #[::fuchsia::test]
2332 async fn test_read_c_string_vector() {
2333 spawn_kernel_and_run(async |current_task| {
2334 let arg_addr = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
2335 let arg = b"test-arg\0";
2336 current_task.write_memory(arg_addr, arg).expect("failed to write test arg");
2337 let arg_usercstr = UserCString::new(current_task, arg_addr);
2338 let null_usercstr = UserCString::null(current_task);
2339
2340 let argv_addr = UserCStringPtr::new(
2341 current_task,
2342 map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE),
2343 );
2344 current_task
2345 .write_multi_arch_ptr(argv_addr.addr(), arg_usercstr)
2346 .expect("failed to write UserCString");
2347 current_task
2348 .write_multi_arch_ptr(argv_addr.next().unwrap().addr(), null_usercstr)
2349 .expect("failed to write UserCString");
2350
2351 assert!(read_c_string_vector(¤t_task, argv_addr, 100, arg.len()).is_ok());
2353 assert_eq!(
2354 read_c_string_vector(
2355 ¤t_task,
2356 argv_addr,
2357 100,
2358 std::str::from_utf8(arg).unwrap().trim_matches('\0').len()
2359 ),
2360 error!(E2BIG)
2361 );
2362 })
2363 .await;
2364 }
2365}