system_image/
lib.rs

1// Copyright 2020 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#![allow(clippy::let_unit_value)]
6
7mod cache_packages;
8mod errors;
9mod path_hash_mapping;
10mod system_image;
11
12pub use crate::cache_packages::CachePackages;
13pub use crate::errors::{
14    AllowListError, CachePackagesInitError, PathHashMappingError, StaticPackagesInitError,
15};
16pub use crate::path_hash_mapping::{Bootfs, PathHashMapping, StaticPackages};
17pub use crate::system_image::{ExecutabilityRestrictions, SystemImage};
18
19static PKGFS_BOOT_ARG_KEY: &str = "zircon.system.pkgfs.cmd";
20static PKGFS_BOOT_ARG_VALUE_PREFIX: &str = "bin/pkgsvr+";
21
22pub async fn get_system_image_hash(
23    args: &fidl_fuchsia_boot::ArgumentsProxy,
24) -> Result<fuchsia_hash::Hash, SystemImageHashError> {
25    let hash = args
26        .get_string(PKGFS_BOOT_ARG_KEY)
27        .await
28        .map_err(SystemImageHashError::Fidl)?
29        .ok_or(SystemImageHashError::MissingValue)?;
30    let hash = hash
31        .strip_prefix(PKGFS_BOOT_ARG_VALUE_PREFIX)
32        .ok_or_else(|| SystemImageHashError::BadPrefix(hash.clone()))?;
33    hash.parse().map_err(SystemImageHashError::BadHash)
34}
35
36#[derive(Debug, thiserror::Error)]
37pub enum SystemImageHashError {
38    #[error("fidl error calling fuchsia.boot/Arguments.GetString")]
39    Fidl(#[source] fidl::Error),
40
41    #[error("boot args have no value for key {}", PKGFS_BOOT_ARG_KEY)]
42    MissingValue,
43
44    #[error(
45        "boot arg for key {} does not start with {}: {:?}",
46        PKGFS_BOOT_ARG_KEY,
47        PKGFS_BOOT_ARG_VALUE_PREFIX,
48        .0
49    )]
50    BadPrefix(String),
51
52    #[error("boot arg for key {} has invalid hash {:?}", PKGFS_BOOT_ARG_KEY, .0)]
53    BadHash(#[source] fuchsia_hash::ParseHashError),
54}
55
56#[cfg(test)]
57mod test_get_system_image_hash {
58    use super::*;
59    use assert_matches::assert_matches;
60    use fuchsia_async as fasync;
61    use mock_boot_arguments::MockBootArgumentsService;
62    use std::collections::HashMap;
63    use std::sync::Arc;
64
65    #[fasync::run_singlethreaded(test)]
66    async fn missing_value() {
67        let mock =
68            MockBootArgumentsService::new(HashMap::from([(PKGFS_BOOT_ARG_KEY.to_string(), None)]));
69        let (proxy, stream) =
70            fidl::endpoints::create_proxy_and_stream::<fidl_fuchsia_boot::ArgumentsMarker>();
71        fasync::Task::spawn(Arc::new(mock).handle_request_stream(stream)).detach();
72
73        assert_matches!(
74            get_system_image_hash(&proxy).await,
75            Err(SystemImageHashError::MissingValue)
76        );
77    }
78
79    #[fasync::run_singlethreaded(test)]
80    async fn bad_prefix() {
81        let mock = MockBootArgumentsService::new(HashMap::from([(
82            PKGFS_BOOT_ARG_KEY.to_string(),
83            Some("bad-prefix".to_string()),
84        )]));
85        let (proxy, stream) =
86            fidl::endpoints::create_proxy_and_stream::<fidl_fuchsia_boot::ArgumentsMarker>();
87        fasync::Task::spawn(Arc::new(mock).handle_request_stream(stream)).detach();
88
89        assert_matches!(
90            get_system_image_hash(&proxy).await,
91            Err(SystemImageHashError::BadPrefix(prefix)) if prefix == "bad-prefix"
92        );
93    }
94
95    #[fasync::run_singlethreaded(test)]
96    async fn bad_hash() {
97        let mock = MockBootArgumentsService::new(HashMap::from([(
98            PKGFS_BOOT_ARG_KEY.to_string(),
99            Some("bin/pkgsvr+bad-hash".to_string()),
100        )]));
101        let (proxy, stream) =
102            fidl::endpoints::create_proxy_and_stream::<fidl_fuchsia_boot::ArgumentsMarker>();
103        fasync::Task::spawn(Arc::new(mock).handle_request_stream(stream)).detach();
104
105        assert_matches!(get_system_image_hash(&proxy).await, Err(SystemImageHashError::BadHash(_)));
106    }
107
108    #[fasync::run_singlethreaded(test)]
109    async fn success() {
110        let mock = MockBootArgumentsService::new(HashMap::from([(
111            PKGFS_BOOT_ARG_KEY.to_string(),
112            Some(
113                "bin/pkgsvr+0000000000000000000000000000000000000000000000000000000000000000"
114                    .to_string(),
115            ),
116        )]));
117        let (proxy, stream) =
118            fidl::endpoints::create_proxy_and_stream::<fidl_fuchsia_boot::ArgumentsMarker>();
119        fasync::Task::spawn(Arc::new(mock).handle_request_stream(stream)).detach();
120
121        assert_eq!(get_system_image_hash(&proxy).await.unwrap(), fuchsia_hash::Hash::from([0; 32]));
122    }
123}