1 /*
2 * Copyright (C) 2024 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 mod boot_params_svc;
18
19 use alloc::vec::Vec;
20 use android_system_desktop_security_gsc::aidl::android::system::desktop::security::gsc::IGsc::BnGsc;
21 use android_system_desktop_security_gsc::aidl::android::system::desktop::security::gsc::IGsc::IGsc;
22 use binder::{BinderFeatures, ExceptionCode, Interface, Result as BinderResult, Status};
23 use log::{error, info};
24 use rpcbinder::RpcServer;
25 use std::borrow::Cow;
26 use std::rc::Rc;
27 use std::sync::Arc;
28 use std::sync::Mutex;
29 use tipc::TipcError;
30 use tipc::{
31 service_dispatcher, ConnectResult, Deserialize, Handle, Manager, MessageResult, PortCfg,
32 Serialize, Serializer, UnbufferedService, Uuid,
33 };
34 use trusty_sys::Error;
35
36 const GSC_SERVICE_PORT: &str = "com.android.trusty.rust.GscAppService.V1";
37 const TUNNEL_SERVICE_PORT: &str = "com.android.trusty.rust.GscTunnelService.V1";
38 const BP_SERVICE_PORT: &str = "com.android.trusty.rust.BootParamsService.V1";
39
40 /// A GscProxy implements the IGsc binder interface and forwards requests from trusty apps to the
41 /// GSC over a GscTunnel.
42 pub struct GscProxy {
43 tunnel: Arc<GscTunnelInner>,
44 }
45
46 impl Interface for GscProxy {}
47
48 impl IGsc for GscProxy {
transmit(&self, data: &[u8]) -> BinderResult<Vec<u8>>49 fn transmit(&self, data: &[u8]) -> BinderResult<Vec<u8>> {
50 self.tunnel
51 .transmit(data)
52 .map_err(|_| Status::new_exception(ExceptionCode::ILLEGAL_STATE, None))
53 }
54 }
55
56 impl GscProxy {
new(tunnel: Arc<GscTunnelInner>) -> Self57 fn new(tunnel: Arc<GscTunnelInner>) -> Self {
58 Self { tunnel }
59 }
60 }
61
62 /// GscTunnelInner satisfies GscProxy's requirement to be Sync + Send due to being a binder
63 /// interface.
64 pub struct GscTunnelInner {
65 handle: Mutex<Option<Handle>>,
66 }
67
68 /// GscTunnel implements the tipc::UnbufferedService trait for an untrusted service (gscd) to
69 /// connect to and receive commands from.
70 pub struct GscTunnel {
71 inner: Arc<GscTunnelInner>,
72 }
73
74 /// The content of a message is a TPM command and opaque to this service.
75 pub struct Message<'a>(Cow<'a, [u8]>);
76
77 impl Deserialize for Message<'_> {
78 type Error = TipcError;
79 const MAX_SERIALIZED_SIZE: usize = 4096;
80
deserialize(bytes: &[u8], _handles: &mut [Option<Handle>]) -> tipc::Result<Self>81 fn deserialize(bytes: &[u8], _handles: &mut [Option<Handle>]) -> tipc::Result<Self> {
82 Ok(Message(Cow::from(bytes.to_vec())))
83 }
84 }
85
86 impl<'s> Serialize<'s> for Message<'_> {
serialize<'a: 's, S: Serializer<'s>>( &'a self, serializer: &mut S, ) -> Result<S::Ok, S::Error>87 fn serialize<'a: 's, S: Serializer<'s>>(
88 &'a self,
89 serializer: &mut S,
90 ) -> Result<S::Ok, S::Error> {
91 serializer.serialize_bytes(self.0.as_ref())
92 }
93 }
94
95 impl UnbufferedService for GscTunnel {
96 type Connection = ();
97
98 /// on_connect stores the connection handle for later use.
on_connect( &self, _port: &PortCfg, handle: &Handle, _peer: &Uuid, ) -> tipc::Result<ConnectResult<Self::Connection>>99 fn on_connect(
100 &self,
101 _port: &PortCfg,
102 handle: &Handle,
103 _peer: &Uuid,
104 ) -> tipc::Result<ConnectResult<Self::Connection>> {
105 *self.inner.handle.lock().map_err(|_| TipcError::SystemError(Error::BadState))? =
106 Some(handle.try_clone()?);
107 info!("gscd connected to the Trusty gsc_svc");
108 Ok(ConnectResult::Accept(()))
109 }
110
111 // on_message is never expected to be called since GscTunnel handles commands synchronously
on_message( &self, _connection: &Self::Connection, _handle: &Handle, _buffer: &mut [u8], ) -> tipc::Result<MessageResult>112 fn on_message(
113 &self,
114 _connection: &Self::Connection,
115 _handle: &Handle,
116 _buffer: &mut [u8],
117 ) -> tipc::Result<MessageResult> {
118 Ok(MessageResult::MaintainConnection)
119 }
120
on_disconnect(&self, _connection: &Self::Connection)121 fn on_disconnect(&self, _connection: &Self::Connection) {
122 error!("gscd disconnected!");
123 *self.inner.handle.lock().unwrap_or_else(|e| e.into_inner()) = None;
124 }
125 }
126
127 impl GscTunnelInner {
new() -> Self128 fn new() -> Self {
129 Self { handle: Mutex::new(None) }
130 }
131
132 /// tipc does not design for trusty applications connection to untrusted apps. As a result,
133 /// it's possible the othe trusty apps will start sending messages before the connection from
134 /// gscd is made.
transmit(&self, data: &[u8]) -> tipc::Result<Vec<u8>>135 fn transmit(&self, data: &[u8]) -> tipc::Result<Vec<u8>> {
136 if let Some(handle) =
137 self.handle.lock().or(Err(TipcError::SystemError(Error::BadState)))?.as_ref()
138 {
139 handle.send(&Message(Cow::from(data)))?;
140 let mut buf = vec![0; Message::MAX_SERIALIZED_SIZE];
141 let msg: Message = handle.recv(buf.as_mut_slice())?;
142 Ok(msg.0.to_vec())
143 } else {
144 Err(TipcError::SystemError(Error::NotReady))
145 }
146 }
147 }
148
149 impl GscTunnel {
new(inner: Arc<GscTunnelInner>) -> Self150 fn new(inner: Arc<GscTunnelInner>) -> Self {
151 Self { inner }
152 }
153 }
154
155 service_dispatcher! {
156 enum GscDispatcher {
157 RpcServer,
158 GscTunnel,
159 }
160 }
161
162 const PORT_COUNT: usize = 3;
163 const CONNECTION_COUNT: usize = 4;
164
init_and_start_loop() -> Result<(), TipcError>165 pub fn init_and_start_loop() -> Result<(), TipcError> {
166 trusty_log::init();
167 let inner_tunnel = Arc::new(GscTunnelInner::new());
168 let tunnel = GscTunnel::new(inner_tunnel.clone());
169 let proxy = GscProxy::new(inner_tunnel);
170
171 let mut dispatcher =
172 GscDispatcher::<PORT_COUNT>::new().expect("Could not create test dispatcher");
173 let gsc_service = BnGsc::new_binder(proxy, BinderFeatures::default());
174 let gsc_rpc_server = RpcServer::new_per_session(move |_uuid| Some(gsc_service.as_binder()));
175
176 let app_cfg =
177 PortCfg::new(GSC_SERVICE_PORT).expect("Could not create port config").allow_ta_connect();
178 dispatcher
179 .add_service(Rc::new(gsc_rpc_server), app_cfg)
180 .expect("Could not add GSC service to dispatcher");
181
182 let tunnel_cfg =
183 PortCfg::new(TUNNEL_SERVICE_PORT).expect("Could not create port config").allow_ns_connect();
184 dispatcher
185 .add_service(Rc::new(tunnel), tunnel_cfg)
186 .expect("Could not add tunnel service to dispatcher");
187
188 let bp_cfg =
189 PortCfg::new(BP_SERVICE_PORT).expect("Could not create port config").allow_ta_connect();
190 let bp = boot_params_svc::create_boot_params_service()?;
191 let bp_rpc_server = RpcServer::new_per_session(move |_uuid| Some(bp.as_binder()));
192 dispatcher
193 .add_service(Rc::new(bp_rpc_server), bp_cfg)
194 .expect("Could not add bp service to dispatcher");
195
196 Manager::<_, _, PORT_COUNT, CONNECTION_COUNT>::new_with_dispatcher(dispatcher, [])
197 .expect("Could not create service manager")
198 .run_event_loop()
199 .expect("GSC tunnel event loop failed");
200
201 Ok(())
202 }
203