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