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