1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 //! # Interface library for communicating with the system state service. 18 19 #![no_std] 20 21 #[allow(non_upper_case_globals)] 22 #[allow(non_camel_case_types)] 23 #[allow(unused)] 24 mod sys { 25 include!(env!("BINDGEN_INC_FILE")); 26 } 27 28 use core::convert::{TryFrom, TryInto}; 29 use core::ffi::CStr; 30 use core::mem; 31 use sys::*; 32 use tipc::{Deserialize, Handle, Serialize, Serializer, TipcError}; 33 34 const SYSTEM_STATE_PORT: &'static [u8] = b"com.android.trusty.system-state\0"; 35 36 /// System state flags. 37 /// 38 /// Supported queries that the system state service provides. 39 #[repr(u32)] 40 #[derive(Copy, Clone, Debug, Eq, PartialEq)] 41 pub enum SystemStateFlag { 42 /// Flag used to restrict when provisioning is allowed. 43 ProvisioningAllowed = system_state_flag_SYSTEM_STATE_FLAG_PROVISIONING_ALLOWED as u32, 44 45 /// Flag used to indicate that loading apps signed with insecure dev keys is 46 /// allowed. 47 AppLoadingUnlocked = system_state_flag_SYSTEM_STATE_FLAG_APP_LOADING_UNLOCKED as u32, 48 49 /// Flag used to permit skipping of app version checks or rollback version 50 /// updates. 51 AppLoadingVersionCheck = system_state_flag_SYSTEM_STATE_FLAG_APP_LOADING_VERSION_CHECK as u32, 52 } 53 54 impl TryFrom<u32> for SystemStateFlag { 55 type Error = TipcError; 56 try_from(value: u32) -> Result<SystemStateFlag, Self::Error>57 fn try_from(value: u32) -> Result<SystemStateFlag, Self::Error> { 58 match value as system_state_flag { 59 sys::system_state_flag_SYSTEM_STATE_FLAG_PROVISIONING_ALLOWED => { 60 Ok(SystemStateFlag::ProvisioningAllowed) 61 } 62 sys::system_state_flag_SYSTEM_STATE_FLAG_APP_LOADING_UNLOCKED => { 63 Ok(SystemStateFlag::AppLoadingUnlocked) 64 } 65 sys::system_state_flag_SYSTEM_STATE_FLAG_APP_LOADING_VERSION_CHECK => { 66 Ok(SystemStateFlag::AppLoadingVersionCheck) 67 } 68 _ => Err(TipcError::InvalidData), 69 } 70 } 71 } 72 73 /// Possible values for SystemStateFlag::ProvisioningAllowed flag. 74 #[repr(u64)] 75 #[derive(Copy, Clone, Debug, Eq, PartialEq)] 76 pub enum ProvisioningAllowedFlagValues { 77 /// Indicates that provisoning is not currently allowed. 78 ProvisioningNotAllowed = system_state_flag_provisioning_allowed_SYSTEM_STATE_FLAG_PROVISIONING_ALLOWED_VALUE_NOT_ALLOWED as u64, 79 80 /// Indicates that provisoning is currently allowed. 81 ProvisioningAllowed = system_state_flag_provisioning_allowed_SYSTEM_STATE_FLAG_PROVISIONING_ALLOWED_VALUE_ALLOWED as u64, 82 83 /// Indicates that provisoning is currently allowed if the client is in a boot stage. 84 /// 85 /// For backward compatibility. Not recommended for new systems. 86 ProvisioningAllowedAtBoot = system_state_flag_provisioning_allowed_SYSTEM_STATE_FLAG_PROVISIONING_ALLOWED_VALUE_ALLOWED_AT_BOOT as u64, 87 } 88 89 impl TryFrom<u64> for ProvisioningAllowedFlagValues { 90 type Error = TipcError; 91 try_from(value: u64) -> Result<ProvisioningAllowedFlagValues, Self::Error>92 fn try_from(value: u64) -> Result<ProvisioningAllowedFlagValues, Self::Error> { 93 match value as system_state_flag { 94 sys::system_state_flag_provisioning_allowed_SYSTEM_STATE_FLAG_PROVISIONING_ALLOWED_VALUE_NOT_ALLOWED => { 95 Ok(ProvisioningAllowedFlagValues::ProvisioningNotAllowed) 96 } 97 sys::system_state_flag_provisioning_allowed_SYSTEM_STATE_FLAG_PROVISIONING_ALLOWED_VALUE_ALLOWED => { 98 Ok(ProvisioningAllowedFlagValues::ProvisioningAllowed) 99 } 100 sys::system_state_flag_provisioning_allowed_SYSTEM_STATE_FLAG_PROVISIONING_ALLOWED_VALUE_ALLOWED_AT_BOOT => { 101 Ok(ProvisioningAllowedFlagValues::ProvisioningAllowedAtBoot) 102 } 103 _ => Err(TipcError::InvalidData), 104 } 105 } 106 } 107 108 /// Connection to the system state service 109 pub struct SystemState(Handle); 110 111 impl SystemState { 112 /// Attempt to connect to the system state service. try_connect() -> Result<Self, TipcError>113 pub fn try_connect() -> Result<Self, TipcError> { 114 let port = CStr::from_bytes_with_nul(SYSTEM_STATE_PORT) 115 .expect("SYSTEM_STATE_PORT was not null terminated"); 116 Handle::connect(port).map(Self) 117 } 118 119 /// Retrieve a state value from the system state service. get_flag(&self, flag: SystemStateFlag) -> Result<u64, TipcError>120 pub fn get_flag(&self, flag: SystemStateFlag) -> Result<u64, TipcError> { 121 self.0.send(&Request::get_flag(flag))?; 122 123 let mut buf = [0; Response::MAX_SERIALIZED_SIZE]; 124 let response: Response = self.0.recv(&mut buf)?; 125 assert_eq!(response.flag, flag); 126 Ok(response.value) 127 } 128 } 129 130 struct Request(system_state_req, RequestPayload); 131 132 enum RequestPayload { 133 GetFlag(system_state_get_flag_req), 134 } 135 136 const GET_FLAG_REQ_CMD: u32 = system_state_cmd_SYSTEM_STATE_CMD_GET_FLAG as u32; 137 const GET_FLAG_RESP_CMD: u32 = (system_state_cmd_SYSTEM_STATE_CMD_GET_FLAG 138 | system_state_cmd_SYSTEM_STATE_CMD_RESP_BIT) as u32; 139 140 impl Request { get_flag(flag: SystemStateFlag) -> Self141 fn get_flag(flag: SystemStateFlag) -> Self { 142 let header = system_state_req { 143 cmd: GET_FLAG_REQ_CMD, 144 reserved: 0, 145 payload: __IncompleteArrayField::new(), 146 }; 147 let payload = RequestPayload::GetFlag(system_state_get_flag_req { flag: flag as u32 }); 148 Self(header, payload) 149 } 150 } 151 152 impl<'s> Serialize<'s> for Request { serialize<'a: 's, S: Serializer<'s>>( &'a self, serializer: &mut S, ) -> Result<S::Ok, S::Error>153 fn serialize<'a: 's, S: Serializer<'s>>( 154 &'a self, 155 serializer: &mut S, 156 ) -> Result<S::Ok, S::Error> { 157 // SAFETY: system_state_req is a fully-initialized, repr(C) struct that 158 // outlives the Serializer lifetime. 159 unsafe { serializer.serialize_as_bytes(&self.0)? }; 160 161 match &self.1 { 162 RequestPayload::GetFlag(req) => { 163 // SAFETY: system_state_get_flag_req is a fully-initialized, 164 // repr(C) struct that outlives the Serializer lifetime. 165 unsafe { serializer.serialize_as_bytes(req) } 166 } 167 } 168 } 169 } 170 171 struct Response { 172 flag: SystemStateFlag, 173 value: u64, 174 } 175 176 impl Deserialize for Response { 177 type Error = TipcError; 178 179 const MAX_SERIALIZED_SIZE: usize = 180 mem::size_of::<system_state_resp>() + mem::size_of::<system_state_get_flag_resp>(); 181 deserialize(bytes: &[u8], _handles: &mut [Option<Handle>]) -> Result<Self, Self::Error>182 fn deserialize(bytes: &[u8], _handles: &mut [Option<Handle>]) -> Result<Self, Self::Error> { 183 if bytes.len() < mem::size_of::<system_state_resp>() { 184 return Err(TipcError::NotEnoughBuffer); 185 } 186 // SAFETY: We have validated that the buffer contains enough data to 187 // represent a system_state_resp. The constructed lifetime here does not 188 // outlive the function and thus cannot outlive the lifetime of the 189 // buffer. 190 let header = unsafe { &*(bytes.as_ptr() as *const system_state_resp) }; 191 match header.cmd { 192 GET_FLAG_RESP_CMD => { 193 if bytes.len() 194 < mem::size_of::<system_state_resp>() 195 + mem::size_of::<system_state_get_flag_resp>() 196 { 197 return Err(TipcError::NotEnoughBuffer); 198 } 199 // SAFETY: We have validated that the buffer is large enough for 200 // both the header and the get_flag payload. 201 let payload = 202 unsafe { &*(header.payload.as_ptr() as *const system_state_get_flag_resp) }; 203 Ok(Self { flag: payload.flag.try_into()?, value: payload.value }) 204 } 205 _ => Err(TipcError::InvalidData), 206 } 207 } 208 } 209