Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7171c676 authored by David Drysdale's avatar David Drysdale
Browse files

Secretkeeper HAL: support large messages

The TIPC channel between HAL service and TA has a max message size of
around 4K. Cope with larger messages by using fragmentation and
reassembly for all messages.

Test: VtsSecretkeeperTargetTest
Change-Id: I18cc9a9f6e6b90ab66bc3bcf1972e1a5c5112c89
parent 80b2bf16
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -28,12 +28,13 @@ rust_binary {
    ],
    rustlibs: [
        "libandroid_logger",
        "libbinder_rs",
        "libauthgraph_hal",
        "libtrusty-rs",
        "libauthgraph_wire",
        "libbinder_rs",
        "liblibc",
        "liblog_rust",
        "libsecretkeeper_hal",
        "libtrusty-rs",
    ],
    defaults: [
        "secretkeeper_use_latest_hal_aidl_rust",
+37 −29
Original line number Diff line number Diff line
@@ -14,7 +14,8 @@
// limitations under the License.

//! This module implements the HAL service for Secretkeeper in Trusty.
use authgraph_hal::{channel::SerializedChannel};
use authgraph_hal::channel::SerializedChannel;
use authgraph_wire::fragmentation::{Fragmenter, Reassembler};
use secretkeeper_hal::SecretkeeperService;
use android_hardware_security_secretkeeper::aidl::android::hardware::security::secretkeeper::ISecretkeeper::{
    ISecretkeeper, BpSecretkeeper,
@@ -22,6 +23,7 @@ use android_hardware_security_secretkeeper::aidl::android::hardware::security::s
use log::{error, info};
use std::{
    ffi::CString,
    fmt::Debug,
    panic,
    sync::{Arc, Mutex},
};
@@ -29,6 +31,7 @@ use trusty::DEFAULT_DEVICE;

const SK_TIPC_SERVICE_PORT: &str = "com.android.trusty.secretkeeper";
const AG_TIPC_SERVICE_PORT: &str = "com.android.trusty.secretkeeper.authgraph";
const TIPC_MAX_SIZE: usize = 4000;

static SERVICE_INSTANCE: &str = "default";

@@ -47,38 +50,43 @@ impl TipcChannel {
    }
}

fn binderr<E: Debug>(msg: &str, e: E) -> binder::Status {
    binder::Status::new_exception(
        binder::ExceptionCode::TRANSACTION_FAILED,
        Some(&CString::new(format!("Failed to {msg} via tipc channel: {e:?}",)).unwrap()),
    )
}

impl SerializedChannel for TipcChannel {
    const MAX_SIZE: usize = 4000;
    // No maximum size for messages passed to `execute()` because it performs fragmentation
    // and reassembly internally.
    const MAX_SIZE: usize = usize::MAX;

    fn execute(&self, req_data: &[u8]) -> binder::Result<Vec<u8>> {
        // Hold lock across both request and response.
        let mut channel = self.channel.lock().unwrap();
        channel.send(req_data).map_err(|e| {
            binder::Status::new_exception(
                binder::ExceptionCode::TRANSACTION_FAILED,
                Some(
                    &CString::new(format!(
                        "Failed to send the request via tipc channel because of {:?}",
                        e
                    ))
                    .unwrap(),
                ),
            )
        })?;
        // TODO: cope with fragmentation and reassembly
        let mut rsp_data = Vec::new();
        channel.recv(&mut rsp_data).map_err(|e| {
            binder::Status::new_exception(
                binder::ExceptionCode::TRANSACTION_FAILED,
                Some(
                    &CString::new(format!(
                        "Failed to receive the response via tipc channel because of {:?}",
                        e
                    ))
                    .unwrap(),
                ),
            )
        })?;
        Ok(rsp_data)
        let mut pending_rsp = Reassembler::default();

        // Break request message into fragments to send.
        for req_frag in Fragmenter::new(req_data, TIPC_MAX_SIZE) {
            channel.send(&req_frag).map_err(|e| binderr("send request", e))?;

            // Every request gets a response.
            let mut rsp_frag = Vec::new();
            channel.recv(&mut rsp_frag).map_err(|e| binderr("receive response", e))?;

            if let Some(full_rsp) = pending_rsp.accumulate(&rsp_frag) {
                return Ok(full_rsp.to_vec());
            }
        }
        // There may be additional response fragments to receive.
        loop {
            let mut rsp_frag = Vec::new();
            channel.recv(&mut rsp_frag).map_err(|e| binderr("receive response", e))?;
            if let Some(full_rsp) = pending_rsp.accumulate(&rsp_frag) {
                return Ok(full_rsp.to_vec());
            }
        }
    }
}