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::{Context, anyhow};
7use fidl::endpoints::{ClientEnd, Proxy};
8use fuchsia_async::{self as fasync, TimeoutExt};
9use fuchsia_runtime::{HandleInfo, HandleType};
10use futures::prelude::*;
11use std::ffi::{CStr, CString};
12use std::{iter, mem};
13use thiserror::Error;
14use zx::{self as zx, AsHandleRef, HandleBased};
15use {fidl_fuchsia_io as fio, fidl_fuchsia_ldsvc as fldsvc};
16
17/// 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::NullableHandle] 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: entry.directory.into(),
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 =
476                mem::replace(&mut self.executable, zx::NullableHandle::invalid().into());
477            let msg = self.build_linker_message(ldsvc, executable, loaded_elf.vmar)?;
478            msg.write(&bootstrap_wr).map_err(ProcessBuilderError::WriteBootstrapMessage)?;
479        } else {
480            // Statically linked but still position-independent (ET_DYN) ELF, load directly.
481            dynamic = false;
482
483            loaded_elf =
484                elf_load::load_elf(&self.executable, &elf_headers, &self.common.root_vmar)?;
485            self.msg_contents.handles.push(process_args::StartupHandle {
486                handle: loaded_elf.vmar.into_handle(),
487                info: HandleInfo::new(HandleType::LoadedVmar, 0),
488            });
489        }
490
491        // Load the vDSO - either the default system vDSO, or the user-provided one - into the
492        // process's address space and a handle to it to the bootstrap message.
493        let vdso_base = self.load_vdso()?;
494
495        // Calculate initial stack size.
496        let mut stack_size;
497        let stack_vmo_name;
498        if dynamic {
499            // Calculate the initial stack size for the dynamic linker. This factors in the size of
500            // an extra handle for the stack that hasn't yet been added to the message contents,
501            // since creating the stack requires this size.
502            stack_size = calculate_initial_linker_stack_size(&mut self.msg_contents, 1)?;
503            stack_vmo_name = format!("stack: msg of {:#x?}", stack_size);
504        } else {
505            // Set stack size from PT_GNU_STACK header, if present, or use the default. The dynamic
506            // linker handles this for dynamically linked ELFs (above case).
507            const ZIRCON_DEFAULT_STACK_SIZE: usize = 256 << 10; // 256KiB
508            let mut ss = ("default", ZIRCON_DEFAULT_STACK_SIZE);
509            if let Some(stack_hdr) =
510                elf_headers.program_header_with_type(elf_parse::SegmentType::GnuStack)?
511            {
512                if stack_hdr.memsz > 0 {
513                    ss = ("explicit", stack_hdr.memsz as usize);
514                }
515            }
516
517            // Stack size must be page aligned.
518            stack_size = util::page_end(ss.1);
519            stack_vmo_name = format!("stack: {} {:#x?}", ss.0, stack_size);
520        }
521        if stack_size < self.min_stack_size {
522            stack_size = util::page_end(self.min_stack_size);
523        }
524
525        // Allocate the initial thread's stack, map it, and add a handle to the bootstrap message.
526        let stack_vmo_name =
527            zx::Name::new(&stack_vmo_name).expect("Stack VMO name must be less than 31 bytes");
528        let stack_info = self.create_stack(stack_size, &stack_vmo_name)?;
529
530        // Build and send the primary bootstrap message.
531        let msg = process_args::Message::build(self.msg_contents)?;
532        msg.write(&bootstrap_wr).map_err(ProcessBuilderError::WriteBootstrapMessage)?;
533
534        // Explicitly destroy the reservation VMAR before returning so that we can be sure it is
535        // gone (so we don't end up with a process with half its address space gone).
536        if let Some(mut r) = reserve_vmar {
537            r.destroy().map_err(ProcessBuilderError::DestroyReservationVMAR)?;
538        }
539
540        Ok(BuiltProcess {
541            process: self.common.process,
542            root_vmar: self.common.root_vmar,
543            thread: self.common.thread,
544            entry: loaded_elf.entry,
545            stack: stack_info.stack_ptr,
546            stack_base: stack_info.stack_base,
547            stack_vmo: stack_info.stack_vmo,
548            bootstrap: bootstrap_rd,
549            vdso_base: vdso_base,
550            elf_base: loaded_elf.vmar_base,
551            elf_headers,
552        })
553    }
554
555    /// Build the bootstrap message for the dynamic linker, which uses the same process_args
556    /// protocol as the message for the main process but somewhat different contents.
557    ///
558    /// The LoaderProxy provided must be ready to be converted to a Handle with into_channel(). In
559    /// other words, there must be no other active clones of the proxy, no open requests, etc. The
560    /// intention is that the user provides a handle only (perhaps wrapped in a ClientEnd) through
561    /// [ProcessBuilder::set_loader_service()], not a Proxy, so the library can be sure this
562    /// invariant is maintained and a failure is a library bug.
563    fn build_linker_message(
564        &self,
565        ldsvc: fldsvc::LoaderProxy,
566        executable: zx::Vmo,
567        loaded_vmar: zx::Vmar,
568    ) -> Result<process_args::Message, ProcessBuilderError> {
569        // Don't need to use the ldsvc.Loader anymore; turn it back into into a raw handle so
570        // we can pass it along in the dynamic linker bootstrap message.
571        let ldsvc_hnd =
572            ldsvc.into_channel().expect("Failed to get channel from LoaderProxy").into_zx_channel();
573
574        // The linker message only needs a subset of argv and envvars.
575        let args = extract_ld_arguments(&self.msg_contents.args);
576        let environment_vars =
577            extract_ld_environment_variables(&self.msg_contents.environment_vars);
578
579        let mut linker_msg_contents = process_args::MessageContents {
580            // Argument strings are sent to the linker so that it can use argv[0] in messages it
581            // prints.
582            args,
583            // Environment variables are sent to the linker so that it can see vars like LD_DEBUG.
584            environment_vars,
585            // Process namespace is not set up or used in the linker.
586            namespace_paths: vec![],
587            // Loader message includes a few special handles needed to do its job, plus a set of
588            // handles common to both messages which are generated by this library.
589            handles: vec![
590                process_args::StartupHandle {
591                    handle: ldsvc_hnd.into_handle(),
592                    info: HandleInfo::new(HandleType::LdsvcLoader, 0),
593                },
594                process_args::StartupHandle {
595                    handle: executable.into_handle(),
596                    info: HandleInfo::new(HandleType::ExecutableVmo, 0),
597                },
598                process_args::StartupHandle {
599                    handle: loaded_vmar.into_handle(),
600                    info: HandleInfo::new(HandleType::LoadedVmar, 0),
601                },
602            ],
603        };
604        self.common.add_process_self(&mut linker_msg_contents)?;
605        self.common.add_root_vmar(&mut linker_msg_contents)?;
606        Ok(process_args::Message::build(linker_msg_contents)?)
607    }
608
609    /// Load the vDSO VMO into the process's address space and a handle to it to the bootstrap
610    /// message. If a vDSO VMO is provided, loads that one, otherwise loads the default system
611    /// vDSO, invaliding the duplicate default system vDSO handle stored in this object.
612    /// Returns the base address that the vDSO was mapped into.
613    fn load_vdso(&mut self) -> Result<usize, ProcessBuilderError> {
614        let vdso = match self.non_default_vdso.take() {
615            Some(vmo) => vmo,
616            None => mem::replace(&mut self.system_vdso_vmo, zx::NullableHandle::invalid().into()),
617        };
618        let vdso_headers = elf_parse::Elf64Headers::from_vmo(&vdso)?;
619        let loaded_vdso = elf_load::load_elf(&vdso, &vdso_headers, &self.common.root_vmar)?;
620
621        self.msg_contents.handles.push(process_args::StartupHandle {
622            handle: vdso.into_handle(),
623            info: HandleInfo::new(HandleType::VdsoVmo, 0),
624        });
625
626        Ok(loaded_vdso.vmar_base)
627    }
628
629    /// Allocate the initial thread's stack, map it, and add a handle to the bootstrap message.
630    /// Returns the initial stack pointer for the process.
631    ///
632    /// Note that launchpad supported not allocating a stack at all, but that only happened if an
633    /// explicit stack size of 0 is set. ProcessBuilder does not support overriding the stack size
634    /// so a stack is always created.
635    fn create_stack(
636        &mut self,
637        stack_size: usize,
638        vmo_name: &zx::Name,
639    ) -> Result<StackInfo, ProcessBuilderError> {
640        let stack_vmo = zx::Vmo::create(stack_size as u64).map_err(|s| {
641            ProcessBuilderError::GenericStatus("Failed to create VMO for initial thread stack", s)
642        })?;
643        stack_vmo
644            .set_name(vmo_name)
645            .map_err(|s| ProcessBuilderError::GenericStatus("Failed to set stack VMO name", s))?;
646        let stack_flags = zx::VmarFlags::PERM_READ | zx::VmarFlags::PERM_WRITE;
647        let stack_base =
648            self.common.root_vmar.map(0, &stack_vmo, 0, stack_size, stack_flags).map_err(|s| {
649                ProcessBuilderError::GenericStatus("Failed to map initial stack", s)
650            })?;
651        let stack_ptr = compute_initial_stack_pointer(stack_base, stack_size);
652        let dup_stack_vmo = stack_vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).map_err(|s| {
653            ProcessBuilderError::GenericStatus("Failed to duplicate initial stack", s)
654        })?;
655
656        // Pass the stack VMO to the process. Our protocol with the new process is that we warrant
657        // that this is the VMO from which the initial stack is mapped and that we've exactly
658        // mapped the entire thing, so vm_object_get_size on this in concert with the initial SP
659        // value tells it the exact bounds of its stack.
660        self.msg_contents.handles.push(process_args::StartupHandle {
661            handle: dup_stack_vmo.into_handle(),
662            info: HandleInfo::new(HandleType::StackVmo, 0),
663        });
664
665        Ok(StackInfo { stack_ptr, stack_base, stack_vmo })
666    }
667}
668
669/// Calculate the size of the initial stack to allocate for the dynamic linker, based on the given
670/// process_args message contents.
671///
672/// The initial stack is used just for startup work in the dynamic linker and to hold the bootstrap
673/// message, so we only attempt to make it only as big as needed. The size returned is based on the
674/// stack space needed to read the bootstrap message with zx_channel_read, and thus includes the
675/// message data itself plus the size of the handles (i.e. the size of N zx_handle_t's).
676///
677/// This also allows the caller to specify an number of "extra handles" to factor into the size
678/// calculation. This allows the size to be calculated before all the real handles have been added
679/// to the contents, for example if the size is needed to create those handles.
680pub fn calculate_initial_linker_stack_size(
681    msg_contents: &mut process_args::MessageContents,
682    extra_handles: usize,
683) -> Result<usize, ProcessBuilderError> {
684    // Add N placeholder handles temporarily to factor in the size of handles that are not yet
685    // added to the message contents.
686    msg_contents.handles.extend(
687        iter::repeat_with(|| process_args::StartupHandle {
688            handle: zx::NullableHandle::invalid(),
689            info: HandleInfo::new(HandleType::User0, 0),
690        })
691        .take(extra_handles),
692    );
693
694    // Include both the message data size and the size of the handles since we're calculating the
695    // stack space required to read the message.
696    let num_handles = msg_contents.handles.len();
697    let msg_stack_size = process_args::Message::calculate_size(msg_contents)?
698        + num_handles * mem::size_of::<zx::sys::zx_handle_t>();
699    msg_contents.handles.truncate(num_handles - extra_handles);
700
701    // PTHREAD_STACK_MIN is defined by the C library in
702    // //zircon/third_party/ulib/musl/include/limits.h. It is tuned enough to cover the dynamic
703    // linker and C library startup code's stack usage (up until the point it switches to its own
704    // stack in __libc_start_main), but leave a little space so for small bootstrap message sizes
705    // the stack needs only one page.
706    const PTHREAD_STACK_MIN: usize = 3072;
707    Ok(util::page_end(msg_stack_size + PTHREAD_STACK_MIN))
708}
709
710/// Extract only the arguments that are needed for a linker message.
711fn extract_ld_arguments(arguments: &[CString]) -> Vec<CString> {
712    let mut extracted = vec![];
713
714    if let Some(argument) = arguments.get(0) {
715        extracted.push(argument.clone())
716    }
717
718    extracted
719}
720
721/// Extract only the environment variables that are needed for a linker message.
722fn extract_ld_environment_variables(envvars: &[CString]) -> Vec<CString> {
723    let prefixes = ["LD_DEBUG=", "LD_TRACE="];
724
725    let mut extracted = vec![];
726    for envvar in envvars {
727        for prefix in &prefixes {
728            let envvar_bytes: &[u8] = envvar.to_bytes();
729            let prefix_bytes: &[u8] = prefix.as_bytes();
730            if envvar_bytes.starts_with(prefix_bytes) {
731                extracted.push(envvar.clone());
732                continue;
733            }
734        }
735    }
736
737    extracted
738}
739
740impl CommonMessageHandles {
741    fn add_process_self(
742        &self,
743        msg: &mut process_args::MessageContents,
744    ) -> Result<(), ProcessBuilderError> {
745        Self::add_to_message(msg, self.process.as_handle_ref(), HandleType::ProcessSelf)
746    }
747
748    fn add_thread_self(
749        &self,
750        msg: &mut process_args::MessageContents,
751    ) -> Result<(), ProcessBuilderError> {
752        Self::add_to_message(msg, self.thread.as_handle_ref(), HandleType::ThreadSelf)
753    }
754
755    fn add_root_vmar(
756        &self,
757        msg: &mut process_args::MessageContents,
758    ) -> Result<(), ProcessBuilderError> {
759        Self::add_to_message(msg, self.root_vmar.as_handle_ref(), HandleType::RootVmar)
760    }
761
762    /// Add a handle to the procargs message with `0` for its `arg`.
763    fn add_to_message(
764        msg: &mut process_args::MessageContents,
765        handle: zx::HandleRef<'_>,
766        handle_type: HandleType,
767    ) -> Result<(), ProcessBuilderError> {
768        let dup = handle
769            .duplicate(zx::Rights::SAME_RIGHTS)
770            .map_err(|s| ProcessBuilderError::DuplicateHandle(handle_type, s))?;
771        msg.handles.push(process_args::StartupHandle {
772            handle: dup,
773            info: HandleInfo::new(handle_type, 0),
774        });
775        Ok(())
776    }
777}
778
779/// Given the base and size of the stack block, compute the appropriate initial
780/// SP value for an initial thread according to the C calling convention for the
781/// machine.
782///
783/// Copied from, and must be kept in sync with:
784/// //zircon/system/ulib/elf-psabi/include/lib/elf-psabi/sp.h
785pub fn compute_initial_stack_pointer(base: usize, size: usize) -> usize {
786    // Assume stack grows down.
787    let mut sp = base.checked_add(size).expect("Overflow in stack pointer calculation");
788
789    // The x86-64 and AArch64 ABIs require 16-byte alignment.
790    // The 32-bit ARM ABI only requires 8-byte alignment, but 16-byte alignment is preferable for
791    // NEON so use it there too.
792    // RISC-V ABIs also require 16-byte alignment.
793    sp &= 16usize.wrapping_neg();
794
795    // The x86-64 ABI requires %rsp % 16 = 8 on entry.  The zero word at (%rsp) serves as the
796    // return address for the outermost frame.
797    #[cfg(target_arch = "x86_64")]
798    {
799        sp -= 8;
800    }
801
802    // The ARMv7 and ARMv8 ABIs both just require that SP be aligned, so just catch unknown archs.
803    #[cfg(not(any(
804        target_arch = "x86_64",
805        target_arch = "arm",
806        target_arch = "aarch64",
807        target_arch = "riscv64"
808    )))]
809    {
810        compile_error!("Unknown target_arch");
811    }
812
813    sp
814}
815
816/// Load the dynamic linker/loader specified in the PT_INTERP header via the fuchsia.ldsvc.Loader
817/// handle.
818pub async fn get_dynamic_linker<'a>(
819    ldsvc: &'a fldsvc::LoaderProxy,
820    executable: &'a zx::Vmo,
821    interp_hdr: &'a elf_parse::Elf64ProgramHeader,
822) -> Result<zx::Vmo, ProcessBuilderError> {
823    // Read the dynamic linker name from the main VMO, based on the PT_INTERP header.
824    let mut interp = vec![0u8; interp_hdr.filesz as usize];
825    executable
826        .read(&mut interp[..], interp_hdr.offset as u64)
827        .map_err(|s| ProcessBuilderError::GenericStatus("Failed to read from VMO", s))?;
828    // Trim null terminator included in filesz.
829    match interp.pop() {
830        Some(b'\0') => Ok(()),
831        _ => Err(ProcessBuilderError::InvalidInterpHeader(anyhow!("Missing null terminator"))),
832    }?;
833    let interp_str = std::str::from_utf8(&interp)
834        .context("Invalid UTF8")
835        .map_err(ProcessBuilderError::InvalidInterpHeader)?;
836
837    // Retrieve the dynamic linker as a VMO from fuchsia.ldsvc.Loader
838    const LDSO_LOAD_TIMEOUT_SEC: i64 = 30;
839    let load_fut =
840        ldsvc.load_object(interp_str).map_err(ProcessBuilderError::LoadDynamicLinker).on_timeout(
841            fasync::MonotonicInstant::after(zx::MonotonicDuration::from_seconds(
842                LDSO_LOAD_TIMEOUT_SEC,
843            )),
844            || Err(ProcessBuilderError::LoadDynamicLinkerTimeout()),
845        );
846    let (status, ld_vmo) = load_fut.await?;
847    zx::Status::ok(status).map_err(|s| {
848        ProcessBuilderError::GenericStatus(
849            "Failed to load dynamic linker from fuchsia.ldsvc.Loader",
850            s,
851        )
852    })?;
853    Ok(ld_vmo.ok_or(ProcessBuilderError::GenericStatus(
854        "load_object status was OK but no VMO",
855        zx::Status::INTERNAL,
856    ))?)
857}
858
859impl BuiltProcess {
860    /// Start an already built process.
861    ///
862    /// This is a simple wrapper around the [zx_process_start] syscall that consumes the handles
863    /// and data in the BuiltProcess struct as needed.
864    ///
865    /// [zx_process_start]: https://fuchsia.dev/fuchsia-src/reference/syscalls/process_start.md
866    pub fn start(self) -> Result<zx::Process, ProcessBuilderError> {
867        self.process
868            .start(
869                &self.thread,
870                self.entry,
871                self.stack,
872                self.bootstrap.into_handle(),
873                self.vdso_base,
874            )
875            .map_err(ProcessBuilderError::ProcessStart)?;
876        Ok(self.process)
877    }
878}
879
880struct ReservationVmar(Option<zx::Vmar>);
881
882impl ReservationVmar {
883    /// Reserve the lower half of the address space of the given VMAR by allocating another VMAR.
884    ///
885    /// The VMAR wrapped by this reservation is automatically destroyed when the reservation
886    /// is dropped.
887    fn reserve_low_address_space(vmar: &zx::Vmar) -> Result<ReservationVmar, ProcessBuilderError> {
888        let info = vmar
889            .info()
890            .map_err(|s| ProcessBuilderError::GenericStatus("Failed to get VMAR info", s))?;
891
892        // Reserve the lower half of the full address space, not just half of the VMAR length.
893        // (base+len) represents the full address space, assuming this is used with a root VMAR and
894        // length extends to the end of the address space, including a region the kernel reserves
895        // at the start of the space.
896        // TODO(https://fxbug.dev/42099306): Clean up address space reservation to avoid unnecessary
897        // reservations, which should also avoid the "fake" reservation in the else-clause.
898        if let Some(reserve_size) =
899            util::page_end((info.base + info.len) / 2).checked_sub(info.base)
900        {
901            let (reserve_vmar, reserve_base) =
902                vmar.allocate(0, reserve_size, zx::VmarFlags::SPECIFIC).map_err(|s| {
903                    ProcessBuilderError::GenericStatus("Failed to allocate reservation VMAR", s)
904                })?;
905            assert_eq!(reserve_base, info.base, "Reservation VMAR allocated at wrong address");
906
907            Ok(ReservationVmar(Some(reserve_vmar)))
908        } else {
909            // The VMAR does not intersect the "bottom half," so return a success but without an
910            // actual reservation.
911            Ok(ReservationVmar(None))
912        }
913    }
914
915    /// Destroy the reservation. The reservation is also automatically destroyed when
916    /// ReservationVmar is dropped.
917    ///
918    /// VMARs are not destroyed when the handle is closed (by dropping), so we must explicit destroy
919    /// it to release the reservation and allow the created process to use the full address space.
920    fn destroy(&mut self) -> Result<(), zx::Status> {
921        match self.0.take() {
922            Some(vmar) => {
923                // This is safe because there are no mappings in the region and it is not a region
924                // in the current process.
925                unsafe { vmar.destroy() }
926            }
927            None => Ok(()),
928        }
929    }
930}
931
932// This is probably unnecessary, but it feels wrong to rely on the side effect of the process's
933// root VMAR going away. We explicitly call destroy if ProcessBuilder.build() succeeds and returns
934// a BuiltProcess, in which case this will do nothing, and if build() fails then the new process
935// and its root VMAR will get cleaned up along with this sub-VMAR.
936impl Drop for ReservationVmar {
937    fn drop(&mut self) {
938        _ = self.destroy();
939    }
940}
941
942#[cfg(test)]
943mod tests {
944    use super::*;
945    use anyhow::Error;
946    use assert_matches::assert_matches;
947    use fidl::prelude::*;
948    use fidl_test_processbuilder::{UtilMarker, UtilProxy};
949    use std::sync::LazyLock;
950    use vfs::file::vmo::read_only;
951    use vfs::pseudo_directory;
952    use zerocopy::Ref;
953    use {fidl_fuchsia_io as fio, fuchsia_async as fasync};
954
955    unsafe extern "C" {
956        fn dl_clone_loader_service(handle: *mut zx::sys::zx_handle_t) -> zx::sys::zx_status_t;
957    }
958
959    fn get_system_vdso_vmo() -> Result<zx::Vmo, ProcessBuilderError> {
960        static VDSO_VMO: LazyLock<zx::Vmo> = LazyLock::new(|| {
961            zx::Vmo::from(
962                fuchsia_runtime::take_startup_handle(HandleInfo::new(HandleType::VdsoVmo, 0))
963                    .expect("Failed to take VDSO VMO startup handle"),
964            )
965        });
966
967        let vdso_dup = VDSO_VMO
968            .duplicate_handle(zx::Rights::SAME_RIGHTS)
969            .map_err(|s| ProcessBuilderError::GenericStatus("Failed to dup vDSO VMO handle", s))?;
970        Ok(vdso_dup)
971    }
972
973    // Clone the current loader service to provide to the new test processes.
974    fn clone_loader_service() -> Result<ClientEnd<fldsvc::LoaderMarker>, zx::Status> {
975        let mut raw = 0;
976        let status = unsafe { dl_clone_loader_service(&mut raw) };
977        zx::Status::ok(status)?;
978
979        let handle = unsafe { zx::NullableHandle::from(zx::NullableHandle::from_raw(raw)) };
980        Ok(ClientEnd::new(zx::Channel::from(handle)))
981    }
982
983    fn connect_util(client: &zx::Channel) -> Result<UtilProxy, Error> {
984        let (proxy, server) = zx::Channel::create();
985        fdio::service_connect_at(&client, UtilMarker::PROTOCOL_NAME, server)
986            .context("failed to connect to util service")?;
987        Ok(UtilProxy::from_channel(fasync::Channel::from_channel(proxy)))
988    }
989
990    fn create_test_util_builder() -> Result<ProcessBuilder, Error> {
991        const TEST_UTIL_BIN: &'static str = "/pkg/bin/process_builder_test_util";
992        let file = fdio::open_fd(TEST_UTIL_BIN, fio::PERM_READABLE | fio::PERM_EXECUTABLE)?;
993        let vmo = fdio::get_vmo_exec_from_file(&file)?;
994        let job = fuchsia_runtime::job_default();
995
996        let procname = CString::new(TEST_UTIL_BIN.to_owned())?;
997        Ok(ProcessBuilder::new(
998            &procname,
999            &job,
1000            zx::ProcessOptions::empty(),
1001            vmo,
1002            get_system_vdso_vmo().unwrap(),
1003        )?)
1004    }
1005
1006    // Common builder setup for all tests that start a test util process.
1007    fn setup_test_util_builder(set_loader: bool) -> Result<(ProcessBuilder, UtilProxy), Error> {
1008        let mut builder = create_test_util_builder()?;
1009        if set_loader {
1010            builder.add_handles(vec![process_args::StartupHandle {
1011                handle: clone_loader_service()?.into_handle(),
1012                info: HandleInfo::new(HandleType::LdsvcLoader, 0),
1013            }])?;
1014        }
1015
1016        let (dir_client, dir_server) = zx::Channel::create();
1017        builder.add_handles(vec![process_args::StartupHandle {
1018            handle: dir_server.into_handle(),
1019            info: HandleInfo::new(HandleType::DirectoryRequest, 0),
1020        }])?;
1021
1022        let proxy = connect_util(&dir_client)?;
1023        Ok((builder, proxy))
1024    }
1025
1026    fn check_process_running(process: &zx::Process) -> Result<(), Error> {
1027        let info = process.info()?;
1028        const STARTED: zx::ProcessInfoFlags = zx::ProcessInfoFlags::STARTED;
1029        assert_matches!(
1030            info,
1031            zx::ProcessInfo {
1032                return_code: 0,
1033                start_time,
1034                flags: STARTED,
1035                ..
1036            } if start_time.into_nanos() > 0
1037        );
1038        Ok(())
1039    }
1040
1041    async fn check_process_exited_ok(process: &zx::Process) -> Result<(), Error> {
1042        fasync::OnSignals::new(process, zx::Signals::PROCESS_TERMINATED).await?;
1043
1044        let info = process.info()?;
1045        const STARTED_AND_EXITED: zx::ProcessInfoFlags =
1046            zx::ProcessInfoFlags::STARTED.union(zx::ProcessInfoFlags::EXITED);
1047        assert_matches!(
1048            info,
1049            zx::ProcessInfo {
1050                return_code: 0,
1051                start_time,
1052                flags: STARTED_AND_EXITED,
1053                ..
1054            } if start_time.into_nanos() > 0
1055        );
1056        Ok(())
1057    }
1058
1059    // These start_util_with_* tests cover the most common paths through ProcessBuilder and
1060    // exercise most of its functionality. They verify that we can create a new process for a
1061    // "standard" dynamically linked executable and that we can provide arguments, environment
1062    // variables, namespace entries, and other handles to it through the startup process_args
1063    // message. The test communicates with the test util process it creates over a test-only FIDL
1064    // API to verify that arguments and whatnot were passed correctly.
1065    #[fasync::run_singlethreaded(test)]
1066    async fn start_util_with_args() -> Result<(), Error> {
1067        let test_args = vec!["arg0", "arg1", "arg2"];
1068        let test_args_cstr =
1069            test_args.iter().map(|&s| CString::new(s)).collect::<Result<_, _>>()?;
1070
1071        let (mut builder, proxy) = setup_test_util_builder(true)?;
1072        builder.add_arguments(test_args_cstr);
1073        let process = builder.build().await?.start()?;
1074        check_process_running(&process)?;
1075
1076        // Use the util protocol to confirm that the new process was set up correctly. A successful
1077        // connection to the util validates that handles are passed correctly to the new process,
1078        // since the DirectoryRequest handle made it.
1079        let proc_args = proxy.get_arguments().await.context("failed to get args from util")?;
1080        assert_eq!(proc_args, test_args);
1081
1082        mem::drop(proxy);
1083        check_process_exited_ok(&process).await?;
1084        Ok(())
1085    }
1086
1087    #[fasync::run_singlethreaded(test)]
1088    async fn start_util_with_huge_args() -> Result<(), Error> {
1089        // This test is partially designed to probe the stack usage of
1090        // code processing the initial loader message. Such processing
1091        // is on a stack of limited size, a few pages, and well
1092        // smaller than a maximally large channel packet. Each
1093        // instance of "arg" takes 4 bytes (counting the separating
1094        // '\0' byte), so let's send 10k of them to be well larger
1095        // than the initial stack but well within the 64k channel size.
1096        let test_args = vec!["arg"; 10 * 1000];
1097        let test_args_cstr =
1098            test_args.iter().map(|&s| CString::new(s)).collect::<Result<_, _>>()?;
1099
1100        let (mut builder, proxy) = setup_test_util_builder(true)?;
1101        builder.add_arguments(test_args_cstr);
1102        let process = builder.build().await?.start()?;
1103        check_process_running(&process)?;
1104
1105        // Use the util protocol to confirm that the new process was set up correctly. A successful
1106        // connection to the util validates that handles are passed correctly to the new process,
1107        // since the DirectoryRequest handle made it.
1108        // We can't use get_arguments() here because the FIDL response will be bigger than the
1109        // maximum message size[1] and cause the process to crash. Instead, we just check the number
1110        // of environment variables and assume that if that's correct we're good to go.
1111        // Size of each vector entry: (length = 8, pointer = 8) = 16 + (string size = 8) = 24
1112        // Message size = (10k * vector entry size) = 240,000 > 65,536
1113        let proc_args =
1114            proxy.get_argument_count().await.context("failed to get arg count from util")?;
1115
1116        assert_eq!(proc_args, test_args.len() as u64);
1117
1118        mem::drop(proxy);
1119        check_process_exited_ok(&process).await?;
1120        Ok(())
1121    }
1122
1123    // Verify that the lifecycle channel can be passed through the bootstrap
1124    // channel. This test checks by creating a channel, passing it through,
1125    // asking the remote process for the lifecycle channel's koid, and then
1126    // comparing that koid to the one the test recorded.
1127    #[fasync::run_singlethreaded(test)]
1128    async fn start_util_with_lifecycle_channel() -> Result<(), Error> {
1129        let (mut builder, proxy) = setup_test_util_builder(true)?;
1130        let (lifecycle_server, _lifecycle_client) = zx::Channel::create();
1131        let koid = lifecycle_server
1132            .as_handle_ref()
1133            .basic_info()
1134            .expect("error getting server handle info")
1135            .koid
1136            .raw_koid();
1137        builder.add_handles(vec![process_args::StartupHandle {
1138            handle: lifecycle_server.into_handle(),
1139            info: HandleInfo::new(HandleType::Lifecycle, 0),
1140        }])?;
1141        let process = builder.build().await?.start()?;
1142        check_process_running(&process)?;
1143
1144        // Use the util protocol to confirm that the new process received the
1145        // lifecycle channel
1146        let reported_koid =
1147            proxy.get_lifecycle_koid().await.context("failed getting koid from util")?;
1148        assert_eq!(koid, reported_koid);
1149        mem::drop(proxy);
1150        check_process_exited_ok(&process).await?;
1151        Ok(())
1152    }
1153
1154    // Verify that if no lifecycle channel is sent via the bootstrap channel
1155    // that the remote process reports ZX_KOID_INVALID for the channel koid.
1156    #[fasync::run_singlethreaded(test)]
1157    async fn start_util_with_no_lifecycle_channel() -> Result<(), Error> {
1158        let (builder, proxy) = setup_test_util_builder(true)?;
1159        let process = builder.build().await?.start()?;
1160        check_process_running(&process)?;
1161
1162        // Use the util protocol to confirm that the new process received the
1163        // lifecycle channel
1164        let reported_koid =
1165            proxy.get_lifecycle_koid().await.context("failed getting koid from util")?;
1166        assert_eq!(zx::sys::ZX_KOID_INVALID, reported_koid);
1167        mem::drop(proxy);
1168        check_process_exited_ok(&process).await?;
1169        Ok(())
1170    }
1171
1172    #[fasync::run_singlethreaded(test)]
1173    async fn start_util_with_big_stack() -> Result<(), Error> {
1174        let stack_size: usize = zx::system_get_page_size() as usize * 10;
1175
1176        let (mut builder, proxy) = setup_test_util_builder(true)?;
1177        builder.set_min_stack_size(stack_size);
1178        let built = builder.build().await?;
1179        assert!(built.stack_vmo.get_size()? >= stack_size as u64);
1180
1181        let process = built.start()?;
1182        check_process_running(&process)?;
1183        mem::drop(proxy);
1184        check_process_exited_ok(&process).await?;
1185        Ok(())
1186    }
1187
1188    #[fasync::run_singlethreaded(test)]
1189    async fn elf_headers() -> Result<(), Error> {
1190        let (builder, _) = setup_test_util_builder(true)?;
1191        let built = builder.build().await?;
1192        assert!(
1193            built.elf_headers.file_header().phnum
1194                == built.elf_headers.program_headers().len() as u16
1195        );
1196        Ok(())
1197    }
1198
1199    // Verify that a loader service handle is properly handled if passed directly to
1200    // set_loader_service instead of through add_handles. Otherwise this test is identical to
1201    // start_util_with_args.
1202    #[fasync::run_singlethreaded(test)]
1203    async fn set_loader_directly() -> Result<(), Error> {
1204        let test_args = vec!["arg0", "arg1", "arg2"];
1205        let test_args_cstr =
1206            test_args.iter().map(|&s| CString::new(s)).collect::<Result<_, _>>()?;
1207
1208        let (mut builder, proxy) = setup_test_util_builder(false)?;
1209        builder.set_loader_service(clone_loader_service()?)?;
1210        builder.add_arguments(test_args_cstr);
1211        let process = builder.build().await?.start()?;
1212        check_process_running(&process)?;
1213
1214        // Use the util protocol to confirm that the new process was set up correctly. A successful
1215        // connection to the util validates that handles are passed correctly to the new process,
1216        // since the DirectoryRequest handle made it.
1217        let proc_args = proxy.get_arguments().await.context("failed to get args from util")?;
1218        assert_eq!(proc_args, test_args);
1219
1220        mem::drop(proxy);
1221        check_process_exited_ok(&process).await?;
1222        Ok(())
1223    }
1224
1225    // Verify that a vDSO handle is properly handled if passed directly to set_vdso_vmo instead of
1226    // relying on the default value.
1227    // Note: There isn't a great way to tell here whether the vDSO VMO we passed in was used
1228    // instead of the default (because the kernel only allows use of vDSOs that it created for
1229    // security, so we can't make a fake vDSO with a different name or something), so that isn't
1230    // checked explicitly. The failure tests below make sure we don't ignore the provided vDSO VMO
1231    // completely.
1232    #[fasync::run_singlethreaded(test)]
1233    async fn set_vdso_directly() -> Result<(), Error> {
1234        let test_args = vec!["arg0", "arg1", "arg2"];
1235        let test_args_cstr =
1236            test_args.iter().map(|&s| CString::new(s)).collect::<Result<_, _>>()?;
1237
1238        let (mut builder, proxy) = setup_test_util_builder(true)?;
1239        builder.set_vdso_vmo(get_system_vdso_vmo()?);
1240        builder.add_arguments(test_args_cstr);
1241        let process = builder.build().await?.start()?;
1242        check_process_running(&process)?;
1243
1244        // Use the util protocol to confirm that the new process was set up correctly.
1245        let proc_args = proxy.get_arguments().await.context("failed to get args from util")?;
1246        assert_eq!(proc_args, test_args);
1247
1248        mem::drop(proxy);
1249        check_process_exited_ok(&process).await?;
1250        Ok(())
1251    }
1252
1253    // Verify that a vDSO handle is properly handled if passed directly to set_vdso_vmo instead of
1254    // relying on the default value, this time by providing an invalid VMO (something that isn't
1255    // ELF and will fail to parse). This also indirectly tests that the reservation VMAR cleanup
1256    // happens properly by testing a failure after it has been created.
1257    #[fasync::run_singlethreaded(test)]
1258    async fn set_invalid_vdso_directly_fails() -> Result<(), Error> {
1259        let bad_vdso = zx::Vmo::create(1)?;
1260
1261        let (mut builder, _) = setup_test_util_builder(true)?;
1262        builder.set_vdso_vmo(bad_vdso);
1263
1264        let result = builder.build().await;
1265        match result {
1266            Err(ProcessBuilderError::ElfParse(elf_parse::ElfParseError::InvalidFileHeader(_))) => {}
1267            Err(err) => {
1268                panic!("Unexpected error type: {}", err);
1269            }
1270            Ok(_) => {
1271                panic!("Unexpectedly succeeded to build process with invalid vDSO");
1272            }
1273        }
1274        Ok(())
1275    }
1276
1277    // Verify that a vDSO handle is properly handled if passed through add_handles instead of
1278    // relying on the default value, this time by providing an invalid VMO (something that isn't
1279    // ELF and will fail to parse). This also indirectly tests that the reservation VMAR cleanup
1280    // happens properly by testing a failure after it has been created.
1281    #[fasync::run_singlethreaded(test)]
1282    async fn set_invalid_vdso_fails() -> Result<(), Error> {
1283        let bad_vdso = zx::Vmo::create(1)?;
1284
1285        let (mut builder, _) = setup_test_util_builder(true)?;
1286        builder.add_handles(vec![process_args::StartupHandle {
1287            handle: bad_vdso.into_handle(),
1288            info: HandleInfo::new(HandleType::VdsoVmo, 0),
1289        }])?;
1290
1291        let result = builder.build().await;
1292        match result {
1293            Err(ProcessBuilderError::ElfParse(elf_parse::ElfParseError::InvalidFileHeader(_))) => {}
1294            Err(err) => {
1295                panic!("Unexpected error type: {}", err);
1296            }
1297            Ok(_) => {
1298                panic!("Unexpectedly succeeded to build process with invalid vDSO");
1299            }
1300        }
1301        Ok(())
1302    }
1303
1304    #[fasync::run_singlethreaded(test)]
1305    async fn add_additional_vdso() -> Result<(), Error> {
1306        let mut builder = create_test_util_builder()?;
1307        builder.set_loader_service(clone_loader_service()?)?;
1308        builder.add_handles(vec![process_args::StartupHandle {
1309            handle: get_system_vdso_vmo().unwrap().into_handle(),
1310            info: HandleInfo::new(HandleType::VdsoVmo, 1),
1311        }])?;
1312        let built = builder.build().await?;
1313
1314        // Ignore linker message handles.
1315        let mut msg_buf = zx::MessageBuf::new();
1316        built.bootstrap.read(&mut msg_buf)?;
1317
1318        // Validate main message handles.
1319        let mut msg_buf = zx::MessageBuf::new();
1320        built.bootstrap.read(&mut msg_buf)?;
1321        let handle_info = parse_handle_info_from_message(&msg_buf)?
1322            .drain(..)
1323            .filter(|info| info.handle_type() == HandleType::VdsoVmo)
1324            .collect::<Vec<_>>();
1325        assert_eq!(2, handle_info.len());
1326        for (i, info) in handle_info.iter().rev().enumerate() {
1327            assert_eq!(HandleType::VdsoVmo, info.handle_type());
1328            assert_eq!(i as u16, info.arg());
1329        }
1330        Ok(())
1331    }
1332
1333    #[fasync::run_singlethreaded(test)]
1334    async fn start_util_with_env() -> Result<(), Error> {
1335        let test_env = vec![("VAR1", "value2"), ("VAR2", "value2")];
1336        let test_env_cstr = test_env
1337            .iter()
1338            .map(|v| CString::new(format!("{}={}", v.0, v.1)))
1339            .collect::<Result<_, _>>()?;
1340
1341        let (mut builder, proxy) = setup_test_util_builder(true)?;
1342        builder.add_environment_variables(test_env_cstr);
1343        let process = builder.build().await?.start()?;
1344        check_process_running(&process)?;
1345
1346        let proc_env = proxy.get_environment().await.context("failed to get env from util")?;
1347        let proc_env_tuple: Vec<(&str, &str)> =
1348            proc_env.iter().map(|v| (&*v.key, &*v.value)).collect();
1349        assert_eq!(proc_env_tuple, test_env);
1350
1351        mem::drop(proxy);
1352        check_process_exited_ok(&process).await?;
1353        Ok(())
1354    }
1355
1356    #[fasync::run_singlethreaded(test)]
1357    async fn start_util_with_huge_env() -> Result<(), Error> {
1358        // This test is partially designed to probe the stack usage of
1359        // code processing the initial loader message. Such processing
1360        // is on a stack of limited size, a few pages, and well
1361        // smaller than a maximally large channel packet. Each
1362        // instance of "a=b" takes 4 bytes (counting the separating
1363        // '\0' byte), so let's send 10k of them to be well larger
1364        // than the initial stack but well within the 64k channel size.
1365        let test_env = vec!["a=b"; 10 * 1000];
1366        let test_env_cstr = test_env.iter().map(|&s| CString::new(s)).collect::<Result<_, _>>()?;
1367
1368        let (mut builder, proxy) = setup_test_util_builder(true)?;
1369        builder.add_environment_variables(test_env_cstr);
1370        let process = builder.build().await?.start()?;
1371        check_process_running(&process)?;
1372
1373        // We can't use get_environment() here because the FIDL response will be bigger than the
1374        // maximum message size and cause the process to crash. Instead, we just check the number
1375        // of environment variables and assume that if that's correct we're good to go.
1376        let proc_env =
1377            proxy.get_environment_count().await.context("failed to get env from util")?;
1378        assert_eq!(proc_env, test_env.len() as u64);
1379
1380        mem::drop(proxy);
1381        check_process_exited_ok(&process).await?;
1382        Ok(())
1383    }
1384
1385    #[fasync::run_singlethreaded(test)]
1386    async fn start_util_with_namespace_entries() -> Result<(), Error> {
1387        let mut randbuf = [0; 8];
1388        zx::cprng_draw(&mut randbuf);
1389        let test_content1 = format!("test content 1 {}", u64::from_le_bytes(randbuf));
1390        zx::cprng_draw(&mut randbuf);
1391        let test_content2 = format!("test content 2 {}", u64::from_le_bytes(randbuf));
1392
1393        let dir1 = pseudo_directory! {
1394            "test_file1" => read_only(test_content1.clone()),
1395        };
1396        let dir1_client = vfs::directory::serve_read_only(dir1).into_client_end().unwrap();
1397
1398        let dir2 = pseudo_directory! {
1399            "test_file2" => read_only(test_content2.clone()),
1400        };
1401        let dir2_client = vfs::directory::serve_read_only(dir2).into_client_end().unwrap();
1402
1403        let (mut builder, proxy) = setup_test_util_builder(true)?;
1404        builder.add_namespace_entries(vec![
1405            NamespaceEntry { path: CString::new("/dir1")?, directory: dir1_client },
1406            NamespaceEntry { path: CString::new("/dir2")?, directory: dir2_client },
1407        ])?;
1408        let process = builder.build().await?.start()?;
1409        check_process_running(&process)?;
1410
1411        let namespace_dump = proxy.dump_namespace().await.context("failed to dump namespace")?;
1412        assert_eq!(namespace_dump, "/dir1, /dir1/test_file1, /dir2, /dir2/test_file2");
1413
1414        let dir1_contents =
1415            proxy.read_file("/dir1/test_file1").await.context("failed to read file via util")?;
1416        assert_eq!(dir1_contents, test_content1);
1417        let dir2_contents =
1418            proxy.read_file("/dir2/test_file2").await.context("failed to read file via util")?;
1419        assert_eq!(dir2_contents, test_content2);
1420
1421        mem::drop(proxy);
1422        check_process_exited_ok(&process).await?;
1423        Ok(())
1424    }
1425
1426    // Trying to start a dynamically linked process without providing a loader service should
1427    // fail. This verifies that nothing is automatically cloning a loader.
1428    #[fasync::run_singlethreaded(test)]
1429    async fn start_util_with_no_loader_fails() -> Result<(), Error> {
1430        let (builder, _) = setup_test_util_builder(false)?;
1431
1432        let result = builder.build().await;
1433        match result {
1434            Err(ProcessBuilderError::LoaderMissing()) => {}
1435            Err(err) => {
1436                panic!("Unexpected error type: {}", err);
1437            }
1438            Ok(_) => {
1439                panic!("Unexpectedly succeeded to build process without loader");
1440            }
1441        }
1442        Ok(())
1443    }
1444
1445    // Checks that, for dynamically linked binaries, the lower half of the address space has been
1446    // reserved for sanitizers.
1447    #[fasync::run_singlethreaded(test)]
1448    async fn verify_low_address_range_reserved() -> Result<(), Error> {
1449        let (builder, _) = setup_test_util_builder(true)?;
1450        let built = builder.build().await?;
1451
1452        // This ends up being the same thing ReservationVmar does, but it's not reused here so that
1453        // this catches bugs or bad changes to ReservationVmar itself.
1454        let info = built.root_vmar.info()?;
1455        let lower_half_len = util::page_end((info.base + info.len) / 2) - info.base;
1456        built
1457            .root_vmar
1458            .allocate(0, lower_half_len, zx::VmarFlags::SPECIFIC)
1459            .context("Unable to allocate lower address range of new process")?;
1460        Ok(())
1461    }
1462
1463    // Parses the given channel message as a process_args message and returns the HandleInfo's
1464    // contained in it.
1465    fn parse_handle_info_from_message(message: &zx::MessageBuf) -> Result<Vec<HandleInfo>, Error> {
1466        let bytes = message.bytes();
1467        let (header, _) = Ref::<&[u8], process_args::MessageHeader>::from_prefix(bytes)
1468            .map_err(|_| anyhow!("Failed to parse process_args header"))?;
1469
1470        let offset = header.handle_info_off as usize;
1471        let len = mem::size_of::<u32>() * message.n_handles();
1472        let info_bytes = &bytes[offset..offset + len];
1473        let raw_info = Ref::<&[u8], [u32]>::from_bytes(info_bytes)
1474            .map_err(|_| anyhow!("Failed to parse raw handle info"))?;
1475
1476        Ok(raw_info.iter().map(|raw| HandleInfo::try_from(*raw)).collect::<Result<_, _>>()?)
1477    }
1478
1479    const LINKER_MESSAGE_HANDLES: &[HandleType] = &[
1480        HandleType::ProcessSelf,
1481        HandleType::RootVmar,
1482        HandleType::LdsvcLoader,
1483        HandleType::LoadedVmar,
1484        HandleType::ExecutableVmo,
1485    ];
1486
1487    const MAIN_MESSAGE_HANDLES: &[HandleType] = &[
1488        HandleType::ProcessSelf,
1489        HandleType::ThreadSelf,
1490        HandleType::RootVmar,
1491        HandleType::VdsoVmo,
1492        HandleType::StackVmo,
1493    ];
1494
1495    #[fasync::run_singlethreaded(test)]
1496    async fn correct_handles_present() -> Result<(), Error> {
1497        let mut builder = create_test_util_builder()?;
1498        builder.set_loader_service(clone_loader_service()?)?;
1499        let built = builder.build().await?;
1500
1501        for correct in &[LINKER_MESSAGE_HANDLES, MAIN_MESSAGE_HANDLES] {
1502            let mut msg_buf = zx::MessageBuf::new();
1503            built.bootstrap.read(&mut msg_buf)?;
1504            let handle_info = parse_handle_info_from_message(&msg_buf)?;
1505
1506            assert_eq!(handle_info.len(), correct.len());
1507            for correct_type in *correct {
1508                // Should only be one of each of these handles present.
1509                assert_eq!(
1510                    1,
1511                    handle_info.iter().filter(|info| &info.handle_type() == correct_type).count()
1512                );
1513            }
1514        }
1515        Ok(())
1516    }
1517
1518    // Verify that [ProcessBuilder::add_handles()] rejects handle types that are added
1519    // automatically by the builder.
1520    #[fasync::run_singlethreaded(test)]
1521    async fn add_handles_rejects_automatic_handle_types() -> Result<(), Error> {
1522        // The VMO doesn't need to be valid since we're not calling build.
1523        let vmo = zx::Vmo::create(1)?;
1524        let job = fuchsia_runtime::job_default();
1525        let procname = CString::new("test_vmo")?;
1526        let mut builder = ProcessBuilder::new(
1527            &procname,
1528            &job,
1529            zx::ProcessOptions::empty(),
1530            vmo,
1531            get_system_vdso_vmo().unwrap(),
1532        )?;
1533
1534        // There's some duplicates between these slices but just checking twice is easier than
1535        // deduping these.
1536        for handle_type in LINKER_MESSAGE_HANDLES.iter().chain(MAIN_MESSAGE_HANDLES) {
1537            if *handle_type == HandleType::LdsvcLoader {
1538                // Skip LdsvcLoader, which is required in the linker message but is not added
1539                // automatically. The user must supply it.
1540                continue;
1541            }
1542
1543            if *handle_type == HandleType::VdsoVmo {
1544                // Skip VdsoVmo, which may be supplied by the user.
1545                continue;
1546            }
1547
1548            // Another VMO, just to have a valid handle.
1549            let vmo = zx::Vmo::create(1)?;
1550            let result = builder.add_handles(vec![process_args::StartupHandle {
1551                handle: vmo.into_handle(),
1552                info: HandleInfo::new(*handle_type, 0),
1553            }]);
1554            match result {
1555                Err(ProcessBuilderError::InvalidArg(_)) => {}
1556                Err(err) => {
1557                    panic!("Unexpected error type, should be invalid arg: {}", err);
1558                }
1559                Ok(_) => {
1560                    panic!("add_handle unexpectedly succeeded for type {:?}", handle_type);
1561                }
1562            }
1563        }
1564        Ok(())
1565    }
1566
1567    // Verify that invalid handles are correctly rejected.
1568    #[fasync::run_singlethreaded(test)]
1569    async fn rejects_invalid_handles() -> Result<(), Error> {
1570        let invalid = || zx::NullableHandle::invalid();
1571        let assert_invalid_arg = |result| match result {
1572            Err(ProcessBuilderError::BadHandle(_)) => {}
1573            Err(err) => {
1574                panic!("Unexpected error type, should be BadHandle: {}", err);
1575            }
1576            Ok(_) => {
1577                panic!("API unexpectedly accepted invalid handle");
1578            }
1579        };
1580
1581        // The VMO doesn't need to be valid since we're not calling build with this.
1582        let vmo = zx::Vmo::create(1)?;
1583        let job = fuchsia_runtime::job_default();
1584        let procname = CString::new("test_vmo")?;
1585
1586        assert_invalid_arg(
1587            ProcessBuilder::new(
1588                &procname,
1589                &zx::NullableHandle::from(invalid()).into(),
1590                zx::ProcessOptions::empty(),
1591                vmo,
1592                get_system_vdso_vmo().unwrap(),
1593            )
1594            .map(|_| ()),
1595        );
1596        assert_invalid_arg(
1597            ProcessBuilder::new(
1598                &procname,
1599                &job,
1600                zx::ProcessOptions::empty(),
1601                zx::NullableHandle::from(invalid()).into(),
1602                get_system_vdso_vmo().unwrap(),
1603            )
1604            .map(|_| ()),
1605        );
1606
1607        let (mut builder, _) = setup_test_util_builder(true)?;
1608
1609        assert_invalid_arg(builder.set_loader_service(invalid().into()));
1610        assert_invalid_arg(builder.add_handles(vec![process_args::StartupHandle {
1611            handle: invalid().into(),
1612            info: HandleInfo::new(HandleType::User0, 0),
1613        }]));
1614        assert_invalid_arg(builder.add_handles(vec![process_args::StartupHandle {
1615            handle: invalid().into(),
1616            info: HandleInfo::new(HandleType::User0, 0),
1617        }]));
1618        assert_invalid_arg(builder.add_namespace_entries(vec![NamespaceEntry {
1619            path: CString::new("/dir")?,
1620            directory: invalid().into(),
1621        }]));
1622
1623        Ok(())
1624    }
1625
1626    #[fasync::run_singlethreaded]
1627    #[test]
1628    async fn start_static_pie_binary() -> Result<(), Error> {
1629        const TEST_BIN: &'static str = "/pkg/bin/static_pie_test_util";
1630        let file = fdio::open_fd(TEST_BIN, fio::PERM_READABLE | fio::PERM_EXECUTABLE)?;
1631        let vmo = fdio::get_vmo_exec_from_file(&file)?;
1632        let job = fuchsia_runtime::job_default();
1633
1634        let procname = CString::new(TEST_BIN.to_owned())?;
1635        let mut builder = ProcessBuilder::new(
1636            &procname,
1637            &job,
1638            zx::ProcessOptions::empty(),
1639            vmo,
1640            get_system_vdso_vmo().unwrap(),
1641        )?;
1642
1643        // We pass the program a channel with handle type User0 which we send a message on and
1644        // expect it to echo back the message on the same channel.
1645        let (local, remote) = zx::Channel::create();
1646        builder.add_handles(vec![process_args::StartupHandle {
1647            handle: remote.into_handle(),
1648            info: HandleInfo::new(HandleType::User0, 0),
1649        }])?;
1650
1651        let mut randbuf = [0; 8];
1652        zx::cprng_draw(&mut randbuf);
1653        let test_message = format!("test content 1 {}", u64::from_le_bytes(randbuf)).into_bytes();
1654        local.write(&test_message, &mut vec![])?;
1655
1656        // Start process and wait for channel to have a message to read or be closed.
1657        builder.build().await?.start()?;
1658        let signals = fasync::OnSignals::new(
1659            &local,
1660            zx::Signals::CHANNEL_READABLE | zx::Signals::CHANNEL_PEER_CLOSED,
1661        )
1662        .await?;
1663        assert!(signals.contains(zx::Signals::CHANNEL_READABLE));
1664
1665        let mut echoed = zx::MessageBuf::new();
1666        local.read(&mut echoed)?;
1667        assert_eq!(echoed.bytes(), test_message.as_slice());
1668        assert_eq!(echoed.n_handles(), 0);
1669        Ok(())
1670    }
1671}