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::directory::entry_container::Directory;
950    use vfs::execution_scope::ExecutionScope;
951    use vfs::file::vmo::read_only;
952    use vfs::{pseudo_directory, ToObjectRequest as _};
953    use zerocopy::Ref;
954    use {fidl_fuchsia_io as fio, fuchsia_async as fasync};
955
956    extern "C" {
957        fn dl_clone_loader_service(handle: *mut zx::sys::zx_handle_t) -> zx::sys::zx_status_t;
958    }
959
960    fn get_system_vdso_vmo() -> Result<zx::Vmo, ProcessBuilderError> {
961        lazy_static! {
962            static ref VDSO_VMO: zx::Vmo = {
963                zx::Vmo::from(
964                    fuchsia_runtime::take_startup_handle(HandleInfo::new(HandleType::VdsoVmo, 0))
965                        .expect("Failed to take VDSO VMO startup handle"),
966                )
967            };
968        }
969
970        let vdso_dup = VDSO_VMO
971            .duplicate_handle(zx::Rights::SAME_RIGHTS)
972            .map_err(|s| ProcessBuilderError::GenericStatus("Failed to dup vDSO VMO handle", s))?;
973        Ok(vdso_dup)
974    }
975
976    // Clone the current loader service to provide to the new test processes.
977    fn clone_loader_service() -> Result<ClientEnd<fldsvc::LoaderMarker>, zx::Status> {
978        let mut raw = 0;
979        let status = unsafe { dl_clone_loader_service(&mut raw) };
980        zx::Status::ok(status)?;
981
982        let handle = unsafe { zx::Handle::from_raw(raw) };
983        Ok(ClientEnd::new(zx::Channel::from(handle)))
984    }
985
986    fn connect_util(client: &zx::Channel) -> Result<UtilProxy, Error> {
987        let (proxy, server) = zx::Channel::create();
988        fdio::service_connect_at(&client, UtilMarker::PROTOCOL_NAME, server)
989            .context("failed to connect to util service")?;
990        Ok(UtilProxy::from_channel(fasync::Channel::from_channel(proxy)))
991    }
992
993    fn create_test_util_builder() -> Result<ProcessBuilder, Error> {
994        const TEST_UTIL_BIN: &'static str = "/pkg/bin/process_builder_test_util";
995        let file = fdio::open_fd(TEST_UTIL_BIN, fio::PERM_READABLE | fio::PERM_EXECUTABLE)?;
996        let vmo = fdio::get_vmo_exec_from_file(&file)?;
997        let job = fuchsia_runtime::job_default();
998
999        let procname = CString::new(TEST_UTIL_BIN.to_owned())?;
1000        Ok(ProcessBuilder::new(
1001            &procname,
1002            &job,
1003            zx::ProcessOptions::empty(),
1004            vmo,
1005            get_system_vdso_vmo().unwrap(),
1006        )?)
1007    }
1008
1009    // Common builder setup for all tests that start a test util process.
1010    fn setup_test_util_builder(set_loader: bool) -> Result<(ProcessBuilder, UtilProxy), Error> {
1011        let mut builder = create_test_util_builder()?;
1012        if set_loader {
1013            builder.add_handles(vec![process_args::StartupHandle {
1014                handle: clone_loader_service()?.into_handle(),
1015                info: HandleInfo::new(HandleType::LdsvcLoader, 0),
1016            }])?;
1017        }
1018
1019        let (dir_client, dir_server) = zx::Channel::create();
1020        builder.add_handles(vec![process_args::StartupHandle {
1021            handle: dir_server.into_handle(),
1022            info: HandleInfo::new(HandleType::DirectoryRequest, 0),
1023        }])?;
1024
1025        let proxy = connect_util(&dir_client)?;
1026        Ok((builder, proxy))
1027    }
1028
1029    fn check_process_running(process: &zx::Process) -> Result<(), Error> {
1030        let info = process.info()?;
1031        const STARTED: u32 = zx::ProcessInfoFlags::STARTED.bits();
1032        assert_matches!(
1033            info,
1034            zx::ProcessInfo {
1035                return_code: 0,
1036                start_time,
1037                flags: STARTED,
1038            } if start_time > 0
1039        );
1040        Ok(())
1041    }
1042
1043    async fn check_process_exited_ok(process: &zx::Process) -> Result<(), Error> {
1044        fasync::OnSignals::new(process, zx::Signals::PROCESS_TERMINATED).await?;
1045
1046        let info = process.info()?;
1047        const STARTED_AND_EXITED: u32 =
1048            zx::ProcessInfoFlags::STARTED.bits() | zx::ProcessInfoFlags::EXITED.bits();
1049        assert_matches!(
1050            info,
1051            zx::ProcessInfo {
1052                return_code: 0,
1053                start_time,
1054                flags: STARTED_AND_EXITED,
1055            } if start_time > 0
1056        );
1057        Ok(())
1058    }
1059
1060    // These start_util_with_* tests cover the most common paths through ProcessBuilder and
1061    // exercise most of its functionality. They verify that we can create a new process for a
1062    // "standard" dynamically linked executable and that we can provide arguments, environment
1063    // variables, namespace entries, and other handles to it through the startup process_args
1064    // message. The test communicates with the test util process it creates over a test-only FIDL
1065    // API to verify that arguments and whatnot were passed correctly.
1066    #[fasync::run_singlethreaded(test)]
1067    async fn start_util_with_args() -> Result<(), Error> {
1068        let test_args = vec!["arg0", "arg1", "arg2"];
1069        let test_args_cstr =
1070            test_args.iter().map(|&s| CString::new(s)).collect::<Result<_, _>>()?;
1071
1072        let (mut builder, proxy) = setup_test_util_builder(true)?;
1073        builder.add_arguments(test_args_cstr);
1074        let process = builder.build().await?.start()?;
1075        check_process_running(&process)?;
1076
1077        // Use the util protocol to confirm that the new process was set up correctly. A successful
1078        // connection to the util validates that handles are passed correctly to the new process,
1079        // since the DirectoryRequest handle made it.
1080        let proc_args = proxy.get_arguments().await.context("failed to get args from util")?;
1081        assert_eq!(proc_args, test_args);
1082
1083        mem::drop(proxy);
1084        check_process_exited_ok(&process).await?;
1085        Ok(())
1086    }
1087
1088    #[fasync::run_singlethreaded(test)]
1089    async fn start_util_with_huge_args() -> Result<(), Error> {
1090        // This test is partially designed to probe the stack usage of
1091        // code processing the initial loader message. Such processing
1092        // is on a stack of limited size, a few pages, and well
1093        // smaller than a maximally large channel packet. Each
1094        // instance of "arg" takes 4 bytes (counting the separating
1095        // '\0' byte), so let's send 10k of them to be well larger
1096        // than the initial stack but well within the 64k channel size.
1097        let test_args = vec!["arg"; 10 * 1000];
1098        let test_args_cstr =
1099            test_args.iter().map(|&s| CString::new(s)).collect::<Result<_, _>>()?;
1100
1101        let (mut builder, proxy) = setup_test_util_builder(true)?;
1102        builder.add_arguments(test_args_cstr);
1103        let process = builder.build().await?.start()?;
1104        check_process_running(&process)?;
1105
1106        // Use the util protocol to confirm that the new process was set up correctly. A successful
1107        // connection to the util validates that handles are passed correctly to the new process,
1108        // since the DirectoryRequest handle made it.
1109        // We can't use get_arguments() here because the FIDL response will be bigger than the
1110        // maximum message size[1] and cause the process to crash. Instead, we just check the number
1111        // of environment variables and assume that if that's correct we're good to go.
1112        // Size of each vector entry: (length = 8, pointer = 8) = 16 + (string size = 8) = 24
1113        // Message size = (10k * vector entry size) = 240,000 > 65,536
1114        let proc_args =
1115            proxy.get_argument_count().await.context("failed to get arg count from util")?;
1116
1117        assert_eq!(proc_args, test_args.len() as u64);
1118
1119        mem::drop(proxy);
1120        check_process_exited_ok(&process).await?;
1121        Ok(())
1122    }
1123
1124    // Verify that the lifecycle channel can be passed through the bootstrap
1125    // channel. This test checks by creating a channel, passing it through,
1126    // asking the remote process for the lifecycle channel's koid, and then
1127    // comparing that koid to the one the test recorded.
1128    #[fasync::run_singlethreaded(test)]
1129    async fn start_util_with_lifecycle_channel() -> Result<(), Error> {
1130        let (mut builder, proxy) = setup_test_util_builder(true)?;
1131        let (lifecycle_server, _lifecycle_client) = zx::Channel::create();
1132        let koid = lifecycle_server
1133            .as_handle_ref()
1134            .basic_info()
1135            .expect("error getting server handle info")
1136            .koid
1137            .raw_koid();
1138        builder.add_handles(vec![process_args::StartupHandle {
1139            handle: lifecycle_server.into_handle(),
1140            info: HandleInfo::new(HandleType::Lifecycle, 0),
1141        }])?;
1142        let process = builder.build().await?.start()?;
1143        check_process_running(&process)?;
1144
1145        // Use the util protocol to confirm that the new process received the
1146        // lifecycle channel
1147        let reported_koid =
1148            proxy.get_lifecycle_koid().await.context("failed getting koid from util")?;
1149        assert_eq!(koid, reported_koid);
1150        mem::drop(proxy);
1151        check_process_exited_ok(&process).await?;
1152        Ok(())
1153    }
1154
1155    // Verify that if no lifecycle channel is sent via the bootstrap channel
1156    // that the remote process reports ZX_KOID_INVALID for the channel koid.
1157    #[fasync::run_singlethreaded(test)]
1158    async fn start_util_with_no_lifecycle_channel() -> Result<(), Error> {
1159        let (builder, proxy) = setup_test_util_builder(true)?;
1160        let process = builder.build().await?.start()?;
1161        check_process_running(&process)?;
1162
1163        // Use the util protocol to confirm that the new process received the
1164        // lifecycle channel
1165        let reported_koid =
1166            proxy.get_lifecycle_koid().await.context("failed getting koid from util")?;
1167        assert_eq!(zx::sys::ZX_KOID_INVALID, reported_koid);
1168        mem::drop(proxy);
1169        check_process_exited_ok(&process).await?;
1170        Ok(())
1171    }
1172
1173    #[fasync::run_singlethreaded(test)]
1174    async fn start_util_with_big_stack() -> Result<(), Error> {
1175        let stack_size: usize = zx::system_get_page_size() as usize * 10;
1176
1177        let (mut builder, proxy) = setup_test_util_builder(true)?;
1178        builder.set_min_stack_size(stack_size);
1179        let built = builder.build().await?;
1180        assert!(built.stack_vmo.get_size()? >= stack_size as u64);
1181
1182        let process = built.start()?;
1183        check_process_running(&process)?;
1184        mem::drop(proxy);
1185        check_process_exited_ok(&process).await?;
1186        Ok(())
1187    }
1188
1189    #[fasync::run_singlethreaded(test)]
1190    async fn elf_headers() -> Result<(), Error> {
1191        let (builder, _) = setup_test_util_builder(true)?;
1192        let built = builder.build().await?;
1193        assert!(
1194            built.elf_headers.file_header().phnum
1195                == built.elf_headers.program_headers().len() as u16
1196        );
1197        Ok(())
1198    }
1199
1200    // Verify that a loader service handle is properly handled if passed directly to
1201    // set_loader_service instead of through add_handles. Otherwise this test is identical to
1202    // start_util_with_args.
1203    #[fasync::run_singlethreaded(test)]
1204    async fn set_loader_directly() -> Result<(), Error> {
1205        let test_args = vec!["arg0", "arg1", "arg2"];
1206        let test_args_cstr =
1207            test_args.iter().map(|&s| CString::new(s)).collect::<Result<_, _>>()?;
1208
1209        let (mut builder, proxy) = setup_test_util_builder(false)?;
1210        builder.set_loader_service(clone_loader_service()?)?;
1211        builder.add_arguments(test_args_cstr);
1212        let process = builder.build().await?.start()?;
1213        check_process_running(&process)?;
1214
1215        // Use the util protocol to confirm that the new process was set up correctly. A successful
1216        // connection to the util validates that handles are passed correctly to the new process,
1217        // since the DirectoryRequest handle made it.
1218        let proc_args = proxy.get_arguments().await.context("failed to get args from util")?;
1219        assert_eq!(proc_args, test_args);
1220
1221        mem::drop(proxy);
1222        check_process_exited_ok(&process).await?;
1223        Ok(())
1224    }
1225
1226    // Verify that a vDSO handle is properly handled if passed directly to set_vdso_vmo instead of
1227    // relying on the default value.
1228    // Note: There isn't a great way to tell here whether the vDSO VMO we passed in was used
1229    // instead of the default (because the kernel only allows use of vDSOs that it created for
1230    // security, so we can't make a fake vDSO with a different name or something), so that isn't
1231    // checked explicitly. The failure tests below make sure we don't ignore the provided vDSO VMO
1232    // completely.
1233    #[fasync::run_singlethreaded(test)]
1234    async fn set_vdso_directly() -> Result<(), Error> {
1235        let test_args = vec!["arg0", "arg1", "arg2"];
1236        let test_args_cstr =
1237            test_args.iter().map(|&s| CString::new(s)).collect::<Result<_, _>>()?;
1238
1239        let (mut builder, proxy) = setup_test_util_builder(true)?;
1240        builder.set_vdso_vmo(get_system_vdso_vmo()?);
1241        builder.add_arguments(test_args_cstr);
1242        let process = builder.build().await?.start()?;
1243        check_process_running(&process)?;
1244
1245        // Use the util protocol to confirm that the new process was set up correctly.
1246        let proc_args = proxy.get_arguments().await.context("failed to get args from util")?;
1247        assert_eq!(proc_args, test_args);
1248
1249        mem::drop(proxy);
1250        check_process_exited_ok(&process).await?;
1251        Ok(())
1252    }
1253
1254    // Verify that a vDSO handle is properly handled if passed directly to set_vdso_vmo instead of
1255    // relying on the default value, this time by providing an invalid VMO (something that isn't
1256    // ELF and will fail to parse). This also indirectly tests that the reservation VMAR cleanup
1257    // happens properly by testing a failure after it has been created.
1258    #[fasync::run_singlethreaded(test)]
1259    async fn set_invalid_vdso_directly_fails() -> Result<(), Error> {
1260        let bad_vdso = zx::Vmo::create(1)?;
1261
1262        let (mut builder, _) = setup_test_util_builder(true)?;
1263        builder.set_vdso_vmo(bad_vdso);
1264
1265        let result = builder.build().await;
1266        match result {
1267            Err(ProcessBuilderError::ElfParse(elf_parse::ElfParseError::InvalidFileHeader(_))) => {}
1268            Err(err) => {
1269                panic!("Unexpected error type: {}", err);
1270            }
1271            Ok(_) => {
1272                panic!("Unexpectedly succeeded to build process with invalid vDSO");
1273            }
1274        }
1275        Ok(())
1276    }
1277
1278    // Verify that a vDSO handle is properly handled if passed through add_handles instead of
1279    // relying on the default value, this time by providing an invalid VMO (something that isn't
1280    // ELF and will fail to parse). This also indirectly tests that the reservation VMAR cleanup
1281    // happens properly by testing a failure after it has been created.
1282    #[fasync::run_singlethreaded(test)]
1283    async fn set_invalid_vdso_fails() -> Result<(), Error> {
1284        let bad_vdso = zx::Vmo::create(1)?;
1285
1286        let (mut builder, _) = setup_test_util_builder(true)?;
1287        builder.add_handles(vec![process_args::StartupHandle {
1288            handle: bad_vdso.into_handle(),
1289            info: HandleInfo::new(HandleType::VdsoVmo, 0),
1290        }])?;
1291
1292        let result = builder.build().await;
1293        match result {
1294            Err(ProcessBuilderError::ElfParse(elf_parse::ElfParseError::InvalidFileHeader(_))) => {}
1295            Err(err) => {
1296                panic!("Unexpected error type: {}", err);
1297            }
1298            Ok(_) => {
1299                panic!("Unexpectedly succeeded to build process with invalid vDSO");
1300            }
1301        }
1302        Ok(())
1303    }
1304
1305    #[fasync::run_singlethreaded(test)]
1306    async fn add_additional_vdso() -> Result<(), Error> {
1307        let mut builder = create_test_util_builder()?;
1308        builder.set_loader_service(clone_loader_service()?)?;
1309        builder.add_handles(vec![process_args::StartupHandle {
1310            handle: get_system_vdso_vmo().unwrap().into_handle(),
1311            info: HandleInfo::new(HandleType::VdsoVmo, 1),
1312        }])?;
1313        let built = builder.build().await?;
1314
1315        // Ignore linker message handles.
1316        let mut msg_buf = zx::MessageBuf::new();
1317        built.bootstrap.read(&mut msg_buf)?;
1318
1319        // Validate main message handles.
1320        let mut msg_buf = zx::MessageBuf::new();
1321        built.bootstrap.read(&mut msg_buf)?;
1322        let handle_info = parse_handle_info_from_message(&msg_buf)?
1323            .drain(..)
1324            .filter(|info| info.handle_type() == HandleType::VdsoVmo)
1325            .collect::<Vec<_>>();
1326        assert_eq!(2, handle_info.len());
1327        for (i, info) in handle_info.iter().rev().enumerate() {
1328            assert_eq!(HandleType::VdsoVmo, info.handle_type());
1329            assert_eq!(i as u16, info.arg());
1330        }
1331        Ok(())
1332    }
1333
1334    #[fasync::run_singlethreaded(test)]
1335    async fn start_util_with_env() -> Result<(), Error> {
1336        let test_env = vec![("VAR1", "value2"), ("VAR2", "value2")];
1337        let test_env_cstr = test_env
1338            .iter()
1339            .map(|v| CString::new(format!("{}={}", v.0, v.1)))
1340            .collect::<Result<_, _>>()?;
1341
1342        let (mut builder, proxy) = setup_test_util_builder(true)?;
1343        builder.add_environment_variables(test_env_cstr);
1344        let process = builder.build().await?.start()?;
1345        check_process_running(&process)?;
1346
1347        let proc_env = proxy.get_environment().await.context("failed to get env from util")?;
1348        let proc_env_tuple: Vec<(&str, &str)> =
1349            proc_env.iter().map(|v| (&*v.key, &*v.value)).collect();
1350        assert_eq!(proc_env_tuple, test_env);
1351
1352        mem::drop(proxy);
1353        check_process_exited_ok(&process).await?;
1354        Ok(())
1355    }
1356
1357    #[fasync::run_singlethreaded(test)]
1358    async fn start_util_with_huge_env() -> Result<(), Error> {
1359        // This test is partially designed to probe the stack usage of
1360        // code processing the initial loader message. Such processing
1361        // is on a stack of limited size, a few pages, and well
1362        // smaller than a maximally large channel packet. Each
1363        // instance of "a=b" takes 4 bytes (counting the separating
1364        // '\0' byte), so let's send 10k of them to be well larger
1365        // than the initial stack but well within the 64k channel size.
1366        let test_env = vec!["a=b"; 10 * 1000];
1367        let test_env_cstr = test_env.iter().map(|&s| CString::new(s)).collect::<Result<_, _>>()?;
1368
1369        let (mut builder, proxy) = setup_test_util_builder(true)?;
1370        builder.add_environment_variables(test_env_cstr);
1371        let process = builder.build().await?.start()?;
1372        check_process_running(&process)?;
1373
1374        // We can't use get_environment() here because the FIDL response will be bigger than the
1375        // maximum message size and cause the process to crash. Instead, we just check the number
1376        // of environment variables and assume that if that's correct we're good to go.
1377        let proc_env =
1378            proxy.get_environment_count().await.context("failed to get env from util")?;
1379        assert_eq!(proc_env, test_env.len() as u64);
1380
1381        mem::drop(proxy);
1382        check_process_exited_ok(&process).await?;
1383        Ok(())
1384    }
1385
1386    #[fasync::run_singlethreaded(test)]
1387    async fn start_util_with_namespace_entries() -> Result<(), Error> {
1388        let mut randbuf = [0; 8];
1389        zx::cprng_draw(&mut randbuf);
1390        let test_content1 = format!("test content 1 {}", u64::from_le_bytes(randbuf));
1391        zx::cprng_draw(&mut randbuf);
1392        let test_content2 = format!("test content 2 {}", u64::from_le_bytes(randbuf));
1393
1394        let (dir1_server, dir1_client) = zx::Channel::create();
1395        let dir_scope = ExecutionScope::new();
1396        let dir1 = pseudo_directory! {
1397            "test_file1" => read_only(test_content1.clone()),
1398        };
1399        const FLAGS: fio::Flags = fio::PERM_READABLE;
1400        FLAGS
1401            .to_object_request(dir1_server)
1402            .handle(|request| dir1.open3(dir_scope.clone(), vfs::Path::dot(), FLAGS, request));
1403
1404        let (dir2_server, dir2_client) = zx::Channel::create();
1405        let dir2 = pseudo_directory! {
1406            "test_file2" => read_only(test_content2.clone()),
1407        };
1408        FLAGS
1409            .to_object_request(dir2_server)
1410            .handle(|request| dir2.open3(dir_scope.clone(), vfs::Path::dot(), FLAGS, request));
1411
1412        let (mut builder, proxy) = setup_test_util_builder(true)?;
1413        builder.add_namespace_entries(vec![
1414            NamespaceEntry { path: CString::new("/dir1")?, directory: ClientEnd::new(dir1_client) },
1415            NamespaceEntry { path: CString::new("/dir2")?, directory: ClientEnd::new(dir2_client) },
1416        ])?;
1417        let process = builder.build().await?.start()?;
1418        check_process_running(&process)?;
1419
1420        let namespace_dump = proxy.dump_namespace().await.context("failed to dump namespace")?;
1421        assert_eq!(namespace_dump, "/dir1, /dir1/test_file1, /dir2, /dir2/test_file2");
1422
1423        let dir1_contents =
1424            proxy.read_file("/dir1/test_file1").await.context("failed to read file via util")?;
1425        assert_eq!(dir1_contents, test_content1);
1426        let dir2_contents =
1427            proxy.read_file("/dir2/test_file2").await.context("failed to read file via util")?;
1428        assert_eq!(dir2_contents, test_content2);
1429
1430        mem::drop(proxy);
1431        check_process_exited_ok(&process).await?;
1432        Ok(())
1433    }
1434
1435    // Trying to start a dynamically linked process without providing a loader service should
1436    // fail. This verifies that nothing is automatically cloning a loader.
1437    #[fasync::run_singlethreaded(test)]
1438    async fn start_util_with_no_loader_fails() -> Result<(), Error> {
1439        let (builder, _) = setup_test_util_builder(false)?;
1440
1441        let result = builder.build().await;
1442        match result {
1443            Err(ProcessBuilderError::LoaderMissing()) => {}
1444            Err(err) => {
1445                panic!("Unexpected error type: {}", err);
1446            }
1447            Ok(_) => {
1448                panic!("Unexpectedly succeeded to build process without loader");
1449            }
1450        }
1451        Ok(())
1452    }
1453
1454    // Checks that, for dynamically linked binaries, the lower half of the address space has been
1455    // reserved for sanitizers.
1456    #[fasync::run_singlethreaded(test)]
1457    async fn verify_low_address_range_reserved() -> Result<(), Error> {
1458        let (builder, _) = setup_test_util_builder(true)?;
1459        let built = builder.build().await?;
1460
1461        // This ends up being the same thing ReservationVmar does, but it's not reused here so that
1462        // this catches bugs or bad changes to ReservationVmar itself.
1463        let info = built.root_vmar.info()?;
1464        let lower_half_len = util::page_end((info.base + info.len) / 2) - info.base;
1465        built
1466            .root_vmar
1467            .allocate(0, lower_half_len, zx::VmarFlags::SPECIFIC)
1468            .context("Unable to allocate lower address range of new process")?;
1469        Ok(())
1470    }
1471
1472    // Parses the given channel message as a process_args message and returns the HandleInfo's
1473    // contained in it.
1474    fn parse_handle_info_from_message(message: &zx::MessageBuf) -> Result<Vec<HandleInfo>, Error> {
1475        let bytes = message.bytes();
1476        let (header, _) = Ref::<&[u8], process_args::MessageHeader>::from_prefix(bytes)
1477            .map_err(|_| anyhow!("Failed to parse process_args header"))?;
1478
1479        let offset = header.handle_info_off as usize;
1480        let len = mem::size_of::<u32>() * message.n_handles();
1481        let info_bytes = &bytes[offset..offset + len];
1482        let raw_info = Ref::<&[u8], [u32]>::from_bytes(info_bytes)
1483            .map_err(|_| anyhow!("Failed to parse raw handle info"))?;
1484
1485        Ok(raw_info.iter().map(|raw| HandleInfo::try_from(*raw)).collect::<Result<_, _>>()?)
1486    }
1487
1488    const LINKER_MESSAGE_HANDLES: &[HandleType] = &[
1489        HandleType::ProcessSelf,
1490        HandleType::RootVmar,
1491        HandleType::LdsvcLoader,
1492        HandleType::LoadedVmar,
1493        HandleType::ExecutableVmo,
1494    ];
1495
1496    const MAIN_MESSAGE_HANDLES: &[HandleType] = &[
1497        HandleType::ProcessSelf,
1498        HandleType::ThreadSelf,
1499        HandleType::RootVmar,
1500        HandleType::VdsoVmo,
1501        HandleType::StackVmo,
1502    ];
1503
1504    #[fasync::run_singlethreaded(test)]
1505    async fn correct_handles_present() -> Result<(), Error> {
1506        let mut builder = create_test_util_builder()?;
1507        builder.set_loader_service(clone_loader_service()?)?;
1508        let built = builder.build().await?;
1509
1510        for correct in &[LINKER_MESSAGE_HANDLES, MAIN_MESSAGE_HANDLES] {
1511            let mut msg_buf = zx::MessageBuf::new();
1512            built.bootstrap.read(&mut msg_buf)?;
1513            let handle_info = parse_handle_info_from_message(&msg_buf)?;
1514
1515            assert_eq!(handle_info.len(), correct.len());
1516            for correct_type in *correct {
1517                // Should only be one of each of these handles present.
1518                assert_eq!(
1519                    1,
1520                    handle_info.iter().filter(|info| &info.handle_type() == correct_type).count()
1521                );
1522            }
1523        }
1524        Ok(())
1525    }
1526
1527    // Verify that [ProcessBuilder::add_handles()] rejects handle types that are added
1528    // automatically by the builder.
1529    #[fasync::run_singlethreaded(test)]
1530    async fn add_handles_rejects_automatic_handle_types() -> Result<(), Error> {
1531        // The VMO doesn't need to be valid since we're not calling build.
1532        let vmo = zx::Vmo::create(1)?;
1533        let job = fuchsia_runtime::job_default();
1534        let procname = CString::new("test_vmo")?;
1535        let mut builder = ProcessBuilder::new(
1536            &procname,
1537            &job,
1538            zx::ProcessOptions::empty(),
1539            vmo,
1540            get_system_vdso_vmo().unwrap(),
1541        )?;
1542
1543        // There's some duplicates between these slices but just checking twice is easier than
1544        // deduping these.
1545        for handle_type in LINKER_MESSAGE_HANDLES.iter().chain(MAIN_MESSAGE_HANDLES) {
1546            if *handle_type == HandleType::LdsvcLoader {
1547                // Skip LdsvcLoader, which is required in the linker message but is not added
1548                // automatically. The user must supply it.
1549                continue;
1550            }
1551
1552            if *handle_type == HandleType::VdsoVmo {
1553                // Skip VdsoVmo, which may be supplied by the user.
1554                continue;
1555            }
1556
1557            // Another VMO, just to have a valid handle.
1558            let vmo = zx::Vmo::create(1)?;
1559            let result = builder.add_handles(vec![process_args::StartupHandle {
1560                handle: vmo.into_handle(),
1561                info: HandleInfo::new(*handle_type, 0),
1562            }]);
1563            match result {
1564                Err(ProcessBuilderError::InvalidArg(_)) => {}
1565                Err(err) => {
1566                    panic!("Unexpected error type, should be invalid arg: {}", err);
1567                }
1568                Ok(_) => {
1569                    panic!("add_handle unexpectedly succeeded for type {:?}", handle_type);
1570                }
1571            }
1572        }
1573        Ok(())
1574    }
1575
1576    // Verify that invalid handles are correctly rejected.
1577    #[fasync::run_singlethreaded(test)]
1578    async fn rejects_invalid_handles() -> Result<(), Error> {
1579        let invalid = || zx::Handle::invalid();
1580        let assert_invalid_arg = |result| match result {
1581            Err(ProcessBuilderError::BadHandle(_)) => {}
1582            Err(err) => {
1583                panic!("Unexpected error type, should be BadHandle: {}", err);
1584            }
1585            Ok(_) => {
1586                panic!("API unexpectedly accepted invalid handle");
1587            }
1588        };
1589
1590        // The VMO doesn't need to be valid since we're not calling build with this.
1591        let vmo = zx::Vmo::create(1)?;
1592        let job = fuchsia_runtime::job_default();
1593        let procname = CString::new("test_vmo")?;
1594
1595        assert_invalid_arg(
1596            ProcessBuilder::new(
1597                &procname,
1598                &invalid().into(),
1599                zx::ProcessOptions::empty(),
1600                vmo,
1601                get_system_vdso_vmo().unwrap(),
1602            )
1603            .map(|_| ()),
1604        );
1605        assert_invalid_arg(
1606            ProcessBuilder::new(
1607                &procname,
1608                &job,
1609                zx::ProcessOptions::empty(),
1610                invalid().into(),
1611                get_system_vdso_vmo().unwrap(),
1612            )
1613            .map(|_| ()),
1614        );
1615
1616        let (mut builder, _) = setup_test_util_builder(true)?;
1617
1618        assert_invalid_arg(builder.set_loader_service(invalid().into()));
1619        assert_invalid_arg(builder.add_handles(vec![process_args::StartupHandle {
1620            handle: invalid().into(),
1621            info: HandleInfo::new(HandleType::User0, 0),
1622        }]));
1623        assert_invalid_arg(builder.add_handles(vec![process_args::StartupHandle {
1624            handle: invalid().into(),
1625            info: HandleInfo::new(HandleType::User0, 0),
1626        }]));
1627        assert_invalid_arg(builder.add_namespace_entries(vec![NamespaceEntry {
1628            path: CString::new("/dir")?,
1629            directory: invalid().into(),
1630        }]));
1631
1632        Ok(())
1633    }
1634
1635    #[fasync::run_singlethreaded]
1636    #[test]
1637    async fn start_static_pie_binary() -> Result<(), Error> {
1638        const TEST_BIN: &'static str = "/pkg/bin/static_pie_test_util";
1639        let file = fdio::open_fd(TEST_BIN, fio::PERM_READABLE | fio::PERM_EXECUTABLE)?;
1640        let vmo = fdio::get_vmo_exec_from_file(&file)?;
1641        let job = fuchsia_runtime::job_default();
1642
1643        let procname = CString::new(TEST_BIN.to_owned())?;
1644        let mut builder = ProcessBuilder::new(
1645            &procname,
1646            &job,
1647            zx::ProcessOptions::empty(),
1648            vmo,
1649            get_system_vdso_vmo().unwrap(),
1650        )?;
1651
1652        // We pass the program a channel with handle type User0 which we send a message on and
1653        // expect it to echo back the message on the same channel.
1654        let (local, remote) = zx::Channel::create();
1655        builder.add_handles(vec![process_args::StartupHandle {
1656            handle: remote.into_handle(),
1657            info: HandleInfo::new(HandleType::User0, 0),
1658        }])?;
1659
1660        let mut randbuf = [0; 8];
1661        zx::cprng_draw(&mut randbuf);
1662        let test_message = format!("test content 1 {}", u64::from_le_bytes(randbuf)).into_bytes();
1663        local.write(&test_message, &mut vec![])?;
1664
1665        // Start process and wait for channel to have a message to read or be closed.
1666        builder.build().await?.start()?;
1667        let signals = fasync::OnSignals::new(
1668            &local,
1669            zx::Signals::CHANNEL_READABLE | zx::Signals::CHANNEL_PEER_CLOSED,
1670        )
1671        .await?;
1672        assert!(signals.contains(zx::Signals::CHANNEL_READABLE));
1673
1674        let mut echoed = zx::MessageBuf::new();
1675        local.read(&mut echoed)?;
1676        assert_eq!(echoed.bytes(), test_message.as_slice());
1677        assert_eq!(echoed.n_handles(), 0);
1678        Ok(())
1679    }
1680}