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