Skip to main content

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, process_args, util};
6use anyhow::{Context, anyhow};
7use fidl::endpoints::{ClientEnd, Proxy};
8use fidl_fuchsia_io as fio;
9use fidl_fuchsia_ldsvc as fldsvc;
10use fuchsia_async::{self as fasync, TimeoutExt};
11use fuchsia_runtime::{HandleInfo, HandleType};
12use futures::prelude::*;
13use std::ffi::{CStr, CString};
14use std::{iter, mem};
15use thiserror::Error;
16use zx::AsHandleRef;
17
18/// Error type returned by ProcessBuilder methods.
19#[derive(Error, Debug)]
20pub enum ProcessBuilderError {
21    #[error("{}", _0)]
22    InvalidArg(String),
23    #[error("{}", _0)]
24    BadHandle(&'static str),
25    #[error("Failed to create process: {}", _0)]
26    CreateProcess(zx::Status),
27    #[error("Failed to create thread: {}", _0)]
28    CreateThread(zx::Status),
29    #[error("Failed to start process: {}", _0)]
30    ProcessStart(zx::Status),
31    #[error("Failed to parse ELF: {}", _0)]
32    ElfParse(#[from] elf_parse::ElfParseError),
33    #[error("Failed to load ELF: {}", _0)]
34    ElfLoad(#[from] elf_load::ElfLoadError),
35    #[error("{}", _0)]
36    ProcessArgs(#[from] process_args::ProcessargsError),
37    #[error("{}: {}", _0, _1)]
38    GenericStatus(&'static str, zx::Status),
39    #[error("{}: {}", _0, _1)]
40    Internal(&'static str, #[source] anyhow::Error),
41    #[error("Invalid PT_INTERP header: {}", _0)]
42    InvalidInterpHeader(#[source] anyhow::Error),
43    #[error("Failed to build process with dynamic ELF, missing fuchsia.ldsvc.Loader handle")]
44    LoaderMissing(),
45    #[error("Failed to load dynamic linker from fuchsia.ldsvc.Loader: {}", _0)]
46    LoadDynamicLinker(#[source] fidl::Error),
47    #[error("Timed out loading dynamic linker from fuchsia.ldsvc.Loader")]
48    LoadDynamicLinkerTimeout(),
49    #[error("Failed to write bootstrap message to channel: {}", _0)]
50    WriteBootstrapMessage(zx::Status),
51    #[error("Failed to destroy reservation VMAR: {}", _0)]
52    DestroyReservationVMAR(zx::Status),
53    #[error("Failed to duplicate handle of type {:?}: {}", _0, _1)]
54    DuplicateHandle(HandleType, zx::Status),
55}
56
57impl ProcessBuilderError {
58    /// Returns an appropriate zx::Status code for the given error.
59    pub fn as_zx_status(&self) -> zx::Status {
60        match self {
61            ProcessBuilderError::InvalidArg(_)
62            | ProcessBuilderError::InvalidInterpHeader(_)
63            | ProcessBuilderError::LoaderMissing() => zx::Status::INVALID_ARGS,
64            ProcessBuilderError::BadHandle(_) => zx::Status::BAD_HANDLE,
65            ProcessBuilderError::CreateProcess(s)
66            | ProcessBuilderError::CreateThread(s)
67            | ProcessBuilderError::ProcessStart(s)
68            | ProcessBuilderError::GenericStatus(_, s)
69            | ProcessBuilderError::WriteBootstrapMessage(s)
70            | ProcessBuilderError::DestroyReservationVMAR(s) => *s,
71            ProcessBuilderError::ElfParse(e) => e.as_zx_status(),
72            ProcessBuilderError::ElfLoad(e) => e.as_zx_status(),
73            ProcessBuilderError::ProcessArgs(e) => e.as_zx_status(),
74            ProcessBuilderError::Internal(_, _) => zx::Status::INTERNAL,
75            ProcessBuilderError::LoadDynamicLinker(_) => zx::Status::NOT_FOUND,
76            ProcessBuilderError::LoadDynamicLinkerTimeout() => zx::Status::TIMED_OUT,
77            ProcessBuilderError::DuplicateHandle(_, s) => *s,
78        }
79    }
80}
81
82/// A container for a single namespace entry, containing a path and a directory handle. Used as an
83/// input to [ProcessBuilder::add_namespace_entries()].
84pub struct NamespaceEntry {
85    /// Namespace path.
86    pub path: CString,
87
88    /// Namespace directory handle.
89    pub directory: ClientEnd<fio::DirectoryMarker>,
90}
91
92/// The main builder type for this crate. Collects inputs and creates a new process.
93///
94/// See top-level crate documentation for a usage example.
95pub struct ProcessBuilder {
96    /// The ELF binary for the new process.
97    executable: zx::Vmo,
98    /// The fuchsia.ldsvc.Loader service to use for the new process, if dynamically linked.
99    ldsvc: Option<fldsvc::LoaderProxy>,
100    /// A non-default vDSO to use for the new process, if any.
101    non_default_vdso: Option<zx::Vmo>,
102    /// The contents of the main process_args message to be sent to the new process.
103    msg_contents: process_args::MessageContents,
104    /// Handles that are common to both the linker and main process_args messages, wrapped in an
105    /// inner struct for code organization and clarity around borrows.
106    common: CommonMessageHandles,
107    /// Minimum size of the stack for the new process, in bytes.
108    min_stack_size: usize,
109    /// The default system vDSO.
110    system_vdso_vmo: zx::Vmo,
111}
112
113struct CommonMessageHandles {
114    process: zx::Process,
115    thread: zx::Thread,
116    root_vmar: zx::Vmar,
117}
118
119/// A container for a fully built but not yet started (as in, its initial thread is not yet
120/// running) process, with all related handles and metadata. Output of [ProcessBuilder::build()].
121///
122/// You can use this struct to start the process with [BuiltProcess::start()], which is a simple
123/// wrapper around the [zx_process_start] syscall. You can optionally use the handles and
124/// information in this struct to manipulate the process or its address space before starting it,
125/// such as when creating a process in a debugger.
126///
127/// [zx_process_start]: https://fuchsia.dev/fuchsia-src/reference/syscalls/process_start.md
128pub struct BuiltProcess {
129    /// The newly created process.
130    pub process: zx::Process,
131
132    /// The root VMAR for the created process.
133    pub root_vmar: zx::Vmar,
134
135    /// The process's initial thread.
136    pub thread: zx::Thread,
137
138    /// The process's entry point.
139    pub entry: usize,
140
141    /// The initial thread's stack pointer.
142    pub stack: usize,
143
144    /// The base address of the stack for the initial thread.
145    pub stack_base: usize,
146
147    /// The VMO of the stack for the initial thread.
148    pub stack_vmo: zx::Vmo,
149
150    /// The bootstrap channel, to be passed to the process on start as arg1 in zx_process_start /
151    /// zx::Process::start.
152    pub bootstrap: zx::Channel,
153
154    /// The base address of the VDSO in the process's VMAR, to be passed to the process on start as
155    /// arg2 in zx_process_start / zx::Process::start.
156    pub vdso_base: usize,
157
158    /// The base address where the ELF executable, or the dynamic linker if the ELF was dynamically
159    /// linked, was loaded in the process's VMAR.
160    pub elf_base: usize,
161
162    /// The ELF headers of the main module of the newly created process.
163    pub elf_headers: elf_parse::Elf64Headers,
164}
165
166struct StackInfo {
167    /// The initial thread's stack pointer.
168    pub stack_ptr: usize,
169
170    /// The base address of the stack for the initial thread.
171    pub stack_base: usize,
172
173    /// The VMO of the stack for the initial thread.
174    pub stack_vmo: zx::Vmo,
175}
176
177impl ProcessBuilder {
178    /// Create a new ProcessBuilder that can be used to create a new process under the given job
179    /// with the given name and ELF64 executable (as a VMO).
180    ///
181    /// This job is only used to create the process and thus is not taken ownership of. To provide
182    /// a default job handle to be passed to the new process, use [ProcessBuilder::add_handles()]
183    /// with [HandleType::DefaultJob].
184    ///
185    /// The provided VMO must have the [zx::Rights::EXECUTE] right.
186    ///
187    /// # Errors
188    ///
189    /// Returns Err([ProcessBuilderError::CreateProcess]) if process creation fails, such as if the
190    /// process using this is disallowed direct process creation rights through job policy. See
191    /// top-level crate documentation for more details.
192    pub fn new(
193        name: &CStr,
194        job: &zx::Job,
195        options: zx::ProcessOptions,
196        executable: zx::Vmo,
197        system_vdso_vmo: zx::Vmo,
198    ) -> Result<ProcessBuilder, ProcessBuilderError> {
199        if job.is_invalid() {
200            return Err(ProcessBuilderError::BadHandle("Invalid job handle"));
201        }
202        if executable.is_invalid() {
203            return Err(ProcessBuilderError::BadHandle("Invalid executable handle"));
204        }
205
206        // Creating the process immediately has the benefit that we fail fast if the calling
207        // process does not have permission to create processes directly.
208        let (process, root_vmar) = job
209            .create_child_process(options, name.to_bytes())
210            .map_err(ProcessBuilderError::CreateProcess)?;
211
212        // Create the initial thread.
213        let thread =
214            process.create_thread(b"initial-thread").map_err(ProcessBuilderError::CreateThread)?;
215
216        // Add duplicates of the process, VMAR, and thread handles to the bootstrap message.
217        let msg_contents = process_args::MessageContents::default();
218        let mut pb = ProcessBuilder {
219            executable,
220            ldsvc: None,
221            non_default_vdso: None,
222            msg_contents,
223            common: CommonMessageHandles { process, thread, root_vmar },
224            min_stack_size: 0,
225            system_vdso_vmo,
226        };
227        pb.common.add_process_self(&mut pb.msg_contents)?;
228        pb.common.add_thread_self(&mut pb.msg_contents)?;
229        pb.common.add_root_vmar(&mut pb.msg_contents)?;
230        Ok(pb)
231    }
232
233    /// Sets the fuchsia.ldsvc.Loader service for the process.
234    ///
235    /// The loader service is used to load dynamic libraries if the executable is a dynamically
236    /// linked ELF file (i.e. if it contains a PT_INTERP header), and is required for such
237    /// executables. It will only be provided to the new process in this case. Otherwise, it is
238    /// unused and has no effect.
239    ///
240    /// If no loader service has been provided and it is needed, process creation will fail. Note
241    /// that this differs from the automatic fallback behavior of previous process creation
242    /// libraries, which would clone the loader of the current process. This fallback is likely to
243    /// fail in subtle and confusing ways. An appropriate loader service that has access to the
244    /// libraries or interpreter must be provided.
245    ///
246    /// Note that [ProcessBuilder::add_handles()] will automatically pass a handle with type
247    /// [HandleType::LdsvcLoader] to this function.
248    ///
249    /// If called multiple times (e.g. if a loader was initially provided through
250    /// [ProcessBuilder::add_handles()] and you want to replace it), the new loader replaces the
251    /// previous and the handle to the previous loader is dropped.
252    pub fn set_loader_service(
253        &mut self,
254        ldsvc: ClientEnd<fldsvc::LoaderMarker>,
255    ) -> Result<(), ProcessBuilderError> {
256        if ldsvc.as_handle_ref().is_invalid() {
257            return Err(ProcessBuilderError::BadHandle("Invalid loader service handle"));
258        }
259        self.ldsvc = Some(ldsvc.into_proxy());
260        Ok(())
261    }
262
263    /// Sets the vDSO VMO for the process.
264    pub fn set_vdso_vmo(&mut self, vdso: zx::Vmo) {
265        self.non_default_vdso = Some(vdso);
266    }
267
268    /// Add arguments to the process's bootstrap message. Successive calls append (not replace)
269    /// arguments.
270    pub fn add_arguments(&mut self, mut args: Vec<CString>) {
271        self.msg_contents.args.append(&mut args);
272    }
273
274    /// Add environment variables to the process's bootstrap message. Successive calls append (not
275    /// replace) environment variables.
276    pub fn add_environment_variables(&mut self, mut vars: Vec<CString>) {
277        self.msg_contents.environment_vars.append(&mut vars);
278    }
279
280    /// Set the minimum size of the stack for the new process, in bytes.
281    pub fn set_min_stack_size(&mut self, size: usize) {
282        self.min_stack_size = size;
283    }
284
285    /// Add handles to the process's bootstrap message. Successive calls append (not replace)
286    /// handles.
287    ///
288    /// Each [process_args::StartupHandle] contains a [zx::NullableHandle] object accompanied by a [HandleInfo] object
289    /// that includes the handle type and a type/context-dependent argument.
290    ///
291    /// A [HandleType::LdsvcLoader] handle will automatically be passed along to
292    /// [ProcessBuilder::set_loader_service()] if provided through this function.
293    ///
294    /// # Errors
295    ///
296    /// [HandleType::NamespaceDirectory] handles should not be added through this function since
297    /// they must be accompanied with a path. Use [ProcessBuilder::add_namespace_entries()] for
298    /// that instead.
299    ///
300    /// The following handle types cannot be added through this, as they are added automatically by
301    /// the ProcessBuilder:
302    /// * [HandleType::ProcessSelf]
303    /// * [HandleType::ThreadSelf]
304    /// * [HandleType::RootVmar]
305    /// * [HandleType::LoadedVmar]
306    /// * [HandleType::StackVmo]
307    /// * [HandleType::ExecutableVmo]
308    pub fn add_handles(
309        &mut self,
310        startup_handles: Vec<process_args::StartupHandle>,
311    ) -> Result<(), ProcessBuilderError> {
312        // Do a bit of validation before adding to the bootstrap handles.
313        for h in &startup_handles {
314            if h.handle.is_invalid() {
315                return Err(ProcessBuilderError::BadHandle("Invalid handle in startup handles"));
316            }
317
318            let t = h.info.handle_type();
319            match t {
320                HandleType::NamespaceDirectory => {
321                    return Err(ProcessBuilderError::InvalidArg(
322                        "Cannot add NamespaceDirectory handles directly, use add_namespace_entries"
323                            .into(),
324                    ));
325                }
326                HandleType::ProcessSelf
327                | HandleType::ThreadSelf
328                | HandleType::RootVmar
329                | HandleType::LoadedVmar
330                | HandleType::StackVmo
331                | HandleType::ExecutableVmo => {
332                    return Err(ProcessBuilderError::InvalidArg(format!(
333                        "Cannot add a {:?} handle directly, it will be automatically added",
334                        t,
335                    )));
336                }
337                _ => {}
338            }
339        }
340
341        // Intentionally separate from validation so that we don't partially add namespace entries.
342        for h in startup_handles {
343            match h.info.handle_type() {
344                HandleType::LdsvcLoader => {
345                    // Automatically pass this to |set_loader_service| instead.
346                    self.set_loader_service(ClientEnd::from(h.handle))?;
347                }
348                HandleType::VdsoVmo => {
349                    if h.info.arg() == 0 {
350                        self.set_vdso_vmo(h.handle.into());
351                    } else {
352                        // Pass any additional vDSOs.
353                        self.msg_contents.handles.push(h);
354                    }
355                }
356                _ => {
357                    self.msg_contents.handles.push(h);
358                }
359            }
360        }
361        Ok(())
362    }
363
364    /// Add directories to the process's namespace.
365    ///
366    /// Successive calls append new namespace entries, not replace previous entries.
367    ///
368    /// Each [NamespaceEntry] contains a client connection to a fuchsia.io.Directory FIDL service
369    /// and a path to add that directory to the process's namespace as.
370    ///
371    /// # Errors
372    ///
373    /// Returns Err([ProcessBuilderError::InvalidArg]) if the maximum number of namespace entries
374    /// (2^16) was reached and the entry could not be added. This is exceedingly unlikely, and most
375    /// likely if you are anywhere near this limit [ProcessBuilder::build()] will fail because the
376    /// process's process_args startup message is over its own length limit.
377    pub fn add_namespace_entries(
378        &mut self,
379        mut entries: Vec<NamespaceEntry>,
380    ) -> Result<(), ProcessBuilderError> {
381        // Namespace entries are split into a namespace path, that is included in the bootstrap
382        // message (as the so-called "namespace table"), plus a NamespaceDirectory handle, where the arg
383        // value is the index of the path in the namespace table.
384        //
385        // Check that the namespace table doesn't exceed 2^16 entries, since the HandleInfo arg is
386        // only 16-bits. Realistically this will never matter - if you're anywhere near this
387        // many entries, you're going to exceed the bootstrap message length limit - but Rust
388        // encourages us (and makes it easy) to be safe about the edge case here.
389        let mut idx = u16::try_from(self.msg_contents.namespace_paths.len())
390            .expect("namespace_paths.len should never be larger than a u16");
391        let num_entries = u16::try_from(entries.len())
392            .map_err(|_| ProcessBuilderError::InvalidArg("Too many namespace entries".into()))?;
393        if idx.checked_add(num_entries).is_none() {
394            return Err(ProcessBuilderError::InvalidArg(
395                "Can't add namespace entries, limit reached".into(),
396            ));
397        }
398
399        for entry in &entries {
400            if entry.directory.as_handle_ref().is_invalid() {
401                return Err(ProcessBuilderError::BadHandle("Invalid handle in namespace entry"));
402            }
403        }
404
405        // Intentionally separate from validation so that we don't partially add namespace entries=
406        for entry in entries.drain(..) {
407            self.msg_contents.namespace_paths.push(entry.path);
408            self.msg_contents.handles.push(process_args::StartupHandle {
409                handle: entry.directory.into(),
410                info: HandleInfo::new(HandleType::NamespaceDirectory, idx),
411            });
412            idx += 1;
413        }
414        Ok(())
415    }
416
417    /// Build the new process using the data and handles provided to the ProcessBuilder.
418    ///
419    /// The return value of this function is a [BuiltProcess] struct which contains the new process
420    /// and all the handles and data needed to start it, but the process' initial thread is not yet
421    /// started. Use [BuiltProcess::start()] or the [zx_process_start] syscall to actually start
422    /// it.
423    ///
424    /// # Errors
425    ///
426    /// There are many errors that could result during process loading and only some are listed
427    /// here. See [ProcessBuilderError] for the various error types that can be returned.
428    ///
429    /// Returns Err([ProcessBuilderError::LoaderMissing]) if the ELF executable is dynamically
430    /// linked (has a PT_INTERP program header) but no loader service has been provided through
431    /// [ProcessBuilder::set_loader_service()] or [ProcessBuilder::add_handles()].
432    ///
433    /// [zx_process_start]: https://fuchsia.dev/fuchsia-src/reference/syscalls/process_start.md
434    pub async fn build(mut self) -> Result<BuiltProcess, ProcessBuilderError> {
435        // Parse the executable as an ELF64 file, reading in the headers we need. Done first since
436        // this is most likely to be invalid and error out.
437        let elf_headers = elf_parse::Elf64Headers::from_vmo(&self.executable)?;
438
439        // Create bootstrap message channel.
440        let (bootstrap_rd, bootstrap_wr) = zx::Channel::create();
441
442        // Check if main executable is dynamically linked, and handle appropriately.
443        let loaded_elf;
444        let mut reserve_vmar = None;
445        let dynamic;
446        if let Some(interp_hdr) =
447            elf_headers.program_header_with_type(elf_parse::SegmentType::Interp)?
448        {
449            // Dynamically linked so defer loading the main executable to the dynamic
450            // linker/loader, which we load here instead.
451            dynamic = true;
452
453            // Check that a ldsvc.Loader service was provided.
454            let ldsvc = self.ldsvc.take().ok_or(ProcessBuilderError::LoaderMissing())?;
455
456            // A process using PT_INTERP might be loading a libc.so that supports sanitizers;
457            // reserve the low address region for sanitizers to allocate shadow memory.
458            //
459            // The reservation VMAR ensures that the initial allocations & mappings made in this
460            // function stay out of this area. It is destroyed below before returning and the
461            // process's own allocations can use the full address space.
462            //
463            // !! WARNING: This makes a specific address VMAR allocation, so it must come before
464            // any elf_load::load_elf calls. !!
465            reserve_vmar =
466                Some(ReservationVmar::reserve_low_address_space(&self.common.root_vmar)?);
467
468            // Get the dynamic linker and map it into the process's address space.
469            let ld_vmo = get_dynamic_linker(&ldsvc, &self.executable, interp_hdr).await?;
470            let ld_headers = elf_parse::Elf64Headers::from_vmo(&ld_vmo)?;
471            loaded_elf = elf_load::load_elf(&ld_vmo, &ld_headers, &self.common.root_vmar)?;
472
473            // Build the dynamic linker bootstrap message and write it to the bootstrap channel.
474            // This message is written before the primary bootstrap message since it is consumed
475            // first in the dynamic linker.
476            let executable =
477                mem::replace(&mut self.executable, zx::NullableHandle::invalid().into());
478            let msg = self.build_linker_message(ldsvc, executable, loaded_elf.vmar)?;
479            msg.write(&bootstrap_wr).map_err(ProcessBuilderError::WriteBootstrapMessage)?;
480        } else {
481            // Statically linked but still position-independent (ET_DYN) ELF, load directly.
482            dynamic = false;
483
484            loaded_elf =
485                elf_load::load_elf(&self.executable, &elf_headers, &self.common.root_vmar)?;
486            self.msg_contents.handles.push(process_args::StartupHandle {
487                handle: loaded_elf.vmar.into_handle(),
488                info: HandleInfo::new(HandleType::LoadedVmar, 0),
489            });
490        }
491
492        // Load the vDSO - either the default system vDSO, or the user-provided one - into the
493        // process's address space and a handle to it to the bootstrap message.
494        let vdso_base = self.load_vdso()?;
495
496        // Calculate initial stack size.
497        let mut stack_size;
498        let stack_vmo_name;
499        if dynamic {
500            // Calculate the initial stack size for the dynamic linker. This factors in the size of
501            // an extra handle for the stack that hasn't yet been added to the message contents,
502            // since creating the stack requires this size.
503            stack_size = calculate_initial_linker_stack_size(&mut self.msg_contents, 1)?;
504            stack_vmo_name = format!("stack: msg of {:#x?}", stack_size);
505        } else {
506            // Set stack size from PT_GNU_STACK header, if present, or use the default. The dynamic
507            // linker handles this for dynamically linked ELFs (above case).
508            const ZIRCON_DEFAULT_STACK_SIZE: usize = 256 << 10; // 256KiB
509            let mut ss = ("default", ZIRCON_DEFAULT_STACK_SIZE);
510            if let Some(stack_hdr) =
511                elf_headers.program_header_with_type(elf_parse::SegmentType::GnuStack)?
512            {
513                if stack_hdr.memsz > 0 {
514                    ss = ("explicit", stack_hdr.memsz as usize);
515                }
516            }
517
518            // Stack size must be page aligned.
519            stack_size = util::page_end(ss.1);
520            stack_vmo_name = format!("stack: {} {:#x?}", ss.0, stack_size);
521        }
522        if stack_size < self.min_stack_size {
523            stack_size = util::page_end(self.min_stack_size);
524        }
525
526        // Allocate the initial thread's stack, map it, and add a handle to the bootstrap message.
527        let stack_vmo_name =
528            zx::Name::new(&stack_vmo_name).expect("Stack VMO name must be less than 31 bytes");
529        let stack_info = self.create_stack(stack_size, &stack_vmo_name)?;
530
531        // Build and send the primary bootstrap message.
532        let msg = process_args::Message::build(self.msg_contents)?;
533        msg.write(&bootstrap_wr).map_err(ProcessBuilderError::WriteBootstrapMessage)?;
534
535        // Explicitly destroy the reservation VMAR before returning so that we can be sure it is
536        // gone (so we don't end up with a process with half its address space gone).
537        if let Some(mut r) = reserve_vmar {
538            r.destroy().map_err(ProcessBuilderError::DestroyReservationVMAR)?;
539        }
540
541        Ok(BuiltProcess {
542            process: self.common.process,
543            root_vmar: self.common.root_vmar,
544            thread: self.common.thread,
545            entry: loaded_elf.entry,
546            stack: stack_info.stack_ptr,
547            stack_base: stack_info.stack_base,
548            stack_vmo: stack_info.stack_vmo,
549            bootstrap: bootstrap_rd,
550            vdso_base: vdso_base,
551            elf_base: loaded_elf.vmar_base,
552            elf_headers,
553        })
554    }
555
556    /// Build the bootstrap message for the dynamic linker, which uses the same process_args
557    /// protocol as the message for the main process but somewhat different contents.
558    ///
559    /// The LoaderProxy provided must be ready to be converted to a Handle with into_channel(). In
560    /// other words, there must be no other active clones of the proxy, no open requests, etc. The
561    /// intention is that the user provides a handle only (perhaps wrapped in a ClientEnd) through
562    /// [ProcessBuilder::set_loader_service()], not a Proxy, so the library can be sure this
563    /// invariant is maintained and a failure is a library bug.
564    fn build_linker_message(
565        &self,
566        ldsvc: fldsvc::LoaderProxy,
567        executable: zx::Vmo,
568        loaded_vmar: zx::Vmar,
569    ) -> Result<process_args::Message, ProcessBuilderError> {
570        // Don't need to use the ldsvc.Loader anymore; turn it back into into a raw handle so
571        // we can pass it along in the dynamic linker bootstrap message.
572        let ldsvc_hnd =
573            ldsvc.into_channel().expect("Failed to get channel from LoaderProxy").into_zx_channel();
574
575        // The linker message only needs a subset of argv and envvars.
576        let args = extract_ld_arguments(&self.msg_contents.args);
577        let environment_vars =
578            extract_ld_environment_variables(&self.msg_contents.environment_vars);
579
580        let mut linker_msg_contents = process_args::MessageContents {
581            // Argument strings are sent to the linker so that it can use argv[0] in messages it
582            // prints.
583            args,
584            // Environment variables are sent to the linker so that it can see vars like LD_DEBUG.
585            environment_vars,
586            // Process namespace is not set up or used in the linker.
587            namespace_paths: vec![],
588            // Loader message includes a few special handles needed to do its job, plus a set of
589            // handles common to both messages which are generated by this library.
590            handles: vec![
591                process_args::StartupHandle {
592                    handle: ldsvc_hnd.into_handle(),
593                    info: HandleInfo::new(HandleType::LdsvcLoader, 0),
594                },
595                process_args::StartupHandle {
596                    handle: executable.into_handle(),
597                    info: HandleInfo::new(HandleType::ExecutableVmo, 0),
598                },
599                process_args::StartupHandle {
600                    handle: loaded_vmar.into_handle(),
601                    info: HandleInfo::new(HandleType::LoadedVmar, 0),
602                },
603            ],
604        };
605        self.common.add_process_self(&mut linker_msg_contents)?;
606        self.common.add_root_vmar(&mut linker_msg_contents)?;
607        Ok(process_args::Message::build(linker_msg_contents)?)
608    }
609
610    /// Load the vDSO VMO into the process's address space and a handle to it to the bootstrap
611    /// message. If a vDSO VMO is provided, loads that one, otherwise loads the default system
612    /// vDSO, invaliding the duplicate default system vDSO handle stored in this object.
613    /// Returns the base address that the vDSO was mapped into.
614    fn load_vdso(&mut self) -> Result<usize, ProcessBuilderError> {
615        let vdso = match self.non_default_vdso.take() {
616            Some(vmo) => vmo,
617            None => mem::replace(&mut self.system_vdso_vmo, zx::NullableHandle::invalid().into()),
618        };
619        let vdso_headers = elf_parse::Elf64Headers::from_vmo(&vdso)?;
620        let loaded_vdso = elf_load::load_elf(&vdso, &vdso_headers, &self.common.root_vmar)?;
621
622        self.msg_contents.handles.push(process_args::StartupHandle {
623            handle: vdso.into_handle(),
624            info: HandleInfo::new(HandleType::VdsoVmo, 0),
625        });
626
627        Ok(loaded_vdso.vmar_base)
628    }
629
630    /// Allocate the initial thread's stack, map it, and add a handle to the bootstrap message.
631    /// Returns the initial stack pointer for the process.
632    ///
633    /// Note that launchpad supported not allocating a stack at all, but that only happened if an
634    /// explicit stack size of 0 is set. ProcessBuilder does not support overriding the stack size
635    /// so a stack is always created.
636    fn create_stack(
637        &mut self,
638        stack_size: usize,
639        vmo_name: &zx::Name,
640    ) -> Result<StackInfo, ProcessBuilderError> {
641        let stack_vmo = zx::Vmo::create(stack_size as u64).map_err(|s| {
642            ProcessBuilderError::GenericStatus("Failed to create VMO for initial thread stack", s)
643        })?;
644        stack_vmo
645            .set_name(vmo_name)
646            .map_err(|s| ProcessBuilderError::GenericStatus("Failed to set stack VMO name", s))?;
647        let stack_flags = zx::VmarFlags::PERM_READ | zx::VmarFlags::PERM_WRITE;
648        let stack_base =
649            self.common.root_vmar.map(0, &stack_vmo, 0, stack_size, stack_flags).map_err(|s| {
650                ProcessBuilderError::GenericStatus("Failed to map initial stack", s)
651            })?;
652        let stack_ptr = compute_initial_stack_pointer(stack_base, stack_size);
653        let dup_stack_vmo = stack_vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).map_err(|s| {
654            ProcessBuilderError::GenericStatus("Failed to duplicate initial stack", s)
655        })?;
656
657        // Pass the stack VMO to the process. Our protocol with the new process is that we warrant
658        // that this is the VMO from which the initial stack is mapped and that we've exactly
659        // mapped the entire thing, so vm_object_get_size on this in concert with the initial SP
660        // value tells it the exact bounds of its stack.
661        self.msg_contents.handles.push(process_args::StartupHandle {
662            handle: dup_stack_vmo.into_handle(),
663            info: HandleInfo::new(HandleType::StackVmo, 0),
664        });
665
666        Ok(StackInfo { stack_ptr, stack_base, stack_vmo })
667    }
668}
669
670/// Calculate the size of the initial stack to allocate for the dynamic linker, based on the given
671/// process_args message contents.
672///
673/// The initial stack is used just for startup work in the dynamic linker and to hold the bootstrap
674/// message, so we only attempt to make it only as big as needed. The size returned is based on the
675/// stack space needed to read the bootstrap message with zx_channel_read, and thus includes the
676/// message data itself plus the size of the handles (i.e. the size of N zx_handle_t's).
677///
678/// This also allows the caller to specify an number of "extra handles" to factor into the size
679/// calculation. This allows the size to be calculated before all the real handles have been added
680/// to the contents, for example if the size is needed to create those handles.
681pub fn calculate_initial_linker_stack_size(
682    msg_contents: &mut process_args::MessageContents,
683    extra_handles: usize,
684) -> Result<usize, ProcessBuilderError> {
685    // Add N placeholder handles temporarily to factor in the size of handles that are not yet
686    // added to the message contents.
687    msg_contents.handles.extend(
688        iter::repeat_with(|| process_args::StartupHandle {
689            handle: zx::NullableHandle::invalid(),
690            info: HandleInfo::new(HandleType::User0, 0),
691        })
692        .take(extra_handles),
693    );
694
695    // Include both the message data size and the size of the handles since we're calculating the
696    // stack space required to read the message.
697    let num_handles = msg_contents.handles.len();
698    let msg_stack_size = process_args::Message::calculate_size(msg_contents)?
699        + num_handles * mem::size_of::<zx::sys::zx_handle_t>();
700    msg_contents.handles.truncate(num_handles - extra_handles);
701
702    // PTHREAD_STACK_MIN is defined by the C library in
703    // //zircon/third_party/ulib/musl/include/limits.h. It is tuned enough to cover the dynamic
704    // linker and C library startup code's stack usage (up until the point it switches to its own
705    // stack in __libc_start_main), but leave a little space so for small bootstrap message sizes
706    // the stack needs only one page.
707    const PTHREAD_STACK_MIN: usize = 3072;
708    Ok(util::page_end(msg_stack_size + PTHREAD_STACK_MIN))
709}
710
711/// Extract only the arguments that are needed for a linker message.
712fn extract_ld_arguments(arguments: &[CString]) -> Vec<CString> {
713    let mut extracted = vec![];
714
715    if let Some(argument) = arguments.get(0) {
716        extracted.push(argument.clone())
717    }
718
719    extracted
720}
721
722/// Extract only the environment variables that are needed for a linker message.
723fn extract_ld_environment_variables(envvars: &[CString]) -> Vec<CString> {
724    let prefixes = ["LD_DEBUG=", "LD_TRACE="];
725
726    let mut extracted = vec![];
727    for envvar in envvars {
728        for prefix in &prefixes {
729            let envvar_bytes: &[u8] = envvar.to_bytes();
730            let prefix_bytes: &[u8] = prefix.as_bytes();
731            if envvar_bytes.starts_with(prefix_bytes) {
732                extracted.push(envvar.clone());
733                continue;
734            }
735        }
736    }
737
738    extracted
739}
740
741impl CommonMessageHandles {
742    fn add_process_self(
743        &self,
744        msg: &mut process_args::MessageContents,
745    ) -> Result<(), ProcessBuilderError> {
746        Self::add_to_message(msg, self.process.as_handle_ref(), HandleType::ProcessSelf)
747    }
748
749    fn add_thread_self(
750        &self,
751        msg: &mut process_args::MessageContents,
752    ) -> Result<(), ProcessBuilderError> {
753        Self::add_to_message(msg, self.thread.as_handle_ref(), HandleType::ThreadSelf)
754    }
755
756    fn add_root_vmar(
757        &self,
758        msg: &mut process_args::MessageContents,
759    ) -> Result<(), ProcessBuilderError> {
760        Self::add_to_message(msg, self.root_vmar.as_handle_ref(), HandleType::RootVmar)
761    }
762
763    /// Add a handle to the procargs message with `0` for its `arg`.
764    fn add_to_message(
765        msg: &mut process_args::MessageContents,
766        handle: zx::HandleRef<'_>,
767        handle_type: HandleType,
768    ) -> Result<(), ProcessBuilderError> {
769        let dup = handle
770            .duplicate_handle(zx::Rights::SAME_RIGHTS)
771            .map_err(|s| ProcessBuilderError::DuplicateHandle(handle_type, s))?;
772        msg.handles.push(process_args::StartupHandle {
773            handle: dup,
774            info: HandleInfo::new(handle_type, 0),
775        });
776        Ok(())
777    }
778}
779
780/// Given the base and size of the stack block, compute the appropriate initial
781/// SP value for an initial thread according to the C calling convention for the
782/// machine.
783///
784/// Copied from, and must be kept in sync with:
785/// //zircon/system/ulib/elf-psabi/include/lib/elf-psabi/sp.h
786pub fn compute_initial_stack_pointer(base: usize, size: usize) -> usize {
787    // Assume stack grows down.
788    let mut sp = base.checked_add(size).expect("Overflow in stack pointer calculation");
789
790    // The x86-64 and AArch64 ABIs require 16-byte alignment.
791    // The 32-bit ARM ABI only requires 8-byte alignment, but 16-byte alignment is preferable for
792    // NEON so use it there too.
793    // RISC-V ABIs also require 16-byte alignment.
794    sp &= 16usize.wrapping_neg();
795
796    // The x86-64 ABI requires %rsp % 16 = 8 on entry.  The zero word at (%rsp) serves as the
797    // return address for the outermost frame.
798    #[cfg(target_arch = "x86_64")]
799    {
800        sp -= 8;
801    }
802
803    // The ARMv7 and ARMv8 ABIs both just require that SP be aligned, so just catch unknown archs.
804    #[cfg(not(any(
805        target_arch = "x86_64",
806        target_arch = "arm",
807        target_arch = "aarch64",
808        target_arch = "riscv64"
809    )))]
810    {
811        compile_error!("Unknown target_arch");
812    }
813
814    sp
815}
816
817/// Load the dynamic linker/loader specified in the PT_INTERP header via the fuchsia.ldsvc.Loader
818/// handle.
819pub async fn get_dynamic_linker<'a>(
820    ldsvc: &'a fldsvc::LoaderProxy,
821    executable: &'a zx::Vmo,
822    interp_hdr: &'a elf_parse::Elf64ProgramHeader,
823) -> Result<zx::Vmo, ProcessBuilderError> {
824    // Read the dynamic linker name from the main VMO, based on the PT_INTERP header.
825    let mut interp = vec![0u8; interp_hdr.filesz as usize];
826    executable
827        .read(&mut interp[..], interp_hdr.offset as u64)
828        .map_err(|s| ProcessBuilderError::GenericStatus("Failed to read from VMO", s))?;
829    // Trim null terminator included in filesz.
830    match interp.pop() {
831        Some(b'\0') => Ok(()),
832        _ => Err(ProcessBuilderError::InvalidInterpHeader(anyhow!("Missing null terminator"))),
833    }?;
834    let interp_str = std::str::from_utf8(&interp)
835        .context("Invalid UTF8")
836        .map_err(ProcessBuilderError::InvalidInterpHeader)?;
837
838    // Retrieve the dynamic linker as a VMO from fuchsia.ldsvc.Loader
839    const LDSO_LOAD_TIMEOUT_SEC: i64 = 30;
840    let load_fut =
841        ldsvc.load_object(interp_str).map_err(ProcessBuilderError::LoadDynamicLinker).on_timeout(
842            fasync::MonotonicInstant::after(zx::MonotonicDuration::from_seconds(
843                LDSO_LOAD_TIMEOUT_SEC,
844            )),
845            || Err(ProcessBuilderError::LoadDynamicLinkerTimeout()),
846        );
847    let (status, ld_vmo) = load_fut.await?;
848    zx::Status::ok(status).map_err(|s| {
849        ProcessBuilderError::GenericStatus(
850            "Failed to load dynamic linker from fuchsia.ldsvc.Loader",
851            s,
852        )
853    })?;
854    Ok(ld_vmo.ok_or(ProcessBuilderError::GenericStatus(
855        "load_object status was OK but no VMO",
856        zx::Status::INTERNAL,
857    ))?)
858}
859
860impl BuiltProcess {
861    /// Start an already built process.
862    ///
863    /// This is a simple wrapper around the [zx_process_start] syscall that consumes the handles
864    /// and data in the BuiltProcess struct as needed.
865    ///
866    /// [zx_process_start]: https://fuchsia.dev/fuchsia-src/reference/syscalls/process_start.md
867    pub fn start(self) -> Result<zx::Process, ProcessBuilderError> {
868        self.process
869            .start(
870                &self.thread,
871                self.entry,
872                self.stack,
873                self.bootstrap.into_handle(),
874                self.vdso_base,
875            )
876            .map_err(ProcessBuilderError::ProcessStart)?;
877        Ok(self.process)
878    }
879}
880
881struct ReservationVmar(Option<zx::Vmar>);
882
883impl ReservationVmar {
884    /// Reserve the lower half of the address space of the given VMAR by allocating another VMAR.
885    ///
886    /// The VMAR wrapped by this reservation is automatically destroyed when the reservation
887    /// is dropped.
888    fn reserve_low_address_space(vmar: &zx::Vmar) -> Result<ReservationVmar, ProcessBuilderError> {
889        let info = vmar
890            .info()
891            .map_err(|s| ProcessBuilderError::GenericStatus("Failed to get VMAR info", s))?;
892
893        // Reserve the lower half of the full address space, not just half of the VMAR length.
894        // (base+len) represents the full address space, assuming this is used with a root VMAR and
895        // length extends to the end of the address space, including a region the kernel reserves
896        // at the start of the space.
897        // TODO(https://fxbug.dev/42099306): Clean up address space reservation to avoid unnecessary
898        // reservations, which should also avoid the "fake" reservation in the else-clause.
899        if let Some(reserve_size) =
900            util::page_end((info.base + info.len) / 2).checked_sub(info.base)
901        {
902            let (reserve_vmar, reserve_base) =
903                vmar.allocate(0, reserve_size, zx::VmarFlags::SPECIFIC).map_err(|s| {
904                    ProcessBuilderError::GenericStatus("Failed to allocate reservation VMAR", s)
905                })?;
906            assert_eq!(reserve_base, info.base, "Reservation VMAR allocated at wrong address");
907
908            Ok(ReservationVmar(Some(reserve_vmar)))
909        } else {
910            // The VMAR does not intersect the "bottom half," so return a success but without an
911            // actual reservation.
912            Ok(ReservationVmar(None))
913        }
914    }
915
916    /// Destroy the reservation. The reservation is also automatically destroyed when
917    /// ReservationVmar is dropped.
918    ///
919    /// VMARs are not destroyed when the handle is closed (by dropping), so we must explicit destroy
920    /// it to release the reservation and allow the created process to use the full address space.
921    fn destroy(&mut self) -> Result<(), zx::Status> {
922        match self.0.take() {
923            Some(vmar) => {
924                // This is safe because there are no mappings in the region and it is not a region
925                // in the current process.
926                unsafe { vmar.destroy() }
927            }
928            None => Ok(()),
929        }
930    }
931}
932
933// This is probably unnecessary, but it feels wrong to rely on the side effect of the process's
934// root VMAR going away. We explicitly call destroy if ProcessBuilder.build() succeeds and returns
935// a BuiltProcess, in which case this will do nothing, and if build() fails then the new process
936// and its root VMAR will get cleaned up along with this sub-VMAR.
937impl Drop for ReservationVmar {
938    fn drop(&mut self) {
939        _ = self.destroy();
940    }
941}
942
943#[cfg(test)]
944mod tests {
945    use super::*;
946    use anyhow::Error;
947    use assert_matches::assert_matches;
948    use fidl::prelude::*;
949    use fidl_fuchsia_io as fio;
950    use fidl_test_processbuilder::{UtilMarker, UtilProxy};
951    use fuchsia_async as fasync;
952    use std::sync::LazyLock;
953    use vfs::file::vmo::read_only;
954    use vfs::pseudo_directory;
955    use zerocopy::Ref;
956
957    unsafe 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        static VDSO_VMO: LazyLock<zx::Vmo> = LazyLock::new(|| {
963            zx::Vmo::from(
964                fuchsia_runtime::take_startup_handle(HandleInfo::new(HandleType::VdsoVmo, 0))
965                    .expect("Failed to take VDSO VMO startup handle"),
966            )
967        });
968
969        let vdso_dup = VDSO_VMO
970            .duplicate_handle(zx::Rights::SAME_RIGHTS)
971            .map_err(|s| ProcessBuilderError::GenericStatus("Failed to dup vDSO VMO handle", s))?;
972        Ok(vdso_dup)
973    }
974
975    // Clone the current loader service to provide to the new test processes.
976    fn clone_loader_service() -> Result<ClientEnd<fldsvc::LoaderMarker>, zx::Status> {
977        let mut raw = 0;
978        let status = unsafe { dl_clone_loader_service(&mut raw) };
979        zx::Status::ok(status)?;
980
981        let handle = unsafe { zx::NullableHandle::from(zx::NullableHandle::from_raw(raw)) };
982        Ok(ClientEnd::new(zx::Channel::from(handle)))
983    }
984
985    fn connect_util(client: &zx::Channel) -> Result<UtilProxy, Error> {
986        let (proxy, server) = zx::Channel::create();
987        fdio::service_connect_at(&client, UtilMarker::PROTOCOL_NAME, server)
988            .context("failed to connect to util service")?;
989        Ok(UtilProxy::from_channel(fasync::Channel::from_channel(proxy)))
990    }
991
992    fn create_test_util_builder() -> Result<ProcessBuilder, Error> {
993        const TEST_UTIL_BIN: &'static str = "/pkg/bin/process_builder_test_util";
994        let file = fdio::open_fd(TEST_UTIL_BIN, fio::PERM_READABLE | fio::PERM_EXECUTABLE)?;
995        let vmo = fdio::get_vmo_exec_from_file(&file)?;
996        let job = fuchsia_runtime::job_default();
997
998        let procname = CString::new(TEST_UTIL_BIN.to_owned())?;
999        Ok(ProcessBuilder::new(
1000            &procname,
1001            &job,
1002            zx::ProcessOptions::empty(),
1003            vmo,
1004            get_system_vdso_vmo().unwrap(),
1005        )?)
1006    }
1007
1008    // Common builder setup for all tests that start a test util process.
1009    fn setup_test_util_builder(set_loader: bool) -> Result<(ProcessBuilder, UtilProxy), Error> {
1010        let mut builder = create_test_util_builder()?;
1011        if set_loader {
1012            builder.add_handles(vec![process_args::StartupHandle {
1013                handle: clone_loader_service()?.into_channel().into(),
1014                info: HandleInfo::new(HandleType::LdsvcLoader, 0),
1015            }])?;
1016        }
1017
1018        let (dir_client, dir_server) = zx::Channel::create();
1019        builder.add_handles(vec![process_args::StartupHandle {
1020            handle: dir_server.into_handle(),
1021            info: HandleInfo::new(HandleType::DirectoryRequest, 0),
1022        }])?;
1023
1024        let proxy = connect_util(&dir_client)?;
1025        Ok((builder, proxy))
1026    }
1027
1028    fn check_process_running(process: &zx::Process) -> Result<(), Error> {
1029        let info = process.info()?;
1030        const STARTED: zx::ProcessInfoFlags = zx::ProcessInfoFlags::STARTED;
1031        assert_matches!(
1032            info,
1033            zx::ProcessInfo {
1034                return_code: 0,
1035                start_time,
1036                flags: STARTED,
1037                ..
1038            } if start_time.into_nanos() > 0
1039        );
1040        Ok(())
1041    }
1042
1043    async fn check_process_exited_ok(process: &zx::Process) -> Result<(), Error> {
1044        fasync::OnSignals::new(process, zx::Signals::PROCESS_TERMINATED).await?;
1045
1046        let info = process.info()?;
1047        const STARTED_AND_EXITED: zx::ProcessInfoFlags =
1048            zx::ProcessInfoFlags::STARTED.union(zx::ProcessInfoFlags::EXITED);
1049        assert_matches!(
1050            info,
1051            zx::ProcessInfo {
1052                return_code: 0,
1053                start_time,
1054                flags: STARTED_AND_EXITED,
1055                ..
1056            } if start_time.into_nanos() > 0
1057        );
1058        Ok(())
1059    }
1060
1061    // These start_util_with_* tests cover the most common paths through ProcessBuilder and
1062    // exercise most of its functionality. They verify that we can create a new process for a
1063    // "standard" dynamically linked executable and that we can provide arguments, environment
1064    // variables, namespace entries, and other handles to it through the startup process_args
1065    // message. The test communicates with the test util process it creates over a test-only FIDL
1066    // API to verify that arguments and whatnot were passed correctly.
1067    #[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        // Use the util protocol to confirm that the new process was set up correctly. A successful
1079        // connection to the util validates that handles are passed correctly to the new process,
1080        // since the DirectoryRequest handle made it.
1081        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        // This test is partially designed to probe the stack usage of
1092        // code processing the initial loader message. Such processing
1093        // is on a stack of limited size, a few pages, and well
1094        // smaller than a maximally large channel packet. Each
1095        // instance of "arg" takes 4 bytes (counting the separating
1096        // '\0' byte), so let's send 10k of them to be well larger
1097        // than the initial stack but well within the 64k channel size.
1098        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        // Use the util protocol to confirm that the new process was set up correctly. A successful
1108        // connection to the util validates that handles are passed correctly to the new process,
1109        // since the DirectoryRequest handle made it.
1110        // We can't use get_arguments() here because the FIDL response will be bigger than the
1111        // maximum message size[1] and cause the process to crash. Instead, we just check the number
1112        // of environment variables and assume that if that's correct we're good to go.
1113        // Size of each vector entry: (length = 8, pointer = 8) = 16 + (string size = 8) = 24
1114        // Message size = (10k * vector entry size) = 240,000 > 65,536
1115        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    // Verify that the lifecycle channel can be passed through the bootstrap
1126    // channel. This test checks by creating a channel, passing it through,
1127    // asking the remote process for the lifecycle channel's koid, and then
1128    // comparing that koid to the one the test recorded.
1129    #[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        // Use the util protocol to confirm that the new process received the
1147        // lifecycle channel
1148        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    // Verify that if no lifecycle channel is sent via the bootstrap channel
1157    // that the remote process reports ZX_KOID_INVALID for the channel koid.
1158    #[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        // Use the util protocol to confirm that the new process received the
1165        // lifecycle channel
1166        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    // Verify that a loader service handle is properly handled if passed directly to
1202    // set_loader_service instead of through add_handles. Otherwise this test is identical to
1203    // start_util_with_args.
1204    #[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        // Use the util protocol to confirm that the new process was set up correctly. A successful
1217        // connection to the util validates that handles are passed correctly to the new process,
1218        // since the DirectoryRequest handle made it.
1219        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    // Verify that a vDSO handle is properly handled if passed directly to set_vdso_vmo instead of
1228    // relying on the default value.
1229    // Note: There isn't a great way to tell here whether the vDSO VMO we passed in was used
1230    // instead of the default (because the kernel only allows use of vDSOs that it created for
1231    // security, so we can't make a fake vDSO with a different name or something), so that isn't
1232    // checked explicitly. The failure tests below make sure we don't ignore the provided vDSO VMO
1233    // completely.
1234    #[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        // Use the util protocol to confirm that the new process was set up correctly.
1247        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    // Verify that a vDSO handle is properly handled if passed directly to set_vdso_vmo instead of
1256    // relying on the default value, this time by providing an invalid VMO (something that isn't
1257    // ELF and will fail to parse). This also indirectly tests that the reservation VMAR cleanup
1258    // happens properly by testing a failure after it has been created.
1259    #[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    // Verify that a vDSO handle is properly handled if passed through add_handles instead of
1280    // relying on the default value, this time by providing an invalid VMO (something that isn't
1281    // ELF and will fail to parse). This also indirectly tests that the reservation VMAR cleanup
1282    // happens properly by testing a failure after it has been created.
1283    #[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        // Ignore linker message handles.
1317        let mut msg_buf = zx::MessageBuf::new();
1318        built.bootstrap.read(&mut msg_buf)?;
1319
1320        // Validate main message handles.
1321        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        // This test is partially designed to probe the stack usage of
1361        // code processing the initial loader message. Such processing
1362        // is on a stack of limited size, a few pages, and well
1363        // smaller than a maximally large channel packet. Each
1364        // instance of "a=b" takes 4 bytes (counting the separating
1365        // '\0' byte), so let's send 10k of them to be well larger
1366        // than the initial stack but well within the 64k channel size.
1367        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        // We can't use get_environment() here because the FIDL response will be bigger than the
1376        // maximum message size and cause the process to crash. Instead, we just check the number
1377        // of environment variables and assume that if that's correct we're good to go.
1378        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 = pseudo_directory! {
1396            "test_file1" => read_only(test_content1.clone()),
1397        };
1398        let dir1_client = vfs::directory::serve_read_only(dir1).into_client_end().unwrap();
1399
1400        let dir2 = pseudo_directory! {
1401            "test_file2" => read_only(test_content2.clone()),
1402        };
1403        let dir2_client = vfs::directory::serve_read_only(dir2).into_client_end().unwrap();
1404
1405        let (mut builder, proxy) = setup_test_util_builder(true)?;
1406        builder.add_namespace_entries(vec![
1407            NamespaceEntry { path: CString::new("/dir1")?, directory: dir1_client },
1408            NamespaceEntry { path: CString::new("/dir2")?, directory: dir2_client },
1409        ])?;
1410        let process = builder.build().await?.start()?;
1411        check_process_running(&process)?;
1412
1413        let namespace_dump = proxy.dump_namespace().await.context("failed to dump namespace")?;
1414        assert_eq!(namespace_dump, "/dir1, /dir1/test_file1, /dir2, /dir2/test_file2");
1415
1416        let dir1_contents =
1417            proxy.read_file("/dir1/test_file1").await.context("failed to read file via util")?;
1418        assert_eq!(dir1_contents, test_content1);
1419        let dir2_contents =
1420            proxy.read_file("/dir2/test_file2").await.context("failed to read file via util")?;
1421        assert_eq!(dir2_contents, test_content2);
1422
1423        mem::drop(proxy);
1424        check_process_exited_ok(&process).await?;
1425        Ok(())
1426    }
1427
1428    // Trying to start a dynamically linked process without providing a loader service should
1429    // fail. This verifies that nothing is automatically cloning a loader.
1430    #[fasync::run_singlethreaded(test)]
1431    async fn start_util_with_no_loader_fails() -> Result<(), Error> {
1432        let (builder, _) = setup_test_util_builder(false)?;
1433
1434        let result = builder.build().await;
1435        match result {
1436            Err(ProcessBuilderError::LoaderMissing()) => {}
1437            Err(err) => {
1438                panic!("Unexpected error type: {}", err);
1439            }
1440            Ok(_) => {
1441                panic!("Unexpectedly succeeded to build process without loader");
1442            }
1443        }
1444        Ok(())
1445    }
1446
1447    // Checks that, for dynamically linked binaries, the lower half of the address space has been
1448    // reserved for sanitizers.
1449    #[fasync::run_singlethreaded(test)]
1450    async fn verify_low_address_range_reserved() -> Result<(), Error> {
1451        let (builder, _) = setup_test_util_builder(true)?;
1452        let built = builder.build().await?;
1453
1454        // This ends up being the same thing ReservationVmar does, but it's not reused here so that
1455        // this catches bugs or bad changes to ReservationVmar itself.
1456        let info = built.root_vmar.info()?;
1457        let lower_half_len = util::page_end((info.base + info.len) / 2) - info.base;
1458        built
1459            .root_vmar
1460            .allocate(0, lower_half_len, zx::VmarFlags::SPECIFIC)
1461            .context("Unable to allocate lower address range of new process")?;
1462        Ok(())
1463    }
1464
1465    // Parses the given channel message as a process_args message and returns the HandleInfo's
1466    // contained in it.
1467    fn parse_handle_info_from_message(message: &zx::MessageBuf) -> Result<Vec<HandleInfo>, Error> {
1468        let bytes = message.bytes();
1469        let (header, _) = Ref::<&[u8], process_args::MessageHeader>::from_prefix(bytes)
1470            .map_err(|_| anyhow!("Failed to parse process_args header"))?;
1471
1472        let offset = header.handle_info_off as usize;
1473        let len = mem::size_of::<u32>() * message.n_handles();
1474        let info_bytes = &bytes[offset..offset + len];
1475        let raw_info = Ref::<&[u8], [u32]>::from_bytes(info_bytes)
1476            .map_err(|_| anyhow!("Failed to parse raw handle info"))?;
1477
1478        Ok(raw_info.iter().map(|raw| HandleInfo::try_from(*raw)).collect::<Result<_, _>>()?)
1479    }
1480
1481    const LINKER_MESSAGE_HANDLES: &[HandleType] = &[
1482        HandleType::ProcessSelf,
1483        HandleType::RootVmar,
1484        HandleType::LdsvcLoader,
1485        HandleType::LoadedVmar,
1486        HandleType::ExecutableVmo,
1487    ];
1488
1489    const MAIN_MESSAGE_HANDLES: &[HandleType] = &[
1490        HandleType::ProcessSelf,
1491        HandleType::ThreadSelf,
1492        HandleType::RootVmar,
1493        HandleType::VdsoVmo,
1494        HandleType::StackVmo,
1495    ];
1496
1497    #[fasync::run_singlethreaded(test)]
1498    async fn correct_handles_present() -> Result<(), Error> {
1499        let mut builder = create_test_util_builder()?;
1500        builder.set_loader_service(clone_loader_service()?)?;
1501        let built = builder.build().await?;
1502
1503        for correct in &[LINKER_MESSAGE_HANDLES, MAIN_MESSAGE_HANDLES] {
1504            let mut msg_buf = zx::MessageBuf::new();
1505            built.bootstrap.read(&mut msg_buf)?;
1506            let handle_info = parse_handle_info_from_message(&msg_buf)?;
1507
1508            assert_eq!(handle_info.len(), correct.len());
1509            for correct_type in *correct {
1510                // Should only be one of each of these handles present.
1511                assert_eq!(
1512                    1,
1513                    handle_info.iter().filter(|info| &info.handle_type() == correct_type).count()
1514                );
1515            }
1516        }
1517        Ok(())
1518    }
1519
1520    // Verify that [ProcessBuilder::add_handles()] rejects handle types that are added
1521    // automatically by the builder.
1522    #[fasync::run_singlethreaded(test)]
1523    async fn add_handles_rejects_automatic_handle_types() -> Result<(), Error> {
1524        // The VMO doesn't need to be valid since we're not calling build.
1525        let vmo = zx::Vmo::create(1)?;
1526        let job = fuchsia_runtime::job_default();
1527        let procname = CString::new("test_vmo")?;
1528        let mut builder = ProcessBuilder::new(
1529            &procname,
1530            &job,
1531            zx::ProcessOptions::empty(),
1532            vmo,
1533            get_system_vdso_vmo().unwrap(),
1534        )?;
1535
1536        // There's some duplicates between these slices but just checking twice is easier than
1537        // deduping these.
1538        for handle_type in LINKER_MESSAGE_HANDLES.iter().chain(MAIN_MESSAGE_HANDLES) {
1539            if *handle_type == HandleType::LdsvcLoader {
1540                // Skip LdsvcLoader, which is required in the linker message but is not added
1541                // automatically. The user must supply it.
1542                continue;
1543            }
1544
1545            if *handle_type == HandleType::VdsoVmo {
1546                // Skip VdsoVmo, which may be supplied by the user.
1547                continue;
1548            }
1549
1550            // Another VMO, just to have a valid handle.
1551            let vmo = zx::Vmo::create(1)?;
1552            let result = builder.add_handles(vec![process_args::StartupHandle {
1553                handle: vmo.into_handle(),
1554                info: HandleInfo::new(*handle_type, 0),
1555            }]);
1556            match result {
1557                Err(ProcessBuilderError::InvalidArg(_)) => {}
1558                Err(err) => {
1559                    panic!("Unexpected error type, should be invalid arg: {}", err);
1560                }
1561                Ok(_) => {
1562                    panic!("add_handle unexpectedly succeeded for type {:?}", handle_type);
1563                }
1564            }
1565        }
1566        Ok(())
1567    }
1568
1569    // Verify that invalid handles are correctly rejected.
1570    #[fasync::run_singlethreaded(test)]
1571    async fn rejects_invalid_handles() -> Result<(), Error> {
1572        let invalid = || zx::NullableHandle::invalid();
1573        let assert_invalid_arg = |result| match result {
1574            Err(ProcessBuilderError::BadHandle(_)) => {}
1575            Err(err) => {
1576                panic!("Unexpected error type, should be BadHandle: {}", err);
1577            }
1578            Ok(_) => {
1579                panic!("API unexpectedly accepted invalid handle");
1580            }
1581        };
1582
1583        // The VMO doesn't need to be valid since we're not calling build with this.
1584        let vmo = zx::Vmo::create(1)?;
1585        let job = fuchsia_runtime::job_default();
1586        let procname = CString::new("test_vmo")?;
1587
1588        assert_invalid_arg(
1589            ProcessBuilder::new(
1590                &procname,
1591                &zx::NullableHandle::from(invalid()).into(),
1592                zx::ProcessOptions::empty(),
1593                vmo,
1594                get_system_vdso_vmo().unwrap(),
1595            )
1596            .map(|_| ()),
1597        );
1598        assert_invalid_arg(
1599            ProcessBuilder::new(
1600                &procname,
1601                &job,
1602                zx::ProcessOptions::empty(),
1603                zx::NullableHandle::from(invalid()).into(),
1604                get_system_vdso_vmo().unwrap(),
1605            )
1606            .map(|_| ()),
1607        );
1608
1609        let (mut builder, _) = setup_test_util_builder(true)?;
1610
1611        assert_invalid_arg(builder.set_loader_service(invalid().into()));
1612        assert_invalid_arg(builder.add_handles(vec![process_args::StartupHandle {
1613            handle: invalid().into(),
1614            info: HandleInfo::new(HandleType::User0, 0),
1615        }]));
1616        assert_invalid_arg(builder.add_handles(vec![process_args::StartupHandle {
1617            handle: invalid().into(),
1618            info: HandleInfo::new(HandleType::User0, 0),
1619        }]));
1620        assert_invalid_arg(builder.add_namespace_entries(vec![NamespaceEntry {
1621            path: CString::new("/dir")?,
1622            directory: invalid().into(),
1623        }]));
1624
1625        Ok(())
1626    }
1627
1628    #[fasync::run_singlethreaded]
1629    #[test]
1630    async fn start_static_pie_binary() -> Result<(), Error> {
1631        const TEST_BIN: &'static str = "/pkg/bin/static_pie_test_util";
1632        let file = fdio::open_fd(TEST_BIN, fio::PERM_READABLE | fio::PERM_EXECUTABLE)?;
1633        let vmo = fdio::get_vmo_exec_from_file(&file)?;
1634        let job = fuchsia_runtime::job_default();
1635
1636        let procname = CString::new(TEST_BIN.to_owned())?;
1637        let mut builder = ProcessBuilder::new(
1638            &procname,
1639            &job,
1640            zx::ProcessOptions::empty(),
1641            vmo,
1642            get_system_vdso_vmo().unwrap(),
1643        )?;
1644
1645        // We pass the program a channel with handle type User0 which we send a message on and
1646        // expect it to echo back the message on the same channel.
1647        let (local, remote) = zx::Channel::create();
1648        builder.add_handles(vec![process_args::StartupHandle {
1649            handle: remote.into_handle(),
1650            info: HandleInfo::new(HandleType::User0, 0),
1651        }])?;
1652
1653        let mut randbuf = [0; 8];
1654        zx::cprng_draw(&mut randbuf);
1655        let test_message = format!("test content 1 {}", u64::from_le_bytes(randbuf)).into_bytes();
1656        local.write(&test_message, &mut vec![])?;
1657
1658        // Start process and wait for channel to have a message to read or be closed.
1659        builder.build().await?.start()?;
1660        let signals = fasync::OnSignals::new(
1661            &local,
1662            zx::Signals::CHANNEL_READABLE | zx::Signals::CHANNEL_PEER_CLOSED,
1663        )
1664        .await?;
1665        assert!(signals.contains(zx::Signals::CHANNEL_READABLE));
1666
1667        let mut echoed = zx::MessageBuf::new();
1668        local.read(&mut echoed)?;
1669        assert_eq!(echoed.bytes(), test_message.as_slice());
1670        assert_eq!(echoed.n_handles(), 0);
1671        Ok(())
1672    }
1673}