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