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