1#![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}