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