process_builder/
process_builder.rs

1// Copyright 2023 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use 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/// Error type returned by ProcessBuilder methods.
18#[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    /// Returns an appropriate zx::Status code for the given error.
58    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
81/// A container for a single namespace entry, containing a path and a directory handle. Used as an
82/// input to [ProcessBuilder::add_namespace_entries()].
83pub struct NamespaceEntry {
84    /// Namespace path.
85    pub path: CString,
86
87    /// Namespace directory handle.
88    pub directory: ClientEnd<fio::DirectoryMarker>,
89}
90
91/// The main builder type for this crate. Collects inputs and creates a new process.
92///
93/// See top-level crate documentation for a usage example.
94pub struct ProcessBuilder {
95    /// The ELF binary for the new process.
96    executable: zx::Vmo,
97    /// The fuchsia.ldsvc.Loader service to use for the new process, if dynamically linked.
98    ldsvc: Option<fldsvc::LoaderProxy>,
99    /// A non-default vDSO to use for the new process, if any.
100    non_default_vdso: Option<zx::Vmo>,
101    /// The contents of the main process_args message to be sent to the new process.
102    msg_contents: process_args::MessageContents,
103    /// Handles that are common to both the linker and main process_args messages, wrapped in an
104    /// inner struct for code organization and clarity around borrows.
105    common: CommonMessageHandles,
106    /// Minimum size of the stack for the new process, in bytes.
107    min_stack_size: usize,
108    /// The default system vDSO.
109    system_vdso_vmo: zx::Vmo,
110}
111
112struct CommonMessageHandles {
113    process: zx::Process,
114    thread: zx::Thread,
115    root_vmar: zx::Vmar,
116}
117
118/// A container for a fully built but not yet started (as in, its initial thread is not yet
119/// running) process, with all related handles and metadata. Output of [ProcessBuilder::build()].
120///
121/// You can use this struct to start the process with [BuiltProcess::start()], which is a simple
122/// wrapper around the [zx_process_start] syscall. You can optionally use the handles and
123/// information in this struct to manipulate the process or its address space before starting it,
124/// such as when creating a process in a debugger.
125///
126/// [zx_process_start]: https://fuchsia.dev/fuchsia-src/reference/syscalls/process_start.md
127pub struct BuiltProcess {
128    /// The newly created process.
129    pub process: zx::Process,
130
131    /// The root VMAR for the created process.
132    pub root_vmar: zx::Vmar,
133
134    /// The process's initial thread.
135    pub thread: zx::Thread,
136
137    /// The process's entry point.
138    pub entry: usize,
139
140    /// The initial thread's stack pointer.
141    pub stack: usize,
142
143    /// The base address of the stack for the initial thread.
144    pub stack_base: usize,
145
146    /// The VMO of the stack for the initial thread.
147    pub stack_vmo: zx::Vmo,
148
149    /// The bootstrap channel, to be passed to the process on start as arg1 in zx_process_start /
150    /// zx::Process::start.
151    pub bootstrap: zx::Channel,
152
153    /// The base address of the VDSO in the process's VMAR, to be passed to the process on start as
154    /// arg2 in zx_process_start / zx::Process::start.
155    pub vdso_base: usize,
156
157    /// The base address where the ELF executable, or the dynamic linker if the ELF was dynamically
158    /// linked, was loaded in the process's VMAR.
159    pub elf_base: usize,
160
161    /// The ELF headers of the main module of the newly created process.
162    pub elf_headers: elf_parse::Elf64Headers,
163}
164
165struct StackInfo {
166    /// The initial thread's stack pointer.
167    pub stack_ptr: usize,
168
169    /// The base address of the stack for the initial thread.
170    pub stack_base: usize,
171
172    /// The VMO of the stack for the initial thread.
173    pub stack_vmo: zx::Vmo,
174}
175
176impl ProcessBuilder {
177    /// Create a new ProcessBuilder that can be used to create a new process under the given job
178    /// with the given name and ELF64 executable (as a VMO).
179    ///
180    /// This job is only used to create the process and thus is not taken ownership of. To provide
181    /// a default job handle to be passed to the new process, use [ProcessBuilder::add_handles()]
182    /// with [HandleType::DefaultJob].
183    ///
184    /// The provided VMO must have the [zx::Rights::EXECUTE] right.
185    ///
186    /// # Errors
187    ///
188    /// Returns Err([ProcessBuilderError::CreateProcess]) if process creation fails, such as if the
189    /// process using this is disallowed direct process creation rights through job policy. See
190    /// top-level crate documentation for more details.
191    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        // Creating the process immediately has the benefit that we fail fast if the calling
206        // process does not have permission to create processes directly.
207        let (process, root_vmar) = job
208            .create_child_process(options, name.to_bytes())
209            .map_err(ProcessBuilderError::CreateProcess)?;
210
211        // Create the initial thread.
212        let thread =
213            process.create_thread(b"initial-thread").map_err(ProcessBuilderError::CreateThread)?;
214
215        // Add duplicates of the process, VMAR, and thread handles to the bootstrap message.
216        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    /// Sets the fuchsia.ldsvc.Loader service for the process.
233    ///
234    /// The loader service is used to load dynamic libraries if the executable is a dynamically
235    /// linked ELF file (i.e. if it contains a PT_INTERP header), and is required for such
236    /// executables. It will only be provided to the new process in this case. Otherwise, it is
237    /// unused and has no effect.
238    ///
239    /// If no loader service has been provided and it is needed, process creation will fail. Note
240    /// that this differs from the automatic fallback behavior of previous process creation
241    /// libraries, which would clone the loader of the current process. This fallback is likely to
242    /// fail in subtle and confusing ways. An appropriate loader service that has access to the
243    /// libraries or interpreter must be provided.
244    ///
245    /// Note that [ProcessBuilder::add_handles()] will automatically pass a handle with type
246    /// [HandleType::LdsvcLoader] to this function.
247    ///
248    /// If called multiple times (e.g. if a loader was initially provided through
249    /// [ProcessBuilder::add_handles()] and you want to replace it), the new loader replaces the
250    /// previous and the handle to the previous loader is dropped.
251    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    /// Sets the vDSO VMO for the process.
263    pub fn set_vdso_vmo(&mut self, vdso: zx::Vmo) {
264        self.non_default_vdso = Some(vdso);
265    }
266
267    /// Add arguments to the process's bootstrap message. Successive calls append (not replace)
268    /// arguments.
269    pub fn add_arguments(&mut self, mut args: Vec<CString>) {
270        self.msg_contents.args.append(&mut args);
271    }
272
273    /// Add environment variables to the process's bootstrap message. Successive calls append (not
274    /// replace) environment variables.
275    pub fn add_environment_variables(&mut self, mut vars: Vec<CString>) {
276        self.msg_contents.environment_vars.append(&mut vars);
277    }
278
279    /// Set the minimum size of the stack for the new process, in bytes.
280    pub fn set_min_stack_size(&mut self, size: usize) {
281        self.min_stack_size = size;
282    }
283
284    /// Add handles to the process's bootstrap message. Successive calls append (not replace)
285    /// handles.
286    ///
287    /// Each [process_args::StartupHandle] contains a [zx::Handle] object accompanied by a [HandleInfo] object
288    /// that includes the handle type and a type/context-dependent argument.
289    ///
290    /// A [HandleType::LdsvcLoader] handle will automatically be passed along to
291    /// [ProcessBuilder::set_loader_service()] if provided through this function.
292    ///
293    /// # Errors
294    ///
295    /// [HandleType::NamespaceDirectory] handles should not be added through this function since
296    /// they must be accompanied with a path. Use [ProcessBuilder::add_namespace_entries()] for
297    /// that instead.
298    ///
299    /// The following handle types cannot be added through this, as they are added automatically by
300    /// the ProcessBuilder:
301    /// * [HandleType::ProcessSelf]
302    /// * [HandleType::ThreadSelf]
303    /// * [HandleType::RootVmar]
304    /// * [HandleType::LoadedVmar]
305    /// * [HandleType::StackVmo]
306    /// * [HandleType::ExecutableVmo]
307    pub fn add_handles(
308        &mut self,
309        startup_handles: Vec<process_args::StartupHandle>,
310    ) -> Result<(), ProcessBuilderError> {
311        // Do a bit of validation before adding to the bootstrap handles.
312        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        // Intentionally separate from validation so that we don't partially add namespace entries.
341        for h in startup_handles {
342            match h.info.handle_type() {
343                HandleType::LdsvcLoader => {
344                    // Automatically pass this to |set_loader_service| instead.
345                    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                        // Pass any additional vDSOs.
352                        self.msg_contents.handles.push(h);
353                    }
354                }
355                _ => {
356                    self.msg_contents.handles.push(h);
357                }
358            }
359        }
360        Ok(())
361    }
362
363    /// Add directories to the process's namespace.
364    ///
365    /// Successive calls append new namespace entries, not replace previous entries.
366    ///
367    /// Each [NamespaceEntry] contains a client connection to a fuchsia.io.Directory FIDL service
368    /// and a path to add that directory to the process's namespace as.
369    ///
370    /// # Errors
371    ///
372    /// Returns Err([ProcessBuilderError::InvalidArg]) if the maximum number of namespace entries
373    /// (2^16) was reached and the entry could not be added. This is exceedingly unlikely, and most
374    /// likely if you are anywhere near this limit [ProcessBuilder::build()] will fail because the
375    /// process's process_args startup message is over its own length limit.
376    pub fn add_namespace_entries(
377        &mut self,
378        mut entries: Vec<NamespaceEntry>,
379    ) -> Result<(), ProcessBuilderError> {
380        // Namespace entries are split into a namespace path, that is included in the bootstrap
381        // message (as the so-called "namespace table"), plus a NamespaceDirectory handle, where the arg
382        // value is the index of the path in the namespace table.
383        //
384        // Check that the namespace table doesn't exceed 2^16 entries, since the HandleInfo arg is
385        // only 16-bits. Realistically this will never matter - if you're anywhere near this
386        // many entries, you're going to exceed the bootstrap message length limit - but Rust
387        // encourages us (and makes it easy) to be safe about the edge case here.
388        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        // Intentionally separate from validation so that we don't partially add namespace entries=
405        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    /// Build the new process using the data and handles provided to the ProcessBuilder.
417    ///
418    /// The return value of this function is a [BuiltProcess] struct which contains the new process
419    /// and all the handles and data needed to start it, but the process' initial thread is not yet
420    /// started. Use [BuiltProcess::start()] or the [zx_process_start] syscall to actually start
421    /// it.
422    ///
423    /// # Errors
424    ///
425    /// There are many errors that could result during process loading and only some are listed
426    /// here. See [ProcessBuilderError] for the various error types that can be returned.
427    ///
428    /// Returns Err([ProcessBuilderError::LoaderMissing]) if the ELF executable is dynamically
429    /// linked (has a PT_INTERP program header) but no loader service has been provided through
430    /// [ProcessBuilder::set_loader_service()] or [ProcessBuilder::add_handles()].
431    ///
432    /// [zx_process_start]: https://fuchsia.dev/fuchsia-src/reference/syscalls/process_start.md
433    pub async fn build(mut self) -> Result<BuiltProcess, ProcessBuilderError> {
434        // Parse the executable as an ELF64 file, reading in the headers we need. Done first since
435        // this is most likely to be invalid and error out.
436        let elf_headers = elf_parse::Elf64Headers::from_vmo(&self.executable)?;
437
438        // Create bootstrap message channel.
439        let (bootstrap_rd, bootstrap_wr) = zx::Channel::create();
440
441        // Check if main executable is dynamically linked, and handle appropriately.
442        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            // Dynamically linked so defer loading the main executable to the dynamic
449            // linker/loader, which we load here instead.
450            dynamic = true;
451
452            // Check that a ldsvc.Loader service was provided.
453            let ldsvc = self.ldsvc.take().ok_or(ProcessBuilderError::LoaderMissing())?;
454
455            // A process using PT_INTERP might be loading a libc.so that supports sanitizers;
456            // reserve the low address region for sanitizers to allocate shadow memory.
457            //
458            // The reservation VMAR ensures that the initial allocations & mappings made in this
459            // function stay out of this area. It is destroyed below before returning and the
460            // process's own allocations can use the full address space.
461            //
462            // !! WARNING: This makes a specific address VMAR allocation, so it must come before
463            // any elf_load::load_elf calls. !!
464            reserve_vmar =
465                Some(ReservationVmar::reserve_low_address_space(&self.common.root_vmar)?);
466
467            // Get the dynamic linker and map it into the process's address space.
468            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            // Build the dynamic linker bootstrap message and write it to the bootstrap channel.
473            // This message is written before the primary bootstrap message since it is consumed
474            // first in the dynamic linker.
475            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            // Statically linked but still position-independent (ET_DYN) ELF, load directly.
480            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        // Load the vDSO - either the default system vDSO, or the user-provided one - into the
491        // process's address space and a handle to it to the bootstrap message.
492        let vdso_base = self.load_vdso()?;
493
494        // Calculate initial stack size.
495        let mut stack_size;
496        let stack_vmo_name;
497        if dynamic {
498            // Calculate the initial stack size for the dynamic linker. This factors in the size of
499            // an extra handle for the stack that hasn't yet been added to the message contents,
500            // since creating the stack requires this size.
501            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            // Set stack size from PT_GNU_STACK header, if present, or use the default. The dynamic
505            // linker handles this for dynamically linked ELFs (above case).
506            const ZIRCON_DEFAULT_STACK_SIZE: usize = 256 << 10; // 256KiB
507            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 must be page aligned.
517            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        // Allocate the initial thread's stack, map it, and add a handle to the bootstrap message.
525        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        // Build and send the primary bootstrap message.
530        let msg = process_args::Message::build(self.msg_contents)?;
531        msg.write(&bootstrap_wr).map_err(ProcessBuilderError::WriteBootstrapMessage)?;
532
533        // Explicitly destroy the reservation VMAR before returning so that we can be sure it is
534        // gone (so we don't end up with a process with half its address space gone).
535        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    /// Build the bootstrap message for the dynamic linker, which uses the same process_args
555    /// protocol as the message for the main process but somewhat different contents.
556    ///
557    /// The LoaderProxy provided must be ready to be converted to a Handle with into_channel(). In
558    /// other words, there must be no other active clones of the proxy, no open requests, etc. The
559    /// intention is that the user provides a handle only (perhaps wrapped in a ClientEnd) through
560    /// [ProcessBuilder::set_loader_service()], not a Proxy, so the library can be sure this
561    /// invariant is maintained and a failure is a library bug.
562    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        // Don't need to use the ldsvc.Loader anymore; turn it back into into a raw handle so
569        // we can pass it along in the dynamic linker bootstrap message.
570        let ldsvc_hnd =
571            ldsvc.into_channel().expect("Failed to get channel from LoaderProxy").into_zx_channel();
572
573        // The linker message only needs a subset of argv and envvars.
574        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            // Argument strings are sent to the linker so that it can use argv[0] in messages it
580            // prints.
581            args,
582            // Environment variables are sent to the linker so that it can see vars like LD_DEBUG.
583            environment_vars,
584            // Process namespace is not set up or used in the linker.
585            namespace_paths: vec![],
586            // Loader message includes a few special handles needed to do its job, plus a set of
587            // handles common to both messages which are generated by this library.
588            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    /// Load the vDSO VMO into the process's address space and a handle to it to the bootstrap
609    /// message. If a vDSO VMO is provided, loads that one, otherwise loads the default system
610    /// vDSO, invaliding the duplicate default system vDSO handle stored in this object.
611    /// Returns the base address that the vDSO was mapped into.
612    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    /// Allocate the initial thread's stack, map it, and add a handle to the bootstrap message.
629    /// Returns the initial stack pointer for the process.
630    ///
631    /// Note that launchpad supported not allocating a stack at all, but that only happened if an
632    /// explicit stack size of 0 is set. ProcessBuilder does not support overriding the stack size
633    /// so a stack is always created.
634    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        // Pass the stack VMO to the process. Our protocol with the new process is that we warrant
656        // that this is the VMO from which the initial stack is mapped and that we've exactly
657        // mapped the entire thing, so vm_object_get_size on this in concert with the initial SP
658        // value tells it the exact bounds of its stack.
659        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
668/// Calculate the size of the initial stack to allocate for the dynamic linker, based on the given
669/// process_args message contents.
670///
671/// The initial stack is used just for startup work in the dynamic linker and to hold the bootstrap
672/// message, so we only attempt to make it only as big as needed. The size returned is based on the
673/// stack space needed to read the bootstrap message with zx_channel_read, and thus includes the
674/// message data itself plus the size of the handles (i.e. the size of N zx_handle_t's).
675///
676/// This also allows the caller to specify an number of "extra handles" to factor into the size
677/// calculation. This allows the size to be calculated before all the real handles have been added
678/// to the contents, for example if the size is needed to create those handles.
679pub fn calculate_initial_linker_stack_size(
680    msg_contents: &mut process_args::MessageContents,
681    extra_handles: usize,
682) -> Result<usize, ProcessBuilderError> {
683    // Add N placeholder handles temporarily to factor in the size of handles that are not yet
684    // added to the message contents.
685    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    // Include both the message data size and the size of the handles since we're calculating the
694    // stack space required to read the message.
695    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    // PTHREAD_STACK_MIN is defined by the C library in
701    // //zircon/third_party/ulib/musl/include/limits.h. It is tuned enough to cover the dynamic
702    // linker and C library startup code's stack usage (up until the point it switches to its own
703    // stack in __libc_start_main), but leave a little space so for small bootstrap message sizes
704    // the stack needs only one page.
705    const PTHREAD_STACK_MIN: usize = 3072;
706    Ok(util::page_end(msg_stack_size + PTHREAD_STACK_MIN))
707}
708
709/// Extract only the arguments that are needed for a linker message.
710fn 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
720/// Extract only the environment variables that are needed for a linker message.
721fn 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    /// Add a handle to the procargs message with `0` for its `arg`.
762    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
778/// Given the base and size of the stack block, compute the appropriate initial
779/// SP value for an initial thread according to the C calling convention for the
780/// machine.
781///
782/// Copied from, and must be kept in sync with:
783/// //zircon/system/ulib/elf-psabi/include/lib/elf-psabi/sp.h
784pub fn compute_initial_stack_pointer(base: usize, size: usize) -> usize {
785    // Assume stack grows down.
786    let mut sp = base.checked_add(size).expect("Overflow in stack pointer calculation");
787
788    // The x86-64 and AArch64 ABIs require 16-byte alignment.
789    // The 32-bit ARM ABI only requires 8-byte alignment, but 16-byte alignment is preferable for
790    // NEON so use it there too.
791    // RISC-V ABIs also require 16-byte alignment.
792    sp &= 16usize.wrapping_neg();
793
794    // The x86-64 ABI requires %rsp % 16 = 8 on entry.  The zero word at (%rsp) serves as the
795    // return address for the outermost frame.
796    #[cfg(target_arch = "x86_64")]
797    {
798        sp -= 8;
799    }
800
801    // The ARMv7 and ARMv8 ABIs both just require that SP be aligned, so just catch unknown archs.
802    #[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
815/// Load the dynamic linker/loader specified in the PT_INTERP header via the fuchsia.ldsvc.Loader
816/// handle.
817pub 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    // Read the dynamic linker name from the main VMO, based on the PT_INTERP header.
823    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    // Trim null terminator included in filesz.
828    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    // Retrieve the dynamic linker as a VMO from fuchsia.ldsvc.Loader
837    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    /// Start an already built process.
860    ///
861    /// This is a simple wrapper around the [zx_process_start] syscall that consumes the handles
862    /// and data in the BuiltProcess struct as needed.
863    ///
864    /// [zx_process_start]: https://fuchsia.dev/fuchsia-src/reference/syscalls/process_start.md
865    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    /// Reserve the lower half of the address space of the given VMAR by allocating another VMAR.
883    ///
884    /// The VMAR wrapped by this reservation is automatically destroyed when the reservation
885    /// is dropped.
886    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        // Reserve the lower half of the full address space, not just half of the VMAR length.
892        // (base+len) represents the full address space, assuming this is used with a root VMAR and
893        // length extends to the end of the address space, including a region the kernel reserves
894        // at the start of the space.
895        // TODO(https://fxbug.dev/42099306): Clean up address space reservation to avoid unnecessary
896        // reservations, which should also avoid the "fake" reservation in the else-clause.
897        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            // The VMAR does not intersect the "bottom half," so return a success but without an
909            // actual reservation.
910            Ok(ReservationVmar(None))
911        }
912    }
913
914    /// Destroy the reservation. The reservation is also automatically destroyed when
915    /// ReservationVmar is dropped.
916    ///
917    /// VMARs are not destroyed when the handle is closed (by dropping), so we must explicit destroy
918    /// it to release the reservation and allow the created process to use the full address space.
919    fn destroy(&mut self) -> Result<(), zx::Status> {
920        match self.0.take() {
921            Some(vmar) => {
922                // This is safe because there are no mappings in the region and it is not a region
923                // in the current process.
924                unsafe { vmar.destroy() }
925            }
926            None => Ok(()),
927        }
928    }
929}
930
931// This is probably unnecessary, but it feels wrong to rely on the side effect of the process's
932// root VMAR going away. We explicitly call destroy if ProcessBuilder.build() succeeds and returns
933// a BuiltProcess, in which case this will do nothing, and if build() fails then the new process
934// and its root VMAR will get cleaned up along with this sub-VMAR.
935impl Drop for ReservationVmar {
936    fn drop(&mut self) {
937        _ = self.destroy();
938    }
939}
940
941#[cfg(test)]
942mod tests {
943    use super::*;
944    use anyhow::Error;
945    use assert_matches::assert_matches;
946    use fidl::prelude::*;
947    use fidl_test_processbuilder::{UtilMarker, UtilProxy};
948    use lazy_static::lazy_static;
949    use vfs::file::vmo::read_only;
950    use vfs::pseudo_directory;
951    use zerocopy::Ref;
952    use {fidl_fuchsia_io as fio, fuchsia_async as fasync};
953
954    extern "C" {
955        fn dl_clone_loader_service(handle: *mut zx::sys::zx_handle_t) -> zx::sys::zx_status_t;
956    }
957
958    fn get_system_vdso_vmo() -> Result<zx::Vmo, ProcessBuilderError> {
959        lazy_static! {
960            static ref VDSO_VMO: zx::Vmo = {
961                zx::Vmo::from(
962                    fuchsia_runtime::take_startup_handle(HandleInfo::new(HandleType::VdsoVmo, 0))
963                        .expect("Failed to take VDSO VMO startup handle"),
964                )
965            };
966        }
967
968        let vdso_dup = VDSO_VMO
969            .duplicate_handle(zx::Rights::SAME_RIGHTS)
970            .map_err(|s| ProcessBuilderError::GenericStatus("Failed to dup vDSO VMO handle", s))?;
971        Ok(vdso_dup)
972    }
973
974    // Clone the current loader service to provide to the new test processes.
975    fn clone_loader_service() -> Result<ClientEnd<fldsvc::LoaderMarker>, zx::Status> {
976        let mut raw = 0;
977        let status = unsafe { dl_clone_loader_service(&mut raw) };
978        zx::Status::ok(status)?;
979
980        let handle = unsafe { zx::Handle::from_raw(raw) };
981        Ok(ClientEnd::new(zx::Channel::from(handle)))
982    }
983
984    fn connect_util(client: &zx::Channel) -> Result<UtilProxy, Error> {
985        let (proxy, server) = zx::Channel::create();
986        fdio::service_connect_at(&client, UtilMarker::PROTOCOL_NAME, server)
987            .context("failed to connect to util service")?;
988        Ok(UtilProxy::from_channel(fasync::Channel::from_channel(proxy)))
989    }
990
991    fn create_test_util_builder() -> Result<ProcessBuilder, Error> {
992        const TEST_UTIL_BIN: &'static str = "/pkg/bin/process_builder_test_util";
993        let file = fdio::open_fd(TEST_UTIL_BIN, fio::PERM_READABLE | fio::PERM_EXECUTABLE)?;
994        let vmo = fdio::get_vmo_exec_from_file(&file)?;
995        let job = fuchsia_runtime::job_default();
996
997        let procname = CString::new(TEST_UTIL_BIN.to_owned())?;
998        Ok(ProcessBuilder::new(
999            &procname,
1000            &job,
1001            zx::ProcessOptions::empty(),
1002            vmo,
1003            get_system_vdso_vmo().unwrap(),
1004        )?)
1005    }
1006
1007    // Common builder setup for all tests that start a test util process.
1008    fn setup_test_util_builder(set_loader: bool) -> Result<(ProcessBuilder, UtilProxy), Error> {
1009        let mut builder = create_test_util_builder()?;
1010        if set_loader {
1011            builder.add_handles(vec![process_args::StartupHandle {
1012                handle: clone_loader_service()?.into_handle(),
1013                info: HandleInfo::new(HandleType::LdsvcLoader, 0),
1014            }])?;
1015        }
1016
1017        let (dir_client, dir_server) = zx::Channel::create();
1018        builder.add_handles(vec![process_args::StartupHandle {
1019            handle: dir_server.into_handle(),
1020            info: HandleInfo::new(HandleType::DirectoryRequest, 0),
1021        }])?;
1022
1023        let proxy = connect_util(&dir_client)?;
1024        Ok((builder, proxy))
1025    }
1026
1027    fn check_process_running(process: &zx::Process) -> Result<(), Error> {
1028        let info = process.info()?;
1029        const STARTED: u32 = zx::ProcessInfoFlags::STARTED.bits();
1030        assert_matches!(
1031            info,
1032            zx::ProcessInfo {
1033                return_code: 0,
1034                start_time,
1035                flags: STARTED,
1036            } if start_time > 0
1037        );
1038        Ok(())
1039    }
1040
1041    async fn check_process_exited_ok(process: &zx::Process) -> Result<(), Error> {
1042        fasync::OnSignals::new(process, zx::Signals::PROCESS_TERMINATED).await?;
1043
1044        let info = process.info()?;
1045        const STARTED_AND_EXITED: u32 =
1046            zx::ProcessInfoFlags::STARTED.bits() | zx::ProcessInfoFlags::EXITED.bits();
1047        assert_matches!(
1048            info,
1049            zx::ProcessInfo {
1050                return_code: 0,
1051                start_time,
1052                flags: STARTED_AND_EXITED,
1053            } if start_time > 0
1054        );
1055        Ok(())
1056    }
1057
1058    // These start_util_with_* tests cover the most common paths through ProcessBuilder and
1059    // exercise most of its functionality. They verify that we can create a new process for a
1060    // "standard" dynamically linked executable and that we can provide arguments, environment
1061    // variables, namespace entries, and other handles to it through the startup process_args
1062    // message. The test communicates with the test util process it creates over a test-only FIDL
1063    // API to verify that arguments and whatnot were passed correctly.
1064    #[fasync::run_singlethreaded(test)]
1065    async fn start_util_with_args() -> Result<(), Error> {
1066        let test_args = vec!["arg0", "arg1", "arg2"];
1067        let test_args_cstr =
1068            test_args.iter().map(|&s| CString::new(s)).collect::<Result<_, _>>()?;
1069
1070        let (mut builder, proxy) = setup_test_util_builder(true)?;
1071        builder.add_arguments(test_args_cstr);
1072        let process = builder.build().await?.start()?;
1073        check_process_running(&process)?;
1074
1075        // Use the util protocol to confirm that the new process was set up correctly. A successful
1076        // connection to the util validates that handles are passed correctly to the new process,
1077        // since the DirectoryRequest handle made it.
1078        let proc_args = proxy.get_arguments().await.context("failed to get args from util")?;
1079        assert_eq!(proc_args, test_args);
1080
1081        mem::drop(proxy);
1082        check_process_exited_ok(&process).await?;
1083        Ok(())
1084    }
1085
1086    #[fasync::run_singlethreaded(test)]
1087    async fn start_util_with_huge_args() -> Result<(), Error> {
1088        // This test is partially designed to probe the stack usage of
1089        // code processing the initial loader message. Such processing
1090        // is on a stack of limited size, a few pages, and well
1091        // smaller than a maximally large channel packet. Each
1092        // instance of "arg" takes 4 bytes (counting the separating
1093        // '\0' byte), so let's send 10k of them to be well larger
1094        // than the initial stack but well within the 64k channel size.
1095        let test_args = vec!["arg"; 10 * 1000];
1096        let test_args_cstr =
1097            test_args.iter().map(|&s| CString::new(s)).collect::<Result<_, _>>()?;
1098
1099        let (mut builder, proxy) = setup_test_util_builder(true)?;
1100        builder.add_arguments(test_args_cstr);
1101        let process = builder.build().await?.start()?;
1102        check_process_running(&process)?;
1103
1104        // Use the util protocol to confirm that the new process was set up correctly. A successful
1105        // connection to the util validates that handles are passed correctly to the new process,
1106        // since the DirectoryRequest handle made it.
1107        // We can't use get_arguments() here because the FIDL response will be bigger than the
1108        // maximum message size[1] and cause the process to crash. Instead, we just check the number
1109        // of environment variables and assume that if that's correct we're good to go.
1110        // Size of each vector entry: (length = 8, pointer = 8) = 16 + (string size = 8) = 24
1111        // Message size = (10k * vector entry size) = 240,000 > 65,536
1112        let proc_args =
1113            proxy.get_argument_count().await.context("failed to get arg count from util")?;
1114
1115        assert_eq!(proc_args, test_args.len() as u64);
1116
1117        mem::drop(proxy);
1118        check_process_exited_ok(&process).await?;
1119        Ok(())
1120    }
1121
1122    // Verify that the lifecycle channel can be passed through the bootstrap
1123    // channel. This test checks by creating a channel, passing it through,
1124    // asking the remote process for the lifecycle channel's koid, and then
1125    // comparing that koid to the one the test recorded.
1126    #[fasync::run_singlethreaded(test)]
1127    async fn start_util_with_lifecycle_channel() -> Result<(), Error> {
1128        let (mut builder, proxy) = setup_test_util_builder(true)?;
1129        let (lifecycle_server, _lifecycle_client) = zx::Channel::create();
1130        let koid = lifecycle_server
1131            .as_handle_ref()
1132            .basic_info()
1133            .expect("error getting server handle info")
1134            .koid
1135            .raw_koid();
1136        builder.add_handles(vec![process_args::StartupHandle {
1137            handle: lifecycle_server.into_handle(),
1138            info: HandleInfo::new(HandleType::Lifecycle, 0),
1139        }])?;
1140        let process = builder.build().await?.start()?;
1141        check_process_running(&process)?;
1142
1143        // Use the util protocol to confirm that the new process received the
1144        // lifecycle channel
1145        let reported_koid =
1146            proxy.get_lifecycle_koid().await.context("failed getting koid from util")?;
1147        assert_eq!(koid, reported_koid);
1148        mem::drop(proxy);
1149        check_process_exited_ok(&process).await?;
1150        Ok(())
1151    }
1152
1153    // Verify that if no lifecycle channel is sent via the bootstrap channel
1154    // that the remote process reports ZX_KOID_INVALID for the channel koid.
1155    #[fasync::run_singlethreaded(test)]
1156    async fn start_util_with_no_lifecycle_channel() -> Result<(), Error> {
1157        let (builder, proxy) = setup_test_util_builder(true)?;
1158        let process = builder.build().await?.start()?;
1159        check_process_running(&process)?;
1160
1161        // Use the util protocol to confirm that the new process received the
1162        // lifecycle channel
1163        let reported_koid =
1164            proxy.get_lifecycle_koid().await.context("failed getting koid from util")?;
1165        assert_eq!(zx::sys::ZX_KOID_INVALID, reported_koid);
1166        mem::drop(proxy);
1167        check_process_exited_ok(&process).await?;
1168        Ok(())
1169    }
1170
1171    #[fasync::run_singlethreaded(test)]
1172    async fn start_util_with_big_stack() -> Result<(), Error> {
1173        let stack_size: usize = zx::system_get_page_size() as usize * 10;
1174
1175        let (mut builder, proxy) = setup_test_util_builder(true)?;
1176        builder.set_min_stack_size(stack_size);
1177        let built = builder.build().await?;
1178        assert!(built.stack_vmo.get_size()? >= stack_size as u64);
1179
1180        let process = built.start()?;
1181        check_process_running(&process)?;
1182        mem::drop(proxy);
1183        check_process_exited_ok(&process).await?;
1184        Ok(())
1185    }
1186
1187    #[fasync::run_singlethreaded(test)]
1188    async fn elf_headers() -> Result<(), Error> {
1189        let (builder, _) = setup_test_util_builder(true)?;
1190        let built = builder.build().await?;
1191        assert!(
1192            built.elf_headers.file_header().phnum
1193                == built.elf_headers.program_headers().len() as u16
1194        );
1195        Ok(())
1196    }
1197
1198    // Verify that a loader service handle is properly handled if passed directly to
1199    // set_loader_service instead of through add_handles. Otherwise this test is identical to
1200    // start_util_with_args.
1201    #[fasync::run_singlethreaded(test)]
1202    async fn set_loader_directly() -> Result<(), Error> {
1203        let test_args = vec!["arg0", "arg1", "arg2"];
1204        let test_args_cstr =
1205            test_args.iter().map(|&s| CString::new(s)).collect::<Result<_, _>>()?;
1206
1207        let (mut builder, proxy) = setup_test_util_builder(false)?;
1208        builder.set_loader_service(clone_loader_service()?)?;
1209        builder.add_arguments(test_args_cstr);
1210        let process = builder.build().await?.start()?;
1211        check_process_running(&process)?;
1212
1213        // Use the util protocol to confirm that the new process was set up correctly. A successful
1214        // connection to the util validates that handles are passed correctly to the new process,
1215        // since the DirectoryRequest handle made it.
1216        let proc_args = proxy.get_arguments().await.context("failed to get args from util")?;
1217        assert_eq!(proc_args, test_args);
1218
1219        mem::drop(proxy);
1220        check_process_exited_ok(&process).await?;
1221        Ok(())
1222    }
1223
1224    // Verify that a vDSO handle is properly handled if passed directly to set_vdso_vmo instead of
1225    // relying on the default value.
1226    // Note: There isn't a great way to tell here whether the vDSO VMO we passed in was used
1227    // instead of the default (because the kernel only allows use of vDSOs that it created for
1228    // security, so we can't make a fake vDSO with a different name or something), so that isn't
1229    // checked explicitly. The failure tests below make sure we don't ignore the provided vDSO VMO
1230    // completely.
1231    #[fasync::run_singlethreaded(test)]
1232    async fn set_vdso_directly() -> Result<(), Error> {
1233        let test_args = vec!["arg0", "arg1", "arg2"];
1234        let test_args_cstr =
1235            test_args.iter().map(|&s| CString::new(s)).collect::<Result<_, _>>()?;
1236
1237        let (mut builder, proxy) = setup_test_util_builder(true)?;
1238        builder.set_vdso_vmo(get_system_vdso_vmo()?);
1239        builder.add_arguments(test_args_cstr);
1240        let process = builder.build().await?.start()?;
1241        check_process_running(&process)?;
1242
1243        // Use the util protocol to confirm that the new process was set up correctly.
1244        let proc_args = proxy.get_arguments().await.context("failed to get args from util")?;
1245        assert_eq!(proc_args, test_args);
1246
1247        mem::drop(proxy);
1248        check_process_exited_ok(&process).await?;
1249        Ok(())
1250    }
1251
1252    // Verify that a vDSO handle is properly handled if passed directly to set_vdso_vmo instead of
1253    // relying on the default value, this time by providing an invalid VMO (something that isn't
1254    // ELF and will fail to parse). This also indirectly tests that the reservation VMAR cleanup
1255    // happens properly by testing a failure after it has been created.
1256    #[fasync::run_singlethreaded(test)]
1257    async fn set_invalid_vdso_directly_fails() -> Result<(), Error> {
1258        let bad_vdso = zx::Vmo::create(1)?;
1259
1260        let (mut builder, _) = setup_test_util_builder(true)?;
1261        builder.set_vdso_vmo(bad_vdso);
1262
1263        let result = builder.build().await;
1264        match result {
1265            Err(ProcessBuilderError::ElfParse(elf_parse::ElfParseError::InvalidFileHeader(_))) => {}
1266            Err(err) => {
1267                panic!("Unexpected error type: {}", err);
1268            }
1269            Ok(_) => {
1270                panic!("Unexpectedly succeeded to build process with invalid vDSO");
1271            }
1272        }
1273        Ok(())
1274    }
1275
1276    // Verify that a vDSO handle is properly handled if passed through add_handles instead of
1277    // relying on the default value, this time by providing an invalid VMO (something that isn't
1278    // ELF and will fail to parse). This also indirectly tests that the reservation VMAR cleanup
1279    // happens properly by testing a failure after it has been created.
1280    #[fasync::run_singlethreaded(test)]
1281    async fn set_invalid_vdso_fails() -> Result<(), Error> {
1282        let bad_vdso = zx::Vmo::create(1)?;
1283
1284        let (mut builder, _) = setup_test_util_builder(true)?;
1285        builder.add_handles(vec![process_args::StartupHandle {
1286            handle: bad_vdso.into_handle(),
1287            info: HandleInfo::new(HandleType::VdsoVmo, 0),
1288        }])?;
1289
1290        let result = builder.build().await;
1291        match result {
1292            Err(ProcessBuilderError::ElfParse(elf_parse::ElfParseError::InvalidFileHeader(_))) => {}
1293            Err(err) => {
1294                panic!("Unexpected error type: {}", err);
1295            }
1296            Ok(_) => {
1297                panic!("Unexpectedly succeeded to build process with invalid vDSO");
1298            }
1299        }
1300        Ok(())
1301    }
1302
1303    #[fasync::run_singlethreaded(test)]
1304    async fn add_additional_vdso() -> Result<(), Error> {
1305        let mut builder = create_test_util_builder()?;
1306        builder.set_loader_service(clone_loader_service()?)?;
1307        builder.add_handles(vec![process_args::StartupHandle {
1308            handle: get_system_vdso_vmo().unwrap().into_handle(),
1309            info: HandleInfo::new(HandleType::VdsoVmo, 1),
1310        }])?;
1311        let built = builder.build().await?;
1312
1313        // Ignore linker message handles.
1314        let mut msg_buf = zx::MessageBuf::new();
1315        built.bootstrap.read(&mut msg_buf)?;
1316
1317        // Validate main message handles.
1318        let mut msg_buf = zx::MessageBuf::new();
1319        built.bootstrap.read(&mut msg_buf)?;
1320        let handle_info = parse_handle_info_from_message(&msg_buf)?
1321            .drain(..)
1322            .filter(|info| info.handle_type() == HandleType::VdsoVmo)
1323            .collect::<Vec<_>>();
1324        assert_eq!(2, handle_info.len());
1325        for (i, info) in handle_info.iter().rev().enumerate() {
1326            assert_eq!(HandleType::VdsoVmo, info.handle_type());
1327            assert_eq!(i as u16, info.arg());
1328        }
1329        Ok(())
1330    }
1331
1332    #[fasync::run_singlethreaded(test)]
1333    async fn start_util_with_env() -> Result<(), Error> {
1334        let test_env = vec![("VAR1", "value2"), ("VAR2", "value2")];
1335        let test_env_cstr = test_env
1336            .iter()
1337            .map(|v| CString::new(format!("{}={}", v.0, v.1)))
1338            .collect::<Result<_, _>>()?;
1339
1340        let (mut builder, proxy) = setup_test_util_builder(true)?;
1341        builder.add_environment_variables(test_env_cstr);
1342        let process = builder.build().await?.start()?;
1343        check_process_running(&process)?;
1344
1345        let proc_env = proxy.get_environment().await.context("failed to get env from util")?;
1346        let proc_env_tuple: Vec<(&str, &str)> =
1347            proc_env.iter().map(|v| (&*v.key, &*v.value)).collect();
1348        assert_eq!(proc_env_tuple, test_env);
1349
1350        mem::drop(proxy);
1351        check_process_exited_ok(&process).await?;
1352        Ok(())
1353    }
1354
1355    #[fasync::run_singlethreaded(test)]
1356    async fn start_util_with_huge_env() -> Result<(), Error> {
1357        // This test is partially designed to probe the stack usage of
1358        // code processing the initial loader message. Such processing
1359        // is on a stack of limited size, a few pages, and well
1360        // smaller than a maximally large channel packet. Each
1361        // instance of "a=b" takes 4 bytes (counting the separating
1362        // '\0' byte), so let's send 10k of them to be well larger
1363        // than the initial stack but well within the 64k channel size.
1364        let test_env = vec!["a=b"; 10 * 1000];
1365        let test_env_cstr = test_env.iter().map(|&s| CString::new(s)).collect::<Result<_, _>>()?;
1366
1367        let (mut builder, proxy) = setup_test_util_builder(true)?;
1368        builder.add_environment_variables(test_env_cstr);
1369        let process = builder.build().await?.start()?;
1370        check_process_running(&process)?;
1371
1372        // We can't use get_environment() here because the FIDL response will be bigger than the
1373        // maximum message size and cause the process to crash. Instead, we just check the number
1374        // of environment variables and assume that if that's correct we're good to go.
1375        let proc_env =
1376            proxy.get_environment_count().await.context("failed to get env from util")?;
1377        assert_eq!(proc_env, test_env.len() as u64);
1378
1379        mem::drop(proxy);
1380        check_process_exited_ok(&process).await?;
1381        Ok(())
1382    }
1383
1384    #[fasync::run_singlethreaded(test)]
1385    async fn start_util_with_namespace_entries() -> Result<(), Error> {
1386        let mut randbuf = [0; 8];
1387        zx::cprng_draw(&mut randbuf);
1388        let test_content1 = format!("test content 1 {}", u64::from_le_bytes(randbuf));
1389        zx::cprng_draw(&mut randbuf);
1390        let test_content2 = format!("test content 2 {}", u64::from_le_bytes(randbuf));
1391
1392        let dir1 = pseudo_directory! {
1393            "test_file1" => read_only(test_content1.clone()),
1394        };
1395        let dir1_client = vfs::directory::serve_read_only(dir1).into_client_end().unwrap();
1396
1397        let dir2 = pseudo_directory! {
1398            "test_file2" => read_only(test_content2.clone()),
1399        };
1400        let dir2_client = vfs::directory::serve_read_only(dir2).into_client_end().unwrap();
1401
1402        let (mut builder, proxy) = setup_test_util_builder(true)?;
1403        builder.add_namespace_entries(vec![
1404            NamespaceEntry { path: CString::new("/dir1")?, directory: dir1_client },
1405            NamespaceEntry { path: CString::new("/dir2")?, directory: dir2_client },
1406        ])?;
1407        let process = builder.build().await?.start()?;
1408        check_process_running(&process)?;
1409
1410        let namespace_dump = proxy.dump_namespace().await.context("failed to dump namespace")?;
1411        assert_eq!(namespace_dump, "/dir1, /dir1/test_file1, /dir2, /dir2/test_file2");
1412
1413        let dir1_contents =
1414            proxy.read_file("/dir1/test_file1").await.context("failed to read file via util")?;
1415        assert_eq!(dir1_contents, test_content1);
1416        let dir2_contents =
1417            proxy.read_file("/dir2/test_file2").await.context("failed to read file via util")?;
1418        assert_eq!(dir2_contents, test_content2);
1419
1420        mem::drop(proxy);
1421        check_process_exited_ok(&process).await?;
1422        Ok(())
1423    }
1424
1425    // Trying to start a dynamically linked process without providing a loader service should
1426    // fail. This verifies that nothing is automatically cloning a loader.
1427    #[fasync::run_singlethreaded(test)]
1428    async fn start_util_with_no_loader_fails() -> Result<(), Error> {
1429        let (builder, _) = setup_test_util_builder(false)?;
1430
1431        let result = builder.build().await;
1432        match result {
1433            Err(ProcessBuilderError::LoaderMissing()) => {}
1434            Err(err) => {
1435                panic!("Unexpected error type: {}", err);
1436            }
1437            Ok(_) => {
1438                panic!("Unexpectedly succeeded to build process without loader");
1439            }
1440        }
1441        Ok(())
1442    }
1443
1444    // Checks that, for dynamically linked binaries, the lower half of the address space has been
1445    // reserved for sanitizers.
1446    #[fasync::run_singlethreaded(test)]
1447    async fn verify_low_address_range_reserved() -> Result<(), Error> {
1448        let (builder, _) = setup_test_util_builder(true)?;
1449        let built = builder.build().await?;
1450
1451        // This ends up being the same thing ReservationVmar does, but it's not reused here so that
1452        // this catches bugs or bad changes to ReservationVmar itself.
1453        let info = built.root_vmar.info()?;
1454        let lower_half_len = util::page_end((info.base + info.len) / 2) - info.base;
1455        built
1456            .root_vmar
1457            .allocate(0, lower_half_len, zx::VmarFlags::SPECIFIC)
1458            .context("Unable to allocate lower address range of new process")?;
1459        Ok(())
1460    }
1461
1462    // Parses the given channel message as a process_args message and returns the HandleInfo's
1463    // contained in it.
1464    fn parse_handle_info_from_message(message: &zx::MessageBuf) -> Result<Vec<HandleInfo>, Error> {
1465        let bytes = message.bytes();
1466        let (header, _) = Ref::<&[u8], process_args::MessageHeader>::from_prefix(bytes)
1467            .map_err(|_| anyhow!("Failed to parse process_args header"))?;
1468
1469        let offset = header.handle_info_off as usize;
1470        let len = mem::size_of::<u32>() * message.n_handles();
1471        let info_bytes = &bytes[offset..offset + len];
1472        let raw_info = Ref::<&[u8], [u32]>::from_bytes(info_bytes)
1473            .map_err(|_| anyhow!("Failed to parse raw handle info"))?;
1474
1475        Ok(raw_info.iter().map(|raw| HandleInfo::try_from(*raw)).collect::<Result<_, _>>()?)
1476    }
1477
1478    const LINKER_MESSAGE_HANDLES: &[HandleType] = &[
1479        HandleType::ProcessSelf,
1480        HandleType::RootVmar,
1481        HandleType::LdsvcLoader,
1482        HandleType::LoadedVmar,
1483        HandleType::ExecutableVmo,
1484    ];
1485
1486    const MAIN_MESSAGE_HANDLES: &[HandleType] = &[
1487        HandleType::ProcessSelf,
1488        HandleType::ThreadSelf,
1489        HandleType::RootVmar,
1490        HandleType::VdsoVmo,
1491        HandleType::StackVmo,
1492    ];
1493
1494    #[fasync::run_singlethreaded(test)]
1495    async fn correct_handles_present() -> Result<(), Error> {
1496        let mut builder = create_test_util_builder()?;
1497        builder.set_loader_service(clone_loader_service()?)?;
1498        let built = builder.build().await?;
1499
1500        for correct in &[LINKER_MESSAGE_HANDLES, MAIN_MESSAGE_HANDLES] {
1501            let mut msg_buf = zx::MessageBuf::new();
1502            built.bootstrap.read(&mut msg_buf)?;
1503            let handle_info = parse_handle_info_from_message(&msg_buf)?;
1504
1505            assert_eq!(handle_info.len(), correct.len());
1506            for correct_type in *correct {
1507                // Should only be one of each of these handles present.
1508                assert_eq!(
1509                    1,
1510                    handle_info.iter().filter(|info| &info.handle_type() == correct_type).count()
1511                );
1512            }
1513        }
1514        Ok(())
1515    }
1516
1517    // Verify that [ProcessBuilder::add_handles()] rejects handle types that are added
1518    // automatically by the builder.
1519    #[fasync::run_singlethreaded(test)]
1520    async fn add_handles_rejects_automatic_handle_types() -> Result<(), Error> {
1521        // The VMO doesn't need to be valid since we're not calling build.
1522        let vmo = zx::Vmo::create(1)?;
1523        let job = fuchsia_runtime::job_default();
1524        let procname = CString::new("test_vmo")?;
1525        let mut builder = ProcessBuilder::new(
1526            &procname,
1527            &job,
1528            zx::ProcessOptions::empty(),
1529            vmo,
1530            get_system_vdso_vmo().unwrap(),
1531        )?;
1532
1533        // There's some duplicates between these slices but just checking twice is easier than
1534        // deduping these.
1535        for handle_type in LINKER_MESSAGE_HANDLES.iter().chain(MAIN_MESSAGE_HANDLES) {
1536            if *handle_type == HandleType::LdsvcLoader {
1537                // Skip LdsvcLoader, which is required in the linker message but is not added
1538                // automatically. The user must supply it.
1539                continue;
1540            }
1541
1542            if *handle_type == HandleType::VdsoVmo {
1543                // Skip VdsoVmo, which may be supplied by the user.
1544                continue;
1545            }
1546
1547            // Another VMO, just to have a valid handle.
1548            let vmo = zx::Vmo::create(1)?;
1549            let result = builder.add_handles(vec![process_args::StartupHandle {
1550                handle: vmo.into_handle(),
1551                info: HandleInfo::new(*handle_type, 0),
1552            }]);
1553            match result {
1554                Err(ProcessBuilderError::InvalidArg(_)) => {}
1555                Err(err) => {
1556                    panic!("Unexpected error type, should be invalid arg: {}", err);
1557                }
1558                Ok(_) => {
1559                    panic!("add_handle unexpectedly succeeded for type {:?}", handle_type);
1560                }
1561            }
1562        }
1563        Ok(())
1564    }
1565
1566    // Verify that invalid handles are correctly rejected.
1567    #[fasync::run_singlethreaded(test)]
1568    async fn rejects_invalid_handles() -> Result<(), Error> {
1569        let invalid = || zx::Handle::invalid();
1570        let assert_invalid_arg = |result| match result {
1571            Err(ProcessBuilderError::BadHandle(_)) => {}
1572            Err(err) => {
1573                panic!("Unexpected error type, should be BadHandle: {}", err);
1574            }
1575            Ok(_) => {
1576                panic!("API unexpectedly accepted invalid handle");
1577            }
1578        };
1579
1580        // The VMO doesn't need to be valid since we're not calling build with this.
1581        let vmo = zx::Vmo::create(1)?;
1582        let job = fuchsia_runtime::job_default();
1583        let procname = CString::new("test_vmo")?;
1584
1585        assert_invalid_arg(
1586            ProcessBuilder::new(
1587                &procname,
1588                &invalid().into(),
1589                zx::ProcessOptions::empty(),
1590                vmo,
1591                get_system_vdso_vmo().unwrap(),
1592            )
1593            .map(|_| ()),
1594        );
1595        assert_invalid_arg(
1596            ProcessBuilder::new(
1597                &procname,
1598                &job,
1599                zx::ProcessOptions::empty(),
1600                invalid().into(),
1601                get_system_vdso_vmo().unwrap(),
1602            )
1603            .map(|_| ()),
1604        );
1605
1606        let (mut builder, _) = setup_test_util_builder(true)?;
1607
1608        assert_invalid_arg(builder.set_loader_service(invalid().into()));
1609        assert_invalid_arg(builder.add_handles(vec![process_args::StartupHandle {
1610            handle: invalid().into(),
1611            info: HandleInfo::new(HandleType::User0, 0),
1612        }]));
1613        assert_invalid_arg(builder.add_handles(vec![process_args::StartupHandle {
1614            handle: invalid().into(),
1615            info: HandleInfo::new(HandleType::User0, 0),
1616        }]));
1617        assert_invalid_arg(builder.add_namespace_entries(vec![NamespaceEntry {
1618            path: CString::new("/dir")?,
1619            directory: invalid().into(),
1620        }]));
1621
1622        Ok(())
1623    }
1624
1625    #[fasync::run_singlethreaded]
1626    #[test]
1627    async fn start_static_pie_binary() -> Result<(), Error> {
1628        const TEST_BIN: &'static str = "/pkg/bin/static_pie_test_util";
1629        let file = fdio::open_fd(TEST_BIN, fio::PERM_READABLE | fio::PERM_EXECUTABLE)?;
1630        let vmo = fdio::get_vmo_exec_from_file(&file)?;
1631        let job = fuchsia_runtime::job_default();
1632
1633        let procname = CString::new(TEST_BIN.to_owned())?;
1634        let mut builder = ProcessBuilder::new(
1635            &procname,
1636            &job,
1637            zx::ProcessOptions::empty(),
1638            vmo,
1639            get_system_vdso_vmo().unwrap(),
1640        )?;
1641
1642        // We pass the program a channel with handle type User0 which we send a message on and
1643        // expect it to echo back the message on the same channel.
1644        let (local, remote) = zx::Channel::create();
1645        builder.add_handles(vec![process_args::StartupHandle {
1646            handle: remote.into_handle(),
1647            info: HandleInfo::new(HandleType::User0, 0),
1648        }])?;
1649
1650        let mut randbuf = [0; 8];
1651        zx::cprng_draw(&mut randbuf);
1652        let test_message = format!("test content 1 {}", u64::from_le_bytes(randbuf)).into_bytes();
1653        local.write(&test_message, &mut vec![])?;
1654
1655        // Start process and wait for channel to have a message to read or be closed.
1656        builder.build().await?.start()?;
1657        let signals = fasync::OnSignals::new(
1658            &local,
1659            zx::Signals::CHANNEL_READABLE | zx::Signals::CHANNEL_PEER_CLOSED,
1660        )
1661        .await?;
1662        assert!(signals.contains(zx::Signals::CHANNEL_READABLE));
1663
1664        let mut echoed = zx::MessageBuf::new();
1665        local.read(&mut echoed)?;
1666        assert_eq!(echoed.bytes(), test_message.as_slice());
1667        assert_eq!(echoed.n_handles(), 0);
1668        Ok(())
1669    }
1670}