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