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