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