1use crate::{elf_load, process_args, util};
6use anyhow::{Context, anyhow};
7use fidl::endpoints::{ClientEnd, Proxy};
8use fidl_fuchsia_io as fio;
9use fidl_fuchsia_ldsvc as fldsvc;
10use fuchsia_async::{self as fasync, TimeoutExt};
11use fuchsia_runtime::{HandleInfo, HandleType};
12use futures::prelude::*;
13use std::ffi::{CStr, CString};
14use std::{iter, mem};
15use thiserror::Error;
16use zx::AsHandleRef;
17
18#[derive(Error, Debug)]
20pub enum ProcessBuilderError {
21 #[error("{}", _0)]
22 InvalidArg(String),
23 #[error("{}", _0)]
24 BadHandle(&'static str),
25 #[error("Failed to create process: {}", _0)]
26 CreateProcess(zx::Status),
27 #[error("Failed to create thread: {}", _0)]
28 CreateThread(zx::Status),
29 #[error("Failed to start process: {}", _0)]
30 ProcessStart(zx::Status),
31 #[error("Failed to parse ELF: {}", _0)]
32 ElfParse(#[from] elf_parse::ElfParseError),
33 #[error("Failed to load ELF: {}", _0)]
34 ElfLoad(#[from] elf_load::ElfLoadError),
35 #[error("{}", _0)]
36 ProcessArgs(#[from] process_args::ProcessargsError),
37 #[error("{}: {}", _0, _1)]
38 GenericStatus(&'static str, zx::Status),
39 #[error("{}: {}", _0, _1)]
40 Internal(&'static str, #[source] anyhow::Error),
41 #[error("Invalid PT_INTERP header: {}", _0)]
42 InvalidInterpHeader(#[source] anyhow::Error),
43 #[error("Failed to build process with dynamic ELF, missing fuchsia.ldsvc.Loader handle")]
44 LoaderMissing(),
45 #[error("Failed to load dynamic linker from fuchsia.ldsvc.Loader: {}", _0)]
46 LoadDynamicLinker(#[source] fidl::Error),
47 #[error("Timed out loading dynamic linker from fuchsia.ldsvc.Loader")]
48 LoadDynamicLinkerTimeout(),
49 #[error("Failed to write bootstrap message to channel: {}", _0)]
50 WriteBootstrapMessage(zx::Status),
51 #[error("Failed to destroy reservation VMAR: {}", _0)]
52 DestroyReservationVMAR(zx::Status),
53 #[error("Failed to duplicate handle of type {:?}: {}", _0, _1)]
54 DuplicateHandle(HandleType, zx::Status),
55}
56
57impl ProcessBuilderError {
58 pub fn as_zx_status(&self) -> zx::Status {
60 match self {
61 ProcessBuilderError::InvalidArg(_)
62 | ProcessBuilderError::InvalidInterpHeader(_)
63 | ProcessBuilderError::LoaderMissing() => zx::Status::INVALID_ARGS,
64 ProcessBuilderError::BadHandle(_) => zx::Status::BAD_HANDLE,
65 ProcessBuilderError::CreateProcess(s)
66 | ProcessBuilderError::CreateThread(s)
67 | ProcessBuilderError::ProcessStart(s)
68 | ProcessBuilderError::GenericStatus(_, s)
69 | ProcessBuilderError::WriteBootstrapMessage(s)
70 | ProcessBuilderError::DestroyReservationVMAR(s) => *s,
71 ProcessBuilderError::ElfParse(e) => e.as_zx_status(),
72 ProcessBuilderError::ElfLoad(e) => e.as_zx_status(),
73 ProcessBuilderError::ProcessArgs(e) => e.as_zx_status(),
74 ProcessBuilderError::Internal(_, _) => zx::Status::INTERNAL,
75 ProcessBuilderError::LoadDynamicLinker(_) => zx::Status::NOT_FOUND,
76 ProcessBuilderError::LoadDynamicLinkerTimeout() => zx::Status::TIMED_OUT,
77 ProcessBuilderError::DuplicateHandle(_, s) => *s,
78 }
79 }
80}
81
82pub struct NamespaceEntry {
85 pub path: CString,
87
88 pub directory: ClientEnd<fio::DirectoryMarker>,
90}
91
92pub struct ProcessBuilder {
96 executable: zx::Vmo,
98 ldsvc: Option<fldsvc::LoaderProxy>,
100 non_default_vdso: Option<zx::Vmo>,
102 msg_contents: process_args::MessageContents,
104 common: CommonMessageHandles,
107 min_stack_size: usize,
109 system_vdso_vmo: zx::Vmo,
111}
112
113struct CommonMessageHandles {
114 process: zx::Process,
115 thread: zx::Thread,
116 root_vmar: zx::Vmar,
117}
118
119pub struct BuiltProcess {
129 pub process: zx::Process,
131
132 pub root_vmar: zx::Vmar,
134
135 pub thread: zx::Thread,
137
138 pub entry: usize,
140
141 pub stack: usize,
143
144 pub stack_base: usize,
146
147 pub stack_vmo: zx::Vmo,
149
150 pub bootstrap: zx::Channel,
153
154 pub vdso_base: usize,
157
158 pub elf_base: usize,
161
162 pub elf_headers: elf_parse::Elf64Headers,
164}
165
166struct StackInfo {
167 pub stack_ptr: usize,
169
170 pub stack_base: usize,
172
173 pub stack_vmo: zx::Vmo,
175}
176
177impl ProcessBuilder {
178 pub fn new(
193 name: &CStr,
194 job: &zx::Job,
195 options: zx::ProcessOptions,
196 executable: zx::Vmo,
197 system_vdso_vmo: zx::Vmo,
198 ) -> Result<ProcessBuilder, ProcessBuilderError> {
199 if job.is_invalid() {
200 return Err(ProcessBuilderError::BadHandle("Invalid job handle"));
201 }
202 if executable.is_invalid() {
203 return Err(ProcessBuilderError::BadHandle("Invalid executable handle"));
204 }
205
206 let (process, root_vmar) = job
209 .create_child_process(options, name.to_bytes())
210 .map_err(ProcessBuilderError::CreateProcess)?;
211
212 let thread =
214 process.create_thread(b"initial-thread").map_err(ProcessBuilderError::CreateThread)?;
215
216 let msg_contents = process_args::MessageContents::default();
218 let mut pb = ProcessBuilder {
219 executable,
220 ldsvc: None,
221 non_default_vdso: None,
222 msg_contents,
223 common: CommonMessageHandles { process, thread, root_vmar },
224 min_stack_size: 0,
225 system_vdso_vmo,
226 };
227 pb.common.add_process_self(&mut pb.msg_contents)?;
228 pb.common.add_thread_self(&mut pb.msg_contents)?;
229 pb.common.add_root_vmar(&mut pb.msg_contents)?;
230 Ok(pb)
231 }
232
233 pub fn set_loader_service(
253 &mut self,
254 ldsvc: ClientEnd<fldsvc::LoaderMarker>,
255 ) -> Result<(), ProcessBuilderError> {
256 if ldsvc.as_handle_ref().is_invalid() {
257 return Err(ProcessBuilderError::BadHandle("Invalid loader service handle"));
258 }
259 self.ldsvc = Some(ldsvc.into_proxy());
260 Ok(())
261 }
262
263 pub fn set_vdso_vmo(&mut self, vdso: zx::Vmo) {
265 self.non_default_vdso = Some(vdso);
266 }
267
268 pub fn add_arguments(&mut self, mut args: Vec<CString>) {
271 self.msg_contents.args.append(&mut args);
272 }
273
274 pub fn add_environment_variables(&mut self, mut vars: Vec<CString>) {
277 self.msg_contents.environment_vars.append(&mut vars);
278 }
279
280 pub fn set_min_stack_size(&mut self, size: usize) {
282 self.min_stack_size = size;
283 }
284
285 pub fn add_handles(
309 &mut self,
310 startup_handles: Vec<process_args::StartupHandle>,
311 ) -> Result<(), ProcessBuilderError> {
312 for h in &startup_handles {
314 if h.handle.is_invalid() {
315 return Err(ProcessBuilderError::BadHandle("Invalid handle in startup handles"));
316 }
317
318 let t = h.info.handle_type();
319 match t {
320 HandleType::NamespaceDirectory => {
321 return Err(ProcessBuilderError::InvalidArg(
322 "Cannot add NamespaceDirectory handles directly, use add_namespace_entries"
323 .into(),
324 ));
325 }
326 HandleType::ProcessSelf
327 | HandleType::ThreadSelf
328 | HandleType::RootVmar
329 | HandleType::LoadedVmar
330 | HandleType::StackVmo
331 | HandleType::ExecutableVmo => {
332 return Err(ProcessBuilderError::InvalidArg(format!(
333 "Cannot add a {:?} handle directly, it will be automatically added",
334 t,
335 )));
336 }
337 _ => {}
338 }
339 }
340
341 for h in startup_handles {
343 match h.info.handle_type() {
344 HandleType::LdsvcLoader => {
345 self.set_loader_service(ClientEnd::from(h.handle))?;
347 }
348 HandleType::VdsoVmo => {
349 if h.info.arg() == 0 {
350 self.set_vdso_vmo(h.handle.into());
351 } else {
352 self.msg_contents.handles.push(h);
354 }
355 }
356 _ => {
357 self.msg_contents.handles.push(h);
358 }
359 }
360 }
361 Ok(())
362 }
363
364 pub fn add_namespace_entries(
378 &mut self,
379 mut entries: Vec<NamespaceEntry>,
380 ) -> Result<(), ProcessBuilderError> {
381 let mut idx = u16::try_from(self.msg_contents.namespace_paths.len())
390 .expect("namespace_paths.len should never be larger than a u16");
391 let num_entries = u16::try_from(entries.len())
392 .map_err(|_| ProcessBuilderError::InvalidArg("Too many namespace entries".into()))?;
393 if idx.checked_add(num_entries).is_none() {
394 return Err(ProcessBuilderError::InvalidArg(
395 "Can't add namespace entries, limit reached".into(),
396 ));
397 }
398
399 for entry in &entries {
400 if entry.directory.as_handle_ref().is_invalid() {
401 return Err(ProcessBuilderError::BadHandle("Invalid handle in namespace entry"));
402 }
403 }
404
405 for entry in entries.drain(..) {
407 self.msg_contents.namespace_paths.push(entry.path);
408 self.msg_contents.handles.push(process_args::StartupHandle {
409 handle: entry.directory.into(),
410 info: HandleInfo::new(HandleType::NamespaceDirectory, idx),
411 });
412 idx += 1;
413 }
414 Ok(())
415 }
416
417 pub async fn build(mut self) -> Result<BuiltProcess, ProcessBuilderError> {
435 let elf_headers = elf_parse::Elf64Headers::from_vmo(&self.executable)?;
438
439 let (bootstrap_rd, bootstrap_wr) = zx::Channel::create();
441
442 let loaded_elf;
444 let mut reserve_vmar = None;
445 let dynamic;
446 if let Some(interp_hdr) =
447 elf_headers.program_header_with_type(elf_parse::SegmentType::Interp)?
448 {
449 dynamic = true;
452
453 let ldsvc = self.ldsvc.take().ok_or(ProcessBuilderError::LoaderMissing())?;
455
456 reserve_vmar =
466 Some(ReservationVmar::reserve_low_address_space(&self.common.root_vmar)?);
467
468 let ld_vmo = get_dynamic_linker(&ldsvc, &self.executable, interp_hdr).await?;
470 let ld_headers = elf_parse::Elf64Headers::from_vmo(&ld_vmo)?;
471 loaded_elf = elf_load::load_elf(&ld_vmo, &ld_headers, &self.common.root_vmar)?;
472
473 let executable =
477 mem::replace(&mut self.executable, zx::NullableHandle::invalid().into());
478 let msg = self.build_linker_message(ldsvc, executable, loaded_elf.vmar)?;
479 msg.write(&bootstrap_wr).map_err(ProcessBuilderError::WriteBootstrapMessage)?;
480 } else {
481 dynamic = false;
483
484 loaded_elf =
485 elf_load::load_elf(&self.executable, &elf_headers, &self.common.root_vmar)?;
486 self.msg_contents.handles.push(process_args::StartupHandle {
487 handle: loaded_elf.vmar.into_handle(),
488 info: HandleInfo::new(HandleType::LoadedVmar, 0),
489 });
490 }
491
492 let vdso_base = self.load_vdso()?;
495
496 let mut stack_size;
498 let stack_vmo_name;
499 if dynamic {
500 stack_size = calculate_initial_linker_stack_size(&mut self.msg_contents, 1)?;
504 stack_vmo_name = format!("stack: msg of {:#x?}", stack_size);
505 } else {
506 const ZIRCON_DEFAULT_STACK_SIZE: usize = 256 << 10; let mut ss = ("default", ZIRCON_DEFAULT_STACK_SIZE);
510 if let Some(stack_hdr) =
511 elf_headers.program_header_with_type(elf_parse::SegmentType::GnuStack)?
512 {
513 if stack_hdr.memsz > 0 {
514 ss = ("explicit", stack_hdr.memsz as usize);
515 }
516 }
517
518 stack_size = util::page_end(ss.1);
520 stack_vmo_name = format!("stack: {} {:#x?}", ss.0, stack_size);
521 }
522 if stack_size < self.min_stack_size {
523 stack_size = util::page_end(self.min_stack_size);
524 }
525
526 let stack_vmo_name =
528 zx::Name::new(&stack_vmo_name).expect("Stack VMO name must be less than 31 bytes");
529 let stack_info = self.create_stack(stack_size, &stack_vmo_name)?;
530
531 let msg = process_args::Message::build(self.msg_contents)?;
533 msg.write(&bootstrap_wr).map_err(ProcessBuilderError::WriteBootstrapMessage)?;
534
535 if let Some(mut r) = reserve_vmar {
538 r.destroy().map_err(ProcessBuilderError::DestroyReservationVMAR)?;
539 }
540
541 Ok(BuiltProcess {
542 process: self.common.process,
543 root_vmar: self.common.root_vmar,
544 thread: self.common.thread,
545 entry: loaded_elf.entry,
546 stack: stack_info.stack_ptr,
547 stack_base: stack_info.stack_base,
548 stack_vmo: stack_info.stack_vmo,
549 bootstrap: bootstrap_rd,
550 vdso_base: vdso_base,
551 elf_base: loaded_elf.vmar_base,
552 elf_headers,
553 })
554 }
555
556 fn build_linker_message(
565 &self,
566 ldsvc: fldsvc::LoaderProxy,
567 executable: zx::Vmo,
568 loaded_vmar: zx::Vmar,
569 ) -> Result<process_args::Message, ProcessBuilderError> {
570 let ldsvc_hnd =
573 ldsvc.into_channel().expect("Failed to get channel from LoaderProxy").into_zx_channel();
574
575 let args = extract_ld_arguments(&self.msg_contents.args);
577 let environment_vars =
578 extract_ld_environment_variables(&self.msg_contents.environment_vars);
579
580 let mut linker_msg_contents = process_args::MessageContents {
581 args,
584 environment_vars,
586 namespace_paths: vec![],
588 handles: vec![
591 process_args::StartupHandle {
592 handle: ldsvc_hnd.into_handle(),
593 info: HandleInfo::new(HandleType::LdsvcLoader, 0),
594 },
595 process_args::StartupHandle {
596 handle: executable.into_handle(),
597 info: HandleInfo::new(HandleType::ExecutableVmo, 0),
598 },
599 process_args::StartupHandle {
600 handle: loaded_vmar.into_handle(),
601 info: HandleInfo::new(HandleType::LoadedVmar, 0),
602 },
603 ],
604 };
605 self.common.add_process_self(&mut linker_msg_contents)?;
606 self.common.add_root_vmar(&mut linker_msg_contents)?;
607 Ok(process_args::Message::build(linker_msg_contents)?)
608 }
609
610 fn load_vdso(&mut self) -> Result<usize, ProcessBuilderError> {
615 let vdso = match self.non_default_vdso.take() {
616 Some(vmo) => vmo,
617 None => mem::replace(&mut self.system_vdso_vmo, zx::NullableHandle::invalid().into()),
618 };
619 let vdso_headers = elf_parse::Elf64Headers::from_vmo(&vdso)?;
620 let loaded_vdso = elf_load::load_elf(&vdso, &vdso_headers, &self.common.root_vmar)?;
621
622 self.msg_contents.handles.push(process_args::StartupHandle {
623 handle: vdso.into_handle(),
624 info: HandleInfo::new(HandleType::VdsoVmo, 0),
625 });
626
627 Ok(loaded_vdso.vmar_base)
628 }
629
630 fn create_stack(
637 &mut self,
638 stack_size: usize,
639 vmo_name: &zx::Name,
640 ) -> Result<StackInfo, ProcessBuilderError> {
641 let stack_vmo = zx::Vmo::create(stack_size as u64).map_err(|s| {
642 ProcessBuilderError::GenericStatus("Failed to create VMO for initial thread stack", s)
643 })?;
644 stack_vmo
645 .set_name(vmo_name)
646 .map_err(|s| ProcessBuilderError::GenericStatus("Failed to set stack VMO name", s))?;
647 let stack_flags = zx::VmarFlags::PERM_READ | zx::VmarFlags::PERM_WRITE;
648 let stack_base =
649 self.common.root_vmar.map(0, &stack_vmo, 0, stack_size, stack_flags).map_err(|s| {
650 ProcessBuilderError::GenericStatus("Failed to map initial stack", s)
651 })?;
652 let stack_ptr = compute_initial_stack_pointer(stack_base, stack_size);
653 let dup_stack_vmo = stack_vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).map_err(|s| {
654 ProcessBuilderError::GenericStatus("Failed to duplicate initial stack", s)
655 })?;
656
657 self.msg_contents.handles.push(process_args::StartupHandle {
662 handle: dup_stack_vmo.into_handle(),
663 info: HandleInfo::new(HandleType::StackVmo, 0),
664 });
665
666 Ok(StackInfo { stack_ptr, stack_base, stack_vmo })
667 }
668}
669
670pub fn calculate_initial_linker_stack_size(
682 msg_contents: &mut process_args::MessageContents,
683 extra_handles: usize,
684) -> Result<usize, ProcessBuilderError> {
685 msg_contents.handles.extend(
688 iter::repeat_with(|| process_args::StartupHandle {
689 handle: zx::NullableHandle::invalid(),
690 info: HandleInfo::new(HandleType::User0, 0),
691 })
692 .take(extra_handles),
693 );
694
695 let num_handles = msg_contents.handles.len();
698 let msg_stack_size = process_args::Message::calculate_size(msg_contents)?
699 + num_handles * mem::size_of::<zx::sys::zx_handle_t>();
700 msg_contents.handles.truncate(num_handles - extra_handles);
701
702 const PTHREAD_STACK_MIN: usize = 3072;
708 Ok(util::page_end(msg_stack_size + PTHREAD_STACK_MIN))
709}
710
711fn extract_ld_arguments(arguments: &[CString]) -> Vec<CString> {
713 let mut extracted = vec![];
714
715 if let Some(argument) = arguments.get(0) {
716 extracted.push(argument.clone())
717 }
718
719 extracted
720}
721
722fn extract_ld_environment_variables(envvars: &[CString]) -> Vec<CString> {
724 let prefixes = ["LD_DEBUG=", "LD_TRACE="];
725
726 let mut extracted = vec![];
727 for envvar in envvars {
728 for prefix in &prefixes {
729 let envvar_bytes: &[u8] = envvar.to_bytes();
730 let prefix_bytes: &[u8] = prefix.as_bytes();
731 if envvar_bytes.starts_with(prefix_bytes) {
732 extracted.push(envvar.clone());
733 continue;
734 }
735 }
736 }
737
738 extracted
739}
740
741impl CommonMessageHandles {
742 fn add_process_self(
743 &self,
744 msg: &mut process_args::MessageContents,
745 ) -> Result<(), ProcessBuilderError> {
746 Self::add_to_message(msg, self.process.as_handle_ref(), HandleType::ProcessSelf)
747 }
748
749 fn add_thread_self(
750 &self,
751 msg: &mut process_args::MessageContents,
752 ) -> Result<(), ProcessBuilderError> {
753 Self::add_to_message(msg, self.thread.as_handle_ref(), HandleType::ThreadSelf)
754 }
755
756 fn add_root_vmar(
757 &self,
758 msg: &mut process_args::MessageContents,
759 ) -> Result<(), ProcessBuilderError> {
760 Self::add_to_message(msg, self.root_vmar.as_handle_ref(), HandleType::RootVmar)
761 }
762
763 fn add_to_message(
765 msg: &mut process_args::MessageContents,
766 handle: zx::HandleRef<'_>,
767 handle_type: HandleType,
768 ) -> Result<(), ProcessBuilderError> {
769 let dup = handle
770 .duplicate_handle(zx::Rights::SAME_RIGHTS)
771 .map_err(|s| ProcessBuilderError::DuplicateHandle(handle_type, s))?;
772 msg.handles.push(process_args::StartupHandle {
773 handle: dup,
774 info: HandleInfo::new(handle_type, 0),
775 });
776 Ok(())
777 }
778}
779
780pub fn compute_initial_stack_pointer(base: usize, size: usize) -> usize {
787 let mut sp = base.checked_add(size).expect("Overflow in stack pointer calculation");
789
790 sp &= 16usize.wrapping_neg();
795
796 #[cfg(target_arch = "x86_64")]
799 {
800 sp -= 8;
801 }
802
803 #[cfg(not(any(
805 target_arch = "x86_64",
806 target_arch = "arm",
807 target_arch = "aarch64",
808 target_arch = "riscv64"
809 )))]
810 {
811 compile_error!("Unknown target_arch");
812 }
813
814 sp
815}
816
817pub async fn get_dynamic_linker<'a>(
820 ldsvc: &'a fldsvc::LoaderProxy,
821 executable: &'a zx::Vmo,
822 interp_hdr: &'a elf_parse::Elf64ProgramHeader,
823) -> Result<zx::Vmo, ProcessBuilderError> {
824 let mut interp = vec![0u8; interp_hdr.filesz as usize];
826 executable
827 .read(&mut interp[..], interp_hdr.offset as u64)
828 .map_err(|s| ProcessBuilderError::GenericStatus("Failed to read from VMO", s))?;
829 match interp.pop() {
831 Some(b'\0') => Ok(()),
832 _ => Err(ProcessBuilderError::InvalidInterpHeader(anyhow!("Missing null terminator"))),
833 }?;
834 let interp_str = std::str::from_utf8(&interp)
835 .context("Invalid UTF8")
836 .map_err(ProcessBuilderError::InvalidInterpHeader)?;
837
838 const LDSO_LOAD_TIMEOUT_SEC: i64 = 30;
840 let load_fut =
841 ldsvc.load_object(interp_str).map_err(ProcessBuilderError::LoadDynamicLinker).on_timeout(
842 fasync::MonotonicInstant::after(zx::MonotonicDuration::from_seconds(
843 LDSO_LOAD_TIMEOUT_SEC,
844 )),
845 || Err(ProcessBuilderError::LoadDynamicLinkerTimeout()),
846 );
847 let (status, ld_vmo) = load_fut.await?;
848 zx::Status::ok(status).map_err(|s| {
849 ProcessBuilderError::GenericStatus(
850 "Failed to load dynamic linker from fuchsia.ldsvc.Loader",
851 s,
852 )
853 })?;
854 Ok(ld_vmo.ok_or(ProcessBuilderError::GenericStatus(
855 "load_object status was OK but no VMO",
856 zx::Status::INTERNAL,
857 ))?)
858}
859
860impl BuiltProcess {
861 pub fn start(self) -> Result<zx::Process, ProcessBuilderError> {
868 self.process
869 .start(
870 &self.thread,
871 self.entry,
872 self.stack,
873 self.bootstrap.into_handle(),
874 self.vdso_base,
875 )
876 .map_err(ProcessBuilderError::ProcessStart)?;
877 Ok(self.process)
878 }
879}
880
881struct ReservationVmar(Option<zx::Vmar>);
882
883impl ReservationVmar {
884 fn reserve_low_address_space(vmar: &zx::Vmar) -> Result<ReservationVmar, ProcessBuilderError> {
889 let info = vmar
890 .info()
891 .map_err(|s| ProcessBuilderError::GenericStatus("Failed to get VMAR info", s))?;
892
893 if let Some(reserve_size) =
900 util::page_end((info.base + info.len) / 2).checked_sub(info.base)
901 {
902 let (reserve_vmar, reserve_base) =
903 vmar.allocate(0, reserve_size, zx::VmarFlags::SPECIFIC).map_err(|s| {
904 ProcessBuilderError::GenericStatus("Failed to allocate reservation VMAR", s)
905 })?;
906 assert_eq!(reserve_base, info.base, "Reservation VMAR allocated at wrong address");
907
908 Ok(ReservationVmar(Some(reserve_vmar)))
909 } else {
910 Ok(ReservationVmar(None))
913 }
914 }
915
916 fn destroy(&mut self) -> Result<(), zx::Status> {
922 match self.0.take() {
923 Some(vmar) => {
924 unsafe { vmar.destroy() }
927 }
928 None => Ok(()),
929 }
930 }
931}
932
933impl Drop for ReservationVmar {
938 fn drop(&mut self) {
939 _ = self.destroy();
940 }
941}
942
943#[cfg(test)]
944mod tests {
945 use super::*;
946 use anyhow::Error;
947 use assert_matches::assert_matches;
948 use fidl::prelude::*;
949 use fidl_fuchsia_io as fio;
950 use fidl_test_processbuilder::{UtilMarker, UtilProxy};
951 use fuchsia_async as fasync;
952 use std::sync::LazyLock;
953 use vfs::file::vmo::read_only;
954 use vfs::pseudo_directory;
955 use zerocopy::Ref;
956
957 unsafe extern "C" {
958 fn dl_clone_loader_service(handle: *mut zx::sys::zx_handle_t) -> zx::sys::zx_status_t;
959 }
960
961 fn get_system_vdso_vmo() -> Result<zx::Vmo, ProcessBuilderError> {
962 static VDSO_VMO: LazyLock<zx::Vmo> = LazyLock::new(|| {
963 zx::Vmo::from(
964 fuchsia_runtime::take_startup_handle(HandleInfo::new(HandleType::VdsoVmo, 0))
965 .expect("Failed to take VDSO VMO startup handle"),
966 )
967 });
968
969 let vdso_dup = VDSO_VMO
970 .duplicate_handle(zx::Rights::SAME_RIGHTS)
971 .map_err(|s| ProcessBuilderError::GenericStatus("Failed to dup vDSO VMO handle", s))?;
972 Ok(vdso_dup)
973 }
974
975 fn clone_loader_service() -> Result<ClientEnd<fldsvc::LoaderMarker>, zx::Status> {
977 let mut raw = 0;
978 let status = unsafe { dl_clone_loader_service(&mut raw) };
979 zx::Status::ok(status)?;
980
981 let handle = unsafe { zx::NullableHandle::from(zx::NullableHandle::from_raw(raw)) };
982 Ok(ClientEnd::new(zx::Channel::from(handle)))
983 }
984
985 fn connect_util(client: &zx::Channel) -> Result<UtilProxy, Error> {
986 let (proxy, server) = zx::Channel::create();
987 fdio::service_connect_at(&client, UtilMarker::PROTOCOL_NAME, server)
988 .context("failed to connect to util service")?;
989 Ok(UtilProxy::from_channel(fasync::Channel::from_channel(proxy)))
990 }
991
992 fn create_test_util_builder() -> Result<ProcessBuilder, Error> {
993 const TEST_UTIL_BIN: &'static str = "/pkg/bin/process_builder_test_util";
994 let file = fdio::open_fd(TEST_UTIL_BIN, fio::PERM_READABLE | fio::PERM_EXECUTABLE)?;
995 let vmo = fdio::get_vmo_exec_from_file(&file)?;
996 let job = fuchsia_runtime::job_default();
997
998 let procname = CString::new(TEST_UTIL_BIN.to_owned())?;
999 Ok(ProcessBuilder::new(
1000 &procname,
1001 &job,
1002 zx::ProcessOptions::empty(),
1003 vmo,
1004 get_system_vdso_vmo().unwrap(),
1005 )?)
1006 }
1007
1008 fn setup_test_util_builder(set_loader: bool) -> Result<(ProcessBuilder, UtilProxy), Error> {
1010 let mut builder = create_test_util_builder()?;
1011 if set_loader {
1012 builder.add_handles(vec![process_args::StartupHandle {
1013 handle: clone_loader_service()?.into_channel().into(),
1014 info: HandleInfo::new(HandleType::LdsvcLoader, 0),
1015 }])?;
1016 }
1017
1018 let (dir_client, dir_server) = zx::Channel::create();
1019 builder.add_handles(vec![process_args::StartupHandle {
1020 handle: dir_server.into_handle(),
1021 info: HandleInfo::new(HandleType::DirectoryRequest, 0),
1022 }])?;
1023
1024 let proxy = connect_util(&dir_client)?;
1025 Ok((builder, proxy))
1026 }
1027
1028 fn check_process_running(process: &zx::Process) -> Result<(), Error> {
1029 let info = process.info()?;
1030 const STARTED: zx::ProcessInfoFlags = zx::ProcessInfoFlags::STARTED;
1031 assert_matches!(
1032 info,
1033 zx::ProcessInfo {
1034 return_code: 0,
1035 start_time,
1036 flags: STARTED,
1037 ..
1038 } if start_time.into_nanos() > 0
1039 );
1040 Ok(())
1041 }
1042
1043 async fn check_process_exited_ok(process: &zx::Process) -> Result<(), Error> {
1044 fasync::OnSignals::new(process, zx::Signals::PROCESS_TERMINATED).await?;
1045
1046 let info = process.info()?;
1047 const STARTED_AND_EXITED: zx::ProcessInfoFlags =
1048 zx::ProcessInfoFlags::STARTED.union(zx::ProcessInfoFlags::EXITED);
1049 assert_matches!(
1050 info,
1051 zx::ProcessInfo {
1052 return_code: 0,
1053 start_time,
1054 flags: STARTED_AND_EXITED,
1055 ..
1056 } if start_time.into_nanos() > 0
1057 );
1058 Ok(())
1059 }
1060
1061 #[fasync::run_singlethreaded(test)]
1068 async fn start_util_with_args() -> Result<(), Error> {
1069 let test_args = vec!["arg0", "arg1", "arg2"];
1070 let test_args_cstr =
1071 test_args.iter().map(|&s| CString::new(s)).collect::<Result<_, _>>()?;
1072
1073 let (mut builder, proxy) = setup_test_util_builder(true)?;
1074 builder.add_arguments(test_args_cstr);
1075 let process = builder.build().await?.start()?;
1076 check_process_running(&process)?;
1077
1078 let proc_args = proxy.get_arguments().await.context("failed to get args from util")?;
1082 assert_eq!(proc_args, test_args);
1083
1084 mem::drop(proxy);
1085 check_process_exited_ok(&process).await?;
1086 Ok(())
1087 }
1088
1089 #[fasync::run_singlethreaded(test)]
1090 async fn start_util_with_huge_args() -> Result<(), Error> {
1091 let test_args = vec!["arg"; 10 * 1000];
1099 let test_args_cstr =
1100 test_args.iter().map(|&s| CString::new(s)).collect::<Result<_, _>>()?;
1101
1102 let (mut builder, proxy) = setup_test_util_builder(true)?;
1103 builder.add_arguments(test_args_cstr);
1104 let process = builder.build().await?.start()?;
1105 check_process_running(&process)?;
1106
1107 let proc_args =
1116 proxy.get_argument_count().await.context("failed to get arg count from util")?;
1117
1118 assert_eq!(proc_args, test_args.len() as u64);
1119
1120 mem::drop(proxy);
1121 check_process_exited_ok(&process).await?;
1122 Ok(())
1123 }
1124
1125 #[fasync::run_singlethreaded(test)]
1130 async fn start_util_with_lifecycle_channel() -> Result<(), Error> {
1131 let (mut builder, proxy) = setup_test_util_builder(true)?;
1132 let (lifecycle_server, _lifecycle_client) = zx::Channel::create();
1133 let koid = lifecycle_server
1134 .as_handle_ref()
1135 .basic_info()
1136 .expect("error getting server handle info")
1137 .koid
1138 .raw_koid();
1139 builder.add_handles(vec![process_args::StartupHandle {
1140 handle: lifecycle_server.into_handle(),
1141 info: HandleInfo::new(HandleType::Lifecycle, 0),
1142 }])?;
1143 let process = builder.build().await?.start()?;
1144 check_process_running(&process)?;
1145
1146 let reported_koid =
1149 proxy.get_lifecycle_koid().await.context("failed getting koid from util")?;
1150 assert_eq!(koid, reported_koid);
1151 mem::drop(proxy);
1152 check_process_exited_ok(&process).await?;
1153 Ok(())
1154 }
1155
1156 #[fasync::run_singlethreaded(test)]
1159 async fn start_util_with_no_lifecycle_channel() -> Result<(), Error> {
1160 let (builder, proxy) = setup_test_util_builder(true)?;
1161 let process = builder.build().await?.start()?;
1162 check_process_running(&process)?;
1163
1164 let reported_koid =
1167 proxy.get_lifecycle_koid().await.context("failed getting koid from util")?;
1168 assert_eq!(zx::sys::ZX_KOID_INVALID, reported_koid);
1169 mem::drop(proxy);
1170 check_process_exited_ok(&process).await?;
1171 Ok(())
1172 }
1173
1174 #[fasync::run_singlethreaded(test)]
1175 async fn start_util_with_big_stack() -> Result<(), Error> {
1176 let stack_size: usize = zx::system_get_page_size() as usize * 10;
1177
1178 let (mut builder, proxy) = setup_test_util_builder(true)?;
1179 builder.set_min_stack_size(stack_size);
1180 let built = builder.build().await?;
1181 assert!(built.stack_vmo.get_size()? >= stack_size as u64);
1182
1183 let process = built.start()?;
1184 check_process_running(&process)?;
1185 mem::drop(proxy);
1186 check_process_exited_ok(&process).await?;
1187 Ok(())
1188 }
1189
1190 #[fasync::run_singlethreaded(test)]
1191 async fn elf_headers() -> Result<(), Error> {
1192 let (builder, _) = setup_test_util_builder(true)?;
1193 let built = builder.build().await?;
1194 assert!(
1195 built.elf_headers.file_header().phnum
1196 == built.elf_headers.program_headers().len() as u16
1197 );
1198 Ok(())
1199 }
1200
1201 #[fasync::run_singlethreaded(test)]
1205 async fn set_loader_directly() -> Result<(), Error> {
1206 let test_args = vec!["arg0", "arg1", "arg2"];
1207 let test_args_cstr =
1208 test_args.iter().map(|&s| CString::new(s)).collect::<Result<_, _>>()?;
1209
1210 let (mut builder, proxy) = setup_test_util_builder(false)?;
1211 builder.set_loader_service(clone_loader_service()?)?;
1212 builder.add_arguments(test_args_cstr);
1213 let process = builder.build().await?.start()?;
1214 check_process_running(&process)?;
1215
1216 let proc_args = proxy.get_arguments().await.context("failed to get args from util")?;
1220 assert_eq!(proc_args, test_args);
1221
1222 mem::drop(proxy);
1223 check_process_exited_ok(&process).await?;
1224 Ok(())
1225 }
1226
1227 #[fasync::run_singlethreaded(test)]
1235 async fn set_vdso_directly() -> Result<(), Error> {
1236 let test_args = vec!["arg0", "arg1", "arg2"];
1237 let test_args_cstr =
1238 test_args.iter().map(|&s| CString::new(s)).collect::<Result<_, _>>()?;
1239
1240 let (mut builder, proxy) = setup_test_util_builder(true)?;
1241 builder.set_vdso_vmo(get_system_vdso_vmo()?);
1242 builder.add_arguments(test_args_cstr);
1243 let process = builder.build().await?.start()?;
1244 check_process_running(&process)?;
1245
1246 let proc_args = proxy.get_arguments().await.context("failed to get args from util")?;
1248 assert_eq!(proc_args, test_args);
1249
1250 mem::drop(proxy);
1251 check_process_exited_ok(&process).await?;
1252 Ok(())
1253 }
1254
1255 #[fasync::run_singlethreaded(test)]
1260 async fn set_invalid_vdso_directly_fails() -> Result<(), Error> {
1261 let bad_vdso = zx::Vmo::create(1)?;
1262
1263 let (mut builder, _) = setup_test_util_builder(true)?;
1264 builder.set_vdso_vmo(bad_vdso);
1265
1266 let result = builder.build().await;
1267 match result {
1268 Err(ProcessBuilderError::ElfParse(elf_parse::ElfParseError::InvalidFileHeader(_))) => {}
1269 Err(err) => {
1270 panic!("Unexpected error type: {}", err);
1271 }
1272 Ok(_) => {
1273 panic!("Unexpectedly succeeded to build process with invalid vDSO");
1274 }
1275 }
1276 Ok(())
1277 }
1278
1279 #[fasync::run_singlethreaded(test)]
1284 async fn set_invalid_vdso_fails() -> Result<(), Error> {
1285 let bad_vdso = zx::Vmo::create(1)?;
1286
1287 let (mut builder, _) = setup_test_util_builder(true)?;
1288 builder.add_handles(vec![process_args::StartupHandle {
1289 handle: bad_vdso.into_handle(),
1290 info: HandleInfo::new(HandleType::VdsoVmo, 0),
1291 }])?;
1292
1293 let result = builder.build().await;
1294 match result {
1295 Err(ProcessBuilderError::ElfParse(elf_parse::ElfParseError::InvalidFileHeader(_))) => {}
1296 Err(err) => {
1297 panic!("Unexpected error type: {}", err);
1298 }
1299 Ok(_) => {
1300 panic!("Unexpectedly succeeded to build process with invalid vDSO");
1301 }
1302 }
1303 Ok(())
1304 }
1305
1306 #[fasync::run_singlethreaded(test)]
1307 async fn add_additional_vdso() -> Result<(), Error> {
1308 let mut builder = create_test_util_builder()?;
1309 builder.set_loader_service(clone_loader_service()?)?;
1310 builder.add_handles(vec![process_args::StartupHandle {
1311 handle: get_system_vdso_vmo().unwrap().into_handle(),
1312 info: HandleInfo::new(HandleType::VdsoVmo, 1),
1313 }])?;
1314 let built = builder.build().await?;
1315
1316 let mut msg_buf = zx::MessageBuf::new();
1318 built.bootstrap.read(&mut msg_buf)?;
1319
1320 let mut msg_buf = zx::MessageBuf::new();
1322 built.bootstrap.read(&mut msg_buf)?;
1323 let handle_info = parse_handle_info_from_message(&msg_buf)?
1324 .drain(..)
1325 .filter(|info| info.handle_type() == HandleType::VdsoVmo)
1326 .collect::<Vec<_>>();
1327 assert_eq!(2, handle_info.len());
1328 for (i, info) in handle_info.iter().rev().enumerate() {
1329 assert_eq!(HandleType::VdsoVmo, info.handle_type());
1330 assert_eq!(i as u16, info.arg());
1331 }
1332 Ok(())
1333 }
1334
1335 #[fasync::run_singlethreaded(test)]
1336 async fn start_util_with_env() -> Result<(), Error> {
1337 let test_env = vec![("VAR1", "value2"), ("VAR2", "value2")];
1338 let test_env_cstr = test_env
1339 .iter()
1340 .map(|v| CString::new(format!("{}={}", v.0, v.1)))
1341 .collect::<Result<_, _>>()?;
1342
1343 let (mut builder, proxy) = setup_test_util_builder(true)?;
1344 builder.add_environment_variables(test_env_cstr);
1345 let process = builder.build().await?.start()?;
1346 check_process_running(&process)?;
1347
1348 let proc_env = proxy.get_environment().await.context("failed to get env from util")?;
1349 let proc_env_tuple: Vec<(&str, &str)> =
1350 proc_env.iter().map(|v| (&*v.key, &*v.value)).collect();
1351 assert_eq!(proc_env_tuple, test_env);
1352
1353 mem::drop(proxy);
1354 check_process_exited_ok(&process).await?;
1355 Ok(())
1356 }
1357
1358 #[fasync::run_singlethreaded(test)]
1359 async fn start_util_with_huge_env() -> Result<(), Error> {
1360 let test_env = vec!["a=b"; 10 * 1000];
1368 let test_env_cstr = test_env.iter().map(|&s| CString::new(s)).collect::<Result<_, _>>()?;
1369
1370 let (mut builder, proxy) = setup_test_util_builder(true)?;
1371 builder.add_environment_variables(test_env_cstr);
1372 let process = builder.build().await?.start()?;
1373 check_process_running(&process)?;
1374
1375 let proc_env =
1379 proxy.get_environment_count().await.context("failed to get env from util")?;
1380 assert_eq!(proc_env, test_env.len() as u64);
1381
1382 mem::drop(proxy);
1383 check_process_exited_ok(&process).await?;
1384 Ok(())
1385 }
1386
1387 #[fasync::run_singlethreaded(test)]
1388 async fn start_util_with_namespace_entries() -> Result<(), Error> {
1389 let mut randbuf = [0; 8];
1390 zx::cprng_draw(&mut randbuf);
1391 let test_content1 = format!("test content 1 {}", u64::from_le_bytes(randbuf));
1392 zx::cprng_draw(&mut randbuf);
1393 let test_content2 = format!("test content 2 {}", u64::from_le_bytes(randbuf));
1394
1395 let dir1 = pseudo_directory! {
1396 "test_file1" => read_only(test_content1.clone()),
1397 };
1398 let dir1_client = vfs::directory::serve_read_only(dir1).into_client_end().unwrap();
1399
1400 let dir2 = pseudo_directory! {
1401 "test_file2" => read_only(test_content2.clone()),
1402 };
1403 let dir2_client = vfs::directory::serve_read_only(dir2).into_client_end().unwrap();
1404
1405 let (mut builder, proxy) = setup_test_util_builder(true)?;
1406 builder.add_namespace_entries(vec![
1407 NamespaceEntry { path: CString::new("/dir1")?, directory: dir1_client },
1408 NamespaceEntry { path: CString::new("/dir2")?, directory: dir2_client },
1409 ])?;
1410 let process = builder.build().await?.start()?;
1411 check_process_running(&process)?;
1412
1413 let namespace_dump = proxy.dump_namespace().await.context("failed to dump namespace")?;
1414 assert_eq!(namespace_dump, "/dir1, /dir1/test_file1, /dir2, /dir2/test_file2");
1415
1416 let dir1_contents =
1417 proxy.read_file("/dir1/test_file1").await.context("failed to read file via util")?;
1418 assert_eq!(dir1_contents, test_content1);
1419 let dir2_contents =
1420 proxy.read_file("/dir2/test_file2").await.context("failed to read file via util")?;
1421 assert_eq!(dir2_contents, test_content2);
1422
1423 mem::drop(proxy);
1424 check_process_exited_ok(&process).await?;
1425 Ok(())
1426 }
1427
1428 #[fasync::run_singlethreaded(test)]
1431 async fn start_util_with_no_loader_fails() -> Result<(), Error> {
1432 let (builder, _) = setup_test_util_builder(false)?;
1433
1434 let result = builder.build().await;
1435 match result {
1436 Err(ProcessBuilderError::LoaderMissing()) => {}
1437 Err(err) => {
1438 panic!("Unexpected error type: {}", err);
1439 }
1440 Ok(_) => {
1441 panic!("Unexpectedly succeeded to build process without loader");
1442 }
1443 }
1444 Ok(())
1445 }
1446
1447 #[fasync::run_singlethreaded(test)]
1450 async fn verify_low_address_range_reserved() -> Result<(), Error> {
1451 let (builder, _) = setup_test_util_builder(true)?;
1452 let built = builder.build().await?;
1453
1454 let info = built.root_vmar.info()?;
1457 let lower_half_len = util::page_end((info.base + info.len) / 2) - info.base;
1458 built
1459 .root_vmar
1460 .allocate(0, lower_half_len, zx::VmarFlags::SPECIFIC)
1461 .context("Unable to allocate lower address range of new process")?;
1462 Ok(())
1463 }
1464
1465 fn parse_handle_info_from_message(message: &zx::MessageBuf) -> Result<Vec<HandleInfo>, Error> {
1468 let bytes = message.bytes();
1469 let (header, _) = Ref::<&[u8], process_args::MessageHeader>::from_prefix(bytes)
1470 .map_err(|_| anyhow!("Failed to parse process_args header"))?;
1471
1472 let offset = header.handle_info_off as usize;
1473 let len = mem::size_of::<u32>() * message.n_handles();
1474 let info_bytes = &bytes[offset..offset + len];
1475 let raw_info = Ref::<&[u8], [u32]>::from_bytes(info_bytes)
1476 .map_err(|_| anyhow!("Failed to parse raw handle info"))?;
1477
1478 Ok(raw_info.iter().map(|raw| HandleInfo::try_from(*raw)).collect::<Result<_, _>>()?)
1479 }
1480
1481 const LINKER_MESSAGE_HANDLES: &[HandleType] = &[
1482 HandleType::ProcessSelf,
1483 HandleType::RootVmar,
1484 HandleType::LdsvcLoader,
1485 HandleType::LoadedVmar,
1486 HandleType::ExecutableVmo,
1487 ];
1488
1489 const MAIN_MESSAGE_HANDLES: &[HandleType] = &[
1490 HandleType::ProcessSelf,
1491 HandleType::ThreadSelf,
1492 HandleType::RootVmar,
1493 HandleType::VdsoVmo,
1494 HandleType::StackVmo,
1495 ];
1496
1497 #[fasync::run_singlethreaded(test)]
1498 async fn correct_handles_present() -> Result<(), Error> {
1499 let mut builder = create_test_util_builder()?;
1500 builder.set_loader_service(clone_loader_service()?)?;
1501 let built = builder.build().await?;
1502
1503 for correct in &[LINKER_MESSAGE_HANDLES, MAIN_MESSAGE_HANDLES] {
1504 let mut msg_buf = zx::MessageBuf::new();
1505 built.bootstrap.read(&mut msg_buf)?;
1506 let handle_info = parse_handle_info_from_message(&msg_buf)?;
1507
1508 assert_eq!(handle_info.len(), correct.len());
1509 for correct_type in *correct {
1510 assert_eq!(
1512 1,
1513 handle_info.iter().filter(|info| &info.handle_type() == correct_type).count()
1514 );
1515 }
1516 }
1517 Ok(())
1518 }
1519
1520 #[fasync::run_singlethreaded(test)]
1523 async fn add_handles_rejects_automatic_handle_types() -> Result<(), Error> {
1524 let vmo = zx::Vmo::create(1)?;
1526 let job = fuchsia_runtime::job_default();
1527 let procname = CString::new("test_vmo")?;
1528 let mut builder = ProcessBuilder::new(
1529 &procname,
1530 &job,
1531 zx::ProcessOptions::empty(),
1532 vmo,
1533 get_system_vdso_vmo().unwrap(),
1534 )?;
1535
1536 for handle_type in LINKER_MESSAGE_HANDLES.iter().chain(MAIN_MESSAGE_HANDLES) {
1539 if *handle_type == HandleType::LdsvcLoader {
1540 continue;
1543 }
1544
1545 if *handle_type == HandleType::VdsoVmo {
1546 continue;
1548 }
1549
1550 let vmo = zx::Vmo::create(1)?;
1552 let result = builder.add_handles(vec![process_args::StartupHandle {
1553 handle: vmo.into_handle(),
1554 info: HandleInfo::new(*handle_type, 0),
1555 }]);
1556 match result {
1557 Err(ProcessBuilderError::InvalidArg(_)) => {}
1558 Err(err) => {
1559 panic!("Unexpected error type, should be invalid arg: {}", err);
1560 }
1561 Ok(_) => {
1562 panic!("add_handle unexpectedly succeeded for type {:?}", handle_type);
1563 }
1564 }
1565 }
1566 Ok(())
1567 }
1568
1569 #[fasync::run_singlethreaded(test)]
1571 async fn rejects_invalid_handles() -> Result<(), Error> {
1572 let invalid = || zx::NullableHandle::invalid();
1573 let assert_invalid_arg = |result| match result {
1574 Err(ProcessBuilderError::BadHandle(_)) => {}
1575 Err(err) => {
1576 panic!("Unexpected error type, should be BadHandle: {}", err);
1577 }
1578 Ok(_) => {
1579 panic!("API unexpectedly accepted invalid handle");
1580 }
1581 };
1582
1583 let vmo = zx::Vmo::create(1)?;
1585 let job = fuchsia_runtime::job_default();
1586 let procname = CString::new("test_vmo")?;
1587
1588 assert_invalid_arg(
1589 ProcessBuilder::new(
1590 &procname,
1591 &zx::NullableHandle::from(invalid()).into(),
1592 zx::ProcessOptions::empty(),
1593 vmo,
1594 get_system_vdso_vmo().unwrap(),
1595 )
1596 .map(|_| ()),
1597 );
1598 assert_invalid_arg(
1599 ProcessBuilder::new(
1600 &procname,
1601 &job,
1602 zx::ProcessOptions::empty(),
1603 zx::NullableHandle::from(invalid()).into(),
1604 get_system_vdso_vmo().unwrap(),
1605 )
1606 .map(|_| ()),
1607 );
1608
1609 let (mut builder, _) = setup_test_util_builder(true)?;
1610
1611 assert_invalid_arg(builder.set_loader_service(invalid().into()));
1612 assert_invalid_arg(builder.add_handles(vec![process_args::StartupHandle {
1613 handle: invalid().into(),
1614 info: HandleInfo::new(HandleType::User0, 0),
1615 }]));
1616 assert_invalid_arg(builder.add_handles(vec![process_args::StartupHandle {
1617 handle: invalid().into(),
1618 info: HandleInfo::new(HandleType::User0, 0),
1619 }]));
1620 assert_invalid_arg(builder.add_namespace_entries(vec![NamespaceEntry {
1621 path: CString::new("/dir")?,
1622 directory: invalid().into(),
1623 }]));
1624
1625 Ok(())
1626 }
1627
1628 #[fasync::run_singlethreaded]
1629 #[test]
1630 async fn start_static_pie_binary() -> Result<(), Error> {
1631 const TEST_BIN: &'static str = "/pkg/bin/static_pie_test_util";
1632 let file = fdio::open_fd(TEST_BIN, fio::PERM_READABLE | fio::PERM_EXECUTABLE)?;
1633 let vmo = fdio::get_vmo_exec_from_file(&file)?;
1634 let job = fuchsia_runtime::job_default();
1635
1636 let procname = CString::new(TEST_BIN.to_owned())?;
1637 let mut builder = ProcessBuilder::new(
1638 &procname,
1639 &job,
1640 zx::ProcessOptions::empty(),
1641 vmo,
1642 get_system_vdso_vmo().unwrap(),
1643 )?;
1644
1645 let (local, remote) = zx::Channel::create();
1648 builder.add_handles(vec![process_args::StartupHandle {
1649 handle: remote.into_handle(),
1650 info: HandleInfo::new(HandleType::User0, 0),
1651 }])?;
1652
1653 let mut randbuf = [0; 8];
1654 zx::cprng_draw(&mut randbuf);
1655 let test_message = format!("test content 1 {}", u64::from_le_bytes(randbuf)).into_bytes();
1656 local.write(&test_message, &mut vec![])?;
1657
1658 builder.build().await?.start()?;
1660 let signals = fasync::OnSignals::new(
1661 &local,
1662 zx::Signals::CHANNEL_READABLE | zx::Signals::CHANNEL_PEER_CLOSED,
1663 )
1664 .await?;
1665 assert!(signals.contains(zx::Signals::CHANNEL_READABLE));
1666
1667 let mut echoed = zx::MessageBuf::new();
1668 local.read(&mut echoed)?;
1669 assert_eq!(echoed.bytes(), test_message.as_slice());
1670 assert_eq!(echoed.n_handles(), 0);
1671 Ok(())
1672 }
1673}