1use crate::mm::MemoryManager;
6use crate::security;
7use crate::signals::SignalActions;
8use crate::task::{
9 CurrentTask, Kernel, PidTable, ProcessGroup, RobustListHeadPtr, SeccompFilterContainer,
10 SeccompState, Task, TaskBuilder, ThreadGroup, ThreadGroupParent, ThreadGroupWriteGuard,
11};
12use crate::vfs::{FdTable, FsContext};
13use starnix_sync::{
14 LockBefore, Locked, ProcessGroupState, RwLockWriteGuard, TaskRelease, Unlocked,
15};
16use starnix_task_command::TaskCommand;
17use starnix_types::arch::ArchWidth;
18use starnix_types::ownership::TempRef;
19use starnix_types::release_on_error;
20use starnix_uapi::auth::Credentials;
21use starnix_uapi::errors::Errno;
22use starnix_uapi::resource_limits::Resource;
23use starnix_uapi::signals::{SIGCHLD, Signal};
24use starnix_uapi::{errno, error, from_status_like_fdio, pid_t, rlimit};
25use std::ffi::CString;
26use std::sync::Arc;
27
28pub struct TaskInfo {
30 pub thread: Option<zx::Thread>,
32
33 pub thread_group: Arc<ThreadGroup>,
35
36 pub memory_manager: Option<Arc<MemoryManager>>,
38}
39
40pub fn create_zircon_process<L>(
41 locked: &mut Locked<L>,
42 kernel: &Arc<Kernel>,
43 parent: Option<ThreadGroupWriteGuard<'_>>,
44 pid: pid_t,
45 exit_signal: Option<Signal>,
46 process_group: Arc<ProcessGroup>,
47 signal_actions: Arc<SignalActions>,
48 name: TaskCommand,
49 arch_width: ArchWidth,
50) -> Result<TaskInfo, Errno>
51where
52 L: LockBefore<ProcessGroupState>,
53{
54 if kernel.is_shutting_down() {
56 return error!(EBUSY);
57 }
58 let (process, root_vmar) =
59 create_shared(&kernel.kthreads.starnix_process, zx::ProcessOptions::empty(), name)
60 .map_err(|status| from_status_like_fdio!(status))?;
61
62 fuchsia_runtime::job_default()
64 .set_critical(zx::JobCriticalOptions::RETCODE_NONZERO, &process)
65 .map_err(|status| from_status_like_fdio!(status))?;
66
67 let memory_manager = Arc::new(
68 MemoryManager::new(root_vmar, arch_width)
69 .map_err(|status| from_status_like_fdio!(status))?,
70 );
71
72 let thread_group = ThreadGroup::new(
73 locked,
74 kernel.clone(),
75 process,
76 parent,
77 pid,
78 exit_signal,
79 process_group,
80 signal_actions,
81 );
82
83 Ok(TaskInfo { thread: None, thread_group, memory_manager: Some(memory_manager) })
84}
85
86fn create_shared(
96 process: &zx::Process,
97 options: zx::ProcessOptions,
98 name: TaskCommand,
99) -> Result<(zx::Process, zx::Vmar), zx::Status> {
100 let self_raw = process.raw_handle();
101 let name_bytes = name.as_bytes();
102 let mut process_out = 0;
103 let mut restricted_vmar_out = 0;
104 #[allow(
105 clippy::undocumented_unsafe_blocks,
106 reason = "Force documented unsafe blocks in Starnix"
107 )]
108 let status = unsafe {
109 zx::sys::zx_process_create_shared(
110 self_raw,
111 options.bits(),
112 name_bytes.as_ptr(),
113 name_bytes.len(),
114 &mut process_out,
115 &mut restricted_vmar_out,
116 )
117 };
118 zx::ok(status)?;
119 #[allow(
120 clippy::undocumented_unsafe_blocks,
121 reason = "Force documented unsafe blocks in Starnix"
122 )]
123 unsafe {
124 Ok((
125 zx::Process::from(zx::NullableHandle::from_raw(process_out)),
126 zx::Vmar::from(zx::NullableHandle::from_raw(restricted_vmar_out)),
127 ))
128 }
129}
130
131pub fn create_init_child_process<L>(
150 locked: &mut Locked<L>,
151 kernel: &Arc<Kernel>,
152 initial_name: TaskCommand,
153 mut creds: Credentials,
154 seclabel: Option<&CString>,
155) -> Result<TaskBuilder, Errno>
156where
157 L: LockBefore<TaskRelease>,
158{
159 let weak_init = kernel.pids.read().get_task(1);
160 let init_task = weak_init.upgrade().ok_or_else(|| errno!(EINVAL))?;
161
162 let security_state = if let Some(seclabel) = seclabel {
163 security::task_for_context(&init_task, seclabel.as_bytes().into())?
164 } else if let Some(default_seclabel) = kernel.features.default_seclabel.as_ref() {
165 security::task_for_context(&init_task, default_seclabel.as_bytes().into())?
166 } else {
167 security::task_for_context(&init_task, b"".into()).map_err(|_| {
169 errno!(EINVAL, "Container has SELinux enabled but no Security Context specified")
170 })?
171 };
172 creds.security_state = security_state;
173
174 let task = create_task(
175 locked,
176 kernel,
177 initial_name.clone(),
178 init_task.fs().fork(),
179 |locked, pid, process_group| {
180 create_zircon_process(
181 locked.cast_locked::<TaskRelease>(),
182 kernel,
183 None,
184 pid,
185 Some(SIGCHLD),
186 process_group,
187 SignalActions::default(),
188 initial_name.clone(),
189 ArchWidth::Arch64,
190 )
191 },
192 creds.into(),
193 )?;
194 {
195 let mut init_writer = init_task.thread_group().write();
196 let mut new_process_writer = task.thread_group().write();
197 new_process_writer.parent =
198 Some(ThreadGroupParent::new(Arc::downgrade(&init_task.thread_group())));
199 init_writer.children.insert(task.tid, Arc::downgrade(task.thread_group()));
200 }
201 let limits = init_task.thread_group().limits.lock(locked.cast_locked::<TaskRelease>()).clone();
204 *task.thread_group().limits.lock(locked.cast_locked::<TaskRelease>()) = limits;
205 Ok(task)
206}
207
208pub fn create_init_process(
227 locked: &mut Locked<Unlocked>,
228 kernel: &Arc<Kernel>,
229 pid: pid_t,
230 initial_name: TaskCommand,
231 fs: Arc<FsContext>,
232 rlimits: &[(Resource, u64)],
233) -> Result<TaskBuilder, Errno> {
234 let pids = kernel.pids.write();
235 create_task_with_pid(
236 locked,
237 kernel,
238 pids,
239 pid,
240 initial_name.clone(),
241 fs,
242 |locked, pid, process_group| {
243 create_zircon_process(
244 locked,
245 kernel,
246 None,
247 pid,
248 Some(SIGCHLD),
249 process_group,
250 SignalActions::default(),
251 initial_name.clone(),
252 ArchWidth::Arch64,
253 )
254 },
255 Credentials::root(),
256 rlimits,
257 )
258}
259
260pub fn create_system_task<L>(
272 locked: &mut Locked<L>,
273 kernel: &Arc<Kernel>,
274 fs: Arc<FsContext>,
275) -> Result<CurrentTask, Errno>
276where
277 L: LockBefore<TaskRelease>,
278{
279 let builder = create_task(
280 locked,
281 kernel,
282 TaskCommand::new(b"kthreadd"),
283 fs,
284 |locked, pid, process_group| {
285 let process = zx::Process::from(zx::NullableHandle::invalid());
286 let thread_group = ThreadGroup::new(
287 locked.cast_locked::<TaskRelease>(),
288 kernel.clone(),
289 process,
290 None,
291 pid,
292 Some(SIGCHLD),
293 process_group,
294 SignalActions::default(),
295 );
296 Ok(TaskInfo { thread: None, thread_group, memory_manager: None }.into())
297 },
298 Credentials::root(),
299 )?;
300 Ok(builder.into())
301}
302
303pub fn create_task<F, L>(
304 locked: &mut Locked<L>,
305 kernel: &Kernel,
306 initial_name: TaskCommand,
307 root_fs: Arc<FsContext>,
308 task_info_factory: F,
309 creds: Arc<Credentials>,
310) -> Result<TaskBuilder, Errno>
311where
312 F: FnOnce(&mut Locked<L>, i32, Arc<ProcessGroup>) -> Result<TaskInfo, Errno>,
313 L: LockBefore<TaskRelease>,
314{
315 let mut pids = kernel.pids.write();
316 let pid = pids.allocate_pid();
317 create_task_with_pid(
318 locked,
319 kernel,
320 pids,
321 pid,
322 initial_name,
323 root_fs,
324 task_info_factory,
325 creds,
326 &[],
327 )
328}
329
330fn create_task_with_pid<F, L>(
331 locked: &mut Locked<L>,
332 kernel: &Kernel,
333 mut pids: RwLockWriteGuard<'_, PidTable>,
334 pid: pid_t,
335 initial_name: TaskCommand,
336 root_fs: Arc<FsContext>,
337 task_info_factory: F,
338 creds: Arc<Credentials>,
339 rlimits: &[(Resource, u64)],
340) -> Result<TaskBuilder, Errno>
341where
342 F: FnOnce(&mut Locked<L>, i32, Arc<ProcessGroup>) -> Result<TaskInfo, Errno>,
343 L: LockBefore<TaskRelease>,
344{
345 debug_assert!(pids.get_task(pid).upgrade().is_none());
346
347 let process_group = ProcessGroup::new(pid, None);
348 pids.add_process_group(process_group.clone());
349
350 let TaskInfo { thread, thread_group, memory_manager } =
351 task_info_factory(locked, pid, process_group.clone())?;
352
353 process_group.insert(locked.cast_locked::<TaskRelease>(), &thread_group);
354
355 let default_timerslack = 50_000;
360 let builder = TaskBuilder {
361 task: Task::new(
362 pid,
363 initial_name,
364 thread_group,
365 thread,
366 FdTable::default(),
367 memory_manager,
368 root_fs,
369 creds,
370 Arc::clone(&kernel.default_abstract_socket_namespace),
371 Arc::clone(&kernel.default_abstract_vsock_namespace),
372 Default::default(),
373 Default::default(),
374 None,
375 Default::default(),
376 kernel.root_uts_ns.clone(),
377 false,
378 SeccompState::default(),
379 SeccompFilterContainer::default(),
380 RobustListHeadPtr::null(&ArchWidth::Arch64),
381 default_timerslack,
382 ),
383 thread_state: Default::default(),
384 };
385 release_on_error!(builder, locked, {
386 let temp_task = TempRef::from(&builder.task);
387 builder.thread_group().add(&temp_task)?;
388 for (resource, limit) in rlimits {
389 builder
390 .thread_group()
391 .limits
392 .lock(locked.cast_locked::<TaskRelease>())
393 .set(*resource, rlimit { rlim_cur: *limit, rlim_max: *limit });
394 }
395
396 pids.add_task(&temp_task);
397 Ok(())
398 });
399 Ok(builder)
400}
401
402pub fn create_kernel_thread<L>(
406 locked: &mut Locked<L>,
407 system_task: &Task,
408 initial_name: TaskCommand,
409) -> Result<CurrentTask, Errno>
410where
411 L: LockBefore<TaskRelease>,
412{
413 let mut pids = system_task.kernel().pids.write();
414 let pid = pids.allocate_pid();
415
416 let scheduler_state;
417 let uts_ns;
418 let default_timerslack_ns;
419 {
420 let state = system_task.read();
421 scheduler_state = state.scheduler_state;
422 uts_ns = state.uts_ns.clone();
423 default_timerslack_ns = state.default_timerslack_ns;
424 }
425
426 let current_task: CurrentTask = TaskBuilder::new(Task::new(
427 pid,
428 initial_name,
429 system_task.thread_group().clone(),
430 None,
431 FdTable::default(),
432 system_task.mm().ok(),
433 system_task.fs(),
434 system_task.clone_creds(),
435 Arc::clone(&system_task.abstract_socket_namespace),
436 Arc::clone(&system_task.abstract_vsock_namespace),
437 Default::default(),
438 Default::default(),
439 None,
440 scheduler_state,
441 uts_ns,
442 false,
443 SeccompState::default(),
444 SeccompFilterContainer::default(),
445 RobustListHeadPtr::null(&ArchWidth::Arch64),
446 default_timerslack_ns,
447 ))
448 .into();
449 release_on_error!(current_task, locked, {
450 let temp_task = current_task.temp_task();
451 current_task.thread_group().add(&temp_task)?;
452 pids.add_task(&temp_task);
453 Ok(())
454 });
455 Ok(current_task)
456}