1use crate::{elf_load, elf_parse, process_args, util};
6use anyhow::{Context, anyhow};
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: entry.directory.into(),
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 =
476 mem::replace(&mut self.executable, zx::NullableHandle::invalid().into());
477 let msg = self.build_linker_message(ldsvc, executable, loaded_elf.vmar)?;
478 msg.write(&bootstrap_wr).map_err(ProcessBuilderError::WriteBootstrapMessage)?;
479 } else {
480 dynamic = false;
482
483 loaded_elf =
484 elf_load::load_elf(&self.executable, &elf_headers, &self.common.root_vmar)?;
485 self.msg_contents.handles.push(process_args::StartupHandle {
486 handle: loaded_elf.vmar.into_handle(),
487 info: HandleInfo::new(HandleType::LoadedVmar, 0),
488 });
489 }
490
491 let vdso_base = self.load_vdso()?;
494
495 let mut stack_size;
497 let stack_vmo_name;
498 if dynamic {
499 stack_size = calculate_initial_linker_stack_size(&mut self.msg_contents, 1)?;
503 stack_vmo_name = format!("stack: msg of {:#x?}", stack_size);
504 } else {
505 const ZIRCON_DEFAULT_STACK_SIZE: usize = 256 << 10; let mut ss = ("default", ZIRCON_DEFAULT_STACK_SIZE);
509 if let Some(stack_hdr) =
510 elf_headers.program_header_with_type(elf_parse::SegmentType::GnuStack)?
511 {
512 if stack_hdr.memsz > 0 {
513 ss = ("explicit", stack_hdr.memsz as usize);
514 }
515 }
516
517 stack_size = util::page_end(ss.1);
519 stack_vmo_name = format!("stack: {} {:#x?}", ss.0, stack_size);
520 }
521 if stack_size < self.min_stack_size {
522 stack_size = util::page_end(self.min_stack_size);
523 }
524
525 let stack_vmo_name =
527 zx::Name::new(&stack_vmo_name).expect("Stack VMO name must be less than 31 bytes");
528 let stack_info = self.create_stack(stack_size, &stack_vmo_name)?;
529
530 let msg = process_args::Message::build(self.msg_contents)?;
532 msg.write(&bootstrap_wr).map_err(ProcessBuilderError::WriteBootstrapMessage)?;
533
534 if let Some(mut r) = reserve_vmar {
537 r.destroy().map_err(ProcessBuilderError::DestroyReservationVMAR)?;
538 }
539
540 Ok(BuiltProcess {
541 process: self.common.process,
542 root_vmar: self.common.root_vmar,
543 thread: self.common.thread,
544 entry: loaded_elf.entry,
545 stack: stack_info.stack_ptr,
546 stack_base: stack_info.stack_base,
547 stack_vmo: stack_info.stack_vmo,
548 bootstrap: bootstrap_rd,
549 vdso_base: vdso_base,
550 elf_base: loaded_elf.vmar_base,
551 elf_headers,
552 })
553 }
554
555 fn build_linker_message(
564 &self,
565 ldsvc: fldsvc::LoaderProxy,
566 executable: zx::Vmo,
567 loaded_vmar: zx::Vmar,
568 ) -> Result<process_args::Message, ProcessBuilderError> {
569 let ldsvc_hnd =
572 ldsvc.into_channel().expect("Failed to get channel from LoaderProxy").into_zx_channel();
573
574 let args = extract_ld_arguments(&self.msg_contents.args);
576 let environment_vars =
577 extract_ld_environment_variables(&self.msg_contents.environment_vars);
578
579 let mut linker_msg_contents = process_args::MessageContents {
580 args,
583 environment_vars,
585 namespace_paths: vec![],
587 handles: vec![
590 process_args::StartupHandle {
591 handle: ldsvc_hnd.into_handle(),
592 info: HandleInfo::new(HandleType::LdsvcLoader, 0),
593 },
594 process_args::StartupHandle {
595 handle: executable.into_handle(),
596 info: HandleInfo::new(HandleType::ExecutableVmo, 0),
597 },
598 process_args::StartupHandle {
599 handle: loaded_vmar.into_handle(),
600 info: HandleInfo::new(HandleType::LoadedVmar, 0),
601 },
602 ],
603 };
604 self.common.add_process_self(&mut linker_msg_contents)?;
605 self.common.add_root_vmar(&mut linker_msg_contents)?;
606 Ok(process_args::Message::build(linker_msg_contents)?)
607 }
608
609 fn load_vdso(&mut self) -> Result<usize, ProcessBuilderError> {
614 let vdso = match self.non_default_vdso.take() {
615 Some(vmo) => vmo,
616 None => mem::replace(&mut self.system_vdso_vmo, zx::NullableHandle::invalid().into()),
617 };
618 let vdso_headers = elf_parse::Elf64Headers::from_vmo(&vdso)?;
619 let loaded_vdso = elf_load::load_elf(&vdso, &vdso_headers, &self.common.root_vmar)?;
620
621 self.msg_contents.handles.push(process_args::StartupHandle {
622 handle: vdso.into_handle(),
623 info: HandleInfo::new(HandleType::VdsoVmo, 0),
624 });
625
626 Ok(loaded_vdso.vmar_base)
627 }
628
629 fn create_stack(
636 &mut self,
637 stack_size: usize,
638 vmo_name: &zx::Name,
639 ) -> Result<StackInfo, ProcessBuilderError> {
640 let stack_vmo = zx::Vmo::create(stack_size as u64).map_err(|s| {
641 ProcessBuilderError::GenericStatus("Failed to create VMO for initial thread stack", s)
642 })?;
643 stack_vmo
644 .set_name(vmo_name)
645 .map_err(|s| ProcessBuilderError::GenericStatus("Failed to set stack VMO name", s))?;
646 let stack_flags = zx::VmarFlags::PERM_READ | zx::VmarFlags::PERM_WRITE;
647 let stack_base =
648 self.common.root_vmar.map(0, &stack_vmo, 0, stack_size, stack_flags).map_err(|s| {
649 ProcessBuilderError::GenericStatus("Failed to map initial stack", s)
650 })?;
651 let stack_ptr = compute_initial_stack_pointer(stack_base, stack_size);
652 let dup_stack_vmo = stack_vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).map_err(|s| {
653 ProcessBuilderError::GenericStatus("Failed to duplicate initial stack", s)
654 })?;
655
656 self.msg_contents.handles.push(process_args::StartupHandle {
661 handle: dup_stack_vmo.into_handle(),
662 info: HandleInfo::new(HandleType::StackVmo, 0),
663 });
664
665 Ok(StackInfo { stack_ptr, stack_base, stack_vmo })
666 }
667}
668
669pub fn calculate_initial_linker_stack_size(
681 msg_contents: &mut process_args::MessageContents,
682 extra_handles: usize,
683) -> Result<usize, ProcessBuilderError> {
684 msg_contents.handles.extend(
687 iter::repeat_with(|| process_args::StartupHandle {
688 handle: zx::NullableHandle::invalid(),
689 info: HandleInfo::new(HandleType::User0, 0),
690 })
691 .take(extra_handles),
692 );
693
694 let num_handles = msg_contents.handles.len();
697 let msg_stack_size = process_args::Message::calculate_size(msg_contents)?
698 + num_handles * mem::size_of::<zx::sys::zx_handle_t>();
699 msg_contents.handles.truncate(num_handles - extra_handles);
700
701 const PTHREAD_STACK_MIN: usize = 3072;
707 Ok(util::page_end(msg_stack_size + PTHREAD_STACK_MIN))
708}
709
710fn extract_ld_arguments(arguments: &[CString]) -> Vec<CString> {
712 let mut extracted = vec![];
713
714 if let Some(argument) = arguments.get(0) {
715 extracted.push(argument.clone())
716 }
717
718 extracted
719}
720
721fn extract_ld_environment_variables(envvars: &[CString]) -> Vec<CString> {
723 let prefixes = ["LD_DEBUG=", "LD_TRACE="];
724
725 let mut extracted = vec![];
726 for envvar in envvars {
727 for prefix in &prefixes {
728 let envvar_bytes: &[u8] = envvar.to_bytes();
729 let prefix_bytes: &[u8] = prefix.as_bytes();
730 if envvar_bytes.starts_with(prefix_bytes) {
731 extracted.push(envvar.clone());
732 continue;
733 }
734 }
735 }
736
737 extracted
738}
739
740impl CommonMessageHandles {
741 fn add_process_self(
742 &self,
743 msg: &mut process_args::MessageContents,
744 ) -> Result<(), ProcessBuilderError> {
745 Self::add_to_message(msg, self.process.as_handle_ref(), HandleType::ProcessSelf)
746 }
747
748 fn add_thread_self(
749 &self,
750 msg: &mut process_args::MessageContents,
751 ) -> Result<(), ProcessBuilderError> {
752 Self::add_to_message(msg, self.thread.as_handle_ref(), HandleType::ThreadSelf)
753 }
754
755 fn add_root_vmar(
756 &self,
757 msg: &mut process_args::MessageContents,
758 ) -> Result<(), ProcessBuilderError> {
759 Self::add_to_message(msg, self.root_vmar.as_handle_ref(), HandleType::RootVmar)
760 }
761
762 fn add_to_message(
764 msg: &mut process_args::MessageContents,
765 handle: zx::HandleRef<'_>,
766 handle_type: HandleType,
767 ) -> Result<(), ProcessBuilderError> {
768 let dup = handle
769 .duplicate(zx::Rights::SAME_RIGHTS)
770 .map_err(|s| ProcessBuilderError::DuplicateHandle(handle_type, s))?;
771 msg.handles.push(process_args::StartupHandle {
772 handle: dup,
773 info: HandleInfo::new(handle_type, 0),
774 });
775 Ok(())
776 }
777}
778
779pub fn compute_initial_stack_pointer(base: usize, size: usize) -> usize {
786 let mut sp = base.checked_add(size).expect("Overflow in stack pointer calculation");
788
789 sp &= 16usize.wrapping_neg();
794
795 #[cfg(target_arch = "x86_64")]
798 {
799 sp -= 8;
800 }
801
802 #[cfg(not(any(
804 target_arch = "x86_64",
805 target_arch = "arm",
806 target_arch = "aarch64",
807 target_arch = "riscv64"
808 )))]
809 {
810 compile_error!("Unknown target_arch");
811 }
812
813 sp
814}
815
816pub async fn get_dynamic_linker<'a>(
819 ldsvc: &'a fldsvc::LoaderProxy,
820 executable: &'a zx::Vmo,
821 interp_hdr: &'a elf_parse::Elf64ProgramHeader,
822) -> Result<zx::Vmo, ProcessBuilderError> {
823 let mut interp = vec![0u8; interp_hdr.filesz as usize];
825 executable
826 .read(&mut interp[..], interp_hdr.offset as u64)
827 .map_err(|s| ProcessBuilderError::GenericStatus("Failed to read from VMO", s))?;
828 match interp.pop() {
830 Some(b'\0') => Ok(()),
831 _ => Err(ProcessBuilderError::InvalidInterpHeader(anyhow!("Missing null terminator"))),
832 }?;
833 let interp_str = std::str::from_utf8(&interp)
834 .context("Invalid UTF8")
835 .map_err(ProcessBuilderError::InvalidInterpHeader)?;
836
837 const LDSO_LOAD_TIMEOUT_SEC: i64 = 30;
839 let load_fut =
840 ldsvc.load_object(interp_str).map_err(ProcessBuilderError::LoadDynamicLinker).on_timeout(
841 fasync::MonotonicInstant::after(zx::MonotonicDuration::from_seconds(
842 LDSO_LOAD_TIMEOUT_SEC,
843 )),
844 || Err(ProcessBuilderError::LoadDynamicLinkerTimeout()),
845 );
846 let (status, ld_vmo) = load_fut.await?;
847 zx::Status::ok(status).map_err(|s| {
848 ProcessBuilderError::GenericStatus(
849 "Failed to load dynamic linker from fuchsia.ldsvc.Loader",
850 s,
851 )
852 })?;
853 Ok(ld_vmo.ok_or(ProcessBuilderError::GenericStatus(
854 "load_object status was OK but no VMO",
855 zx::Status::INTERNAL,
856 ))?)
857}
858
859impl BuiltProcess {
860 pub fn start(self) -> Result<zx::Process, ProcessBuilderError> {
867 self.process
868 .start(
869 &self.thread,
870 self.entry,
871 self.stack,
872 self.bootstrap.into_handle(),
873 self.vdso_base,
874 )
875 .map_err(ProcessBuilderError::ProcessStart)?;
876 Ok(self.process)
877 }
878}
879
880struct ReservationVmar(Option<zx::Vmar>);
881
882impl ReservationVmar {
883 fn reserve_low_address_space(vmar: &zx::Vmar) -> Result<ReservationVmar, ProcessBuilderError> {
888 let info = vmar
889 .info()
890 .map_err(|s| ProcessBuilderError::GenericStatus("Failed to get VMAR info", s))?;
891
892 if let Some(reserve_size) =
899 util::page_end((info.base + info.len) / 2).checked_sub(info.base)
900 {
901 let (reserve_vmar, reserve_base) =
902 vmar.allocate(0, reserve_size, zx::VmarFlags::SPECIFIC).map_err(|s| {
903 ProcessBuilderError::GenericStatus("Failed to allocate reservation VMAR", s)
904 })?;
905 assert_eq!(reserve_base, info.base, "Reservation VMAR allocated at wrong address");
906
907 Ok(ReservationVmar(Some(reserve_vmar)))
908 } else {
909 Ok(ReservationVmar(None))
912 }
913 }
914
915 fn destroy(&mut self) -> Result<(), zx::Status> {
921 match self.0.take() {
922 Some(vmar) => {
923 unsafe { vmar.destroy() }
926 }
927 None => Ok(()),
928 }
929 }
930}
931
932impl Drop for ReservationVmar {
937 fn drop(&mut self) {
938 _ = self.destroy();
939 }
940}
941
942#[cfg(test)]
943mod tests {
944 use super::*;
945 use anyhow::Error;
946 use assert_matches::assert_matches;
947 use fidl::prelude::*;
948 use fidl_test_processbuilder::{UtilMarker, UtilProxy};
949 use std::sync::LazyLock;
950 use vfs::file::vmo::read_only;
951 use vfs::pseudo_directory;
952 use zerocopy::Ref;
953 use {fidl_fuchsia_io as fio, fuchsia_async as fasync};
954
955 unsafe extern "C" {
956 fn dl_clone_loader_service(handle: *mut zx::sys::zx_handle_t) -> zx::sys::zx_status_t;
957 }
958
959 fn get_system_vdso_vmo() -> Result<zx::Vmo, ProcessBuilderError> {
960 static VDSO_VMO: LazyLock<zx::Vmo> = LazyLock::new(|| {
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 let vdso_dup = VDSO_VMO
968 .duplicate_handle(zx::Rights::SAME_RIGHTS)
969 .map_err(|s| ProcessBuilderError::GenericStatus("Failed to dup vDSO VMO handle", s))?;
970 Ok(vdso_dup)
971 }
972
973 fn clone_loader_service() -> Result<ClientEnd<fldsvc::LoaderMarker>, zx::Status> {
975 let mut raw = 0;
976 let status = unsafe { dl_clone_loader_service(&mut raw) };
977 zx::Status::ok(status)?;
978
979 let handle = unsafe { zx::NullableHandle::from(zx::NullableHandle::from_raw(raw)) };
980 Ok(ClientEnd::new(zx::Channel::from(handle)))
981 }
982
983 fn connect_util(client: &zx::Channel) -> Result<UtilProxy, Error> {
984 let (proxy, server) = zx::Channel::create();
985 fdio::service_connect_at(&client, UtilMarker::PROTOCOL_NAME, server)
986 .context("failed to connect to util service")?;
987 Ok(UtilProxy::from_channel(fasync::Channel::from_channel(proxy)))
988 }
989
990 fn create_test_util_builder() -> Result<ProcessBuilder, Error> {
991 const TEST_UTIL_BIN: &'static str = "/pkg/bin/process_builder_test_util";
992 let file = fdio::open_fd(TEST_UTIL_BIN, fio::PERM_READABLE | fio::PERM_EXECUTABLE)?;
993 let vmo = fdio::get_vmo_exec_from_file(&file)?;
994 let job = fuchsia_runtime::job_default();
995
996 let procname = CString::new(TEST_UTIL_BIN.to_owned())?;
997 Ok(ProcessBuilder::new(
998 &procname,
999 &job,
1000 zx::ProcessOptions::empty(),
1001 vmo,
1002 get_system_vdso_vmo().unwrap(),
1003 )?)
1004 }
1005
1006 fn setup_test_util_builder(set_loader: bool) -> Result<(ProcessBuilder, UtilProxy), Error> {
1008 let mut builder = create_test_util_builder()?;
1009 if set_loader {
1010 builder.add_handles(vec![process_args::StartupHandle {
1011 handle: clone_loader_service()?.into_handle(),
1012 info: HandleInfo::new(HandleType::LdsvcLoader, 0),
1013 }])?;
1014 }
1015
1016 let (dir_client, dir_server) = zx::Channel::create();
1017 builder.add_handles(vec![process_args::StartupHandle {
1018 handle: dir_server.into_handle(),
1019 info: HandleInfo::new(HandleType::DirectoryRequest, 0),
1020 }])?;
1021
1022 let proxy = connect_util(&dir_client)?;
1023 Ok((builder, proxy))
1024 }
1025
1026 fn check_process_running(process: &zx::Process) -> Result<(), Error> {
1027 let info = process.info()?;
1028 const STARTED: zx::ProcessInfoFlags = zx::ProcessInfoFlags::STARTED;
1029 assert_matches!(
1030 info,
1031 zx::ProcessInfo {
1032 return_code: 0,
1033 start_time,
1034 flags: STARTED,
1035 ..
1036 } if start_time.into_nanos() > 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: zx::ProcessInfoFlags =
1046 zx::ProcessInfoFlags::STARTED.union(zx::ProcessInfoFlags::EXITED);
1047 assert_matches!(
1048 info,
1049 zx::ProcessInfo {
1050 return_code: 0,
1051 start_time,
1052 flags: STARTED_AND_EXITED,
1053 ..
1054 } if start_time.into_nanos() > 0
1055 );
1056 Ok(())
1057 }
1058
1059 #[fasync::run_singlethreaded(test)]
1066 async fn start_util_with_args() -> Result<(), Error> {
1067 let test_args = vec!["arg0", "arg1", "arg2"];
1068 let test_args_cstr =
1069 test_args.iter().map(|&s| CString::new(s)).collect::<Result<_, _>>()?;
1070
1071 let (mut builder, proxy) = setup_test_util_builder(true)?;
1072 builder.add_arguments(test_args_cstr);
1073 let process = builder.build().await?.start()?;
1074 check_process_running(&process)?;
1075
1076 let proc_args = proxy.get_arguments().await.context("failed to get args from util")?;
1080 assert_eq!(proc_args, test_args);
1081
1082 mem::drop(proxy);
1083 check_process_exited_ok(&process).await?;
1084 Ok(())
1085 }
1086
1087 #[fasync::run_singlethreaded(test)]
1088 async fn start_util_with_huge_args() -> Result<(), Error> {
1089 let test_args = vec!["arg"; 10 * 1000];
1097 let test_args_cstr =
1098 test_args.iter().map(|&s| CString::new(s)).collect::<Result<_, _>>()?;
1099
1100 let (mut builder, proxy) = setup_test_util_builder(true)?;
1101 builder.add_arguments(test_args_cstr);
1102 let process = builder.build().await?.start()?;
1103 check_process_running(&process)?;
1104
1105 let proc_args =
1114 proxy.get_argument_count().await.context("failed to get arg count from util")?;
1115
1116 assert_eq!(proc_args, test_args.len() as u64);
1117
1118 mem::drop(proxy);
1119 check_process_exited_ok(&process).await?;
1120 Ok(())
1121 }
1122
1123 #[fasync::run_singlethreaded(test)]
1128 async fn start_util_with_lifecycle_channel() -> Result<(), Error> {
1129 let (mut builder, proxy) = setup_test_util_builder(true)?;
1130 let (lifecycle_server, _lifecycle_client) = zx::Channel::create();
1131 let koid = lifecycle_server
1132 .as_handle_ref()
1133 .basic_info()
1134 .expect("error getting server handle info")
1135 .koid
1136 .raw_koid();
1137 builder.add_handles(vec![process_args::StartupHandle {
1138 handle: lifecycle_server.into_handle(),
1139 info: HandleInfo::new(HandleType::Lifecycle, 0),
1140 }])?;
1141 let process = builder.build().await?.start()?;
1142 check_process_running(&process)?;
1143
1144 let reported_koid =
1147 proxy.get_lifecycle_koid().await.context("failed getting koid from util")?;
1148 assert_eq!(koid, reported_koid);
1149 mem::drop(proxy);
1150 check_process_exited_ok(&process).await?;
1151 Ok(())
1152 }
1153
1154 #[fasync::run_singlethreaded(test)]
1157 async fn start_util_with_no_lifecycle_channel() -> Result<(), Error> {
1158 let (builder, proxy) = setup_test_util_builder(true)?;
1159 let process = builder.build().await?.start()?;
1160 check_process_running(&process)?;
1161
1162 let reported_koid =
1165 proxy.get_lifecycle_koid().await.context("failed getting koid from util")?;
1166 assert_eq!(zx::sys::ZX_KOID_INVALID, reported_koid);
1167 mem::drop(proxy);
1168 check_process_exited_ok(&process).await?;
1169 Ok(())
1170 }
1171
1172 #[fasync::run_singlethreaded(test)]
1173 async fn start_util_with_big_stack() -> Result<(), Error> {
1174 let stack_size: usize = zx::system_get_page_size() as usize * 10;
1175
1176 let (mut builder, proxy) = setup_test_util_builder(true)?;
1177 builder.set_min_stack_size(stack_size);
1178 let built = builder.build().await?;
1179 assert!(built.stack_vmo.get_size()? >= stack_size as u64);
1180
1181 let process = built.start()?;
1182 check_process_running(&process)?;
1183 mem::drop(proxy);
1184 check_process_exited_ok(&process).await?;
1185 Ok(())
1186 }
1187
1188 #[fasync::run_singlethreaded(test)]
1189 async fn elf_headers() -> Result<(), Error> {
1190 let (builder, _) = setup_test_util_builder(true)?;
1191 let built = builder.build().await?;
1192 assert!(
1193 built.elf_headers.file_header().phnum
1194 == built.elf_headers.program_headers().len() as u16
1195 );
1196 Ok(())
1197 }
1198
1199 #[fasync::run_singlethreaded(test)]
1203 async fn set_loader_directly() -> Result<(), Error> {
1204 let test_args = vec!["arg0", "arg1", "arg2"];
1205 let test_args_cstr =
1206 test_args.iter().map(|&s| CString::new(s)).collect::<Result<_, _>>()?;
1207
1208 let (mut builder, proxy) = setup_test_util_builder(false)?;
1209 builder.set_loader_service(clone_loader_service()?)?;
1210 builder.add_arguments(test_args_cstr);
1211 let process = builder.build().await?.start()?;
1212 check_process_running(&process)?;
1213
1214 let proc_args = proxy.get_arguments().await.context("failed to get args from util")?;
1218 assert_eq!(proc_args, test_args);
1219
1220 mem::drop(proxy);
1221 check_process_exited_ok(&process).await?;
1222 Ok(())
1223 }
1224
1225 #[fasync::run_singlethreaded(test)]
1233 async fn set_vdso_directly() -> Result<(), Error> {
1234 let test_args = vec!["arg0", "arg1", "arg2"];
1235 let test_args_cstr =
1236 test_args.iter().map(|&s| CString::new(s)).collect::<Result<_, _>>()?;
1237
1238 let (mut builder, proxy) = setup_test_util_builder(true)?;
1239 builder.set_vdso_vmo(get_system_vdso_vmo()?);
1240 builder.add_arguments(test_args_cstr);
1241 let process = builder.build().await?.start()?;
1242 check_process_running(&process)?;
1243
1244 let proc_args = proxy.get_arguments().await.context("failed to get args from util")?;
1246 assert_eq!(proc_args, test_args);
1247
1248 mem::drop(proxy);
1249 check_process_exited_ok(&process).await?;
1250 Ok(())
1251 }
1252
1253 #[fasync::run_singlethreaded(test)]
1258 async fn set_invalid_vdso_directly_fails() -> Result<(), Error> {
1259 let bad_vdso = zx::Vmo::create(1)?;
1260
1261 let (mut builder, _) = setup_test_util_builder(true)?;
1262 builder.set_vdso_vmo(bad_vdso);
1263
1264 let result = builder.build().await;
1265 match result {
1266 Err(ProcessBuilderError::ElfParse(elf_parse::ElfParseError::InvalidFileHeader(_))) => {}
1267 Err(err) => {
1268 panic!("Unexpected error type: {}", err);
1269 }
1270 Ok(_) => {
1271 panic!("Unexpectedly succeeded to build process with invalid vDSO");
1272 }
1273 }
1274 Ok(())
1275 }
1276
1277 #[fasync::run_singlethreaded(test)]
1282 async fn set_invalid_vdso_fails() -> Result<(), Error> {
1283 let bad_vdso = zx::Vmo::create(1)?;
1284
1285 let (mut builder, _) = setup_test_util_builder(true)?;
1286 builder.add_handles(vec![process_args::StartupHandle {
1287 handle: bad_vdso.into_handle(),
1288 info: HandleInfo::new(HandleType::VdsoVmo, 0),
1289 }])?;
1290
1291 let result = builder.build().await;
1292 match result {
1293 Err(ProcessBuilderError::ElfParse(elf_parse::ElfParseError::InvalidFileHeader(_))) => {}
1294 Err(err) => {
1295 panic!("Unexpected error type: {}", err);
1296 }
1297 Ok(_) => {
1298 panic!("Unexpectedly succeeded to build process with invalid vDSO");
1299 }
1300 }
1301 Ok(())
1302 }
1303
1304 #[fasync::run_singlethreaded(test)]
1305 async fn add_additional_vdso() -> Result<(), Error> {
1306 let mut builder = create_test_util_builder()?;
1307 builder.set_loader_service(clone_loader_service()?)?;
1308 builder.add_handles(vec![process_args::StartupHandle {
1309 handle: get_system_vdso_vmo().unwrap().into_handle(),
1310 info: HandleInfo::new(HandleType::VdsoVmo, 1),
1311 }])?;
1312 let built = builder.build().await?;
1313
1314 let mut msg_buf = zx::MessageBuf::new();
1316 built.bootstrap.read(&mut msg_buf)?;
1317
1318 let mut msg_buf = zx::MessageBuf::new();
1320 built.bootstrap.read(&mut msg_buf)?;
1321 let handle_info = parse_handle_info_from_message(&msg_buf)?
1322 .drain(..)
1323 .filter(|info| info.handle_type() == HandleType::VdsoVmo)
1324 .collect::<Vec<_>>();
1325 assert_eq!(2, handle_info.len());
1326 for (i, info) in handle_info.iter().rev().enumerate() {
1327 assert_eq!(HandleType::VdsoVmo, info.handle_type());
1328 assert_eq!(i as u16, info.arg());
1329 }
1330 Ok(())
1331 }
1332
1333 #[fasync::run_singlethreaded(test)]
1334 async fn start_util_with_env() -> Result<(), Error> {
1335 let test_env = vec![("VAR1", "value2"), ("VAR2", "value2")];
1336 let test_env_cstr = test_env
1337 .iter()
1338 .map(|v| CString::new(format!("{}={}", v.0, v.1)))
1339 .collect::<Result<_, _>>()?;
1340
1341 let (mut builder, proxy) = setup_test_util_builder(true)?;
1342 builder.add_environment_variables(test_env_cstr);
1343 let process = builder.build().await?.start()?;
1344 check_process_running(&process)?;
1345
1346 let proc_env = proxy.get_environment().await.context("failed to get env from util")?;
1347 let proc_env_tuple: Vec<(&str, &str)> =
1348 proc_env.iter().map(|v| (&*v.key, &*v.value)).collect();
1349 assert_eq!(proc_env_tuple, test_env);
1350
1351 mem::drop(proxy);
1352 check_process_exited_ok(&process).await?;
1353 Ok(())
1354 }
1355
1356 #[fasync::run_singlethreaded(test)]
1357 async fn start_util_with_huge_env() -> Result<(), Error> {
1358 let test_env = vec!["a=b"; 10 * 1000];
1366 let test_env_cstr = test_env.iter().map(|&s| CString::new(s)).collect::<Result<_, _>>()?;
1367
1368 let (mut builder, proxy) = setup_test_util_builder(true)?;
1369 builder.add_environment_variables(test_env_cstr);
1370 let process = builder.build().await?.start()?;
1371 check_process_running(&process)?;
1372
1373 let proc_env =
1377 proxy.get_environment_count().await.context("failed to get env from util")?;
1378 assert_eq!(proc_env, test_env.len() as u64);
1379
1380 mem::drop(proxy);
1381 check_process_exited_ok(&process).await?;
1382 Ok(())
1383 }
1384
1385 #[fasync::run_singlethreaded(test)]
1386 async fn start_util_with_namespace_entries() -> Result<(), Error> {
1387 let mut randbuf = [0; 8];
1388 zx::cprng_draw(&mut randbuf);
1389 let test_content1 = format!("test content 1 {}", u64::from_le_bytes(randbuf));
1390 zx::cprng_draw(&mut randbuf);
1391 let test_content2 = format!("test content 2 {}", u64::from_le_bytes(randbuf));
1392
1393 let dir1 = pseudo_directory! {
1394 "test_file1" => read_only(test_content1.clone()),
1395 };
1396 let dir1_client = vfs::directory::serve_read_only(dir1).into_client_end().unwrap();
1397
1398 let dir2 = pseudo_directory! {
1399 "test_file2" => read_only(test_content2.clone()),
1400 };
1401 let dir2_client = vfs::directory::serve_read_only(dir2).into_client_end().unwrap();
1402
1403 let (mut builder, proxy) = setup_test_util_builder(true)?;
1404 builder.add_namespace_entries(vec![
1405 NamespaceEntry { path: CString::new("/dir1")?, directory: dir1_client },
1406 NamespaceEntry { path: CString::new("/dir2")?, directory: dir2_client },
1407 ])?;
1408 let process = builder.build().await?.start()?;
1409 check_process_running(&process)?;
1410
1411 let namespace_dump = proxy.dump_namespace().await.context("failed to dump namespace")?;
1412 assert_eq!(namespace_dump, "/dir1, /dir1/test_file1, /dir2, /dir2/test_file2");
1413
1414 let dir1_contents =
1415 proxy.read_file("/dir1/test_file1").await.context("failed to read file via util")?;
1416 assert_eq!(dir1_contents, test_content1);
1417 let dir2_contents =
1418 proxy.read_file("/dir2/test_file2").await.context("failed to read file via util")?;
1419 assert_eq!(dir2_contents, test_content2);
1420
1421 mem::drop(proxy);
1422 check_process_exited_ok(&process).await?;
1423 Ok(())
1424 }
1425
1426 #[fasync::run_singlethreaded(test)]
1429 async fn start_util_with_no_loader_fails() -> Result<(), Error> {
1430 let (builder, _) = setup_test_util_builder(false)?;
1431
1432 let result = builder.build().await;
1433 match result {
1434 Err(ProcessBuilderError::LoaderMissing()) => {}
1435 Err(err) => {
1436 panic!("Unexpected error type: {}", err);
1437 }
1438 Ok(_) => {
1439 panic!("Unexpectedly succeeded to build process without loader");
1440 }
1441 }
1442 Ok(())
1443 }
1444
1445 #[fasync::run_singlethreaded(test)]
1448 async fn verify_low_address_range_reserved() -> Result<(), Error> {
1449 let (builder, _) = setup_test_util_builder(true)?;
1450 let built = builder.build().await?;
1451
1452 let info = built.root_vmar.info()?;
1455 let lower_half_len = util::page_end((info.base + info.len) / 2) - info.base;
1456 built
1457 .root_vmar
1458 .allocate(0, lower_half_len, zx::VmarFlags::SPECIFIC)
1459 .context("Unable to allocate lower address range of new process")?;
1460 Ok(())
1461 }
1462
1463 fn parse_handle_info_from_message(message: &zx::MessageBuf) -> Result<Vec<HandleInfo>, Error> {
1466 let bytes = message.bytes();
1467 let (header, _) = Ref::<&[u8], process_args::MessageHeader>::from_prefix(bytes)
1468 .map_err(|_| anyhow!("Failed to parse process_args header"))?;
1469
1470 let offset = header.handle_info_off as usize;
1471 let len = mem::size_of::<u32>() * message.n_handles();
1472 let info_bytes = &bytes[offset..offset + len];
1473 let raw_info = Ref::<&[u8], [u32]>::from_bytes(info_bytes)
1474 .map_err(|_| anyhow!("Failed to parse raw handle info"))?;
1475
1476 Ok(raw_info.iter().map(|raw| HandleInfo::try_from(*raw)).collect::<Result<_, _>>()?)
1477 }
1478
1479 const LINKER_MESSAGE_HANDLES: &[HandleType] = &[
1480 HandleType::ProcessSelf,
1481 HandleType::RootVmar,
1482 HandleType::LdsvcLoader,
1483 HandleType::LoadedVmar,
1484 HandleType::ExecutableVmo,
1485 ];
1486
1487 const MAIN_MESSAGE_HANDLES: &[HandleType] = &[
1488 HandleType::ProcessSelf,
1489 HandleType::ThreadSelf,
1490 HandleType::RootVmar,
1491 HandleType::VdsoVmo,
1492 HandleType::StackVmo,
1493 ];
1494
1495 #[fasync::run_singlethreaded(test)]
1496 async fn correct_handles_present() -> Result<(), Error> {
1497 let mut builder = create_test_util_builder()?;
1498 builder.set_loader_service(clone_loader_service()?)?;
1499 let built = builder.build().await?;
1500
1501 for correct in &[LINKER_MESSAGE_HANDLES, MAIN_MESSAGE_HANDLES] {
1502 let mut msg_buf = zx::MessageBuf::new();
1503 built.bootstrap.read(&mut msg_buf)?;
1504 let handle_info = parse_handle_info_from_message(&msg_buf)?;
1505
1506 assert_eq!(handle_info.len(), correct.len());
1507 for correct_type in *correct {
1508 assert_eq!(
1510 1,
1511 handle_info.iter().filter(|info| &info.handle_type() == correct_type).count()
1512 );
1513 }
1514 }
1515 Ok(())
1516 }
1517
1518 #[fasync::run_singlethreaded(test)]
1521 async fn add_handles_rejects_automatic_handle_types() -> Result<(), Error> {
1522 let vmo = zx::Vmo::create(1)?;
1524 let job = fuchsia_runtime::job_default();
1525 let procname = CString::new("test_vmo")?;
1526 let mut builder = ProcessBuilder::new(
1527 &procname,
1528 &job,
1529 zx::ProcessOptions::empty(),
1530 vmo,
1531 get_system_vdso_vmo().unwrap(),
1532 )?;
1533
1534 for handle_type in LINKER_MESSAGE_HANDLES.iter().chain(MAIN_MESSAGE_HANDLES) {
1537 if *handle_type == HandleType::LdsvcLoader {
1538 continue;
1541 }
1542
1543 if *handle_type == HandleType::VdsoVmo {
1544 continue;
1546 }
1547
1548 let vmo = zx::Vmo::create(1)?;
1550 let result = builder.add_handles(vec![process_args::StartupHandle {
1551 handle: vmo.into_handle(),
1552 info: HandleInfo::new(*handle_type, 0),
1553 }]);
1554 match result {
1555 Err(ProcessBuilderError::InvalidArg(_)) => {}
1556 Err(err) => {
1557 panic!("Unexpected error type, should be invalid arg: {}", err);
1558 }
1559 Ok(_) => {
1560 panic!("add_handle unexpectedly succeeded for type {:?}", handle_type);
1561 }
1562 }
1563 }
1564 Ok(())
1565 }
1566
1567 #[fasync::run_singlethreaded(test)]
1569 async fn rejects_invalid_handles() -> Result<(), Error> {
1570 let invalid = || zx::NullableHandle::invalid();
1571 let assert_invalid_arg = |result| match result {
1572 Err(ProcessBuilderError::BadHandle(_)) => {}
1573 Err(err) => {
1574 panic!("Unexpected error type, should be BadHandle: {}", err);
1575 }
1576 Ok(_) => {
1577 panic!("API unexpectedly accepted invalid handle");
1578 }
1579 };
1580
1581 let vmo = zx::Vmo::create(1)?;
1583 let job = fuchsia_runtime::job_default();
1584 let procname = CString::new("test_vmo")?;
1585
1586 assert_invalid_arg(
1587 ProcessBuilder::new(
1588 &procname,
1589 &zx::NullableHandle::from(invalid()).into(),
1590 zx::ProcessOptions::empty(),
1591 vmo,
1592 get_system_vdso_vmo().unwrap(),
1593 )
1594 .map(|_| ()),
1595 );
1596 assert_invalid_arg(
1597 ProcessBuilder::new(
1598 &procname,
1599 &job,
1600 zx::ProcessOptions::empty(),
1601 zx::NullableHandle::from(invalid()).into(),
1602 get_system_vdso_vmo().unwrap(),
1603 )
1604 .map(|_| ()),
1605 );
1606
1607 let (mut builder, _) = setup_test_util_builder(true)?;
1608
1609 assert_invalid_arg(builder.set_loader_service(invalid().into()));
1610 assert_invalid_arg(builder.add_handles(vec![process_args::StartupHandle {
1611 handle: invalid().into(),
1612 info: HandleInfo::new(HandleType::User0, 0),
1613 }]));
1614 assert_invalid_arg(builder.add_handles(vec![process_args::StartupHandle {
1615 handle: invalid().into(),
1616 info: HandleInfo::new(HandleType::User0, 0),
1617 }]));
1618 assert_invalid_arg(builder.add_namespace_entries(vec![NamespaceEntry {
1619 path: CString::new("/dir")?,
1620 directory: invalid().into(),
1621 }]));
1622
1623 Ok(())
1624 }
1625
1626 #[fasync::run_singlethreaded]
1627 #[test]
1628 async fn start_static_pie_binary() -> Result<(), Error> {
1629 const TEST_BIN: &'static str = "/pkg/bin/static_pie_test_util";
1630 let file = fdio::open_fd(TEST_BIN, fio::PERM_READABLE | fio::PERM_EXECUTABLE)?;
1631 let vmo = fdio::get_vmo_exec_from_file(&file)?;
1632 let job = fuchsia_runtime::job_default();
1633
1634 let procname = CString::new(TEST_BIN.to_owned())?;
1635 let mut builder = ProcessBuilder::new(
1636 &procname,
1637 &job,
1638 zx::ProcessOptions::empty(),
1639 vmo,
1640 get_system_vdso_vmo().unwrap(),
1641 )?;
1642
1643 let (local, remote) = zx::Channel::create();
1646 builder.add_handles(vec![process_args::StartupHandle {
1647 handle: remote.into_handle(),
1648 info: HandleInfo::new(HandleType::User0, 0),
1649 }])?;
1650
1651 let mut randbuf = [0; 8];
1652 zx::cprng_draw(&mut randbuf);
1653 let test_message = format!("test content 1 {}", u64::from_le_bytes(randbuf)).into_bytes();
1654 local.write(&test_message, &mut vec![])?;
1655
1656 builder.build().await?.start()?;
1658 let signals = fasync::OnSignals::new(
1659 &local,
1660 zx::Signals::CHANNEL_READABLE | zx::Signals::CHANNEL_PEER_CLOSED,
1661 )
1662 .await?;
1663 assert!(signals.contains(zx::Signals::CHANNEL_READABLE));
1664
1665 let mut echoed = zx::MessageBuf::new();
1666 local.read(&mut echoed)?;
1667 assert_eq!(echoed.bytes(), test_message.as_slice());
1668 assert_eq!(echoed.n_handles(), 0);
1669 Ok(())
1670 }
1671}