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::directory::entry_container::Directory;
950 use vfs::execution_scope::ExecutionScope;
951 use vfs::file::vmo::read_only;
952 use vfs::{pseudo_directory, ToObjectRequest as _};
953 use zerocopy::Ref;
954 use {fidl_fuchsia_io as fio, fuchsia_async as fasync};
955
956 extern "C" {
957 fn dl_clone_loader_service(handle: *mut zx::sys::zx_handle_t) -> zx::sys::zx_status_t;
958 }
959
960 fn get_system_vdso_vmo() -> Result<zx::Vmo, ProcessBuilderError> {
961 lazy_static! {
962 static ref VDSO_VMO: zx::Vmo = {
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
970 let vdso_dup = VDSO_VMO
971 .duplicate_handle(zx::Rights::SAME_RIGHTS)
972 .map_err(|s| ProcessBuilderError::GenericStatus("Failed to dup vDSO VMO handle", s))?;
973 Ok(vdso_dup)
974 }
975
976 fn clone_loader_service() -> Result<ClientEnd<fldsvc::LoaderMarker>, zx::Status> {
978 let mut raw = 0;
979 let status = unsafe { dl_clone_loader_service(&mut raw) };
980 zx::Status::ok(status)?;
981
982 let handle = unsafe { zx::Handle::from_raw(raw) };
983 Ok(ClientEnd::new(zx::Channel::from(handle)))
984 }
985
986 fn connect_util(client: &zx::Channel) -> Result<UtilProxy, Error> {
987 let (proxy, server) = zx::Channel::create();
988 fdio::service_connect_at(&client, UtilMarker::PROTOCOL_NAME, server)
989 .context("failed to connect to util service")?;
990 Ok(UtilProxy::from_channel(fasync::Channel::from_channel(proxy)))
991 }
992
993 fn create_test_util_builder() -> Result<ProcessBuilder, Error> {
994 const TEST_UTIL_BIN: &'static str = "/pkg/bin/process_builder_test_util";
995 let file = fdio::open_fd(TEST_UTIL_BIN, fio::PERM_READABLE | fio::PERM_EXECUTABLE)?;
996 let vmo = fdio::get_vmo_exec_from_file(&file)?;
997 let job = fuchsia_runtime::job_default();
998
999 let procname = CString::new(TEST_UTIL_BIN.to_owned())?;
1000 Ok(ProcessBuilder::new(
1001 &procname,
1002 &job,
1003 zx::ProcessOptions::empty(),
1004 vmo,
1005 get_system_vdso_vmo().unwrap(),
1006 )?)
1007 }
1008
1009 fn setup_test_util_builder(set_loader: bool) -> Result<(ProcessBuilder, UtilProxy), Error> {
1011 let mut builder = create_test_util_builder()?;
1012 if set_loader {
1013 builder.add_handles(vec![process_args::StartupHandle {
1014 handle: clone_loader_service()?.into_handle(),
1015 info: HandleInfo::new(HandleType::LdsvcLoader, 0),
1016 }])?;
1017 }
1018
1019 let (dir_client, dir_server) = zx::Channel::create();
1020 builder.add_handles(vec![process_args::StartupHandle {
1021 handle: dir_server.into_handle(),
1022 info: HandleInfo::new(HandleType::DirectoryRequest, 0),
1023 }])?;
1024
1025 let proxy = connect_util(&dir_client)?;
1026 Ok((builder, proxy))
1027 }
1028
1029 fn check_process_running(process: &zx::Process) -> Result<(), Error> {
1030 let info = process.info()?;
1031 const STARTED: u32 = zx::ProcessInfoFlags::STARTED.bits();
1032 assert_matches!(
1033 info,
1034 zx::ProcessInfo {
1035 return_code: 0,
1036 start_time,
1037 flags: STARTED,
1038 } if start_time > 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: u32 =
1048 zx::ProcessInfoFlags::STARTED.bits() | zx::ProcessInfoFlags::EXITED.bits();
1049 assert_matches!(
1050 info,
1051 zx::ProcessInfo {
1052 return_code: 0,
1053 start_time,
1054 flags: STARTED_AND_EXITED,
1055 } if start_time > 0
1056 );
1057 Ok(())
1058 }
1059
1060 #[fasync::run_singlethreaded(test)]
1067 async fn start_util_with_args() -> Result<(), Error> {
1068 let test_args = vec!["arg0", "arg1", "arg2"];
1069 let test_args_cstr =
1070 test_args.iter().map(|&s| CString::new(s)).collect::<Result<_, _>>()?;
1071
1072 let (mut builder, proxy) = setup_test_util_builder(true)?;
1073 builder.add_arguments(test_args_cstr);
1074 let process = builder.build().await?.start()?;
1075 check_process_running(&process)?;
1076
1077 let proc_args = proxy.get_arguments().await.context("failed to get args from util")?;
1081 assert_eq!(proc_args, test_args);
1082
1083 mem::drop(proxy);
1084 check_process_exited_ok(&process).await?;
1085 Ok(())
1086 }
1087
1088 #[fasync::run_singlethreaded(test)]
1089 async fn start_util_with_huge_args() -> Result<(), Error> {
1090 let test_args = vec!["arg"; 10 * 1000];
1098 let test_args_cstr =
1099 test_args.iter().map(|&s| CString::new(s)).collect::<Result<_, _>>()?;
1100
1101 let (mut builder, proxy) = setup_test_util_builder(true)?;
1102 builder.add_arguments(test_args_cstr);
1103 let process = builder.build().await?.start()?;
1104 check_process_running(&process)?;
1105
1106 let proc_args =
1115 proxy.get_argument_count().await.context("failed to get arg count from util")?;
1116
1117 assert_eq!(proc_args, test_args.len() as u64);
1118
1119 mem::drop(proxy);
1120 check_process_exited_ok(&process).await?;
1121 Ok(())
1122 }
1123
1124 #[fasync::run_singlethreaded(test)]
1129 async fn start_util_with_lifecycle_channel() -> Result<(), Error> {
1130 let (mut builder, proxy) = setup_test_util_builder(true)?;
1131 let (lifecycle_server, _lifecycle_client) = zx::Channel::create();
1132 let koid = lifecycle_server
1133 .as_handle_ref()
1134 .basic_info()
1135 .expect("error getting server handle info")
1136 .koid
1137 .raw_koid();
1138 builder.add_handles(vec![process_args::StartupHandle {
1139 handle: lifecycle_server.into_handle(),
1140 info: HandleInfo::new(HandleType::Lifecycle, 0),
1141 }])?;
1142 let process = builder.build().await?.start()?;
1143 check_process_running(&process)?;
1144
1145 let reported_koid =
1148 proxy.get_lifecycle_koid().await.context("failed getting koid from util")?;
1149 assert_eq!(koid, reported_koid);
1150 mem::drop(proxy);
1151 check_process_exited_ok(&process).await?;
1152 Ok(())
1153 }
1154
1155 #[fasync::run_singlethreaded(test)]
1158 async fn start_util_with_no_lifecycle_channel() -> Result<(), Error> {
1159 let (builder, proxy) = setup_test_util_builder(true)?;
1160 let process = builder.build().await?.start()?;
1161 check_process_running(&process)?;
1162
1163 let reported_koid =
1166 proxy.get_lifecycle_koid().await.context("failed getting koid from util")?;
1167 assert_eq!(zx::sys::ZX_KOID_INVALID, reported_koid);
1168 mem::drop(proxy);
1169 check_process_exited_ok(&process).await?;
1170 Ok(())
1171 }
1172
1173 #[fasync::run_singlethreaded(test)]
1174 async fn start_util_with_big_stack() -> Result<(), Error> {
1175 let stack_size: usize = zx::system_get_page_size() as usize * 10;
1176
1177 let (mut builder, proxy) = setup_test_util_builder(true)?;
1178 builder.set_min_stack_size(stack_size);
1179 let built = builder.build().await?;
1180 assert!(built.stack_vmo.get_size()? >= stack_size as u64);
1181
1182 let process = built.start()?;
1183 check_process_running(&process)?;
1184 mem::drop(proxy);
1185 check_process_exited_ok(&process).await?;
1186 Ok(())
1187 }
1188
1189 #[fasync::run_singlethreaded(test)]
1190 async fn elf_headers() -> Result<(), Error> {
1191 let (builder, _) = setup_test_util_builder(true)?;
1192 let built = builder.build().await?;
1193 assert!(
1194 built.elf_headers.file_header().phnum
1195 == built.elf_headers.program_headers().len() as u16
1196 );
1197 Ok(())
1198 }
1199
1200 #[fasync::run_singlethreaded(test)]
1204 async fn set_loader_directly() -> Result<(), Error> {
1205 let test_args = vec!["arg0", "arg1", "arg2"];
1206 let test_args_cstr =
1207 test_args.iter().map(|&s| CString::new(s)).collect::<Result<_, _>>()?;
1208
1209 let (mut builder, proxy) = setup_test_util_builder(false)?;
1210 builder.set_loader_service(clone_loader_service()?)?;
1211 builder.add_arguments(test_args_cstr);
1212 let process = builder.build().await?.start()?;
1213 check_process_running(&process)?;
1214
1215 let proc_args = proxy.get_arguments().await.context("failed to get args from util")?;
1219 assert_eq!(proc_args, test_args);
1220
1221 mem::drop(proxy);
1222 check_process_exited_ok(&process).await?;
1223 Ok(())
1224 }
1225
1226 #[fasync::run_singlethreaded(test)]
1234 async fn set_vdso_directly() -> Result<(), Error> {
1235 let test_args = vec!["arg0", "arg1", "arg2"];
1236 let test_args_cstr =
1237 test_args.iter().map(|&s| CString::new(s)).collect::<Result<_, _>>()?;
1238
1239 let (mut builder, proxy) = setup_test_util_builder(true)?;
1240 builder.set_vdso_vmo(get_system_vdso_vmo()?);
1241 builder.add_arguments(test_args_cstr);
1242 let process = builder.build().await?.start()?;
1243 check_process_running(&process)?;
1244
1245 let proc_args = proxy.get_arguments().await.context("failed to get args from util")?;
1247 assert_eq!(proc_args, test_args);
1248
1249 mem::drop(proxy);
1250 check_process_exited_ok(&process).await?;
1251 Ok(())
1252 }
1253
1254 #[fasync::run_singlethreaded(test)]
1259 async fn set_invalid_vdso_directly_fails() -> Result<(), Error> {
1260 let bad_vdso = zx::Vmo::create(1)?;
1261
1262 let (mut builder, _) = setup_test_util_builder(true)?;
1263 builder.set_vdso_vmo(bad_vdso);
1264
1265 let result = builder.build().await;
1266 match result {
1267 Err(ProcessBuilderError::ElfParse(elf_parse::ElfParseError::InvalidFileHeader(_))) => {}
1268 Err(err) => {
1269 panic!("Unexpected error type: {}", err);
1270 }
1271 Ok(_) => {
1272 panic!("Unexpectedly succeeded to build process with invalid vDSO");
1273 }
1274 }
1275 Ok(())
1276 }
1277
1278 #[fasync::run_singlethreaded(test)]
1283 async fn set_invalid_vdso_fails() -> Result<(), Error> {
1284 let bad_vdso = zx::Vmo::create(1)?;
1285
1286 let (mut builder, _) = setup_test_util_builder(true)?;
1287 builder.add_handles(vec![process_args::StartupHandle {
1288 handle: bad_vdso.into_handle(),
1289 info: HandleInfo::new(HandleType::VdsoVmo, 0),
1290 }])?;
1291
1292 let result = builder.build().await;
1293 match result {
1294 Err(ProcessBuilderError::ElfParse(elf_parse::ElfParseError::InvalidFileHeader(_))) => {}
1295 Err(err) => {
1296 panic!("Unexpected error type: {}", err);
1297 }
1298 Ok(_) => {
1299 panic!("Unexpectedly succeeded to build process with invalid vDSO");
1300 }
1301 }
1302 Ok(())
1303 }
1304
1305 #[fasync::run_singlethreaded(test)]
1306 async fn add_additional_vdso() -> Result<(), Error> {
1307 let mut builder = create_test_util_builder()?;
1308 builder.set_loader_service(clone_loader_service()?)?;
1309 builder.add_handles(vec![process_args::StartupHandle {
1310 handle: get_system_vdso_vmo().unwrap().into_handle(),
1311 info: HandleInfo::new(HandleType::VdsoVmo, 1),
1312 }])?;
1313 let built = builder.build().await?;
1314
1315 let mut msg_buf = zx::MessageBuf::new();
1317 built.bootstrap.read(&mut msg_buf)?;
1318
1319 let mut msg_buf = zx::MessageBuf::new();
1321 built.bootstrap.read(&mut msg_buf)?;
1322 let handle_info = parse_handle_info_from_message(&msg_buf)?
1323 .drain(..)
1324 .filter(|info| info.handle_type() == HandleType::VdsoVmo)
1325 .collect::<Vec<_>>();
1326 assert_eq!(2, handle_info.len());
1327 for (i, info) in handle_info.iter().rev().enumerate() {
1328 assert_eq!(HandleType::VdsoVmo, info.handle_type());
1329 assert_eq!(i as u16, info.arg());
1330 }
1331 Ok(())
1332 }
1333
1334 #[fasync::run_singlethreaded(test)]
1335 async fn start_util_with_env() -> Result<(), Error> {
1336 let test_env = vec![("VAR1", "value2"), ("VAR2", "value2")];
1337 let test_env_cstr = test_env
1338 .iter()
1339 .map(|v| CString::new(format!("{}={}", v.0, v.1)))
1340 .collect::<Result<_, _>>()?;
1341
1342 let (mut builder, proxy) = setup_test_util_builder(true)?;
1343 builder.add_environment_variables(test_env_cstr);
1344 let process = builder.build().await?.start()?;
1345 check_process_running(&process)?;
1346
1347 let proc_env = proxy.get_environment().await.context("failed to get env from util")?;
1348 let proc_env_tuple: Vec<(&str, &str)> =
1349 proc_env.iter().map(|v| (&*v.key, &*v.value)).collect();
1350 assert_eq!(proc_env_tuple, test_env);
1351
1352 mem::drop(proxy);
1353 check_process_exited_ok(&process).await?;
1354 Ok(())
1355 }
1356
1357 #[fasync::run_singlethreaded(test)]
1358 async fn start_util_with_huge_env() -> Result<(), Error> {
1359 let test_env = vec!["a=b"; 10 * 1000];
1367 let test_env_cstr = test_env.iter().map(|&s| CString::new(s)).collect::<Result<_, _>>()?;
1368
1369 let (mut builder, proxy) = setup_test_util_builder(true)?;
1370 builder.add_environment_variables(test_env_cstr);
1371 let process = builder.build().await?.start()?;
1372 check_process_running(&process)?;
1373
1374 let proc_env =
1378 proxy.get_environment_count().await.context("failed to get env from util")?;
1379 assert_eq!(proc_env, test_env.len() as u64);
1380
1381 mem::drop(proxy);
1382 check_process_exited_ok(&process).await?;
1383 Ok(())
1384 }
1385
1386 #[fasync::run_singlethreaded(test)]
1387 async fn start_util_with_namespace_entries() -> Result<(), Error> {
1388 let mut randbuf = [0; 8];
1389 zx::cprng_draw(&mut randbuf);
1390 let test_content1 = format!("test content 1 {}", u64::from_le_bytes(randbuf));
1391 zx::cprng_draw(&mut randbuf);
1392 let test_content2 = format!("test content 2 {}", u64::from_le_bytes(randbuf));
1393
1394 let (dir1_server, dir1_client) = zx::Channel::create();
1395 let dir_scope = ExecutionScope::new();
1396 let dir1 = pseudo_directory! {
1397 "test_file1" => read_only(test_content1.clone()),
1398 };
1399 const FLAGS: fio::Flags = fio::PERM_READABLE;
1400 FLAGS
1401 .to_object_request(dir1_server)
1402 .handle(|request| dir1.open3(dir_scope.clone(), vfs::Path::dot(), FLAGS, request));
1403
1404 let (dir2_server, dir2_client) = zx::Channel::create();
1405 let dir2 = pseudo_directory! {
1406 "test_file2" => read_only(test_content2.clone()),
1407 };
1408 FLAGS
1409 .to_object_request(dir2_server)
1410 .handle(|request| dir2.open3(dir_scope.clone(), vfs::Path::dot(), FLAGS, request));
1411
1412 let (mut builder, proxy) = setup_test_util_builder(true)?;
1413 builder.add_namespace_entries(vec![
1414 NamespaceEntry { path: CString::new("/dir1")?, directory: ClientEnd::new(dir1_client) },
1415 NamespaceEntry { path: CString::new("/dir2")?, directory: ClientEnd::new(dir2_client) },
1416 ])?;
1417 let process = builder.build().await?.start()?;
1418 check_process_running(&process)?;
1419
1420 let namespace_dump = proxy.dump_namespace().await.context("failed to dump namespace")?;
1421 assert_eq!(namespace_dump, "/dir1, /dir1/test_file1, /dir2, /dir2/test_file2");
1422
1423 let dir1_contents =
1424 proxy.read_file("/dir1/test_file1").await.context("failed to read file via util")?;
1425 assert_eq!(dir1_contents, test_content1);
1426 let dir2_contents =
1427 proxy.read_file("/dir2/test_file2").await.context("failed to read file via util")?;
1428 assert_eq!(dir2_contents, test_content2);
1429
1430 mem::drop(proxy);
1431 check_process_exited_ok(&process).await?;
1432 Ok(())
1433 }
1434
1435 #[fasync::run_singlethreaded(test)]
1438 async fn start_util_with_no_loader_fails() -> Result<(), Error> {
1439 let (builder, _) = setup_test_util_builder(false)?;
1440
1441 let result = builder.build().await;
1442 match result {
1443 Err(ProcessBuilderError::LoaderMissing()) => {}
1444 Err(err) => {
1445 panic!("Unexpected error type: {}", err);
1446 }
1447 Ok(_) => {
1448 panic!("Unexpectedly succeeded to build process without loader");
1449 }
1450 }
1451 Ok(())
1452 }
1453
1454 #[fasync::run_singlethreaded(test)]
1457 async fn verify_low_address_range_reserved() -> Result<(), Error> {
1458 let (builder, _) = setup_test_util_builder(true)?;
1459 let built = builder.build().await?;
1460
1461 let info = built.root_vmar.info()?;
1464 let lower_half_len = util::page_end((info.base + info.len) / 2) - info.base;
1465 built
1466 .root_vmar
1467 .allocate(0, lower_half_len, zx::VmarFlags::SPECIFIC)
1468 .context("Unable to allocate lower address range of new process")?;
1469 Ok(())
1470 }
1471
1472 fn parse_handle_info_from_message(message: &zx::MessageBuf) -> Result<Vec<HandleInfo>, Error> {
1475 let bytes = message.bytes();
1476 let (header, _) = Ref::<&[u8], process_args::MessageHeader>::from_prefix(bytes)
1477 .map_err(|_| anyhow!("Failed to parse process_args header"))?;
1478
1479 let offset = header.handle_info_off as usize;
1480 let len = mem::size_of::<u32>() * message.n_handles();
1481 let info_bytes = &bytes[offset..offset + len];
1482 let raw_info = Ref::<&[u8], [u32]>::from_bytes(info_bytes)
1483 .map_err(|_| anyhow!("Failed to parse raw handle info"))?;
1484
1485 Ok(raw_info.iter().map(|raw| HandleInfo::try_from(*raw)).collect::<Result<_, _>>()?)
1486 }
1487
1488 const LINKER_MESSAGE_HANDLES: &[HandleType] = &[
1489 HandleType::ProcessSelf,
1490 HandleType::RootVmar,
1491 HandleType::LdsvcLoader,
1492 HandleType::LoadedVmar,
1493 HandleType::ExecutableVmo,
1494 ];
1495
1496 const MAIN_MESSAGE_HANDLES: &[HandleType] = &[
1497 HandleType::ProcessSelf,
1498 HandleType::ThreadSelf,
1499 HandleType::RootVmar,
1500 HandleType::VdsoVmo,
1501 HandleType::StackVmo,
1502 ];
1503
1504 #[fasync::run_singlethreaded(test)]
1505 async fn correct_handles_present() -> Result<(), Error> {
1506 let mut builder = create_test_util_builder()?;
1507 builder.set_loader_service(clone_loader_service()?)?;
1508 let built = builder.build().await?;
1509
1510 for correct in &[LINKER_MESSAGE_HANDLES, MAIN_MESSAGE_HANDLES] {
1511 let mut msg_buf = zx::MessageBuf::new();
1512 built.bootstrap.read(&mut msg_buf)?;
1513 let handle_info = parse_handle_info_from_message(&msg_buf)?;
1514
1515 assert_eq!(handle_info.len(), correct.len());
1516 for correct_type in *correct {
1517 assert_eq!(
1519 1,
1520 handle_info.iter().filter(|info| &info.handle_type() == correct_type).count()
1521 );
1522 }
1523 }
1524 Ok(())
1525 }
1526
1527 #[fasync::run_singlethreaded(test)]
1530 async fn add_handles_rejects_automatic_handle_types() -> Result<(), Error> {
1531 let vmo = zx::Vmo::create(1)?;
1533 let job = fuchsia_runtime::job_default();
1534 let procname = CString::new("test_vmo")?;
1535 let mut builder = ProcessBuilder::new(
1536 &procname,
1537 &job,
1538 zx::ProcessOptions::empty(),
1539 vmo,
1540 get_system_vdso_vmo().unwrap(),
1541 )?;
1542
1543 for handle_type in LINKER_MESSAGE_HANDLES.iter().chain(MAIN_MESSAGE_HANDLES) {
1546 if *handle_type == HandleType::LdsvcLoader {
1547 continue;
1550 }
1551
1552 if *handle_type == HandleType::VdsoVmo {
1553 continue;
1555 }
1556
1557 let vmo = zx::Vmo::create(1)?;
1559 let result = builder.add_handles(vec![process_args::StartupHandle {
1560 handle: vmo.into_handle(),
1561 info: HandleInfo::new(*handle_type, 0),
1562 }]);
1563 match result {
1564 Err(ProcessBuilderError::InvalidArg(_)) => {}
1565 Err(err) => {
1566 panic!("Unexpected error type, should be invalid arg: {}", err);
1567 }
1568 Ok(_) => {
1569 panic!("add_handle unexpectedly succeeded for type {:?}", handle_type);
1570 }
1571 }
1572 }
1573 Ok(())
1574 }
1575
1576 #[fasync::run_singlethreaded(test)]
1578 async fn rejects_invalid_handles() -> Result<(), Error> {
1579 let invalid = || zx::Handle::invalid();
1580 let assert_invalid_arg = |result| match result {
1581 Err(ProcessBuilderError::BadHandle(_)) => {}
1582 Err(err) => {
1583 panic!("Unexpected error type, should be BadHandle: {}", err);
1584 }
1585 Ok(_) => {
1586 panic!("API unexpectedly accepted invalid handle");
1587 }
1588 };
1589
1590 let vmo = zx::Vmo::create(1)?;
1592 let job = fuchsia_runtime::job_default();
1593 let procname = CString::new("test_vmo")?;
1594
1595 assert_invalid_arg(
1596 ProcessBuilder::new(
1597 &procname,
1598 &invalid().into(),
1599 zx::ProcessOptions::empty(),
1600 vmo,
1601 get_system_vdso_vmo().unwrap(),
1602 )
1603 .map(|_| ()),
1604 );
1605 assert_invalid_arg(
1606 ProcessBuilder::new(
1607 &procname,
1608 &job,
1609 zx::ProcessOptions::empty(),
1610 invalid().into(),
1611 get_system_vdso_vmo().unwrap(),
1612 )
1613 .map(|_| ()),
1614 );
1615
1616 let (mut builder, _) = setup_test_util_builder(true)?;
1617
1618 assert_invalid_arg(builder.set_loader_service(invalid().into()));
1619 assert_invalid_arg(builder.add_handles(vec![process_args::StartupHandle {
1620 handle: invalid().into(),
1621 info: HandleInfo::new(HandleType::User0, 0),
1622 }]));
1623 assert_invalid_arg(builder.add_handles(vec![process_args::StartupHandle {
1624 handle: invalid().into(),
1625 info: HandleInfo::new(HandleType::User0, 0),
1626 }]));
1627 assert_invalid_arg(builder.add_namespace_entries(vec![NamespaceEntry {
1628 path: CString::new("/dir")?,
1629 directory: invalid().into(),
1630 }]));
1631
1632 Ok(())
1633 }
1634
1635 #[fasync::run_singlethreaded]
1636 #[test]
1637 async fn start_static_pie_binary() -> Result<(), Error> {
1638 const TEST_BIN: &'static str = "/pkg/bin/static_pie_test_util";
1639 let file = fdio::open_fd(TEST_BIN, fio::PERM_READABLE | fio::PERM_EXECUTABLE)?;
1640 let vmo = fdio::get_vmo_exec_from_file(&file)?;
1641 let job = fuchsia_runtime::job_default();
1642
1643 let procname = CString::new(TEST_BIN.to_owned())?;
1644 let mut builder = ProcessBuilder::new(
1645 &procname,
1646 &job,
1647 zx::ProcessOptions::empty(),
1648 vmo,
1649 get_system_vdso_vmo().unwrap(),
1650 )?;
1651
1652 let (local, remote) = zx::Channel::create();
1655 builder.add_handles(vec![process_args::StartupHandle {
1656 handle: remote.into_handle(),
1657 info: HandleInfo::new(HandleType::User0, 0),
1658 }])?;
1659
1660 let mut randbuf = [0; 8];
1661 zx::cprng_draw(&mut randbuf);
1662 let test_message = format!("test content 1 {}", u64::from_le_bytes(randbuf)).into_bytes();
1663 local.write(&test_message, &mut vec![])?;
1664
1665 builder.build().await?.start()?;
1667 let signals = fasync::OnSignals::new(
1668 &local,
1669 zx::Signals::CHANNEL_READABLE | zx::Signals::CHANNEL_PEER_CLOSED,
1670 )
1671 .await?;
1672 assert!(signals.contains(zx::Signals::CHANNEL_READABLE));
1673
1674 let mut echoed = zx::MessageBuf::new();
1675 local.read(&mut echoed)?;
1676 assert_eq!(echoed.bytes(), test_message.as_slice());
1677 assert_eq!(echoed.n_handles(), 0);
1678 Ok(())
1679 }
1680}