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