• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021, The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 //! This crate implements the KeyMint HAL service in Rust, communicating with a Rust
16 //! trusted application (TA) running on the Cuttlefish host.
17 
18 use kmr_hal::env::get_property;
19 use log::{debug, error, info};
20 use std::ops::DerefMut;
21 use std::os::unix::io::FromRawFd;
22 use std::panic;
23 use std::sync::{Arc, Mutex};
24 
25 /// Device file used to communicate with the KeyMint TA.
26 static DEVICE_FILE_NAME: &str = "/dev/hvc11";
27 
28 /// Name of KeyMint binder device instance.
29 static SERVICE_INSTANCE: &str = "default";
30 
31 static KM_SERVICE_NAME: &str = "android.hardware.security.keymint.IKeyMintDevice";
32 static RPC_SERVICE_NAME: &str = "android.hardware.security.keymint.IRemotelyProvisionedComponent";
33 static CLOCK_SERVICE_NAME: &str = "android.hardware.security.secureclock.ISecureClock";
34 static SECRET_SERVICE_NAME: &str = "android.hardware.security.sharedsecret.ISharedSecret";
35 
36 /// Local error type for failures in the HAL service.
37 #[derive(Debug, Clone)]
38 struct HalServiceError(String);
39 
40 /// Read-write file used for communication with host TA.
41 #[derive(Debug)]
42 struct FileChannel(std::fs::File);
43 
44 impl kmr_hal::SerializedChannel for FileChannel {
45     const MAX_SIZE: usize = kmr_wire::DEFAULT_MAX_SIZE;
46 
execute(&mut self, serialized_req: &[u8]) -> binder::Result<Vec<u8>>47     fn execute(&mut self, serialized_req: &[u8]) -> binder::Result<Vec<u8>> {
48         kmr_hal::write_msg(&mut self.0, serialized_req)?;
49         kmr_hal::read_msg(&mut self.0)
50     }
51 }
52 
53 /// Set 'raw' mode for the given file descriptor.
set_terminal_raw(fd: libc::c_int) -> Result<(), HalServiceError>54 fn set_terminal_raw(fd: libc::c_int) -> Result<(), HalServiceError> {
55     let mut settings: libc::termios = unsafe { std::mem::zeroed() };
56     let result = unsafe { libc::tcgetattr(fd, &mut settings) };
57     if result < 0 {
58         return Err(HalServiceError(format!(
59             "Failed to get terminal attributes for {}: {:?}",
60             fd,
61             std::io::Error::last_os_error()
62         )));
63     }
64 
65     let result = unsafe {
66         libc::cfmakeraw(&mut settings);
67         libc::tcsetattr(fd, libc::TCSANOW, &settings)
68     };
69     if result < 0 {
70         return Err(HalServiceError(format!(
71             "Failed to set terminal attributes for {}: {:?}",
72             fd,
73             std::io::Error::last_os_error()
74         )));
75     }
76     Ok(())
77 }
78 
main()79 fn main() {
80     if let Err(e) = inner_main() {
81         panic!("HAL service failed: {:?}", e);
82     }
83 }
84 
inner_main() -> Result<(), HalServiceError>85 fn inner_main() -> Result<(), HalServiceError> {
86     // Initialize android logging.
87     android_logger::init_once(
88         android_logger::Config::default()
89             .with_tag("keymint-hal")
90             .with_min_level(log::Level::Info)
91             .with_log_id(android_logger::LogId::System),
92     );
93     // Redirect panic messages to logcat.
94     panic::set_hook(Box::new(|panic_info| {
95         error!("{}", panic_info);
96     }));
97 
98     info!("KeyMint HAL service is starting.");
99 
100     info!("Starting thread pool now.");
101     binder::ProcessState::start_thread_pool();
102 
103     // Create a connection to the TA.
104     let path = std::ffi::CString::new(DEVICE_FILE_NAME).unwrap();
105     let fd = unsafe { libc::open(path.as_ptr(), libc::O_RDWR) };
106     if fd < 0 {
107         return Err(HalServiceError(format!(
108             "Failed to open device file '{}': {:?}",
109             DEVICE_FILE_NAME,
110             std::io::Error::last_os_error()
111         )));
112     }
113     set_terminal_raw(fd)?;
114     let channel = Arc::new(Mutex::new(FileChannel(unsafe { std::fs::File::from_raw_fd(fd) })));
115 
116     let km_service = kmr_hal::keymint::Device::new_as_binder(channel.clone());
117     let service_name = format!("{}/{}", KM_SERVICE_NAME, SERVICE_INSTANCE);
118     binder::add_service(&service_name, km_service.as_binder()).map_err(|e| {
119         HalServiceError(format!("Failed to register service {} because of {:?}.", service_name, e))
120     })?;
121 
122     let rpc_service = kmr_hal::rpc::Device::new_as_binder(channel.clone());
123     let service_name = format!("{}/{}", RPC_SERVICE_NAME, SERVICE_INSTANCE);
124     binder::add_service(&service_name, rpc_service.as_binder()).map_err(|e| {
125         HalServiceError(format!("Failed to register service {} because of {:?}.", service_name, e))
126     })?;
127 
128     let clock_service = kmr_hal::secureclock::Device::new_as_binder(channel.clone());
129     let service_name = format!("{}/{}", CLOCK_SERVICE_NAME, SERVICE_INSTANCE);
130     binder::add_service(&service_name, clock_service.as_binder()).map_err(|e| {
131         HalServiceError(format!("Failed to register service {} because of {:?}.", service_name, e))
132     })?;
133 
134     let secret_service = kmr_hal::sharedsecret::Device::new_as_binder(channel.clone());
135     let service_name = format!("{}/{}", SECRET_SERVICE_NAME, SERVICE_INSTANCE);
136     binder::add_service(&service_name, secret_service.as_binder()).map_err(|e| {
137         HalServiceError(format!("Failed to register service {} because of {:?}.", service_name, e))
138     })?;
139 
140     info!("Successfully registered KeyMint HAL services.");
141 
142     // Let the TA know information about the boot environment. In a real device this
143     // is communicated directly from the bootloader to the TA, but here we retrieve
144     // the information from system properties and send from the HAL service.
145     // TODO: investigate Cuttlefish bootloader info propagation
146     // https://android.googlesource.com/platform/external/u-boot/+/2114f87e56d262220c4dc5e00c3321e99e12204b/boot/android_bootloader_keymint.c
147     let boot_req = get_boot_info();
148     debug!("boot/HAL->TA: boot info is {:?}", boot_req);
149     kmr_hal::send_boot_info(channel.lock().unwrap().deref_mut(), boot_req)
150         .map_err(|e| HalServiceError(format!("Failed to send boot info: {:?}", e)))?;
151 
152     // Let the TA know information about the userspace environment.
153     if let Err(e) = kmr_hal::send_hal_info(channel.lock().unwrap().deref_mut()) {
154         error!("Failed to send HAL info: {:?}", e);
155     }
156 
157     // Let the TA know about attestation IDs. (In a real device these would be pre-provisioned into
158     // the TA.)
159     let attest_ids = attestation_id_info();
160     if let Err(e) = kmr_hal::send_attest_ids(channel.lock().unwrap().deref_mut(), attest_ids) {
161         error!("Failed to send attestation ID info: {:?}", e);
162     }
163 
164     info!("Joining thread pool now.");
165     binder::ProcessState::join_thread_pool();
166     info!("KeyMint HAL service is terminating.");
167     Ok(())
168 }
169 
170 /// Populate attestation ID information based on properties (where available).
attestation_id_info() -> kmr_wire::AttestationIdInfo171 fn attestation_id_info() -> kmr_wire::AttestationIdInfo {
172     let prop = |name| {
173         get_property(name).unwrap_or_else(|_| format!("{} unavailable", name)).as_bytes().to_vec()
174     };
175     kmr_wire::AttestationIdInfo {
176         brand: prop("ro.product.brand"),
177         device: prop("ro.product.device"),
178         product: prop("ro.product.name"),
179         serial: prop("ro.serialno"),
180         manufacturer: prop("ro.product.manufacturer"),
181         model: prop("ro.product.model"),
182         // Currently modem_simulator always returns one fixed value. See `handleGetIMEI` in
183         // device/google/cuttlefish/host/commands/modem_simulator/misc_service.cpp for more details.
184         // TODO(b/263188546): Use device-specific IMEI values when available.
185         imei: b"867400022047199".to_vec(),
186         imei2: b"867400022047199".to_vec(),
187         meid: vec![],
188     }
189 }
190 
191 /// Get boot information based on system properties.
get_boot_info() -> kmr_wire::SetBootInfoRequest192 fn get_boot_info() -> kmr_wire::SetBootInfoRequest {
193     // No access to a verified boot key.
194     let verified_boot_key = vec![0; 32];
195     let vbmeta_digest = get_property("ro.boot.vbmeta.digest").unwrap_or_else(|_| "00".repeat(32));
196     let verified_boot_hash = hex::decode(&vbmeta_digest).unwrap_or_else(|_e| {
197         error!("failed to parse hex data in '{}'", vbmeta_digest);
198         vec![0; 32]
199     });
200     let device_boot_locked = match get_property("ro.boot.vbmeta.device_state")
201         .unwrap_or_else(|_| "no-prop".to_string())
202         .as_str()
203     {
204         "locked" => true,
205         "unlocked" => false,
206         v => {
207             error!("Unknown device_state '{}', treating as unlocked", v);
208             false
209         }
210     };
211     let verified_boot_state = match get_property("ro.boot.verifiedbootstate")
212         .unwrap_or_else(|_| "no-prop".to_string())
213         .as_str()
214     {
215         "green" => 0,  // Verified
216         "yellow" => 1, // SelfSigned
217         "orange" => 2, // Unverified,
218         "red" => 3,    // Failed,
219         v => {
220             error!("Unknown boot state '{}', treating as Unverified", v);
221             2
222         }
223     };
224 
225     // Attempt to get the boot patchlevel from a system property.  This requires an SELinux
226     // permission, so fall back to re-using the OS patchlevel if this can't be done.
227     let boot_patchlevel_prop = get_property("ro.vendor.boot_security_patch").unwrap_or_else(|e| {
228         error!("Failed to retrieve boot patchlevel: {:?}", e);
229         get_property(kmr_hal::env::OS_PATCHLEVEL_PROPERTY)
230             .unwrap_or_else(|_| "1970-09-19".to_string())
231     });
232     let boot_patchlevel =
233         kmr_hal::env::extract_patchlevel(&boot_patchlevel_prop).unwrap_or(19700919);
234 
235     kmr_wire::SetBootInfoRequest {
236         verified_boot_key,
237         device_boot_locked,
238         verified_boot_state,
239         verified_boot_hash,
240         boot_patchlevel,
241     }
242 }
243