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, rusage, sched_param, sock_filter, uapi,
55 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
109 if args.stack != 0 {
110 new_task
114 .thread_state
115 .registers
116 .set_stack_pointer_register(args.stack.wrapping_add(args.stack_size));
117 }
118
119 if args.flags & (CLONE_SETTLS as u64) != 0 {
120 new_task.thread_state.registers.set_thread_pointer_register(args.tls);
121 }
122
123 let tid = new_task.task.tid.id;
124 let task_ref = Arc::downgrade(&new_task.task);
125 let trace_kind = current_task.ptrace().on_clone(args, &new_task.task);
126 execute_task(new_task, |_| Ok(()), |_| {})?;
127
128 current_task.ptrace().on_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().on_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;
212 let page_limit_size: usize = PAGE_LIMIT * *PAGE_SIZE as usize;
213 let rlimit = current_task.thread_group().get_rlimit(Resource::STACK);
214 let stack_limit = cmp::min(rlimit / 4, uapi::_STK_LIM as u64 / 4 * 3);
215 let argv_env_limit = cmp::max(page_limit_size, stack_limit as usize);
216
217 let (argv, argv_size) = if user_argv.is_null() {
220 (Vec::new(), 0)
221 } else {
222 read_c_string_vector(current_task, user_argv, page_limit_size, argv_env_limit)?
223 };
224
225 let (environ, _) = if user_environ.is_null() {
226 (Vec::new(), 0)
227 } else {
228 read_c_string_vector(
229 current_task,
230 user_environ,
231 page_limit_size,
232 argv_env_limit - argv_size,
233 )?
234 };
235
236 let path = ¤t_task.read_path(user_path)?;
237
238 log_trace!(argv:?, environ:?, flags:?; "execveat({dir_fd}, {path})");
239
240 let mut open_flags = OpenFlags::empty();
241
242 if flags & AT_SYMLINK_NOFOLLOW != 0 {
243 open_flags |= OpenFlags::NOFOLLOW;
244 }
245
246 if path.is_empty() && flags & AT_EMPTY_PATH == 0 {
247 return error!(ENOENT);
249 }
250
251 let executable = current_task.open_file_for_exec(dir_fd, path.as_ref(), open_flags)?;
252
253 let path = if dir_fd == FdNumber::AT_FDCWD {
256 path.to_vec()
259 } else {
260 match path.first() {
265 Some(b'/') => {
266 path.to_vec()
268 }
269 Some(_) => {
270 let mut new_path = format!("/dev/fd/{}/", dir_fd.raw()).into_bytes();
272 new_path.append(&mut path.to_vec());
273 new_path
274 }
275 None => format!("/dev/fd/{}", dir_fd.raw()).into_bytes(),
277 }
278 };
279
280 let path = CString::new(path).map_err(|_| errno!(EINVAL))?;
281
282 current_task.exec(executable, path, argv, environ)?;
283 Ok(())
284}
285
286pub fn sys_getcpu(
287 current_task: &CurrentTask,
288 cpu_out: UserRef<u32>,
289 node_out: UserRef<u32>,
290) -> Result<(), Errno> {
291 if !cpu_out.is_null() {
294 let thread_stats = current_task
295 .running_state()
296 .thread
297 .get()
298 .expect("current thread is never None when executing")
299 .thread
300 .stats()
301 .map_err(|e| errno!(EINVAL, format!("getting thread stats failed {e:?}")))?;
302 current_task.write_object(cpu_out, &thread_stats.last_scheduled_cpu)?;
303 }
304 if !node_out.is_null() {
305 track_stub!(TODO("https://fxbug.dev/325643815"), "getcpu() numa node");
308 current_task.write_object(node_out, &0)?;
309 }
310 Ok(())
311}
312
313pub fn sys_getpid(current_task: &CurrentTask) -> Result<pid_t, Errno> {
314 Ok(current_task.get_pid())
315}
316
317pub fn sys_gettid(current_task: &CurrentTask) -> Result<pid_t, Errno> {
318 Ok(current_task.get_tid())
319}
320
321pub fn sys_getppid(current_task: &CurrentTask) -> Result<pid_t, Errno> {
322 Ok(current_task.thread_group().read().get_ppid())
323}
324
325fn get_task_or_current(current_task: &CurrentTask, pid: pid_t) -> Result<Arc<Task>, Errno> {
326 if pid == 0 { Ok(current_task.task.clone()) } else { current_task.get_task(pid) }
327}
328
329pub fn sys_getsid(current_task: &CurrentTask, pid: pid_t) -> Result<pid_t, Errno> {
330 let target_task = get_task_or_current(current_task, pid)?;
331 if pid != 0 {
332 security::check_task_getsid(current_task, &target_task)?;
333 }
334 let sid = target_task.thread_group().read().session.id;
335 Ok(sid)
336}
337
338pub fn sys_getpgid(current_task: &CurrentTask, pid: pid_t) -> Result<pid_t, Errno> {
339 let task = get_task_or_current(current_task, pid)?;
340
341 security::check_getpgid_access(current_task, &task)?;
342 Ok(task.thread_group().pgid().id)
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.scheduler_state.lock().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_policy, current_realtime_priority, current_normal_priority, current_reset_on_fork) = {
698 let state = target_task.scheduler_state.lock();
699 (state.policy, state.realtime_priority, state.normal_priority, state.reset_on_fork)
700 };
701
702 let euid_friendly = current_task.is_euid_friendly_with(&target_task);
704 let strengthening = current_realtime_priority < realtime_priority;
705 let rlimited = strengthening
706 && realtime_priority.exceeds(target_task.thread_group().get_rlimit(Resource::RTPRIO));
707 let clearing_reset_on_fork = current_reset_on_fork && !reset_on_fork;
708 let caught_in_idle_trap = current_policy == SchedulingPolicy::Idle
709 && policy != SchedulingPolicy::Idle
710 && current_normal_priority.exceeds(target_task.thread_group().get_rlimit(Resource::NICE));
711 if !euid_friendly || rlimited || clearing_reset_on_fork || caught_in_idle_trap {
712 security::check_task_capable(current_task, CAP_SYS_NICE)?;
713 }
714
715 security::check_task_setscheduler_access(current_task, &target_task)?;
716
717 target_task.set_scheduler_policy_priority_and_reset_on_fork(
719 policy,
720 realtime_priority,
721 reset_on_fork,
722 )?;
723
724 Ok(())
725}
726
727const CPU_SET_SIZE: usize = 128;
728
729#[repr(C)]
730#[derive(Debug, Copy, Clone, IntoBytes, FromBytes, KnownLayout, Immutable)]
731pub struct CpuSet {
732 bits: [u8; CPU_SET_SIZE],
733}
734
735impl Default for CpuSet {
736 fn default() -> Self {
737 Self { bits: [0; CPU_SET_SIZE] }
738 }
739}
740
741fn check_cpu_set_alignment(current_task: &CurrentTask, cpusetsize: u32) -> Result<(), Errno> {
742 let alignment = if current_task.is_arch32() { 4 } else { 8 };
743 if cpusetsize < alignment || cpusetsize % alignment != 0 {
744 return error!(EINVAL);
745 }
746 Ok(())
747}
748
749fn get_default_cpu_set() -> CpuSet {
750 let mut result = CpuSet::default();
751 let mut cpus_count = zx::system_get_num_cpus();
752 let cpus_count_max = (CPU_SET_SIZE * 8) as u32;
753 if cpus_count > cpus_count_max {
754 log_error!("cpus_count={cpus_count}, greater than the {cpus_count_max} max supported.");
755 cpus_count = cpus_count_max;
756 }
757 let mut index = 0;
758 while cpus_count > 0 {
759 let count = std::cmp::min(cpus_count, 8);
760 let (shl, overflow) = 1_u8.overflowing_shl(count);
761 let mask = if overflow { u8::MAX } else { shl - 1 };
762 result.bits[index] = mask;
763 index += 1;
764 cpus_count -= count;
765 }
766 result
767}
768
769pub fn sys_sched_getaffinity(
770 current_task: &CurrentTask,
771 pid: pid_t,
772 cpusetsize: u32,
773 user_mask: UserAddress,
774) -> Result<usize, Errno> {
775 if pid < 0 {
776 return error!(EINVAL);
777 }
778
779 check_cpu_set_alignment(current_task, cpusetsize)?;
780
781 let target_task = get_task_or_current(current_task, pid)?;
782 security::check_task_getscheduler_access(current_task, &target_task)?;
783
784 let mask = get_default_cpu_set();
786 let mask_size = std::cmp::min(cpusetsize as usize, CPU_SET_SIZE);
787 current_task.write_memory(user_mask, &mask.bits[..mask_size])?;
788 track_stub!(TODO("https://fxbug.dev/322874659"), "sched_getaffinity");
789 Ok(mask_size)
790}
791
792pub fn sys_sched_setaffinity(
793 current_task: &CurrentTask,
794 pid: pid_t,
795 cpusetsize: u32,
796 user_mask: UserAddress,
797) -> Result<(), Errno> {
798 if pid < 0 {
799 return error!(EINVAL);
800 }
801 let target_task = get_task_or_current(current_task, pid)?;
802
803 check_cpu_set_alignment(current_task, cpusetsize)?;
804
805 let mask_size = std::cmp::min(cpusetsize as usize, CPU_SET_SIZE);
806 let mut mask = CpuSet::default();
807 current_task.read_memory_to_slice(user_mask, &mut mask.bits[..mask_size])?;
808
809 let max_mask = get_default_cpu_set();
811 let mut has_valid_cpu_in_mask = false;
812 for (l1, l2) in std::iter::zip(max_mask.bits, mask.bits) {
813 has_valid_cpu_in_mask = has_valid_cpu_in_mask || (l1 & l2 > 0);
814 }
815 if !has_valid_cpu_in_mask {
816 return error!(EINVAL);
817 }
818
819 if !current_task.is_euid_friendly_with(&target_task) {
820 security::check_task_capable(current_task, CAP_SYS_NICE)?;
821 }
822
823 security::check_task_setscheduler_access(current_task, &target_task)?;
824
825 track_stub!(TODO("https://fxbug.dev/322874889"), "sched_setaffinity");
828 Ok(())
829}
830
831pub fn sys_sched_getparam(
832 current_task: &CurrentTask,
833 pid: pid_t,
834 param: UserRef<sched_param>,
835) -> Result<(), Errno> {
836 if pid < 0 || param.is_null() {
837 return error!(EINVAL);
838 }
839
840 let target_task = get_task_or_current(current_task, pid)?;
841 let param_value = target_task.scheduler_state.lock().get_sched_param();
842 current_task.write_object(param, ¶m_value)?;
843 Ok(())
844}
845
846pub fn sys_sched_setparam(
847 current_task: &CurrentTask,
848 pid: pid_t,
849 param: UserRef<sched_param>,
850) -> Result<(), Errno> {
851 if pid < 0 || param.is_null() {
853 return error!(EINVAL);
854 }
855 let target_task = get_task_or_current(current_task, pid)?;
856 let param = current_task.read_object(param)?;
857
858 let (policy, current_priority) = {
860 let state = target_task.scheduler_state.lock();
861 (state.policy, state.realtime_priority)
862 };
863
864 let realtime_priority = policy.realtime_priority_from(param.sched_priority)?;
865
866 let euid_friendly = current_task.is_euid_friendly_with(&target_task);
868 let strengthening = current_priority < realtime_priority;
869 let rlimited = strengthening
870 && realtime_priority.exceeds(target_task.thread_group().get_rlimit(Resource::RTPRIO));
871 if !euid_friendly || rlimited {
872 security::check_task_capable(current_task, CAP_SYS_NICE)?;
873 }
874
875 security::check_task_setscheduler_access(current_task, &target_task)?;
876
877 target_task.set_scheduler_priority(realtime_priority)?;
879
880 Ok(())
881}
882
883pub fn sys_sched_get_priority_min(_ctx: &CurrentTask, policy: u32) -> Result<u8, Errno> {
884 min_priority_for_sched_policy(policy)
885}
886
887pub fn sys_sched_get_priority_max(_ctx: &CurrentTask, policy: u32) -> Result<u8, Errno> {
888 max_priority_for_sched_policy(policy)
889}
890
891pub fn sys_ioprio_set(
892 _current_task: &mut CurrentTask,
893 _which: i32,
894 _who: i32,
895 _ioprio: i32,
896) -> Result<(), Errno> {
897 track_stub!(TODO("https://fxbug.dev/297591758"), "ioprio_set()");
898 error!(ENOSYS)
899}
900
901pub fn sys_prctl(
902 current_task: &mut CurrentTask,
903 option: u32,
904 arg2: u64,
905 arg3: u64,
906 arg4: u64,
907 arg5: u64,
908) -> Result<SyscallResult, Errno> {
909 match option {
910 PR_SET_VMA => {
911 if arg2 != PR_SET_VMA_ANON_NAME as u64 {
912 track_stub!(TODO("https://fxbug.dev/322874826"), "prctl PR_SET_VMA", arg2);
913 return error!(ENOSYS);
914 }
915 let addr = UserAddress::from(arg3);
916 let length = arg4 as usize;
917 let name_addr = UserAddress::from(arg5);
918 let name = if name_addr.is_null() {
919 None
920 } else {
921 let name = UserCString::new(current_task, UserAddress::from(arg5));
922 let name = current_task.read_c_string_to_vec(name, 256).map_err(|e| {
923 if e.code == ENAMETOOLONG { errno!(EINVAL) } else { e }
925 })?;
926 if name.iter().any(|b| {
928 matches!(b,
929 0..=0x1f |
930 0x7f..=0xff |
931 b'\\' | b'`' | b'$' | b'[' | b']'
932 )
933 }) {
934 return error!(EINVAL);
935 }
936 Some(name)
937 };
938 current_task.mm()?.set_mapping_name(addr, length, name)?;
939 Ok(().into())
940 }
941 PR_SET_DUMPABLE => {
942 let mm = current_task.mm()?;
943 mm.dumpable.store(match arg2 {
944 0 => DumpPolicy::Disable,
945 1 => DumpPolicy::User,
946 _ => return error!(EINVAL),
947 });
948 Ok(().into())
949 }
950 PR_GET_DUMPABLE => {
951 let mm = current_task.mm()?;
952 Ok(match mm.dumpable.load() {
953 DumpPolicy::Disable => 0.into(),
954 DumpPolicy::User => 1.into(),
955 })
956 }
957 PR_SET_PDEATHSIG => {
958 let signal =
964 if arg2 == 0 { None } else { Some(Signal::try_from(UncheckedSignal::new(arg2))?) };
965 current_task.thread_group().write().set_parent_death_signal(signal);
966 Ok(().into())
967 }
968 PR_GET_PDEATHSIG => {
969 let signal_ptr = UserRef::<i32>::new(UserAddress::from(arg2));
974 let parent_death_signal = current_task.thread_group().read().parent_death_signal();
975 let signal_number = parent_death_signal.map_or(0, |signal| signal.number() as i32);
976 current_task.write_object(signal_ptr, &signal_number)?;
977 Ok(().into())
978 }
979 PR_SET_NAME => {
980 let addr = UserAddress::from(arg2);
981 let name = TaskCommand::new(¤t_task.read_memory_to_array::<16>(addr)?);
982 current_task.set_command_name(name);
983 if current_task.tid == current_task.pid {
984 current_task.thread_group.sync_syscall_log_level();
985 }
986 Ok(0.into())
987 }
988 PR_GET_NAME => {
989 let addr = UserAddress::from(arg2);
990 let name = current_task.command().prctl_name();
991 current_task.write_memory(addr, &name[..])?;
992 Ok(().into())
993 }
994 PR_SET_PTRACER => {
995 let allowed_ptracers = if arg2 == PR_SET_PTRACER_ANY
996 || (current_task.is_arch32() && arg2 == PR_SET_PTRACER_ANY_ARCH32)
997 {
998 PtraceAllowedPtracers::Any
999 } else if arg2 == 0 {
1000 PtraceAllowedPtracers::None
1001 } else {
1002 let task = current_task.get_task(arg2 as i32).map_err(|_| errno!(EINVAL))?;
1003 PtraceAllowedPtracers::Some(task.pid.clone())
1004 };
1005 current_task.thread_group().write().allowed_ptracers = allowed_ptracers;
1006 Ok(().into())
1007 }
1008 PR_GET_KEEPCAPS => {
1009 Ok(current_task.current_creds().securebits.contains(SecureBits::KEEP_CAPS).into())
1010 }
1011 PR_SET_KEEPCAPS => {
1012 if arg2 != 0 && arg2 != 1 {
1013 return error!(EINVAL);
1014 }
1015 if current_task.current_creds().securebits.contains(SecureBits::KEEP_CAPS_LOCKED) {
1018 return error!(EPERM);
1019 }
1020 let mut creds = Credentials::clone(¤t_task.current_creds());
1021 creds.securebits.set(SecureBits::KEEP_CAPS, arg2 != 0);
1022 current_task.set_creds(creds);
1023 Ok(().into())
1024 }
1025 PR_SET_NO_NEW_PRIVS => {
1026 if arg2 != 1 || arg3 != 0 || arg4 != 0 || arg5 != 0 {
1028 return error!(EINVAL);
1029 }
1030 current_task.write().enable_no_new_privs();
1031 Ok(().into())
1032 }
1033 PR_GET_NO_NEW_PRIVS => {
1034 if arg2 != 0 || arg3 != 0 || arg4 != 0 {
1036 return error!(EINVAL);
1037 }
1038 Ok(current_task.read().no_new_privs().into())
1039 }
1040 PR_GET_SECCOMP => {
1041 if current_task.seccomp_filter_state.get() == SeccompStateValue::None {
1042 Ok(0.into())
1043 } else {
1044 Ok(2.into())
1045 }
1046 }
1047 PR_SET_SECCOMP => {
1048 if arg2 == SECCOMP_MODE_STRICT as u64 {
1049 return sys_seccomp(current_task, SECCOMP_SET_MODE_STRICT, 0, UserAddress::NULL);
1050 } else if arg2 == SECCOMP_MODE_FILTER as u64 {
1051 return sys_seccomp(current_task, SECCOMP_SET_MODE_FILTER, 0, arg3.into());
1052 }
1053 Ok(().into())
1054 }
1055 PR_GET_CHILD_SUBREAPER => {
1056 let addr = UserAddress::from(arg2);
1057 #[allow(clippy::bool_to_int_with_if)]
1058 let value: i32 =
1059 if current_task.thread_group().read().is_child_subreaper { 1 } else { 0 };
1060 current_task.write_object(addr.into(), &value)?;
1061 Ok(().into())
1062 }
1063 PR_SET_CHILD_SUBREAPER => {
1064 current_task.thread_group().write().is_child_subreaper = arg2 != 0;
1065 Ok(().into())
1066 }
1067 PR_GET_SECUREBITS => Ok(current_task.current_creds().securebits.bits().into()),
1068 PR_SET_SECUREBITS => {
1069 security::check_task_capable(current_task, CAP_SETPCAP)?;
1070
1071 let flags = u32::try_from(arg2).map_err(|_| errno!(EPERM))?;
1073 let securebits = SecureBits::from_bits(flags).ok_or_else(|| errno!(EPERM))?;
1074
1075 let mut creds = Credentials::clone(¤t_task.current_creds());
1076 creds.set_securebits(securebits)?;
1077 current_task.set_creds(creds);
1078 Ok(().into())
1079 }
1080 PR_CAPBSET_READ => {
1081 let cap = Capabilities::try_from(arg2)?;
1082 Ok(current_task.current_creds().cap_bounding.contains(cap).into())
1083 }
1084 PR_CAPBSET_DROP => {
1085 let mut creds = Credentials::clone(¤t_task.current_creds());
1086 security::check_task_capable(current_task, CAP_SETPCAP)?;
1087
1088 creds.cap_bounding.remove(Capabilities::try_from(arg2)?);
1089 current_task.set_creds(creds);
1090 Ok(().into())
1091 }
1092 PR_CAP_AMBIENT => {
1093 let operation = arg2 as u32;
1094 let capability_arg = Capabilities::try_from(arg3)?;
1095 if arg4 != 0 || arg5 != 0 {
1096 return error!(EINVAL);
1097 }
1098
1099 match operation {
1102 PR_CAP_AMBIENT_RAISE => {
1103 let mut creds = Credentials::clone(¤t_task.current_creds());
1104 if !(creds.cap_permitted.contains(capability_arg)
1105 && creds.cap_inheritable.contains(capability_arg))
1106 {
1107 return error!(EPERM);
1108 }
1109 if creds.securebits.contains(SecureBits::NO_CAP_AMBIENT_RAISE) {
1110 return error!(EPERM);
1111 }
1112
1113 creds.cap_ambient.insert(capability_arg);
1114 current_task.set_creds(creds);
1115 Ok(().into())
1116 }
1117 PR_CAP_AMBIENT_LOWER => {
1118 let mut creds = Credentials::clone(¤t_task.current_creds());
1119 creds.cap_ambient.remove(capability_arg);
1120 current_task.set_creds(creds);
1121 Ok(().into())
1122 }
1123 PR_CAP_AMBIENT_IS_SET => {
1124 Ok(current_task.current_creds().cap_ambient.contains(capability_arg).into())
1125 }
1126 PR_CAP_AMBIENT_CLEAR_ALL => {
1127 if arg3 != 0 {
1128 return error!(EINVAL);
1129 }
1130
1131 let mut creds = Credentials::clone(¤t_task.current_creds());
1132 creds.cap_ambient = Capabilities::empty();
1133 current_task.set_creds(creds);
1134 Ok(().into())
1135 }
1136 _ => error!(EINVAL),
1137 }
1138 }
1139 PR_SET_TIMERSLACK => {
1140 current_task.write().set_timerslack_ns(arg2);
1141 Ok(().into())
1142 }
1143 PR_GET_TIMERSLACK => Ok(current_task.read().timerslack_ns.into()),
1144 #[cfg(target_arch = "aarch64")]
1145 PR_GET_TAGGED_ADDR_CTRL => {
1146 track_stub!(TODO("https://fxbug.dev/408554469"), "PR_GET_TAGGED_ADDR_CTRL");
1147 Ok(0.into())
1148 }
1149 #[cfg(target_arch = "aarch64")]
1150 PR_SET_TAGGED_ADDR_CTRL => match u32::try_from(arg2).map_err(|_| errno!(EINVAL))? {
1151 0 => Ok(().into()),
1153 PR_TAGGED_ADDR_ENABLE => {
1154 track_stub!(TODO("https://fxbug.dev/408554469"), "PR_TAGGED_ADDR_ENABLE");
1155 error!(EINVAL)
1156 }
1157 unknown_mode => {
1158 track_stub!(
1159 TODO("https://fxbug.dev/408554469"),
1160 "PR_SET_TAGGED_ADDR_CTRL unknown mode",
1161 unknown_mode,
1162 );
1163 error!(EINVAL)
1164 }
1165 },
1166 #[cfg(target_arch = "aarch64")]
1167 starnix_uapi::PR_SVE_GET_VL => {
1168 if !current_task.thread_state.extended_pstate.has_sve() {
1171 return error!(EINVAL);
1172 }
1173 Ok((sve_prctl_status(current_task) as usize).into())
1174 }
1175 #[cfg(target_arch = "aarch64")]
1176 starnix_uapi::PR_SVE_SET_VL => {
1177 if !current_task.thread_state.extended_pstate.has_sve() {
1179 return error!(EINVAL);
1180 }
1181 let arg = u32::try_from(arg2).map_err(|_| errno!(EINVAL))?;
1182 let valid_mask = starnix_uapi::PR_SVE_VL_LEN_MASK
1183 | starnix_uapi::PR_SVE_VL_INHERIT
1184 | starnix_uapi::PR_SVE_SET_VL_ONEXEC;
1185 if (arg & !valid_mask) != 0 {
1186 return error!(EINVAL);
1187 }
1188 let vl = arg & starnix_uapi::PR_SVE_VL_LEN_MASK;
1189 if vl < starnix_uapi::SVE_VL_MIN
1190 || vl > starnix_uapi::SVE_VL_MAX
1191 || vl % starnix_uapi::SVE_VQ_BYTES != 0
1192 {
1193 return error!(EINVAL);
1194 }
1195 current_task
1201 .thread_state
1202 .extended_pstate
1203 .set_sve_vl_inherit((arg & starnix_uapi::PR_SVE_VL_INHERIT) != 0);
1204 Ok((sve_prctl_status(current_task) as usize).into())
1205 }
1206 _ => {
1207 track_stub!(TODO("https://fxbug.dev/322874733"), "prctl fallthrough", option);
1208 error!(ENOSYS)
1209 }
1210 }
1211}
1212
1213#[cfg(target_arch = "aarch64")]
1217fn sve_prctl_status(current_task: &CurrentTask) -> u32 {
1218 let inherit = if current_task.thread_state.extended_pstate.sve_vl_inherit() {
1219 starnix_uapi::PR_SVE_VL_INHERIT
1220 } else {
1221 0
1222 };
1223 starnix_uapi::SVE_VL_MIN | inherit
1224}
1225
1226pub fn sys_ptrace(
1227 current_task: &mut CurrentTask,
1228 request: u32,
1229 pid: pid_t,
1230 addr: UserAddress,
1231 data: UserAddress,
1232) -> Result<SyscallResult, Errno> {
1233 if request == PTRACE_TRACEME {
1234 return ptrace_traceme(current_task);
1235 }
1236 let pid = current_task.kernel().pids.get(pid)?;
1237 match request {
1238 PTRACE_ATTACH => ptrace_attach(current_task, &pid, PtraceAttachType::Attach, data),
1239 PTRACE_SEIZE => ptrace_attach(current_task, &pid, PtraceAttachType::Seize, data),
1240 _ => ptrace_dispatch(current_task, request, &pid, addr, data),
1241 }
1242}
1243
1244pub fn sys_set_tid_address(
1245 current_task: &CurrentTask,
1246 user_tid: UserRef<pid_t>,
1247) -> Result<pid_t, Errno> {
1248 current_task.write().clear_child_tid = user_tid;
1249 Ok(current_task.get_tid())
1250}
1251
1252pub fn sys_getrusage(
1253 current_task: &CurrentTask,
1254 who: i32,
1255 user_usage: RUsagePtr,
1256) -> Result<(), Errno> {
1257 const RUSAGE_SELF: i32 = starnix_uapi::uapi::RUSAGE_SELF as i32;
1258 const RUSAGE_THREAD: i32 = starnix_uapi::uapi::RUSAGE_THREAD as i32;
1259 track_stub!(TODO("https://fxbug.dev/297370242"), "real rusage");
1260 let time_stats = match who {
1261 RUSAGE_CHILDREN => current_task.task.thread_group().read().children_time_stats,
1262 RUSAGE_SELF => current_task.task.thread_group().time_stats(),
1263 RUSAGE_THREAD => current_task.task.time_stats(),
1264 _ => return error!(EINVAL),
1265 };
1266
1267 let usage = rusage {
1268 ru_utime: timeval_from_duration(time_stats.user_time),
1269 ru_stime: timeval_from_duration(time_stats.system_time),
1270 ..rusage::default()
1271 };
1272 current_task.write_multi_arch_object(user_usage, usage)?;
1273
1274 Ok(())
1275}
1276
1277type PrLimitRef = MultiArchUserRef<uapi::rlimit, uapi::arch32::rlimit>;
1278
1279pub fn sys_getrlimit(
1280 current_task: &CurrentTask,
1281 resource: u32,
1282 user_rlimit: PrLimitRef,
1283) -> Result<(), Errno> {
1284 do_prlimit64(current_task, 0, resource, PrLimitRef::null(current_task), user_rlimit)
1285}
1286
1287pub fn sys_setrlimit(
1288 current_task: &CurrentTask,
1289 resource: u32,
1290 user_rlimit: PrLimitRef,
1291) -> Result<(), Errno> {
1292 do_prlimit64(current_task, 0, resource, user_rlimit, PrLimitRef::null(current_task))
1293}
1294
1295pub fn sys_prlimit64(
1296 current_task: &CurrentTask,
1297 pid: pid_t,
1298 user_resource: u32,
1299 new_limit_ref: UserRef<uapi::rlimit>,
1300 old_limit_ref: UserRef<uapi::rlimit>,
1301) -> Result<(), Errno> {
1302 do_prlimit64::<uapi::rlimit>(
1303 current_task,
1304 pid,
1305 user_resource,
1306 new_limit_ref.into(),
1307 old_limit_ref.into(),
1308 )
1309}
1310
1311pub fn do_prlimit64<T>(
1312 current_task: &CurrentTask,
1313 pid: pid_t,
1314 user_resource: u32,
1315 new_limit_ref: MultiArchUserRef<uapi::rlimit, T>,
1316 old_limit_ref: MultiArchUserRef<uapi::rlimit, T>,
1317) -> Result<(), Errno>
1318where
1319 T: FromBytes + IntoBytes + Immutable + From<uapi::rlimit> + Into<uapi::rlimit>,
1320{
1321 let target_task = get_task_or_current(current_task, pid)?;
1322
1323 if current_task.get_pid() != target_task.get_pid() {
1327 let self_creds = current_task.current_creds();
1328 let target_creds = target_task.real_creds();
1329 if self_creds.uid != target_creds.uid
1330 || self_creds.euid != target_creds.euid
1331 || self_creds.saved_uid != target_creds.saved_uid
1332 || self_creds.gid != target_creds.gid
1333 || self_creds.egid != target_creds.egid
1334 || self_creds.saved_gid != target_creds.saved_gid
1335 {
1336 security::check_task_capable(current_task, CAP_SYS_RESOURCE)?;
1337 }
1338 security::task_prlimit(
1339 current_task,
1340 &target_task,
1341 !old_limit_ref.is_null(),
1342 !new_limit_ref.is_null(),
1343 )?;
1344 }
1345
1346 let resource = Resource::from_raw(user_resource)?;
1347
1348 let new_limit = if new_limit_ref.is_null() {
1349 None
1350 } else {
1351 let new_limit = current_task.read_multi_arch_object(new_limit_ref)?;
1352 if new_limit.rlim_cur > new_limit.rlim_max {
1353 return error!(EINVAL);
1354 }
1355 Some(new_limit)
1356 };
1357 let old_limit = ThreadGroup::adjust_rlimits(current_task, &target_task, resource, new_limit)?;
1358 if resource == Resource::STACK && new_limit.is_some() {
1363 track_stub!(
1364 TODO("https://fxbug.dev/571982693"),
1365 "prlimit64 does not enforce RLIMIT_STACK on stack growth"
1366 );
1367 }
1368 if !old_limit_ref.is_null() {
1369 current_task.write_multi_arch_object(old_limit_ref, old_limit)?;
1370 }
1371 Ok(())
1372}
1373
1374pub fn sys_quotactl(
1375 _current_task: &CurrentTask,
1376 _cmd: i32,
1377 _special: UserRef<c_char>,
1378 _id: i32,
1379 _addr: UserRef<c_char>,
1380) -> Result<SyscallResult, Errno> {
1381 track_stub!(TODO("https://fxbug.dev/297302197"), "quotacl()");
1382 error!(ENOSYS)
1383}
1384
1385pub fn sys_capget(
1386 current_task: &CurrentTask,
1387 user_header: UserRef<__user_cap_header_struct>,
1388 user_data: UserRef<__user_cap_data_struct>,
1389) -> Result<(), Errno> {
1390 let mut header = current_task.read_object(user_header)?;
1391 let is_version_valid =
1392 [_LINUX_CAPABILITY_VERSION_1, _LINUX_CAPABILITY_VERSION_2, _LINUX_CAPABILITY_VERSION_3]
1393 .contains(&header.version);
1394 if !is_version_valid {
1395 header.version = _LINUX_CAPABILITY_VERSION_3;
1396 current_task.write_object(user_header, &header)?;
1397 }
1398 if user_data.is_null() {
1399 return Ok(());
1400 }
1401 if !is_version_valid || header.pid < 0 {
1402 return error!(EINVAL);
1403 }
1404
1405 let target_task = get_task_or_current(current_task, header.pid)?;
1406
1407 security::check_getcap_access(current_task, &target_task)?;
1408
1409 let (permitted, effective, inheritable) = {
1410 let creds = &target_task.real_creds();
1411 (creds.cap_permitted, creds.cap_effective, creds.cap_inheritable)
1412 };
1413
1414 match header.version {
1415 _LINUX_CAPABILITY_VERSION_1 => {
1416 let data: [__user_cap_data_struct; 1] = [__user_cap_data_struct {
1417 effective: effective.as_abi_v1(),
1418 inheritable: inheritable.as_abi_v1(),
1419 permitted: permitted.as_abi_v1(),
1420 }];
1421 current_task.write_objects(user_data, &data)?;
1422 }
1423 _LINUX_CAPABILITY_VERSION_2 | _LINUX_CAPABILITY_VERSION_3 => {
1424 let (permitted, effective, inheritable) =
1426 (permitted.as_abi_v3(), effective.as_abi_v3(), inheritable.as_abi_v3());
1427 let data: [__user_cap_data_struct; 2] = [
1428 __user_cap_data_struct {
1429 effective: effective.0,
1430 inheritable: inheritable.0,
1431 permitted: permitted.0,
1432 },
1433 __user_cap_data_struct {
1434 effective: effective.1,
1435 inheritable: inheritable.1,
1436 permitted: permitted.1,
1437 },
1438 ];
1439 current_task.write_objects(user_data, &data)?;
1440 }
1441 _ => {
1442 unreachable!("already returned if Linux capability version is not valid")
1443 }
1444 }
1445 Ok(())
1446}
1447
1448pub fn sys_capset(
1449 current_task: &CurrentTask,
1450 user_header: UserRef<__user_cap_header_struct>,
1451 user_data: UserRef<__user_cap_data_struct>,
1452) -> Result<(), Errno> {
1453 let mut header = current_task.read_object(user_header)?;
1454 let is_version_valid =
1455 [_LINUX_CAPABILITY_VERSION_1, _LINUX_CAPABILITY_VERSION_2, _LINUX_CAPABILITY_VERSION_3]
1456 .contains(&header.version);
1457 if !is_version_valid {
1458 header.version = _LINUX_CAPABILITY_VERSION_3;
1459 current_task.write_object(user_header, &header)?;
1460 return error!(EINVAL);
1461 }
1462 if header.pid != 0 && header.pid != current_task.tid.id {
1463 return error!(EPERM);
1464 }
1465
1466 let (new_permitted, new_effective, new_inheritable) = match header.version {
1467 _LINUX_CAPABILITY_VERSION_1 => {
1468 let data = current_task.read_object(user_data)?;
1469 (
1470 Capabilities::from_abi_v1(data.permitted),
1471 Capabilities::from_abi_v1(data.effective),
1472 Capabilities::from_abi_v1(data.inheritable),
1473 )
1474 }
1475 _LINUX_CAPABILITY_VERSION_2 | _LINUX_CAPABILITY_VERSION_3 => {
1476 let data =
1477 current_task.read_objects_to_array::<__user_cap_data_struct, 2>(user_data)?;
1478 (
1479 Capabilities::from_abi_v3((data[0].permitted, data[1].permitted)),
1480 Capabilities::from_abi_v3((data[0].effective, data[1].effective)),
1481 Capabilities::from_abi_v3((data[0].inheritable, data[1].inheritable)),
1482 )
1483 }
1484 _ => {
1485 unreachable!("already returned if Linux capability version is not valid")
1486 }
1487 };
1488
1489 let mut creds = Credentials::clone(¤t_task.current_creds());
1491 {
1492 log_trace!(
1493 "Capabilities({{permitted={:?} from {:?}, effective={:?} from {:?}, inheritable={:?} from {:?}}}, bounding={:?})",
1494 new_permitted,
1495 creds.cap_permitted,
1496 new_effective,
1497 creds.cap_effective,
1498 new_inheritable,
1499 creds.cap_inheritable,
1500 creds.cap_bounding
1501 );
1502 if !creds.cap_inheritable.union(creds.cap_permitted).contains(new_inheritable) {
1503 security::check_task_capable(current_task, CAP_SETPCAP)?;
1504 }
1505
1506 if !creds.cap_inheritable.union(creds.cap_bounding).contains(new_inheritable) {
1507 return error!(EPERM);
1508 }
1509 if !creds.cap_permitted.contains(new_permitted) {
1510 return error!(EPERM);
1511 }
1512 if !new_permitted.contains(new_effective) {
1513 return error!(EPERM);
1514 }
1515 }
1516 let target_task = get_task_or_current(current_task, header.pid)?;
1517
1518 security::check_setcap_access(current_task, &target_task)?;
1519
1520 creds.cap_permitted = new_permitted;
1521 creds.cap_effective = new_effective;
1522 creds.cap_inheritable = new_inheritable;
1523 creds.cap_ambient = new_permitted & new_inheritable & creds.cap_ambient;
1524 current_task.set_creds(creds);
1525 Ok(())
1526}
1527
1528pub fn sys_seccomp(
1529 current_task: &mut CurrentTask,
1530 operation: u32,
1531 flags: u32,
1532 args: UserAddress,
1533) -> Result<SyscallResult, Errno> {
1534 match operation {
1535 SECCOMP_SET_MODE_STRICT => {
1536 if flags != 0 || args != UserAddress::NULL {
1537 return error!(EINVAL);
1538 }
1539 current_task.set_seccomp_state(SeccompStateValue::Strict)?;
1540 Ok(().into())
1541 }
1542 SECCOMP_SET_MODE_FILTER => {
1543 if flags
1544 & (SECCOMP_FILTER_FLAG_LOG
1545 | SECCOMP_FILTER_FLAG_NEW_LISTENER
1546 | SECCOMP_FILTER_FLAG_SPEC_ALLOW
1547 | SECCOMP_FILTER_FLAG_TSYNC
1548 | SECCOMP_FILTER_FLAG_TSYNC_ESRCH)
1549 != flags
1550 {
1551 return error!(EINVAL);
1552 }
1553 if (flags & SECCOMP_FILTER_FLAG_TSYNC == 0)
1554 && (flags & SECCOMP_FILTER_FLAG_TSYNC_ESRCH != 0)
1555 {
1556 return error!(EINVAL);
1557 }
1558 if (flags & SECCOMP_FILTER_FLAG_NEW_LISTENER != 0)
1559 && (flags & SECCOMP_FILTER_FLAG_TSYNC != 0)
1560 && (flags & SECCOMP_FILTER_FLAG_TSYNC_ESRCH == 0)
1561 {
1562 return error!(EINVAL);
1563 }
1564 let fprog =
1565 current_task.read_multi_arch_object(SockFProgPtr::new(current_task, args))?;
1566 if fprog.len > BPF_MAXINSNS || fprog.len == 0 {
1567 return error!(EINVAL);
1568 }
1569 let code: Vec<sock_filter> =
1570 current_task.read_multi_arch_objects_to_vec(fprog.filter, fprog.len as usize)?;
1571
1572 if !current_task.read().no_new_privs() {
1573 security::check_task_capable(current_task, CAP_SYS_ADMIN)
1574 .map_err(|_| errno!(EACCES))?;
1575 }
1576 current_task.add_seccomp_filter(code, flags)
1577 }
1578 SECCOMP_GET_ACTION_AVAIL => {
1579 if flags != 0 || args.is_null() {
1580 return error!(EINVAL);
1581 }
1582 let action: u32 = current_task.read_object(UserRef::new(args))?;
1583 SeccompAction::is_action_available(action)
1584 }
1585 SECCOMP_GET_NOTIF_SIZES => {
1586 if flags != 0 {
1587 return error!(EINVAL);
1588 }
1589 track_stub!(TODO("https://fxbug.dev/322874791"), "SECCOMP_GET_NOTIF_SIZES");
1590 error!(ENOSYS)
1591 }
1592 _ => {
1593 track_stub!(TODO("https://fxbug.dev/322874916"), "seccomp fallthrough", operation);
1594 error!(EINVAL)
1595 }
1596 }
1597}
1598
1599pub fn sys_setgroups(
1600 current_task: &CurrentTask,
1601 size: usize,
1602 groups_addr: UserAddress,
1603) -> Result<(), Errno> {
1604 if size > NGROUPS_MAX as usize {
1605 return error!(EINVAL);
1606 }
1607 let groups = current_task.read_objects_to_vec::<gid_t>(groups_addr.into(), size)?;
1608 security::check_task_capable(current_task, CAP_SETGID)?;
1609 let mut creds = Credentials::clone(¤t_task.current_creds());
1610 creds.groups = groups;
1611 current_task.set_creds(creds);
1612 Ok(())
1613}
1614
1615pub fn sys_getgroups(
1616 current_task: &CurrentTask,
1617 size: usize,
1618 groups_addr: UserAddress,
1619) -> Result<usize, Errno> {
1620 if size > NGROUPS_MAX as usize {
1621 return error!(EINVAL);
1622 }
1623 let creds = current_task.current_creds();
1624 if size != 0 {
1625 if size < creds.groups.len() {
1626 return error!(EINVAL);
1627 }
1628 current_task.write_memory(groups_addr, creds.groups.as_slice().as_bytes())?;
1629 }
1630 Ok(creds.groups.len())
1631}
1632
1633pub fn sys_setsid(current_task: &CurrentTask) -> Result<pid_t, Errno> {
1634 current_task.thread_group().setsid()?;
1635 Ok(current_task.get_pid())
1636}
1637
1638pub fn sys_getpriority(current_task: &CurrentTask, which: u32, who: i32) -> Result<u8, Errno> {
1642 match which {
1643 PRIO_PROCESS => {}
1644 _ => return error!(EINVAL),
1646 }
1647 track_stub!(TODO("https://fxbug.dev/322893809"), "getpriority permissions");
1648 let target_task = get_task_or_current(current_task, who)?;
1649 Ok(target_task.scheduler_state.lock().normal_priority.raw_priority())
1650}
1651
1652pub fn sys_setpriority(
1657 current_task: &CurrentTask,
1658 which: u32,
1659 who: i32,
1660 priority: i32,
1661) -> Result<(), Errno> {
1662 match which {
1664 PRIO_PROCESS => {}
1665 _ => return error!(EINVAL),
1667 }
1668
1669 let target_task = get_task_or_current(current_task, who)?;
1670
1671 let normal_priority = NormalPriority::from_setpriority_syscall(priority);
1672
1673 let current_priority = target_task.scheduler_state.lock().normal_priority;
1675
1676 let euid_friendly = current_task.is_euid_friendly_with(&target_task);
1678 let strengthening = current_priority < normal_priority;
1679 let rlimited = strengthening
1680 && normal_priority.exceeds(target_task.thread_group().get_rlimit(Resource::NICE));
1681 if !euid_friendly {
1682 security::check_task_capable(current_task, CAP_SYS_NICE)?;
1683 } else if rlimited {
1684 security::check_task_capable(current_task, CAP_SYS_NICE).map_err(|_| errno!(EACCES))?;
1685 }
1686
1687 security::check_task_setnice_access(current_task, &target_task)?;
1688
1689 target_task.set_scheduler_nice(normal_priority)?;
1691
1692 Ok(())
1693}
1694
1695pub fn sys_setns(current_task: &CurrentTask, ns_fd: FdNumber, ns_type: c_int) -> Result<(), Errno> {
1696 let file_handle = current_task.files().get(ns_fd)?;
1697
1698 security::check_task_capable(current_task, CAP_SYS_ADMIN)?;
1702
1703 if let Some(mount_ns) = file_handle.downcast_file::<MountNamespaceFile>() {
1704 if !(ns_type == 0 || ns_type == CLONE_NEWNS as i32) {
1705 log_trace!("invalid type");
1706 return error!(EINVAL);
1707 }
1708
1709 track_stub!(TODO("https://fxbug.dev/297312091"), "setns CLONE_FS limitations");
1710 current_task.fs().set_namespace(mount_ns.0.clone())?;
1711 return Ok(());
1712 }
1713
1714 if let Some(_pidfd) = file_handle.downcast_file::<PidFdFileObject>() {
1715 track_stub!(TODO("https://fxbug.dev/297312844"), "setns w/ pidfd");
1716 return error!(ENOSYS);
1717 }
1718
1719 track_stub!(TODO("https://fxbug.dev/322893829"), "unknown ns file for setns, see logs");
1720 log_info!("ns_fd was not a supported namespace file: {}", file_handle.ops_type_name());
1721 error!(EINVAL)
1722}
1723
1724pub fn sys_unshare(current_task: &CurrentTask, flags: u32) -> Result<(), Errno> {
1725 const IMPLEMENTED_FLAGS: u32 = CLONE_FILES | CLONE_FS | CLONE_NEWNS | CLONE_NEWUTS;
1726 if flags & !IMPLEMENTED_FLAGS != 0 {
1727 track_stub!(TODO("https://fxbug.dev/322893372"), "unshare", flags & !IMPLEMENTED_FLAGS);
1728 return error!(EINVAL);
1729 }
1730
1731 if (flags & CLONE_FILES) != 0 {
1732 current_task.running_state().unshare_files(current_task);
1733 }
1734
1735 if (flags & CLONE_FS) != 0 {
1736 current_task.unshare_fs();
1737 }
1738
1739 if (flags & CLONE_NEWNS) != 0 {
1740 security::check_task_capable(current_task, CAP_SYS_ADMIN)?;
1741 current_task.fs().unshare_namespace();
1742 }
1743
1744 if (flags & CLONE_NEWUTS) != 0 {
1745 security::check_task_capable(current_task, CAP_SYS_ADMIN)?;
1746 let mut task_state = current_task.write();
1748 let new_uts_ns = task_state.uts_ns.read().clone();
1749 task_state.uts_ns = Arc::new(new_uts_ns.into());
1750 }
1751
1752 Ok(())
1753}
1754
1755pub fn sys_swapon(
1756 current_task: &CurrentTask,
1757 user_path: UserCString,
1758 flags: u32,
1759) -> Result<(), Errno> {
1760 const MAX_SWAPFILES: usize = 32; const SWAP_FLAGS_VALID: u32 = 0x7ffff; if (flags & !SWAP_FLAGS_VALID) != 0 {
1764 return error!(EINVAL);
1765 }
1766
1767 security::check_task_capable(current_task, CAP_SYS_ADMIN)?;
1768
1769 if flags != 0 {
1770 track_stub!(TODO("https://fxbug.dev/322893905"), "swapon flags", flags);
1771 }
1772
1773 let path = current_task.read_path(user_path)?;
1774 let file = current_task.open_file(path.as_ref(), OpenFlags::RDWR)?;
1775
1776 let node = file.node();
1777 let mode = node.info().mode;
1778 if !mode.is_reg() && !mode.is_blk() {
1779 return error!(EINVAL);
1780 }
1781
1782 const MAGIC_OFFSET: usize = 0xff6;
1787 let swap_magic = b"SWAPSPACE2";
1788 let mut buffer = VecOutputBuffer::new(swap_magic.len());
1789 if file.read_at(current_task, MAGIC_OFFSET, &mut buffer)? != swap_magic.len()
1790 || buffer.data() != swap_magic
1791 {
1792 return error!(EINVAL);
1793 }
1794
1795 let mut swap_files = current_task.kernel().swap_files.lock();
1796 for swap_node in swap_files.iter() {
1797 if Arc::ptr_eq(swap_node, node) {
1798 return error!(EBUSY);
1799 }
1800 }
1801 if swap_files.len() >= MAX_SWAPFILES {
1802 return error!(EPERM);
1803 }
1804 swap_files.push(node.clone());
1805 Ok(())
1806}
1807
1808pub fn sys_swapoff(current_task: &CurrentTask, user_path: UserCString) -> Result<(), Errno> {
1809 security::check_task_capable(current_task, CAP_SYS_ADMIN)?;
1810
1811 let path = current_task.read_path(user_path)?;
1812 let file = current_task.open_file(path.as_ref(), OpenFlags::RDWR)?;
1813 let node = file.node();
1814
1815 let mut swap_files = current_task.kernel().swap_files.lock();
1816 let original_length = swap_files.len();
1817 swap_files.retain(|swap_node| !Arc::ptr_eq(swap_node, node));
1818 if swap_files.len() == original_length {
1819 return error!(EINVAL);
1820 }
1821 Ok(())
1822}
1823
1824#[derive(Default, Debug, IntoBytes, KnownLayout, FromBytes, Immutable)]
1825#[repr(C)]
1826struct KcmpParams {
1827 mask: usize,
1828 shuffle: usize,
1829}
1830
1831static KCMP_PARAMS: LazyLock<KcmpParams> = LazyLock::new(|| {
1832 let mut params = KcmpParams::default();
1833 starnix_crypto::cprng_draw(params.as_mut_bytes());
1834 params.shuffle |= 1;
1836 params
1837});
1838
1839fn obfuscate_value(value: usize) -> usize {
1840 let KcmpParams { mask, shuffle } = *KCMP_PARAMS;
1841 (value ^ mask).wrapping_mul(shuffle)
1842}
1843
1844fn obfuscate_ptr<T>(ptr: *const T) -> usize {
1845 obfuscate_value(ptr as usize)
1846}
1847
1848fn obfuscate_arc<T>(arc: &Arc<T>) -> usize {
1849 obfuscate_ptr(Arc::as_ptr(arc))
1850}
1851
1852pub fn sys_kcmp(
1853 current_task: &CurrentTask,
1854 pid1: pid_t,
1855 pid2: pid_t,
1856 resource_type: u32,
1857 index1: u64,
1858 index2: u64,
1859) -> Result<u32, Errno> {
1860 let task1 = current_task.get_task(pid1)?;
1861 let task2 = current_task.get_task(pid2)?;
1862
1863 current_task.check_ptrace_access_mode(PTRACE_MODE_READ_REALCREDS, &task1)?;
1864 current_task.check_ptrace_access_mode(PTRACE_MODE_READ_REALCREDS, &task2)?;
1865
1866 let resource_type = KcmpResource::from_raw(resource_type)?;
1867
1868 fn encode_ordering(value: cmp::Ordering) -> u32 {
1876 match value {
1877 cmp::Ordering::Equal => 0,
1878 cmp::Ordering::Less => 1,
1879 cmp::Ordering::Greater => 2,
1880 }
1881 }
1882
1883 match resource_type {
1884 KcmpResource::FILE => {
1885 fn get_file(task: &Task, index: u64) -> Result<FileHandle, Errno> {
1886 task.files()?.get_allowing_opath(FdNumber::from_raw(
1889 index.try_into().map_err(|_| errno!(EBADF))?,
1890 ))
1891 }
1892 let file1 = get_file(&task1, index1)?;
1893 let file2 = get_file(&task2, index2)?;
1894 Ok(encode_ordering(obfuscate_arc(&file1).cmp(&obfuscate_arc(&file2))))
1895 }
1896 KcmpResource::FILES => {
1897 let files1 = task1.files()?.id();
1898 let files2 = task2.files()?.id();
1899 Ok(encode_ordering(obfuscate_value(files1.raw()).cmp(&obfuscate_value(files2.raw()))))
1900 }
1901 KcmpResource::FS => {
1902 let fs1 = task1.fs()?;
1903 let fs2 = task2.fs()?;
1904 Ok(encode_ordering(obfuscate_arc(&fs1).cmp(&obfuscate_arc(&fs2))))
1905 }
1906 KcmpResource::SIGHAND => Ok(encode_ordering(
1907 obfuscate_arc(&task1.thread_group().signal_actions)
1908 .cmp(&obfuscate_arc(&task2.thread_group().signal_actions)),
1909 )),
1910 KcmpResource::VM => {
1911 Ok(encode_ordering(obfuscate_arc(&task1.mm()?).cmp(&obfuscate_arc(&task2.mm()?))))
1912 }
1913 KcmpResource::SYSVSEM => error!(EOPNOTSUPP),
1914 _ => error!(EINVAL),
1915 }
1916}
1917
1918pub fn sys_syslog(
1919 current_task: &CurrentTask,
1920 action_type: i32,
1921 address: UserAddress,
1922 length: i32,
1923) -> Result<i32, Errno> {
1924 let action = SyslogAction::try_from(action_type)?;
1925 let syslog =
1926 current_task.kernel().syslog.access(¤t_task, SyslogAccess::Syscall(action))?;
1927 match action {
1928 SyslogAction::Read => {
1929 if address.is_null() || length < 0 {
1930 return error!(EINVAL);
1931 }
1932 let mut output_buffer =
1933 UserBuffersOutputBuffer::unified_new_at(current_task, address, length as usize)?;
1934 syslog.blocking_read(current_task, &mut output_buffer)
1935 }
1936 SyslogAction::ReadAll => {
1937 if address.is_null() || length < 0 {
1938 return error!(EINVAL);
1939 }
1940 let mut output_buffer =
1941 UserBuffersOutputBuffer::unified_new_at(current_task, address, length as usize)?;
1942 syslog.read_all(current_task.kernel(), &mut output_buffer)
1943 }
1944 SyslogAction::SizeUnread => syslog.size_unread(),
1945 SyslogAction::SizeBuffer => syslog.size_buffer(),
1946 SyslogAction::Close | SyslogAction::Open => Ok(0),
1947 SyslogAction::ReadClear => {
1948 track_stub!(TODO("https://fxbug.dev/322894145"), "syslog: read clear");
1949 Ok(0)
1950 }
1951 SyslogAction::Clear => {
1952 track_stub!(TODO("https://fxbug.dev/322893673"), "syslog: clear");
1953 Ok(0)
1954 }
1955 SyslogAction::ConsoleOff => {
1956 track_stub!(TODO("https://fxbug.dev/322894399"), "syslog: console off");
1957 Ok(0)
1958 }
1959 SyslogAction::ConsoleOn => {
1960 track_stub!(TODO("https://fxbug.dev/322894106"), "syslog: console on");
1961 Ok(0)
1962 }
1963 SyslogAction::ConsoleLevel => {
1964 if length <= 0 || length >= 8 {
1965 return error!(EINVAL);
1966 }
1967 track_stub!(TODO("https://fxbug.dev/322894199"), "syslog: console level");
1968 Ok(0)
1969 }
1970 }
1971}
1972
1973pub fn sys_vhangup(current_task: &CurrentTask) -> Result<(), Errno> {
1974 security::check_task_capable(current_task, CAP_SYS_TTY_CONFIG)?;
1975 track_stub!(TODO("https://fxbug.dev/324079257"), "vhangup");
1976 Ok(())
1977}
1978
1979#[cfg(target_arch = "aarch64")]
1981mod arch32 {
1982 pub use super::{
1983 sys_execve as sys_arch32_execve, sys_execveat as sys_arch32_execveat,
1984 sys_getegid as sys_arch32_getegid32, sys_geteuid as sys_arch32_geteuid32,
1985 sys_getgid as sys_arch32_getgid32, sys_getgroups as sys_arch32_getgroups32,
1986 sys_getpgid as sys_arch32_getpgid, sys_getppid as sys_arch32_getppid,
1987 sys_getpriority as sys_arch32_getpriority, sys_getresgid as sys_arch32_getresgid32,
1988 sys_getresuid as sys_arch32_getresuid32, sys_getrlimit as sys_arch32_ugetrlimit,
1989 sys_getrusage as sys_arch32_getrusage, sys_getuid as sys_arch32_getuid32,
1990 sys_ioprio_set as sys_arch32_ioprio_set, sys_kcmp as sys_arch32_kcmp,
1991 sys_ptrace as sys_arch32_ptrace, sys_quotactl as sys_arch32_quotactl,
1992 sys_sched_get_priority_max as sys_arch32_sched_get_priority_max,
1993 sys_sched_get_priority_min as sys_arch32_sched_get_priority_min,
1994 sys_sched_getaffinity as sys_arch32_sched_getaffinity,
1995 sys_sched_getparam as sys_arch32_sched_getparam,
1996 sys_sched_setaffinity as sys_arch32_sched_setaffinity,
1997 sys_sched_setparam as sys_arch32_sched_setparam,
1998 sys_sched_setscheduler as sys_arch32_sched_setscheduler, sys_seccomp as sys_arch32_seccomp,
1999 sys_setfsgid as sys_arch32_setfsgid, sys_setfsgid as sys_arch32_setfsgid32,
2000 sys_setfsuid as sys_arch32_setfsuid, sys_setfsuid as sys_arch32_setfsuid32,
2001 sys_setgid as sys_arch32_setgid32, sys_setgroups as sys_arch32_setgroups32,
2002 sys_setns as sys_arch32_setns, sys_setpgid as sys_arch32_setpgid,
2003 sys_setpriority as sys_arch32_setpriority, sys_setregid as sys_arch32_setregid32,
2004 sys_setresgid as sys_arch32_setresgid32, sys_setresuid as sys_arch32_setresuid32,
2005 sys_setreuid as sys_arch32_setreuid32, sys_setreuid as sys_arch32_setreuid,
2006 sys_setrlimit as sys_arch32_setrlimit, sys_setsid as sys_arch32_setsid,
2007 sys_syslog as sys_arch32_syslog, sys_unshare as sys_arch32_unshare,
2008 };
2009}
2010
2011#[cfg(target_arch = "aarch64")]
2012pub use arch32::*;
2013
2014#[cfg(test)]
2015mod tests {
2016 use super::*;
2017 use crate::mm::syscalls::sys_munmap;
2018 use crate::testing::{AutoReleasableTask, map_memory, spawn_kernel_and_run};
2019 use starnix_syscalls::SUCCESS;
2020 use starnix_task_command::TaskCommand;
2021 use starnix_uapi::auth::Credentials;
2022 use starnix_uapi::signals::SIGCHLD;
2023 use starnix_uapi::uapi::{kcmp_type_KCMP_SYSVSEM, kcmp_type_KCMP_TYPES, kcmp_type_KCMP_VM};
2024 use starnix_uapi::{SCHED_FIFO, SCHED_NORMAL};
2025 use std::ffi::CString;
2026
2027 #[::fuchsia::test]
2028 async fn test_prctl_set_vma_anon_name() {
2029 spawn_kernel_and_run(async |current_task| {
2030 let mapped_address = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
2031 let name_addr = (mapped_address + 128u64).unwrap();
2032 let name = "test-name\0";
2033 current_task.write_memory(name_addr, name.as_bytes()).expect("failed to write name");
2034 sys_prctl(
2035 current_task,
2036 PR_SET_VMA,
2037 PR_SET_VMA_ANON_NAME as u64,
2038 mapped_address.ptr() as u64,
2039 32,
2040 name_addr.ptr() as u64,
2041 )
2042 .expect("failed to set name");
2043 assert_eq!(
2044 "test-name",
2045 current_task
2046 .mm()
2047 .unwrap()
2048 .get_mapping_name((mapped_address + 24u64).unwrap())
2049 .expect("failed to get address")
2050 .unwrap()
2051 .to_string(),
2052 );
2053
2054 sys_munmap(¤t_task, mapped_address, *PAGE_SIZE as usize)
2055 .expect("failed to unmap memory");
2056 assert_eq!(
2057 error!(EFAULT),
2058 current_task.mm().unwrap().get_mapping_name((mapped_address + 24u64).unwrap())
2059 );
2060 })
2061 .await;
2062 }
2063
2064 #[::fuchsia::test]
2065 async fn test_set_vma_name_special_chars() {
2066 spawn_kernel_and_run(async |current_task| {
2067 let name_addr = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
2068
2069 let mapping_addr = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
2070
2071 for c in 1..255 {
2072 let vma_name = CString::new([c]).unwrap();
2073 current_task.write_memory(name_addr, vma_name.as_bytes_with_nul()).unwrap();
2074
2075 let result = sys_prctl(
2076 current_task,
2077 PR_SET_VMA,
2078 PR_SET_VMA_ANON_NAME as u64,
2079 mapping_addr.ptr() as u64,
2080 *PAGE_SIZE,
2081 name_addr.ptr() as u64,
2082 );
2083
2084 if c > 0x1f
2085 && c < 0x7f
2086 && c != b'\\'
2087 && c != b'`'
2088 && c != b'$'
2089 && c != b'['
2090 && c != b']'
2091 {
2092 assert_eq!(result, Ok(SUCCESS));
2093 } else {
2094 assert_eq!(result, error!(EINVAL));
2095 }
2096 }
2097 })
2098 .await;
2099 }
2100
2101 #[::fuchsia::test]
2102 async fn test_set_vma_name_long() {
2103 spawn_kernel_and_run(async |current_task| {
2104 let name_addr = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
2105
2106 let mapping_addr = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
2107
2108 let name_too_long = CString::new(vec![b'a'; 256]).unwrap();
2109
2110 current_task.write_memory(name_addr, name_too_long.as_bytes_with_nul()).unwrap();
2111
2112 assert_eq!(
2113 sys_prctl(
2114 current_task,
2115 PR_SET_VMA,
2116 PR_SET_VMA_ANON_NAME as u64,
2117 mapping_addr.ptr() as u64,
2118 *PAGE_SIZE,
2119 name_addr.ptr() as u64,
2120 ),
2121 error!(EINVAL)
2122 );
2123
2124 let name_just_long_enough = CString::new(vec![b'a'; 255]).unwrap();
2125
2126 current_task
2127 .write_memory(name_addr, name_just_long_enough.as_bytes_with_nul())
2128 .unwrap();
2129
2130 assert_eq!(
2131 sys_prctl(
2132 current_task,
2133 PR_SET_VMA,
2134 PR_SET_VMA_ANON_NAME as u64,
2135 mapping_addr.ptr() as u64,
2136 *PAGE_SIZE,
2137 name_addr.ptr() as u64,
2138 ),
2139 Ok(SUCCESS)
2140 );
2141 })
2142 .await;
2143 }
2144
2145 #[::fuchsia::test]
2146 async fn test_set_vma_name_misaligned() {
2147 spawn_kernel_and_run(async |current_task| {
2148 let name_addr = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
2149
2150 let mapping_addr = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
2151
2152 let name = CString::new("name").unwrap();
2153 current_task.write_memory(name_addr, name.as_bytes_with_nul()).unwrap();
2154
2155 assert_eq!(
2157 sys_prctl(
2158 current_task,
2159 PR_SET_VMA,
2160 PR_SET_VMA_ANON_NAME as u64,
2161 1 + mapping_addr.ptr() as u64,
2162 *PAGE_SIZE - 1,
2163 name_addr.ptr() as u64,
2164 ),
2165 error!(EINVAL)
2166 );
2167
2168 assert_eq!(
2170 sys_prctl(
2171 current_task,
2172 PR_SET_VMA,
2173 PR_SET_VMA_ANON_NAME as u64,
2174 mapping_addr.ptr() as u64,
2175 *PAGE_SIZE - 1,
2176 name_addr.ptr() as u64,
2177 ),
2178 Ok(SUCCESS)
2179 );
2180 })
2181 .await;
2182 }
2183
2184 #[::fuchsia::test]
2185 async fn test_prctl_get_set_dumpable() {
2186 spawn_kernel_and_run(async |current_task| {
2187 assert_eq!(sys_prctl(current_task, PR_GET_DUMPABLE, 0, 0, 0, 0), Ok(1.into()));
2188
2189 sys_prctl(current_task, PR_SET_DUMPABLE, 0, 0, 0, 0).expect("failed to set dumpable");
2190 assert_eq!(sys_prctl(current_task, PR_GET_DUMPABLE, 0, 0, 0, 0), Ok(0.into()));
2191
2192 sys_prctl(current_task, PR_SET_DUMPABLE, 1, 0, 0, 0).expect("failed to set dumpable");
2193 assert_eq!(sys_prctl(current_task, PR_GET_DUMPABLE, 0, 0, 0, 0), Ok(1.into()));
2194
2195 assert_eq!(sys_prctl(current_task, PR_SET_DUMPABLE, 2, 0, 0, 0), error!(EINVAL));
2197 assert_eq!(sys_prctl(current_task, PR_GET_DUMPABLE, 0, 0, 0, 0), Ok(1.into()));
2198 })
2199 .await;
2200 }
2201
2202 #[cfg(target_arch = "aarch64")]
2203 #[::fuchsia::test]
2204 async fn test_prctl_sve_vl() {
2205 use crate::task::ArchExtendedPstateStorage;
2206 use extended_pstate::ExtendedPstateState;
2207 use starnix_uapi::{
2208 PR_SVE_GET_VL, PR_SVE_SET_VL, PR_SVE_SET_VL_ONEXEC, PR_SVE_VL_INHERIT, SVE_VL_MAX,
2209 SVE_VL_MIN,
2210 };
2211
2212 fn vl_result(value: u32) -> Result<SyscallResult, Errno> {
2213 Ok((value as usize).into())
2214 }
2215
2216 fn assert_sve_regs(current_task: &CurrentTask, p_regs: &[u16; 16], ffr: u16) {
2217 let ArchExtendedPstateStorage::State64(state) =
2218 ¤t_task.thread_state.extended_pstate
2219 else {
2220 unreachable!()
2221 };
2222 assert_eq!(state.get_arm64_p_regs(), p_regs);
2223 assert_eq!(state.get_arm64_ffr(), ffr);
2224 }
2225
2226 spawn_kernel_and_run(async |current_task| {
2227 current_task.thread_state.extended_pstate =
2230 ArchExtendedPstateStorage::State64(Box::new(ExtendedPstateState::with_sve(false)));
2231 assert_eq!(sys_prctl(current_task, PR_SVE_GET_VL, 0, 0, 0, 0), error!(EINVAL));
2232 assert_eq!(
2233 sys_prctl(current_task, PR_SVE_SET_VL, SVE_VL_MIN as u64, 0, 0, 0),
2234 error!(EINVAL)
2235 );
2236
2237 current_task.thread_state.extended_pstate =
2239 ArchExtendedPstateStorage::State32(Box::default());
2240 assert_eq!(sys_prctl(current_task, PR_SVE_GET_VL, 0, 0, 0, 0), error!(EINVAL));
2241 assert_eq!(
2242 sys_prctl(current_task, PR_SVE_SET_VL, SVE_VL_MIN as u64, 0, 0, 0),
2243 error!(EINVAL)
2244 );
2245
2246 let pregs = [0x5a5au16; 16];
2248 let mut pstate = ExtendedPstateState::with_sve(true);
2249 pstate.set_arm64_sve_state(&pregs, 0x00ff);
2250 current_task.thread_state.extended_pstate =
2251 ArchExtendedPstateStorage::State64(Box::new(pstate));
2252
2253 assert_eq!(sys_prctl(current_task, PR_SVE_GET_VL, 0, 0, 0, 0), vl_result(SVE_VL_MIN));
2257 assert_eq!(sys_prctl(current_task, PR_SVE_GET_VL, 1, 2, 3, 4), vl_result(SVE_VL_MIN));
2258
2259 assert_eq!(
2261 sys_prctl(current_task, PR_SVE_SET_VL, (SVE_VL_MIN | (1 << 20)) as u64, 0, 0, 0),
2262 error!(EINVAL)
2263 );
2264 assert_eq!(
2265 sys_prctl(current_task, PR_SVE_SET_VL, (SVE_VL_MIN as u64) | (1 << 32), 0, 0, 0),
2266 error!(EINVAL)
2267 );
2268 for bad_vl in [0u32, 8, 24, SVE_VL_MAX + 16] {
2269 assert_eq!(
2270 sys_prctl(current_task, PR_SVE_SET_VL, bad_vl as u64, 0, 0, 0),
2271 error!(EINVAL),
2272 "bad_vl={} should fail",
2273 bad_vl
2274 );
2275 }
2276 assert_sve_regs(current_task, &pregs, 0x00ff);
2278 assert_eq!(sys_prctl(current_task, PR_SVE_GET_VL, 0, 0, 0, 0), vl_result(SVE_VL_MIN));
2279
2280 assert_eq!(sys_prctl(current_task, PR_SVE_SET_VL, 64, 1, 2, 3), vl_result(SVE_VL_MIN));
2284 assert_sve_regs(current_task, &pregs, 0x00ff);
2285
2286 assert_eq!(
2289 sys_prctl(
2290 current_task,
2291 PR_SVE_SET_VL,
2292 (SVE_VL_MAX | PR_SVE_VL_INHERIT) as u64,
2293 0,
2294 0,
2295 0
2296 ),
2297 vl_result(SVE_VL_MIN | PR_SVE_VL_INHERIT)
2298 );
2299 assert_sve_regs(current_task, &pregs, 0x00ff);
2300 assert_eq!(
2301 sys_prctl(current_task, PR_SVE_GET_VL, 0, 0, 0, 0),
2302 vl_result(SVE_VL_MIN | PR_SVE_VL_INHERIT)
2303 );
2304 current_task.thread_state.extended_pstate.reset();
2305 assert_sve_regs(current_task, &[0u16; 16], 0);
2306 assert_eq!(
2307 sys_prctl(current_task, PR_SVE_GET_VL, 0, 0, 0, 0),
2308 vl_result(SVE_VL_MIN | PR_SVE_VL_INHERIT)
2309 );
2310
2311 assert_eq!(
2314 sys_prctl(current_task, PR_SVE_SET_VL, (32 | PR_SVE_SET_VL_ONEXEC) as u64, 0, 0, 0),
2315 vl_result(SVE_VL_MIN)
2316 );
2317 assert_eq!(sys_prctl(current_task, PR_SVE_GET_VL, 0, 0, 0, 0), vl_result(SVE_VL_MIN));
2318 assert_eq!(
2319 sys_prctl(
2320 current_task,
2321 PR_SVE_SET_VL,
2322 (32 | PR_SVE_SET_VL_ONEXEC | PR_SVE_VL_INHERIT) as u64,
2323 0,
2324 0,
2325 0
2326 ),
2327 vl_result(SVE_VL_MIN | PR_SVE_VL_INHERIT)
2328 );
2329 assert_eq!(
2330 sys_prctl(current_task, PR_SVE_GET_VL, 0, 0, 0, 0),
2331 vl_result(SVE_VL_MIN | PR_SVE_VL_INHERIT)
2332 );
2333
2334 assert_eq!(
2336 sys_prctl(current_task, PR_SVE_SET_VL, SVE_VL_MIN as u64, 0, 0, 0),
2337 vl_result(SVE_VL_MIN)
2338 );
2339 assert_eq!(sys_prctl(current_task, PR_SVE_GET_VL, 0, 0, 0, 0), vl_result(SVE_VL_MIN));
2340 })
2341 .await;
2342 }
2343
2344 #[cfg(target_arch = "aarch64")]
2346 struct SveTestRegs {
2347 qregs: [u128; 32],
2348 fpsr: u32,
2349 fpcr: u32,
2350 pregs: [u16; 16],
2351 ffr: u16,
2352 }
2353
2354 #[cfg(target_arch = "aarch64")]
2355 impl SveTestRegs {
2356 fn sample() -> Self {
2357 let mut qregs = [0u128; 32];
2358 for (i, q) in qregs.iter_mut().enumerate() {
2359 *q = (i as u128 + 1) * 0x0102030405060708_u128;
2360 }
2361 let mut pregs = [0u16; 16];
2362 for (i, p) in pregs.iter_mut().enumerate() {
2363 *p = 0x5a00 | (i as u16 + 1);
2364 }
2365 Self { qregs, fpsr: 0x10, fpcr: 0x20, pregs, ffr: 0x00ff }
2366 }
2367
2368 fn install(&self, current_task: &mut CurrentTask, has_sve: bool) {
2369 use crate::task::ArchExtendedPstateStorage;
2370 use extended_pstate::ExtendedPstateState;
2371 let mut pstate = ExtendedPstateState::with_sve(has_sve);
2372 pstate.set_arm64_state(&self.qregs, self.fpsr, self.fpcr);
2373 pstate.set_arm64_sve_state(&self.pregs, self.ffr);
2374 current_task.thread_state.extended_pstate =
2375 ArchExtendedPstateStorage::State64(Box::new(pstate));
2376 }
2377
2378 fn assert_live(&self, current_task: &CurrentTask, context: &str) {
2379 use crate::task::ArchExtendedPstateStorage;
2380 let ArchExtendedPstateStorage::State64(state) =
2381 ¤t_task.thread_state.extended_pstate
2382 else {
2383 panic!("{context}: not 64-bit state");
2384 };
2385 assert_eq!(state.get_arm64_qregs(), &self.qregs, "{context}");
2386 assert_eq!(state.get_arm64_fpsr(), self.fpsr, "{context}");
2387 assert_eq!(state.get_arm64_fpcr(), self.fpcr, "{context}");
2388 assert_eq!(state.get_arm64_p_regs(), &self.pregs, "{context}");
2389 assert_eq!(state.get_arm64_ffr(), self.ffr, "{context}");
2390 }
2391 }
2392
2393 #[cfg(target_arch = "aarch64")]
2394 fn sve_vl_result(value: u32) -> Result<SyscallResult, Errno> {
2395 Ok((value as usize).into())
2396 }
2397
2398 #[cfg(target_arch = "aarch64")]
2399 #[::fuchsia::test]
2400 async fn test_prctl_sve_vl_ignores_trailing_args_and_preserves_registers() {
2401 use starnix_uapi::{
2402 PR_SVE_GET_VL, PR_SVE_SET_VL, PR_SVE_SET_VL_ONEXEC, PR_SVE_VL_INHERIT, SVE_VL_MAX,
2403 SVE_VL_MIN,
2404 };
2405 const INHERIT: u32 = PR_SVE_VL_INHERIT;
2406 const ONEXEC: u32 = PR_SVE_SET_VL_ONEXEC;
2407
2408 spawn_kernel_and_run(async |current_task| {
2409 let regs = SveTestRegs::sample();
2410 regs.install(current_task, true);
2411
2412 let junk_args: [[u64; 4]; 5] = [
2416 [0, 0, 0, 0],
2417 [u64::MAX, u64::MAX, u64::MAX, u64::MAX],
2418 [1 << 63, 0, 0, 0],
2419 [0, 0, 0, u64::MAX],
2420 [0xdead_beef, 0xcafe_babe, 0xfeed_face, 0xbaad_f00d],
2421 ];
2422 for [arg2, arg3, arg4, arg5] in junk_args {
2423 assert_eq!(
2424 sys_prctl(current_task, PR_SVE_GET_VL, arg2, arg3, arg4, arg5),
2425 sve_vl_result(SVE_VL_MIN),
2426 "PR_SVE_GET_VL({arg2:#x}, {arg3:#x}, {arg4:#x}, {arg5:#x})"
2427 );
2428 }
2429 regs.assert_live(current_task, "after PR_SVE_GET_VL");
2430
2431 let set_vl_cases: [(u32, [u64; 3], u32); 9] = [
2437 (SVE_VL_MIN, [0, 0, 0], SVE_VL_MIN),
2438 (SVE_VL_MIN, [u64::MAX, u64::MAX, u64::MAX], SVE_VL_MIN),
2439 (SVE_VL_MAX | INHERIT, [u64::MAX, 1, 0], SVE_VL_MIN | INHERIT),
2440 (32 | ONEXEC, [u64::MAX, u64::MAX, u64::MAX], SVE_VL_MIN),
2441 (
2442 SVE_VL_MIN | ONEXEC | INHERIT,
2443 [u64::MAX, u64::MAX, u64::MAX],
2444 SVE_VL_MIN | INHERIT,
2445 ),
2446 (4096 | ONEXEC | INHERIT, [7, 8, 9], SVE_VL_MIN | INHERIT),
2447 (SVE_VL_MIN | ONEXEC, [0, 0, 0], SVE_VL_MIN),
2448 (256 | INHERIT, [0, 0, 1 << 63], SVE_VL_MIN | INHERIT),
2449 (SVE_VL_MIN, [1, 2, 3], SVE_VL_MIN),
2450 ];
2451 for (arg2, [arg3, arg4, arg5], expected) in set_vl_cases {
2452 let context = format!("PR_SVE_SET_VL({arg2:#x}, {arg3:#x}, {arg4:#x}, {arg5:#x})");
2453 assert_eq!(
2454 sys_prctl(current_task, PR_SVE_SET_VL, arg2 as u64, arg3, arg4, arg5),
2455 sve_vl_result(expected),
2456 "{context}"
2457 );
2458 regs.assert_live(current_task, &context);
2459 assert_eq!(
2460 current_task.thread_state.extended_pstate.sve_vl_inherit(),
2461 (arg2 & INHERIT) != 0,
2462 "{context}"
2463 );
2464 for [garg2, garg3, garg4, garg5] in junk_args {
2465 assert_eq!(
2466 sys_prctl(current_task, PR_SVE_GET_VL, garg2, garg3, garg4, garg5),
2467 sve_vl_result(expected),
2468 "{context}"
2469 );
2470 }
2471 }
2472
2473 assert_eq!(
2476 sys_prctl(current_task, PR_SVE_SET_VL, (SVE_VL_MIN | INHERIT) as u64, 0, 0, 0),
2477 sve_vl_result(SVE_VL_MIN | INHERIT)
2478 );
2479 let invalid_arg2: [u64; 7] = [
2480 u64::MAX,
2481 (SVE_VL_MIN as u64) | (1 << 32),
2482 0,
2483 8,
2484 (SVE_VL_MAX + 16) as u64,
2485 (SVE_VL_MIN | ONEXEC | INHERIT | (1 << 16)) as u64,
2486 (SVE_VL_MIN | (1 << 31)) as u64,
2487 ];
2488 for arg2 in invalid_arg2 {
2489 for [_, arg3, arg4, arg5] in junk_args {
2490 let context =
2491 format!("PR_SVE_SET_VL({arg2:#x}, {arg3:#x}, {arg4:#x}, {arg5:#x})");
2492 assert_eq!(
2493 sys_prctl(current_task, PR_SVE_SET_VL, arg2, arg3, arg4, arg5),
2494 error!(EINVAL),
2495 "{context}"
2496 );
2497 regs.assert_live(current_task, &context);
2498 assert!(
2499 current_task.thread_state.extended_pstate.sve_vl_inherit(),
2500 "{context}"
2501 );
2502 }
2503 }
2504 assert_eq!(
2505 sys_prctl(current_task, PR_SVE_GET_VL, u64::MAX, u64::MAX, u64::MAX, u64::MAX),
2506 sve_vl_result(SVE_VL_MIN | INHERIT)
2507 );
2508 })
2509 .await;
2510 }
2511
2512 #[cfg(target_arch = "aarch64")]
2513 #[::fuchsia::test]
2514 async fn test_prctl_sve_vl_arch32() {
2515 use crate::task::ArchExtendedPstateStorage;
2516 use starnix_uapi::{
2517 PR_SVE_GET_VL, PR_SVE_SET_VL, PR_SVE_SET_VL_ONEXEC, PR_SVE_VL_INHERIT, SVE_VL_MAX,
2518 SVE_VL_MIN,
2519 };
2520
2521 spawn_kernel_and_run(async |current_task| {
2522 SveTestRegs::sample().install(current_task, true);
2527 assert_eq!(
2528 sys_prctl(
2529 current_task,
2530 PR_SVE_SET_VL,
2531 (SVE_VL_MIN | PR_SVE_VL_INHERIT) as u64,
2532 0,
2533 0,
2534 0
2535 ),
2536 sve_vl_result(SVE_VL_MIN | PR_SVE_VL_INHERIT)
2537 );
2538 let mut regs32 = zx::sys::zx_restricted_state_t::default();
2539 regs32.cpsr = zx::sys::ZX_REG_CPSR_ARCH_32_MASK as u32;
2540 current_task.thread_state.registers.load(regs32);
2541 let arch_width = current_task.thread_state.arch_width();
2542 current_task.thread_state.extended_pstate.reset_with_arch(arch_width);
2543 assert!(current_task.is_arch32());
2544 assert!(matches!(
2545 current_task.thread_state.extended_pstate,
2546 ArchExtendedPstateStorage::State32(_)
2547 ));
2548 assert!(!current_task.thread_state.extended_pstate.has_sve());
2549 assert!(!current_task.thread_state.extended_pstate.sve_vl_inherit());
2550
2551 let args: [[u64; 4]; 7] = [
2554 [0, 0, 0, 0],
2555 [SVE_VL_MIN as u64, 0, 0, 0],
2556 [(SVE_VL_MIN | PR_SVE_VL_INHERIT) as u64, 0, 0, 0],
2557 [(SVE_VL_MAX | PR_SVE_SET_VL_ONEXEC | PR_SVE_VL_INHERIT) as u64, 0, 0, 0],
2558 [SVE_VL_MIN as u64, u64::MAX, u64::MAX, u64::MAX],
2559 [u64::MAX, u64::MAX, u64::MAX, u64::MAX],
2560 [1, 2, 3, 4],
2561 ];
2562 for [arg2, arg3, arg4, arg5] in args {
2563 let context = format!("({arg2:#x}, {arg3:#x}, {arg4:#x}, {arg5:#x})");
2564 assert_eq!(
2565 sys_prctl(current_task, PR_SVE_GET_VL, arg2, arg3, arg4, arg5),
2566 error!(EINVAL),
2567 "PR_SVE_GET_VL{context}"
2568 );
2569 assert_eq!(
2570 sys_prctl(current_task, PR_SVE_SET_VL, arg2, arg3, arg4, arg5),
2571 error!(EINVAL),
2572 "PR_SVE_SET_VL{context}"
2573 );
2574 }
2575 let ArchExtendedPstateStorage::State32(state32) =
2577 ¤t_task.thread_state.extended_pstate
2578 else {
2579 unreachable!()
2580 };
2581 assert_eq!(state32.get_arm32_qregs(), &[0u128; 16]);
2582 assert_eq!(state32.get_arm32_fpsr(), 0);
2583 assert_eq!(state32.get_arm32_fpcr(), 0);
2584 assert!(!current_task.thread_state.extended_pstate.sve_vl_inherit());
2585
2586 current_task.thread_state.registers.load(zx::sys::zx_restricted_state_t::default());
2589 let arch_width = current_task.thread_state.arch_width();
2590 current_task.thread_state.extended_pstate.reset_with_arch(arch_width);
2591 assert!(!current_task.is_arch32());
2592 assert!(matches!(
2593 current_task.thread_state.extended_pstate,
2594 ArchExtendedPstateStorage::State64(_)
2595 ));
2596 assert!(!current_task.thread_state.extended_pstate.sve_vl_inherit());
2597 let expected = if current_task.thread_state.extended_pstate.has_sve() {
2598 sve_vl_result(SVE_VL_MIN)
2599 } else {
2600 error!(EINVAL)
2601 };
2602 assert_eq!(sys_prctl(current_task, PR_SVE_GET_VL, 0, 0, 0, 0), expected);
2603 })
2604 .await;
2605 }
2606
2607 #[cfg(target_arch = "aarch64")]
2608 #[::fuchsia::test]
2609 async fn test_prctl_sve_vl_inherited_by_clone() {
2610 use crate::task::ArchExtendedPstateStorage;
2611 use extended_pstate::ExtendedPstateState;
2612 use starnix_uapi::{PR_SVE_GET_VL, PR_SVE_SET_VL, PR_SVE_VL_INHERIT, SVE_VL_MIN};
2613
2614 spawn_kernel_and_run(async |current_task| {
2615 let regs = SveTestRegs::sample();
2616 regs.install(current_task, true);
2617 assert_eq!(
2618 sys_prctl(
2619 current_task,
2620 PR_SVE_SET_VL,
2621 (SVE_VL_MIN | PR_SVE_VL_INHERIT) as u64,
2622 0,
2623 0,
2624 0
2625 ),
2626 sve_vl_result(SVE_VL_MIN | PR_SVE_VL_INHERIT)
2627 );
2628
2629 let mut child = current_task.clone_task_for_test(0, Some(SIGCHLD));
2633 assert!(child.thread_state.extended_pstate.has_sve());
2634 assert!(child.thread_state.extended_pstate.sve_vl_inherit());
2635 regs.assert_live(&child, "child after clone");
2636 assert_eq!(
2637 sys_prctl(&mut child, PR_SVE_GET_VL, 0, 0, 0, 0),
2638 sve_vl_result(SVE_VL_MIN | PR_SVE_VL_INHERIT)
2639 );
2640 let (
2641 ArchExtendedPstateStorage::State64(parent_state),
2642 ArchExtendedPstateStorage::State64(child_state),
2643 ) = (¤t_task.thread_state.extended_pstate, &child.thread_state.extended_pstate)
2644 else {
2645 unreachable!()
2646 };
2647 assert!(!std::ptr::eq(parent_state.as_ref(), child_state.as_ref()));
2648
2649 assert_eq!(
2652 sys_prctl(&mut child, PR_SVE_SET_VL, SVE_VL_MIN as u64, 0, 0, 0),
2653 sve_vl_result(SVE_VL_MIN)
2654 );
2655 assert_eq!(sys_prctl(&mut child, PR_SVE_GET_VL, 0, 0, 0, 0), sve_vl_result(SVE_VL_MIN));
2656 assert_eq!(
2657 sys_prctl(current_task, PR_SVE_GET_VL, 0, 0, 0, 0),
2658 sve_vl_result(SVE_VL_MIN | PR_SVE_VL_INHERIT)
2659 );
2660 regs.assert_live(current_task, "parent after child's PR_SVE_SET_VL");
2661 current_task.thread_state.extended_pstate.reset();
2662 regs.assert_live(&child, "child after parent's reset");
2663 assert_eq!(
2664 sys_prctl(current_task, PR_SVE_GET_VL, 0, 0, 0, 0),
2665 sve_vl_result(SVE_VL_MIN | PR_SVE_VL_INHERIT)
2666 );
2667
2668 assert_eq!(
2671 sys_prctl(current_task, PR_SVE_SET_VL, SVE_VL_MIN as u64, 0, 0, 0),
2672 sve_vl_result(SVE_VL_MIN)
2673 );
2674 let mut child2 = current_task.clone_task_for_test(0, Some(SIGCHLD));
2675 assert!(child2.thread_state.extended_pstate.has_sve());
2676 assert!(!child2.thread_state.extended_pstate.sve_vl_inherit());
2677 assert_eq!(
2678 sys_prctl(&mut child2, PR_SVE_GET_VL, 0, 0, 0, 0),
2679 sve_vl_result(SVE_VL_MIN)
2680 );
2681
2682 current_task.thread_state.extended_pstate =
2684 ArchExtendedPstateStorage::State64(Box::new(ExtendedPstateState::with_sve(false)));
2685 let mut child3 = current_task.clone_task_for_test(0, Some(SIGCHLD));
2686 assert!(!child3.thread_state.extended_pstate.has_sve());
2687 assert_eq!(sys_prctl(&mut child3, PR_SVE_GET_VL, 0, 0, 0, 0), error!(EINVAL));
2688 assert_eq!(
2689 sys_prctl(&mut child3, PR_SVE_SET_VL, SVE_VL_MIN as u64, 0, 0, 0),
2690 error!(EINVAL)
2691 );
2692 })
2693 .await;
2694 }
2695
2696 #[::fuchsia::test]
2697 async fn test_sys_getsid() {
2698 spawn_kernel_and_run(async |current_task| {
2699 let kernel = current_task.kernel();
2700 assert_eq!(
2701 current_task.get_tid(),
2702 sys_getsid(¤t_task, 0).expect("failed to get sid")
2703 );
2704
2705 let second_task = crate::execution::create_init_child_process(
2706 &kernel.weak_self.upgrade().unwrap(),
2707 TaskCommand::new(b"second task"),
2708 Credentials::with_ids(0, 0),
2709 None,
2710 )
2711 .expect("failed to create second task");
2712 let second_current = AutoReleasableTask::from(second_task);
2713
2714 assert_eq!(
2715 second_current.get_tid(),
2716 sys_getsid(¤t_task, second_current.get_tid()).expect("failed to get sid")
2717 );
2718 })
2719 .await;
2720 }
2721
2722 #[::fuchsia::test]
2723 async fn test_get_affinity_size() {
2724 spawn_kernel_and_run(async |current_task| {
2725 let mapped_address = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
2726 let pid = current_task.get_pid();
2727 assert_eq!(sys_sched_getaffinity(¤t_task, pid, 16, mapped_address), Ok(16));
2728 assert_eq!(
2729 sys_sched_getaffinity(¤t_task, pid, 1024, mapped_address),
2730 Ok(std::mem::size_of::<CpuSet>())
2731 );
2732 assert_eq!(
2733 sys_sched_getaffinity(¤t_task, pid, 1, mapped_address),
2734 error!(EINVAL)
2735 );
2736 assert_eq!(
2737 sys_sched_getaffinity(¤t_task, pid, 9, mapped_address),
2738 error!(EINVAL)
2739 );
2740 })
2741 .await;
2742 }
2743
2744 #[::fuchsia::test]
2745 async fn test_set_affinity_size() {
2746 spawn_kernel_and_run(async |current_task| {
2747 let mapped_address = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
2748 current_task.write_memory(mapped_address, &[0xffu8]).expect("failed to cpumask");
2749 let pid = current_task.get_pid();
2750 assert_eq!(
2751 sys_sched_setaffinity(¤t_task, pid, *PAGE_SIZE as u32, mapped_address),
2752 Ok(())
2753 );
2754 assert_eq!(
2755 sys_sched_setaffinity(¤t_task, pid, 1, mapped_address),
2756 error!(EINVAL)
2757 );
2758 })
2759 .await;
2760 }
2761
2762 #[::fuchsia::test]
2763 async fn test_task_name() {
2764 spawn_kernel_and_run(async |current_task| {
2765 let mapped_address = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
2766 let name = "my-task-name\0";
2767 current_task
2768 .write_memory(mapped_address, name.as_bytes())
2769 .expect("failed to write name");
2770
2771 let result =
2772 sys_prctl(current_task, PR_SET_NAME, mapped_address.ptr() as u64, 0, 0, 0).unwrap();
2773 assert_eq!(SUCCESS, result);
2774
2775 let mapped_address = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
2776 let result =
2777 sys_prctl(current_task, PR_GET_NAME, mapped_address.ptr() as u64, 0, 0, 0).unwrap();
2778 assert_eq!(SUCCESS, result);
2779
2780 let name_length = name.len();
2781
2782 let out_name = current_task.read_memory_to_vec(mapped_address, name_length).unwrap();
2783 assert_eq!(name.as_bytes(), &out_name);
2784 })
2785 .await;
2786 }
2787
2788 #[::fuchsia::test]
2789 async fn test_sched_get_priority_min_max() {
2790 spawn_kernel_and_run(async |current_task| {
2791 let non_rt_min = sys_sched_get_priority_min(¤t_task, SCHED_NORMAL).unwrap();
2792 assert_eq!(non_rt_min, 0);
2793 let non_rt_max = sys_sched_get_priority_max(¤t_task, SCHED_NORMAL).unwrap();
2794 assert_eq!(non_rt_max, 0);
2795
2796 let rt_min = sys_sched_get_priority_min(¤t_task, SCHED_FIFO).unwrap();
2797 assert_eq!(rt_min, 1);
2798 let rt_max = sys_sched_get_priority_max(¤t_task, SCHED_FIFO).unwrap();
2799 assert_eq!(rt_max, 99);
2800
2801 let min_bad_policy_error =
2802 sys_sched_get_priority_min(¤t_task, u32::MAX).unwrap_err();
2803 assert_eq!(min_bad_policy_error, errno!(EINVAL));
2804
2805 let max_bad_policy_error =
2806 sys_sched_get_priority_max(¤t_task, u32::MAX).unwrap_err();
2807 assert_eq!(max_bad_policy_error, errno!(EINVAL));
2808 })
2809 .await;
2810 }
2811
2812 #[::fuchsia::test]
2813 async fn test_sched_setscheduler() {
2814 spawn_kernel_and_run(async |current_task| {
2815 current_task
2816 .thread_group()
2817 .limits
2818 .lock()
2819 .set(Resource::RTPRIO, uapi::rlimit { rlim_cur: 255, rlim_max: 255 });
2820
2821 let scheduler = sys_sched_getscheduler(¤t_task, 0).unwrap();
2822 assert_eq!(scheduler, SCHED_NORMAL, "tasks should have normal scheduler by default");
2823
2824 let mapped_address = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
2825 let requested_params = sched_param { sched_priority: 15 };
2826 current_task.write_object(mapped_address.into(), &requested_params).unwrap();
2827
2828 sys_sched_setscheduler(¤t_task, 0, SCHED_FIFO, mapped_address.into()).unwrap();
2829
2830 let new_scheduler = sys_sched_getscheduler(¤t_task, 0).unwrap();
2831 assert_eq!(new_scheduler, SCHED_FIFO, "task should have been assigned fifo scheduler");
2832
2833 let mapped_address = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
2834 sys_sched_getparam(¤t_task, 0, mapped_address.into()).expect("sched_getparam");
2835 let param_value: sched_param =
2836 current_task.read_object(mapped_address.into()).expect("read_object");
2837 assert_eq!(param_value.sched_priority, 15);
2838 })
2839 .await;
2840 }
2841
2842 #[::fuchsia::test]
2843 async fn test_sched_getparam() {
2844 spawn_kernel_and_run(async |current_task| {
2845 let mapped_address = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
2846 sys_sched_getparam(¤t_task, 0, mapped_address.into()).expect("sched_getparam");
2847 let param_value: sched_param =
2848 current_task.read_object(mapped_address.into()).expect("read_object");
2849 assert_eq!(param_value.sched_priority, 0);
2850 })
2851 .await;
2852 }
2853
2854 #[::fuchsia::test]
2855 async fn test_setuid() {
2856 spawn_kernel_and_run(async |current_task| {
2857 current_task.set_creds(Credentials::with_ids(0, 0));
2859 sys_setuid(¤t_task, 42).expect("setuid");
2860 let mut creds = Credentials::clone(¤t_task.current_creds());
2861 assert_eq!(creds.euid, 42);
2862 assert_eq!(creds.uid, 42);
2863 assert_eq!(creds.saved_uid, 42);
2864
2865 creds.cap_effective.remove(CAP_SETUID);
2867 current_task.set_creds(creds);
2868
2869 assert_eq!(sys_setuid(¤t_task, 0), error!(EPERM));
2871 assert_eq!(sys_setuid(¤t_task, 43), error!(EPERM));
2872
2873 sys_setuid(¤t_task, 42).expect("setuid");
2874 assert_eq!(current_task.current_creds().euid, 42);
2875 assert_eq!(current_task.current_creds().uid, 42);
2876 assert_eq!(current_task.current_creds().saved_uid, 42);
2877
2878 let mut creds = Credentials::clone(¤t_task.current_creds());
2880 creds.uid = 41;
2881 creds.euid = 42;
2882 creds.saved_uid = 43;
2883 current_task.set_creds(creds);
2884
2885 sys_setuid(¤t_task, 41).expect("setuid");
2886 assert_eq!(current_task.current_creds().euid, 41);
2887 assert_eq!(current_task.current_creds().uid, 41);
2888 assert_eq!(current_task.current_creds().saved_uid, 43);
2889
2890 let mut creds = Credentials::clone(¤t_task.current_creds());
2891 creds.uid = 41;
2892 creds.euid = 42;
2893 creds.saved_uid = 43;
2894 current_task.set_creds(creds);
2895
2896 sys_setuid(¤t_task, 43).expect("setuid");
2897 assert_eq!(current_task.current_creds().euid, 43);
2898 assert_eq!(current_task.current_creds().uid, 41);
2899 assert_eq!(current_task.current_creds().saved_uid, 43);
2900 })
2901 .await;
2902 }
2903
2904 #[::fuchsia::test]
2905 async fn test_prlimit64_stack() {
2906 spawn_kernel_and_run(async |current_task| {
2907 let mapped_address = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
2908 let old_limit_ref = UserRef::<uapi::rlimit>::new(mapped_address);
2909 let new_limit_ref = UserRef::<uapi::rlimit>::new(
2910 (mapped_address + std::mem::size_of::<uapi::rlimit>()).unwrap(),
2911 );
2912
2913 sys_prlimit64(current_task, 0, uapi::RLIMIT_STACK, UserRef::default(), old_limit_ref)
2914 .expect("prlimit64 get RLIMIT_STACK");
2915 let initial_limit: uapi::rlimit =
2916 current_task.read_object(old_limit_ref).expect("read initial limit");
2917 assert_eq!(
2918 (initial_limit.rlim_cur, initial_limit.rlim_max),
2919 (uapi::_STK_LIM as u64, uapi::RLIM_INFINITY as u64)
2920 );
2921
2922 let updated_limit =
2923 uapi::rlimit { rlim_cur: 4 * 1024 * 1024, rlim_max: 16 * 1024 * 1024 };
2924 current_task.write_object(new_limit_ref, &updated_limit).expect("write new limit");
2925 sys_prlimit64(current_task, 0, uapi::RLIMIT_STACK, new_limit_ref, old_limit_ref)
2926 .expect("prlimit64 set RLIMIT_STACK");
2927 let prev_limit: uapi::rlimit =
2928 current_task.read_object(old_limit_ref).expect("read previous limit");
2929 assert_eq!(
2930 (prev_limit.rlim_cur, prev_limit.rlim_max),
2931 (initial_limit.rlim_cur, initial_limit.rlim_max)
2932 );
2933 let current_limit = current_task.thread_group().limits.lock().get(Resource::STACK);
2934 assert_eq!(
2935 (current_limit.rlim_cur, current_limit.rlim_max),
2936 (updated_limit.rlim_cur, updated_limit.rlim_max)
2937 );
2938
2939 let invalid_limit =
2941 uapi::rlimit { rlim_cur: 32 * 1024 * 1024, rlim_max: 16 * 1024 * 1024 };
2942 current_task.write_object(new_limit_ref, &invalid_limit).expect("write invalid limit");
2943 assert_eq!(
2944 sys_prlimit64(
2945 current_task,
2946 0,
2947 uapi::RLIMIT_STACK,
2948 new_limit_ref,
2949 UserRef::default()
2950 ),
2951 error!(EINVAL)
2952 );
2953 let current_limit = current_task.thread_group().limits.lock().get(Resource::STACK);
2954 assert_eq!(
2955 (current_limit.rlim_cur, current_limit.rlim_max),
2956 (updated_limit.rlim_cur, updated_limit.rlim_max)
2957 );
2958
2959 let zero_soft_limit = uapi::rlimit { rlim_cur: 0, rlim_max: 16 * 1024 * 1024 };
2962 current_task
2963 .write_object(new_limit_ref, &zero_soft_limit)
2964 .expect("write zero soft limit");
2965 sys_prlimit64(current_task, 0, uapi::RLIMIT_STACK, new_limit_ref, UserRef::default())
2966 .expect("prlimit64 set zero RLIMIT_STACK");
2967 assert_eq!(current_task.thread_group().get_rlimit(Resource::STACK), 0);
2968
2969 let arg_addr = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
2970 current_task.write_memory(arg_addr, b"test-arg\0").expect("write test arg");
2971 let empty_path_addr = (arg_addr + 16usize).unwrap();
2972 current_task.write_memory(empty_path_addr, b"\0").expect("write empty path");
2973 let argv_addr = UserCStringPtr::new(
2974 current_task,
2975 map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE),
2976 );
2977 current_task
2978 .write_multi_arch_ptr(argv_addr.addr(), UserCString::new(current_task, arg_addr))
2979 .expect("write argv[0]");
2980 current_task
2981 .write_multi_arch_ptr(
2982 argv_addr.next().unwrap().addr(),
2983 UserCString::null(current_task),
2984 )
2985 .expect("write argv[1]");
2986 assert_eq!(
2987 sys_execve(
2988 current_task,
2989 UserCString::new(current_task, empty_path_addr),
2990 argv_addr,
2991 UserCStringPtr::null(current_task),
2992 ),
2993 error!(ENOENT)
2994 );
2995 })
2996 .await;
2997 }
2998
2999 #[::fuchsia::test]
3000 async fn test_read_c_string_vector() {
3001 spawn_kernel_and_run(async |current_task| {
3002 let arg_addr = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
3003 let arg = b"test-arg\0";
3004 current_task.write_memory(arg_addr, arg).expect("failed to write test arg");
3005 let arg_usercstr = UserCString::new(current_task, arg_addr);
3006 let null_usercstr = UserCString::null(current_task);
3007
3008 let argv_addr = UserCStringPtr::new(
3009 current_task,
3010 map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE),
3011 );
3012 current_task
3013 .write_multi_arch_ptr(argv_addr.addr(), arg_usercstr)
3014 .expect("failed to write UserCString");
3015 current_task
3016 .write_multi_arch_ptr(argv_addr.next().unwrap().addr(), null_usercstr)
3017 .expect("failed to write UserCString");
3018
3019 assert!(read_c_string_vector(¤t_task, argv_addr, 100, arg.len()).is_ok());
3021 assert_eq!(
3022 read_c_string_vector(
3023 ¤t_task,
3024 argv_addr,
3025 100,
3026 std::str::from_utf8(arg).unwrap().trim_matches('\0').len()
3027 ),
3028 error!(E2BIG)
3029 );
3030 })
3031 .await;
3032 }
3033
3034 #[::fuchsia::test]
3035 async fn test_kcmp() {
3036 spawn_kernel_and_run(async |current_task| {
3037 let pid = current_task.get_pid();
3038 assert_eq!(sys_kcmp(¤t_task, pid, pid, kcmp_type_KCMP_VM, 0, 0), Ok(0));
3039 assert_eq!(
3040 sys_kcmp(¤t_task, pid, pid, kcmp_type_KCMP_SYSVSEM, 0, 0),
3041 error!(EOPNOTSUPP)
3042 );
3043 assert_eq!(
3044 sys_kcmp(¤t_task, pid, pid, kcmp_type_KCMP_SYSVSEM, 1, 2),
3045 error!(EOPNOTSUPP)
3046 );
3047 assert_eq!(
3048 sys_kcmp(¤t_task, pid, pid, kcmp_type_KCMP_SYSVSEM, u64::MAX, u64::MAX),
3049 error!(EOPNOTSUPP)
3050 );
3051 assert_eq!(
3052 sys_kcmp(¤t_task, pid, pid, kcmp_type_KCMP_TYPES, 0, 0),
3053 error!(EINVAL)
3054 );
3055 assert_eq!(sys_kcmp(¤t_task, pid, pid, u32::MAX, 0, 0), error!(EINVAL));
3056 assert_eq!(
3057 sys_kcmp(¤t_task, 0, pid, kcmp_type_KCMP_SYSVSEM, 0, 0),
3058 error!(ESRCH)
3059 );
3060 assert_eq!(
3061 sys_kcmp(¤t_task, pid, 0, kcmp_type_KCMP_SYSVSEM, 0, 0),
3062 error!(ESRCH)
3063 );
3064 assert_eq!(
3065 sys_kcmp(¤t_task, -1, pid, kcmp_type_KCMP_SYSVSEM, 0, 0),
3066 error!(ESRCH)
3067 );
3068 assert_eq!(
3069 sys_kcmp(¤t_task, pid, -1, kcmp_type_KCMP_SYSVSEM, 0, 0),
3070 error!(ESRCH)
3071 );
3072
3073 let target_task = current_task.clone_task_for_test(0, Some(SIGCHLD));
3075 let target_pid = target_task.get_pid();
3076 current_task.set_creds(Credentials::with_ids(1, 1));
3077 assert_eq!(
3078 sys_kcmp(¤t_task, target_pid, target_pid, kcmp_type_KCMP_SYSVSEM, 0, 0),
3079 error!(EPERM)
3080 );
3081 assert_eq!(
3082 sys_kcmp(¤t_task, pid, target_pid, kcmp_type_KCMP_SYSVSEM, 0, 0),
3083 error!(EPERM)
3084 );
3085 assert_eq!(
3086 sys_kcmp(¤t_task, target_pid, pid, kcmp_type_KCMP_SYSVSEM, 0, 0),
3087 error!(EPERM)
3088 );
3089 })
3090 .await;
3091 }
3092}