fuchsia_runtime/
lib.rs

1// Copyright 2019 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
5//! Type-safe bindings for Fuchsia-specific `libc` functionality.
6//!
7//! This crate is a minimal extension on top of the `fuchsia-zircon` crate,
8//! which provides bindings to the Zircon kernel's syscalls, but does not
9//! depend on functionality from `libc`.
10
11// AKA `libc`-granted ambient-authority crate ;)
12
13#![deny(missing_docs)]
14
15use num_derive::FromPrimitive;
16use num_traits::cast::FromPrimitive;
17use thiserror::Error;
18use zx::sys::{zx_handle_t, zx_status_t, ZX_HANDLE_INVALID};
19use zx::{
20    BootTimeline, Clock, ClockDetails, ClockTransformation, ClockUpdate, Duration, Handle,
21    HandleBased, Instant, Job, Process, Rights, Status, Thread, Timeline, Unowned, Vmar,
22};
23
24// TODO(https://fxbug.dev/42139436): Document these.
25#[allow(missing_docs)]
26extern "C" {
27    pub fn dl_clone_loader_service(out: *mut zx_handle_t) -> zx_status_t;
28    pub fn zx_take_startup_handle(hnd_info: u32) -> zx_handle_t;
29    pub fn zx_thread_self() -> zx_handle_t;
30    pub fn zx_process_self() -> zx_handle_t;
31    pub fn thrd_get_zx_process() -> zx_handle_t;
32    pub fn zx_vmar_root_self() -> zx_handle_t;
33    pub fn zx_job_default() -> zx_handle_t;
34    pub fn zx_utc_reference_get() -> zx_handle_t;
35    pub fn zx_utc_reference_swap(
36        new_handle: zx_handle_t,
37        prev_handle: *mut zx_handle_t,
38    ) -> zx_status_t;
39}
40
41/// Handle types as defined by the processargs protocol.
42///
43/// See [//zircon/system/public/zircon/processargs.h][processargs.h] for canonical definitions.
44///
45/// Short descriptions of each handle type are given, but more complete documentation may be found
46/// in the [processargs.h] header.
47///
48/// [processargs.h]: https://fuchsia.googlesource.com/fuchsia/+/HEAD/zircon/system/public/zircon/processargs.h
49#[repr(u8)]
50#[derive(FromPrimitive, Copy, Clone, Debug, Eq, PartialEq)]
51#[non_exhaustive]
52pub enum HandleType {
53    /// Handle to our own process.
54    ///
55    /// Equivalent to PA_PROC_SELF.
56    ProcessSelf = 0x01,
57
58    /// Handle to the initial thread of our own process.
59    ///
60    /// Equivalent to PA_THREAD_SELF.
61    ThreadSelf = 0x02,
62
63    /// Handle to a job object which can be used to make child processes.
64    ///
65    /// The job can be the same as the one used to create this process or it can
66    /// be different.
67    ///
68    /// Equivalent to PA_JOB_DEFAULT.
69    DefaultJob = 0x03,
70
71    /// Handle to the root of our address space.
72    ///
73    /// Equivalent to PA_VMAR_ROOT.
74    RootVmar = 0x04,
75
76    /// Handle to the VMAR used to load the initial program image.
77    ///
78    /// Equivalent to PA_VMAR_LOADED.
79    LoadedVmar = 0x05,
80
81    /// Service for loading shared libraries.
82    ///
83    /// See `fuchsia.ldsvc.Loader` for the interface definition.
84    ///
85    /// Equivalent to PA_LDSVC_LOADER.
86    LdsvcLoader = 0x10,
87
88    /// Handle to the VMO containing the vDSO ELF image.
89    ///
90    /// Equivalent to PA_VMO_VDSO.
91    VdsoVmo = 0x11,
92
93    /// Handle to the VMO used to map the initial thread's stack.
94    ///
95    /// Equivalent to PA_VMO_STACK.
96    StackVmo = 0x13,
97
98    /// Handle to the VMO for the main executable file.
99    ///
100    /// Equivalent to PA_VMO_EXECUTABLE.
101    ExecutableVmo = 0x14,
102
103    /// Used by kernel and userboot during startup.
104    ///
105    /// Equivalent to PA_VMO_BOOTDATA.
106    BootdataVmo = 0x1A,
107
108    /// Used by kernel and userboot during startup.
109    ///
110    /// Equivalent to PA_VMO_BOOTFS.
111    BootfsVmo = 0x1B,
112
113    /// Used by the kernel to export debug information as a file in bootfs.
114    ///
115    /// Equivalent to PA_VMO_KERNEL_FILE.
116    KernelFileVmo = 0x1C,
117
118    /// A Handle to a component's process' configuration VMO.
119    ///
120    /// Equivalent to PA_VMO_COMPONENT_CONFIG.
121    ComponentConfigVmo = 0x1D,
122
123    /// A handle to a fuchsia.io.Directory service to be used as a directory in the process's
124    /// namespace. Corresponds to a path in the processargs bootstrap message's namespace table
125    /// based on the argument of a HandleInfo of this type.
126    ///
127    /// Equivalent to PA_NS_DIR.
128    NamespaceDirectory = 0x20,
129
130    /// A handle which will be used as a file descriptor.
131    ///
132    /// Equivalent to PA_FD.
133    FileDescriptor = 0x30,
134
135    /// A Handle to a channel on which the process may serve the
136    /// the |fuchsia.process.Lifecycle| protocol.
137    ///
138    /// Equivalent to PA_LIFECYCLE.
139    Lifecycle = 0x3A,
140
141    /// Server endpoint for handling connections to a process's outgoing directory.
142    ///
143    /// Equivalent to PA_DIRECTORY_REQUEST.
144    DirectoryRequest = 0x3B,
145
146    /// A |fuchsia.component.sandbox/Dictionary| client endpoint where the process
147    /// may find a dictionary that it has stowed away earlier via
148    /// |fuchsia.process.Lifecycle/OnEscrow|.
149    ///
150    /// Equivalent to PA_ESCROWED_DICTIONARY.
151    EscrowedDictionary = 0x3C,
152
153    /// A Handle to a resource object. Used by devcoordinator and devhosts.
154    ///
155    /// Equivalent to PA_RESOURCE.
156    Resource = 0x3F,
157
158    /// A Handle to a clock object representing UTC.  Used by runtimes to gain
159    /// access to UTC time.
160    ///
161    /// Equivalent to PA_CLOCK_UTC.
162    ClockUtc = 0x40,
163
164    /// A Handle to an MMIO resource object.
165    ///
166    /// Equivalent to PA_MMIO_RESOURCE.
167    MmioResource = 0x50,
168
169    /// A Handle to an IRQ resource object.
170    ///
171    /// Equivalent to PA_IRQ_RESOURCE.
172    IrqResource = 0x51,
173
174    /// A Handle to an IO Port resource object.
175    ///
176    /// Equivalent to PA_IOPORT_RESOURCE.
177    IoportResource = 0x52,
178
179    /// A Handle to an SMC resource object.
180    ///
181    /// Equivalent to PA_SMC_RESOURCE.
182    SmcResource = 0x53,
183
184    /// A Handle to the System resource object.
185    ///
186    /// Equivalent to PA_SYSTEM_RESOURCE.
187    SystemResource = 0x54,
188
189    /// A handle type with user-defined meaning.
190    ///
191    /// Equivalent to PA_USER0.
192    User0 = 0xF0,
193
194    /// A handle type with user-defined meaning.
195    ///
196    /// Equivalent to PA_USER1.
197    User1 = 0xF1,
198
199    /// A handle type with user-defined meaning.
200    ///
201    /// Equivalent to PA_USER2.
202    User2 = 0xF2,
203}
204
205/// Metadata information for a handle in a processargs message. Contains a handle type and an
206/// unsigned 16-bit value, whose meaning is handle type dependent.
207#[derive(Debug, Copy, Clone, Eq, PartialEq)]
208pub struct HandleInfo {
209    htype: HandleType,
210    arg: u16,
211}
212
213impl HandleInfo {
214    /// Create a handle info struct from a handle type and an argument.
215    ///
216    /// For example, a `HandleInfo::new(HandleType::FileDescriptor, 32)` identifies
217    /// the respective handle as file descriptor 32.
218    ///
219    /// Corresponds to PA_HND in processargs.h.
220    pub const fn new(htype: HandleType, arg: u16) -> Self {
221        HandleInfo { htype, arg }
222    }
223
224    /// Returns the handle type for this handle info struct.
225    #[inline(always)]
226    pub fn handle_type(&self) -> HandleType {
227        self.htype
228    }
229
230    /// Returns the argument for this handle info struct.
231    #[inline(always)]
232    pub fn arg(&self) -> u16 {
233        self.arg
234    }
235
236    /// Convert the handle info into a raw u32 value for FFI purposes.
237    pub const fn as_raw(&self) -> u32 {
238        ((self.htype as u32) & 0xFF) | (self.arg as u32) << 16
239    }
240}
241
242/// An implementation of the From trait to create a [HandleInfo] from a [HandleType] with an argument
243/// of 0.
244impl From<HandleType> for HandleInfo {
245    fn from(ty: HandleType) -> Self {
246        Self::new(ty, 0)
247    }
248}
249
250/// Possible errors when converting a raw u32 to a HandleInfo with the  TryFrom<u32> impl on
251/// HandleInfo.
252#[derive(Error, Debug)]
253pub enum HandleInfoError {
254    /// Unknown handle type.
255    #[error("Unknown handle type for HandleInfo: {:#x?}", _0)]
256    UnknownHandleType(u32),
257
258    /// Otherwise invalid raw value, like reserved bytes being non-zero.
259    #[error("Invalid value for HandleInfo: {:#x?}", _0)]
260    InvalidHandleInfo(u32),
261}
262
263impl TryFrom<u32> for HandleInfo {
264    type Error = HandleInfoError;
265
266    /// Attempt to convert a u32 to a handle ID value. Can fail if the value represents an
267    /// unknown handle type or is otherwise invalid.
268    ///
269    /// Useful to convert existing handle info values received through FIDL APIs, e.g. from a
270    /// client that creates them using the PA_HND macro in processargs.h from C/C++.
271    fn try_from(value: u32) -> Result<HandleInfo, HandleInfoError> {
272        // 2nd byte should be zero, it is currently unused.
273        if value & 0xFF00 != 0 {
274            return Err(HandleInfoError::InvalidHandleInfo(value));
275        }
276
277        let htype = HandleType::from_u8((value & 0xFF) as u8)
278            .ok_or(HandleInfoError::UnknownHandleType(value))?;
279        Ok(HandleInfo::new(htype, (value >> 16) as u16))
280    }
281}
282
283/// Removes the handle of type `HandleType` from the list of handles received at startup.
284///
285/// This function will return `Some` at-most once per handle type.
286/// This function will return `None` if the requested type was not received at
287/// startup or if the handle with the provided type was already taken.
288pub fn take_startup_handle(info: HandleInfo) -> Option<Handle> {
289    unsafe {
290        let raw = zx_take_startup_handle(info.as_raw());
291        if raw == ZX_HANDLE_INVALID {
292            None
293        } else {
294            Some(Handle::from_raw(raw))
295        }
296    }
297}
298
299/// Provides temporary scoped access to the current thread's handle.
300///
301/// Callers who need to store a thread handle or to send it to another thread should duplicate the
302/// handle to ensure it can outlive the current thread.
303pub fn with_thread_self<F, R>(f: F) -> R
304where
305    F: for<'a> FnOnce(&Thread) -> R,
306{
307    // SAFETY: The handle returned by zx_thread_self() is guaranteed to be valid for the duration of
308    // the calling thread's execution and by creating this on our stack we prevent it from outliving
309    // this thread.
310    let thread = unsafe { Unowned::from_raw_handle(zx_thread_self()) };
311    f(&thread)
312}
313
314/// Get a reference to the handle of the current process.
315pub fn process_self() -> Unowned<'static, Process> {
316    unsafe {
317        // zx_process_self() doesn't work correctly in jobs where multiple processes share
318        // the portion of their address space for global variables. Use thrd_get_zx_process() to
319        // return the correct value in that context. See https://fxbug.dev/42083701 for background.
320        let handle = thrd_get_zx_process();
321        Unowned::from_raw_handle(handle)
322    }
323}
324
325/// Get a reference to the handle of the current address space.
326pub fn vmar_root_self() -> Unowned<'static, Vmar> {
327    unsafe {
328        let handle = zx_vmar_root_self();
329        Unowned::from_raw_handle(handle)
330    }
331}
332
333/// Get a reference to the fuchsia.ldsvc.Loader channel.
334pub fn loader_svc() -> Result<Handle, Status> {
335    unsafe {
336        let mut handle: zx_handle_t = 0;
337        let status = dl_clone_loader_service(&mut handle);
338        Status::ok(status)?;
339        Ok(Handle::from_raw(handle))
340    }
341}
342
343/// Get a reference to the default `Job` provided to the process on startup.
344///
345/// This typically refers to the `Job` that is the immediate parent of the current
346/// process.
347///
348/// If the current process was launched as a Fuchsia Component, this `Job`
349/// will begin with no child processes other than the current process.
350pub fn job_default() -> Unowned<'static, Job> {
351    unsafe {
352        let handle = zx_job_default();
353        Unowned::from_raw_handle(handle)
354    }
355}
356
357/// Marker type for the UTC timeline.
358#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
359pub struct UtcTimeline;
360impl Timeline for UtcTimeline {}
361
362/// A UTC timestamp, measured in nanoseconds since Jan 1 1970.
363pub type UtcInstant = Instant<UtcTimeline>;
364
365/// A duration in the UTC timeline.
366pub type UtcDuration = Duration<UtcTimeline>;
367
368/// Special methods that are only valid for UtcDuration.
369pub trait UtcDurationExt {
370    /// Converts the reading of a duration on the UTC timeline to a reading on the boot timeline.
371    ///
372    /// This is "lossy" because durations are usually differences of
373    /// two Instants, and Boot time and UTC time mostly tick at the same rate.
374    /// However, they aren't required to tick in lock-step.
375    fn to_boot_lossy(&self) -> zx::Duration<BootTimeline>;
376}
377
378impl UtcDurationExt for UtcDuration {
379    fn to_boot_lossy(&self) -> zx::Duration<BootTimeline> {
380        zx::Duration::from_nanos(self.into_nanos())
381    }
382}
383
384/// Special methods that are only valid for zx::BootDuration.
385pub trait BootDurationExt {
386    /// Converts the reading of a duration on the boot timeline to a reading on the UTC timeline.
387    ///
388    /// See notes alongside [UtcDurationExt::to_boot_lossy].
389    fn to_utc_lossy(&self) -> UtcDuration;
390}
391
392impl BootDurationExt for zx::BootDuration {
393    fn to_utc_lossy(&self) -> UtcDuration {
394        zx::Duration::from_nanos(self.into_nanos())
395    }
396}
397
398/// A clock that will return UTC timestamps.
399pub type UtcClock = Clock<BootTimeline, UtcTimeline>;
400
401/// Details of a UTC clock.
402pub type UtcClockDetails = ClockDetails<BootTimeline, UtcTimeline>;
403
404/// A transformation for the UTC clock.
405pub type UtcClockTransform = ClockTransformation<BootTimeline, UtcTimeline>;
406
407/// An update for the UTC clock.
408pub type UtcClockUpdate = ClockUpdate<BootTimeline, UtcTimeline>;
409
410fn utc_clock() -> Unowned<'static, UtcClock> {
411    // SAFETY: basic FFI call which returns either a valid handle or ZX_HANDLE_INVALID.
412    unsafe {
413        let handle = zx_utc_reference_get();
414        Unowned::from_raw_handle(handle)
415    }
416}
417
418/// Duplicate the UTC `Clock` registered with the runtime.
419pub fn duplicate_utc_clock_handle(rights: Rights) -> Result<UtcClock, Status> {
420    utc_clock().duplicate(rights)
421}
422
423/// Swaps the current process-global UTC clock with `new_clock`, returning
424/// the old clock on success.
425/// If `new_clock` is a valid handle but does not have the ZX_RIGHT_READ right,
426/// an error is returned and `new_clock` is dropped.
427pub fn swap_utc_clock_handle(new_clock: UtcClock) -> Result<UtcClock, Status> {
428    Ok(unsafe {
429        let mut prev_handle = ZX_HANDLE_INVALID;
430        Status::ok(zx_utc_reference_swap(new_clock.into_raw(), &mut prev_handle))?;
431        Handle::from_raw(prev_handle)
432    }
433    .into())
434}
435
436/// Reads time from the UTC `Clock` registered with the runtime.
437///
438/// # Panics
439///
440/// Panics if there is no UTC clock registered with the runtime or the registered handle does not
441/// have the required rights.
442#[inline]
443pub fn utc_time() -> UtcInstant {
444    utc_clock().read().expect("Failed to read UTC clock")
445}
446
447#[cfg(test)]
448mod tests {
449    use super::*;
450
451    #[test]
452    fn handle_id() {
453        let mut randbuf = [0; 2];
454        for type_val in 0..0xFF {
455            if let Some(htype) = HandleType::from_u8(type_val as u8) {
456                zx::cprng_draw(&mut randbuf);
457                let arg = u16::from_le_bytes(randbuf);
458
459                let info = HandleInfo::new(htype, arg);
460                assert_eq!(info.handle_type(), htype);
461                assert_eq!(info.arg(), arg);
462
463                let info = HandleInfo::from(htype);
464                assert_eq!(info.handle_type(), htype);
465                assert_eq!(info.arg(), 0);
466            }
467        }
468    }
469
470    #[test]
471    fn handle_id_raw() {
472        assert_eq!(HandleInfo::new(HandleType::ProcessSelf, 0).as_raw(), 0x00000001);
473        assert_eq!(HandleInfo::new(HandleType::DirectoryRequest, 0).as_raw(), 0x0000003B);
474        assert_eq!(HandleInfo::new(HandleType::LdsvcLoader, 0xABCD).as_raw(), 0xABCD0010);
475        assert_eq!(HandleInfo::new(HandleType::User0, 0x1).as_raw(), 0x000100F0);
476        assert_eq!(HandleInfo::new(HandleType::User1, 0xABCD).as_raw(), 0xABCD00F1);
477        assert_eq!(HandleInfo::new(HandleType::User2, 0xFFFF).as_raw(), 0xFFFF00F2);
478    }
479
480    #[test]
481    fn handle_id_from_u32() {
482        assert_eq!(
483            HandleInfo::try_from(0x00000002).unwrap(),
484            HandleInfo::new(HandleType::ThreadSelf, 0)
485        );
486        assert_eq!(
487            HandleInfo::try_from(0x00040030).unwrap(),
488            HandleInfo::new(HandleType::FileDescriptor, 4)
489        );
490        assert_eq!(
491            HandleInfo::try_from(0x501C00F2).unwrap(),
492            HandleInfo::new(HandleType::User2, 0x501C)
493        );
494
495        // Non-zero unused byte
496        assert!(HandleInfo::try_from(0x00001100).is_err());
497        assert!(HandleInfo::try_from(0x00010101).is_err());
498        // Unknown handle type
499        assert!(HandleInfo::try_from(0x00000000).is_err());
500        assert!(HandleInfo::try_from(0x00000006).is_err());
501    }
502
503    #[test]
504    fn read_utc_time() {
505        utc_time();
506    }
507
508    #[test]
509    fn get_loader_svc() {
510        loader_svc().unwrap();
511    }
512}