Loading libs/binder/rust/rpcbinder/src/server/trusty.rs +80 −15 Original line number Diff line number Diff line Loading @@ -14,14 +14,28 @@ * limitations under the License. */ use alloc::boxed::Box; use binder::{unstable_api::AsNative, SpIBinder}; use libc::size_t; use log::error; use std::ffi::{c_char, c_void}; use std::ptr; use tipc::{ConnectResult, Handle, MessageResult, PortCfg, TipcError, UnbufferedService, Uuid}; use tipc::{ ClientIdentifier, ConnectResult, Handle, MessageResult, PortCfg, TipcError, UnbufferedService, Uuid, }; pub trait PerSessionCallback: Fn(Uuid) -> Option<SpIBinder> + Send + Sync + 'static {} impl<T> PerSessionCallback for T where T: Fn(Uuid) -> Option<SpIBinder> + Send + Sync + 'static {} /// Trait alias for the callback passed into the per-session constructor of the RpcServer. /// Note: this is used in this file only, although it is marked as pub to be able to be used in /// the definition of the pub constructor. pub trait PerSessionCallback: Fn(ClientIdentifier) -> Option<SpIBinder> + Send + Sync + 'static { } impl<T> PerSessionCallback for T where T: Fn(ClientIdentifier) -> Option<SpIBinder> + Send + Sync + 'static { } pub struct RpcServer { inner: *mut binder_rpc_server_bindgen::ARpcServerTrusty, Loading Loading @@ -52,7 +66,7 @@ impl RpcServer { /// Allocates a new per-session RpcServer object. /// /// Per-session objects take a closure that gets called once /// for every new connection. The closure gets the UUID of /// for every new connection. The closure gets the `ClientIdentifier` of /// the peer and can accept or reject that connection. pub fn new_per_session<F: PerSessionCallback>(f: F) -> RpcServer { // SAFETY: Takes ownership of the returned handle, which has correct refcount. Loading @@ -68,25 +82,35 @@ impl RpcServer { } unsafe extern "C" fn per_session_callback_wrapper<F: PerSessionCallback>( uuid_ptr: *const c_void, client_id_ptr: *const c_void, len: size_t, cb_ptr: *mut c_char, ) -> *mut binder_rpc_server_bindgen::AIBinder { // SAFETY: This callback should only get called while the RpcServer is alive. let cb = unsafe { &mut *cb_ptr.cast::<F>() }; if len != std::mem::size_of::<Uuid>() { if len < 1 { return ptr::null_mut(); } // SAFETY: We have checked that the length is at least 1 // We know that the pointer has not been freed at this point, because: // 1) The pointer is allocated in the call to: `on_connect` or `on_new_connection` in the // implementation of the `UnbufferredService` trait for `RpcServer`. // 2) `on_connect` and `on_new_connection` invokes `ARpcServerTrusty_handleConnect`, immediately // after the allocation. // 3) this callback is invoked in the callpath of `ARpcServerTrusty_handleConnect`. // We know that there is no concurrent mutable access to the pointer because it is allocated // and accessed in the same (single) process as per the callpath described above. let client_id_data = unsafe { std::slice::from_raw_parts(client_id_ptr.cast(), len) }; let client_id = match ClientIdentifier::from_tagged_bytes(client_id_data) { Ok(c) => c, Err(_) => { error!("error in reconstructing the ClientIdentifier from pointer and length"); return ptr::null_mut(); } // SAFETY: On the previous lines we check that we got exactly the right amount of bytes. let uuid = unsafe { let mut uuid = std::mem::MaybeUninit::<Uuid>::uninit(); uuid.as_mut_ptr().copy_from(uuid_ptr.cast(), 1); uuid.assume_init() }; cb(uuid).map_or_else(ptr::null_mut, |b| { cb(client_id).map_or_else(ptr::null_mut, |b| { // Prevent AIBinder_decStrong from being called before AIBinder_toPlatformBinder. // The per-session callback in C++ is supposed to call AIBinder_decStrong on the // pointer we return here. Loading Loading @@ -129,11 +153,21 @@ impl UnbufferedService for RpcServer { peer: &Uuid, ) -> tipc::Result<ConnectResult<Self::Connection>> { let mut conn = RpcServerConnection { ctx: std::ptr::null_mut() }; let client_identifier = ClientIdentifier::UUID(peer.clone()); let mut data = client_identifier.as_tagged_bytes(); let len = data.len(); // SAFETY: This unsafe block calls into a C++ function, which is considered safe, i.e. it // does not cause undefined behavior for valid inputs (see below), returns an integer which // indicates success or error, does not allocate or deallocate memory that Rust owns. // The inputs passed into the C++ function are valid: Trusty is single threaded, so there is // no concurrent access to `sef.inner`` and other inputs are not freed/deallocated until the // function returns. Correct length of the data pointed to by the pointer is passed in. let rc = unsafe { binder_rpc_server_bindgen::ARpcServerTrusty_handleConnect( self.inner, handle.as_raw_fd(), peer.as_ptr().cast(), data.as_mut_ptr() as *const c_void, len, &mut conn.ctx, ) }; Loading Loading @@ -161,4 +195,35 @@ impl UnbufferedService for RpcServer { fn on_disconnect(&self, conn: &Self::Connection) { unsafe { binder_rpc_server_bindgen::ARpcServerTrusty_handleDisconnect(conn.ctx) }; } fn on_new_connection( &self, _port: &PortCfg, handle: &Handle, client_identifier: &ClientIdentifier, ) -> tipc::Result<ConnectResult<Self::Connection>> { let mut conn = RpcServerConnection { ctx: std::ptr::null_mut() }; let mut data = client_identifier.as_tagged_bytes(); let len = data.len(); // SAFETY: This unsafe block calls into a C++ function, which is considered safe, i.e. it // does not cause undefined behavior for valid inputs (see below), returns an integer which // indicates success or error, does not allocate or deallocate memory that Rust owns. // The inputs passed into the C++ function are valid: Trusty is single threaded, so there is // no concurrent access to `sef.inner`` and other inputs are not freed/deallocated until the // function returns. Correct length of the data pointed to by the pointer is passed in. let rc = unsafe { binder_rpc_server_bindgen::ARpcServerTrusty_handleConnect( self.inner, handle.as_raw_fd(), data.as_mut_ptr() as *const c_void, len, &mut conn.ctx, ) }; if rc < 0 { Err(TipcError::from_uapi(rc.into())) } else { Ok(ConnectResult::Accept(conn)) } } } libs/binder/trusty/RpcServerTrusty.cpp +10 −6 Original line number Diff line number Diff line Loading @@ -97,11 +97,13 @@ RpcServerTrusty::RpcServerTrusty(std::unique_ptr<RpcTransportCtx> ctx, std::stri int RpcServerTrusty::handleConnect(const tipc_port* port, handle_t chan, const uuid* peer, void** ctx_p) { auto* server = reinterpret_cast<RpcServerTrusty*>(const_cast<void*>(port->priv)); return handleConnectInternal(server->mRpcServer.get(), chan, peer, ctx_p); const void* uuid_ptr = static_cast<const void*>(peer); constexpr size_t uuidLen = sizeof(*peer); return handleConnectInternal(server->mRpcServer.get(), chan, uuid_ptr, uuidLen, ctx_p); } int RpcServerTrusty::handleConnectInternal(RpcServer* rpcServer, handle_t chan, const uuid* peer, void** ctx_p) { int RpcServerTrusty::handleConnectInternal(RpcServer* rpcServer, handle_t chan, const void* addrData, size_t addrDataLen, void** ctx_p) { rpcServer->mShutdownTrigger = FdTrigger::make(); rpcServer->mConnectingThreads[rpc_this_thread::get_id()] = RpcMaybeThread(); Loading Loading @@ -137,10 +139,12 @@ int RpcServerTrusty::handleConnectInternal(RpcServer* rpcServer, handle_t chan, android::RpcTransportFd transportFd(std::move(clientFd)); std::array<uint8_t, RpcServer::kRpcAddressSize> addr; constexpr size_t addrLen = sizeof(*peer); memcpy(addr.data(), peer, addrLen); if (addrDataLen > RpcServer::kRpcAddressSize) { return ERR_BAD_LEN; } memcpy(addr.data(), addrData, addrDataLen); RpcServer::establishConnection(sp<RpcServer>::fromExisting(rpcServer), std::move(transportFd), addr, addrLen, joinFn); addr, addrDataLen, joinFn); return rc; } Loading libs/binder/trusty/include/binder/ARpcServerTrusty.h +1 −1 Original line number Diff line number Diff line Loading @@ -28,7 +28,7 @@ struct ARpcServerTrusty* ARpcServerTrusty_newPerSession(struct AIBinder* (*)(con char*), char*, void (*)(char*)); void ARpcServerTrusty_delete(struct ARpcServerTrusty*); int ARpcServerTrusty_handleConnect(struct ARpcServerTrusty*, handle_t, const struct uuid*, void**); int ARpcServerTrusty_handleConnect(struct ARpcServerTrusty*, handle_t, const void*, size_t, void**); int ARpcServerTrusty_handleMessage(void*); void ARpcServerTrusty_handleDisconnect(void*); void ARpcServerTrusty_handleChannelCleanup(void*); Loading libs/binder/trusty/include/binder/RpcServerTrusty.h +15 −3 Original line number Diff line number Diff line Loading @@ -114,7 +114,19 @@ private: char*), char*, void (*)(char*)); friend void ::ARpcServerTrusty_delete(::ARpcServerTrusty*); friend int ::ARpcServerTrusty_handleConnect(::ARpcServerTrusty*, handle_t, const uuid*, void**); /** * @brief Handle the binder RPC connection. * * @param rstr - RpcServer object * @param chan - handle to the connection * @param clientId - identifier of the client as tagged data * @param clientIdLen - length of the client identifier * @param ctx_p - connection context * @return int - error code */ friend int ::ARpcServerTrusty_handleConnect(struct ARpcServerTrusty* rstr, handle_t chan, const void* clientId, size_t clientIdLen, void** ctx_p); friend int ::ARpcServerTrusty_handleMessage(void*); friend void ::ARpcServerTrusty_handleDisconnect(void*); friend void ::ARpcServerTrusty_handleChannelCleanup(void*); Loading @@ -130,8 +142,8 @@ private: static void handleDisconnect(const tipc_port* port, handle_t chan, void* ctx); static void handleChannelCleanup(void* ctx); static int handleConnectInternal(RpcServer* rpcServer, handle_t chan, const uuid* peer, void** ctx_p); static int handleConnectInternal(RpcServer* rpcServer, handle_t chan, const void* addrData, size_t addrDataLen, void** ctx_p); static int handleMessageInternal(void* ctx); static void handleDisconnectInternal(void* ctx); Loading libs/binder/trusty/rust/binder_rpc_server_bindgen/cpp/ARpcServerTrusty.cpp +4 −3 Original line number Diff line number Diff line Loading @@ -72,9 +72,10 @@ void ARpcServerTrusty_delete(ARpcServerTrusty* rstr) { delete rstr; } int ARpcServerTrusty_handleConnect(ARpcServerTrusty* rstr, handle_t chan, const uuid* peer, void** ctx_p) { return RpcServerTrusty::handleConnectInternal(rstr->mRpcServer.get(), chan, peer, ctx_p); int ARpcServerTrusty_handleConnect(ARpcServerTrusty* rstr, handle_t chan, const void* clientId, size_t clientIdLen, void** ctx_p) { return RpcServerTrusty::handleConnectInternal(rstr->mRpcServer.get(), chan, clientId, clientIdLen, ctx_p); } int ARpcServerTrusty_handleMessage(void* ctx) { Loading Loading
libs/binder/rust/rpcbinder/src/server/trusty.rs +80 −15 Original line number Diff line number Diff line Loading @@ -14,14 +14,28 @@ * limitations under the License. */ use alloc::boxed::Box; use binder::{unstable_api::AsNative, SpIBinder}; use libc::size_t; use log::error; use std::ffi::{c_char, c_void}; use std::ptr; use tipc::{ConnectResult, Handle, MessageResult, PortCfg, TipcError, UnbufferedService, Uuid}; use tipc::{ ClientIdentifier, ConnectResult, Handle, MessageResult, PortCfg, TipcError, UnbufferedService, Uuid, }; pub trait PerSessionCallback: Fn(Uuid) -> Option<SpIBinder> + Send + Sync + 'static {} impl<T> PerSessionCallback for T where T: Fn(Uuid) -> Option<SpIBinder> + Send + Sync + 'static {} /// Trait alias for the callback passed into the per-session constructor of the RpcServer. /// Note: this is used in this file only, although it is marked as pub to be able to be used in /// the definition of the pub constructor. pub trait PerSessionCallback: Fn(ClientIdentifier) -> Option<SpIBinder> + Send + Sync + 'static { } impl<T> PerSessionCallback for T where T: Fn(ClientIdentifier) -> Option<SpIBinder> + Send + Sync + 'static { } pub struct RpcServer { inner: *mut binder_rpc_server_bindgen::ARpcServerTrusty, Loading Loading @@ -52,7 +66,7 @@ impl RpcServer { /// Allocates a new per-session RpcServer object. /// /// Per-session objects take a closure that gets called once /// for every new connection. The closure gets the UUID of /// for every new connection. The closure gets the `ClientIdentifier` of /// the peer and can accept or reject that connection. pub fn new_per_session<F: PerSessionCallback>(f: F) -> RpcServer { // SAFETY: Takes ownership of the returned handle, which has correct refcount. Loading @@ -68,25 +82,35 @@ impl RpcServer { } unsafe extern "C" fn per_session_callback_wrapper<F: PerSessionCallback>( uuid_ptr: *const c_void, client_id_ptr: *const c_void, len: size_t, cb_ptr: *mut c_char, ) -> *mut binder_rpc_server_bindgen::AIBinder { // SAFETY: This callback should only get called while the RpcServer is alive. let cb = unsafe { &mut *cb_ptr.cast::<F>() }; if len != std::mem::size_of::<Uuid>() { if len < 1 { return ptr::null_mut(); } // SAFETY: We have checked that the length is at least 1 // We know that the pointer has not been freed at this point, because: // 1) The pointer is allocated in the call to: `on_connect` or `on_new_connection` in the // implementation of the `UnbufferredService` trait for `RpcServer`. // 2) `on_connect` and `on_new_connection` invokes `ARpcServerTrusty_handleConnect`, immediately // after the allocation. // 3) this callback is invoked in the callpath of `ARpcServerTrusty_handleConnect`. // We know that there is no concurrent mutable access to the pointer because it is allocated // and accessed in the same (single) process as per the callpath described above. let client_id_data = unsafe { std::slice::from_raw_parts(client_id_ptr.cast(), len) }; let client_id = match ClientIdentifier::from_tagged_bytes(client_id_data) { Ok(c) => c, Err(_) => { error!("error in reconstructing the ClientIdentifier from pointer and length"); return ptr::null_mut(); } // SAFETY: On the previous lines we check that we got exactly the right amount of bytes. let uuid = unsafe { let mut uuid = std::mem::MaybeUninit::<Uuid>::uninit(); uuid.as_mut_ptr().copy_from(uuid_ptr.cast(), 1); uuid.assume_init() }; cb(uuid).map_or_else(ptr::null_mut, |b| { cb(client_id).map_or_else(ptr::null_mut, |b| { // Prevent AIBinder_decStrong from being called before AIBinder_toPlatformBinder. // The per-session callback in C++ is supposed to call AIBinder_decStrong on the // pointer we return here. Loading Loading @@ -129,11 +153,21 @@ impl UnbufferedService for RpcServer { peer: &Uuid, ) -> tipc::Result<ConnectResult<Self::Connection>> { let mut conn = RpcServerConnection { ctx: std::ptr::null_mut() }; let client_identifier = ClientIdentifier::UUID(peer.clone()); let mut data = client_identifier.as_tagged_bytes(); let len = data.len(); // SAFETY: This unsafe block calls into a C++ function, which is considered safe, i.e. it // does not cause undefined behavior for valid inputs (see below), returns an integer which // indicates success or error, does not allocate or deallocate memory that Rust owns. // The inputs passed into the C++ function are valid: Trusty is single threaded, so there is // no concurrent access to `sef.inner`` and other inputs are not freed/deallocated until the // function returns. Correct length of the data pointed to by the pointer is passed in. let rc = unsafe { binder_rpc_server_bindgen::ARpcServerTrusty_handleConnect( self.inner, handle.as_raw_fd(), peer.as_ptr().cast(), data.as_mut_ptr() as *const c_void, len, &mut conn.ctx, ) }; Loading Loading @@ -161,4 +195,35 @@ impl UnbufferedService for RpcServer { fn on_disconnect(&self, conn: &Self::Connection) { unsafe { binder_rpc_server_bindgen::ARpcServerTrusty_handleDisconnect(conn.ctx) }; } fn on_new_connection( &self, _port: &PortCfg, handle: &Handle, client_identifier: &ClientIdentifier, ) -> tipc::Result<ConnectResult<Self::Connection>> { let mut conn = RpcServerConnection { ctx: std::ptr::null_mut() }; let mut data = client_identifier.as_tagged_bytes(); let len = data.len(); // SAFETY: This unsafe block calls into a C++ function, which is considered safe, i.e. it // does not cause undefined behavior for valid inputs (see below), returns an integer which // indicates success or error, does not allocate or deallocate memory that Rust owns. // The inputs passed into the C++ function are valid: Trusty is single threaded, so there is // no concurrent access to `sef.inner`` and other inputs are not freed/deallocated until the // function returns. Correct length of the data pointed to by the pointer is passed in. let rc = unsafe { binder_rpc_server_bindgen::ARpcServerTrusty_handleConnect( self.inner, handle.as_raw_fd(), data.as_mut_ptr() as *const c_void, len, &mut conn.ctx, ) }; if rc < 0 { Err(TipcError::from_uapi(rc.into())) } else { Ok(ConnectResult::Accept(conn)) } } }
libs/binder/trusty/RpcServerTrusty.cpp +10 −6 Original line number Diff line number Diff line Loading @@ -97,11 +97,13 @@ RpcServerTrusty::RpcServerTrusty(std::unique_ptr<RpcTransportCtx> ctx, std::stri int RpcServerTrusty::handleConnect(const tipc_port* port, handle_t chan, const uuid* peer, void** ctx_p) { auto* server = reinterpret_cast<RpcServerTrusty*>(const_cast<void*>(port->priv)); return handleConnectInternal(server->mRpcServer.get(), chan, peer, ctx_p); const void* uuid_ptr = static_cast<const void*>(peer); constexpr size_t uuidLen = sizeof(*peer); return handleConnectInternal(server->mRpcServer.get(), chan, uuid_ptr, uuidLen, ctx_p); } int RpcServerTrusty::handleConnectInternal(RpcServer* rpcServer, handle_t chan, const uuid* peer, void** ctx_p) { int RpcServerTrusty::handleConnectInternal(RpcServer* rpcServer, handle_t chan, const void* addrData, size_t addrDataLen, void** ctx_p) { rpcServer->mShutdownTrigger = FdTrigger::make(); rpcServer->mConnectingThreads[rpc_this_thread::get_id()] = RpcMaybeThread(); Loading Loading @@ -137,10 +139,12 @@ int RpcServerTrusty::handleConnectInternal(RpcServer* rpcServer, handle_t chan, android::RpcTransportFd transportFd(std::move(clientFd)); std::array<uint8_t, RpcServer::kRpcAddressSize> addr; constexpr size_t addrLen = sizeof(*peer); memcpy(addr.data(), peer, addrLen); if (addrDataLen > RpcServer::kRpcAddressSize) { return ERR_BAD_LEN; } memcpy(addr.data(), addrData, addrDataLen); RpcServer::establishConnection(sp<RpcServer>::fromExisting(rpcServer), std::move(transportFd), addr, addrLen, joinFn); addr, addrDataLen, joinFn); return rc; } Loading
libs/binder/trusty/include/binder/ARpcServerTrusty.h +1 −1 Original line number Diff line number Diff line Loading @@ -28,7 +28,7 @@ struct ARpcServerTrusty* ARpcServerTrusty_newPerSession(struct AIBinder* (*)(con char*), char*, void (*)(char*)); void ARpcServerTrusty_delete(struct ARpcServerTrusty*); int ARpcServerTrusty_handleConnect(struct ARpcServerTrusty*, handle_t, const struct uuid*, void**); int ARpcServerTrusty_handleConnect(struct ARpcServerTrusty*, handle_t, const void*, size_t, void**); int ARpcServerTrusty_handleMessage(void*); void ARpcServerTrusty_handleDisconnect(void*); void ARpcServerTrusty_handleChannelCleanup(void*); Loading
libs/binder/trusty/include/binder/RpcServerTrusty.h +15 −3 Original line number Diff line number Diff line Loading @@ -114,7 +114,19 @@ private: char*), char*, void (*)(char*)); friend void ::ARpcServerTrusty_delete(::ARpcServerTrusty*); friend int ::ARpcServerTrusty_handleConnect(::ARpcServerTrusty*, handle_t, const uuid*, void**); /** * @brief Handle the binder RPC connection. * * @param rstr - RpcServer object * @param chan - handle to the connection * @param clientId - identifier of the client as tagged data * @param clientIdLen - length of the client identifier * @param ctx_p - connection context * @return int - error code */ friend int ::ARpcServerTrusty_handleConnect(struct ARpcServerTrusty* rstr, handle_t chan, const void* clientId, size_t clientIdLen, void** ctx_p); friend int ::ARpcServerTrusty_handleMessage(void*); friend void ::ARpcServerTrusty_handleDisconnect(void*); friend void ::ARpcServerTrusty_handleChannelCleanup(void*); Loading @@ -130,8 +142,8 @@ private: static void handleDisconnect(const tipc_port* port, handle_t chan, void* ctx); static void handleChannelCleanup(void* ctx); static int handleConnectInternal(RpcServer* rpcServer, handle_t chan, const uuid* peer, void** ctx_p); static int handleConnectInternal(RpcServer* rpcServer, handle_t chan, const void* addrData, size_t addrDataLen, void** ctx_p); static int handleMessageInternal(void* ctx); static void handleDisconnectInternal(void* ctx); Loading
libs/binder/trusty/rust/binder_rpc_server_bindgen/cpp/ARpcServerTrusty.cpp +4 −3 Original line number Diff line number Diff line Loading @@ -72,9 +72,10 @@ void ARpcServerTrusty_delete(ARpcServerTrusty* rstr) { delete rstr; } int ARpcServerTrusty_handleConnect(ARpcServerTrusty* rstr, handle_t chan, const uuid* peer, void** ctx_p) { return RpcServerTrusty::handleConnectInternal(rstr->mRpcServer.get(), chan, peer, ctx_p); int ARpcServerTrusty_handleConnect(ARpcServerTrusty* rstr, handle_t chan, const void* clientId, size_t clientIdLen, void** ctx_p) { return RpcServerTrusty::handleConnectInternal(rstr->mRpcServer.get(), chan, clientId, clientIdLen, ctx_p); } int ARpcServerTrusty_handleMessage(void* ctx) { Loading