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

Commit 2302e212 authored by Tri Vo's avatar Tri Vo Committed by Automerger Merge Worker
Browse files

Merge "trusty: ConfirmationUI HAL<->TA IPC using shared memory" am: 09cbde25

Original change: https://android-review.googlesource.com/c/platform/system/core/+/1590278

MUST ONLY BE SUBMITTED BY AUTOMERGER

Change-Id: Ie69953fddcf5bd923a8fd0fd42dec667d1875e6e
parents 33a4442b 09cbde25
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -54,6 +54,7 @@ cc_library {
        "android.hardware.confirmationui@1.0",
        "android.hardware.keymaster@4.0",
        "libbase",
        "libdmabufheap",
        "libhidlbase",
        "libteeui_hal_support",
        "libtrusty",
+128 −113
Original line number Diff line number Diff line
/*
 * Copyright 2020, The Android Open Source Project
 * Copyright 2021, The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
@@ -15,140 +15,155 @@
 */

#include "TrustyApp.h"
#include "TrustyIpc.h"

#include <BufferAllocator/BufferAllocator.h>
#include <android-base/logging.h>
#include <sys/mman.h>
#include <sys/uio.h>
#include <trusty/tipc.h>

#define countof(arr) (sizeof(arr) / sizeof(arr[0]))

namespace android {
namespace trusty {

// 0x1000 is the message buffer size but we need to leave some space for a protocol header.
// This assures that packets can always be read/written in one read/write operation.
static constexpr const uint32_t kPacketSize = 0x1000 - 32;
using ::android::base::unique_fd;

enum class PacketType : uint32_t {
    SND,
    RCV,
    ACK,
};
static inline uintptr_t RoundPageUp(uintptr_t val) {
    return (val + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
}

struct PacketHeader {
    PacketType type;
    uint32_t remaining;
};
ssize_t TrustyApp::TrustyRpc(const uint8_t* obegin, const uint8_t* oend, uint8_t* ibegin,
                             uint8_t* iend) {
    uint32_t olen = oend - obegin;

const char* toString(PacketType t) {
    switch (t) {
    case PacketType::SND:
        return "SND";
    case PacketType::RCV:
        return "RCV";
    case PacketType::ACK:
        return "ACK";
    default:
        return "UNKNOWN";
    }
    if (olen > shm_len_) {
        LOG(ERROR) << AT << "request message too long to fit in shared memory";
        return -1;
    }

static constexpr const uint32_t kHeaderSize = sizeof(PacketHeader);
static constexpr const uint32_t kPayloadSize = kPacketSize - kHeaderSize;
    memcpy(shm_base_, obegin, olen);

ssize_t TrustyRpc(int handle, const uint8_t* obegin, const uint8_t* oend, uint8_t* ibegin,
                  uint8_t* iend) {
    while (obegin != oend) {
        PacketHeader header = {
            .type = PacketType::SND,
            .remaining = uint32_t(oend - obegin),
    confirmationui_hdr hdr = {
        .cmd = CONFIRMATIONUI_CMD_MSG,
    };
    confirmationui_msg_args args = {
        .msg_len = olen,
    };
        uint32_t body_size = std::min(kPayloadSize, header.remaining);
    iovec iov[] = {
        {
                .iov_base = &header,
                .iov_len = kHeaderSize,
            .iov_base = &hdr,
            .iov_len = sizeof(hdr),
        },
        {
                .iov_base = const_cast<uint8_t*>(obegin),
                .iov_len = body_size,
            .iov_base = &args,
            .iov_len = sizeof(args),
        },
    };
        int rc = writev(handle, iov, 2);
        if (!rc) {
            PLOG(ERROR) << "Error sending SND message. " << rc;
            return rc;

    int rc = tipc_send(handle_, iov, countof(iov), NULL, 0);
    if (rc != static_cast<int>(sizeof(hdr) + sizeof(args))) {
        LOG(ERROR) << AT << "failed to send MSG request";
        return -1;
    }

        obegin += body_size;
    rc = readv(handle_, iov, countof(iov));
    if (rc != static_cast<int>(sizeof(hdr) + sizeof(args))) {
        LOG(ERROR) << AT << "failed to receive MSG response";
        return -1;
    }

        rc = read(handle, &header, kHeaderSize);
        if (!rc) {
            PLOG(ERROR) << "Error reading ACK. " << rc;
            return rc;
    if (hdr.cmd != (CONFIRMATIONUI_CMD_MSG | CONFIRMATIONUI_RESP_BIT)) {
        LOG(ERROR) << AT << "unknown response command: " << hdr.cmd;
        return -1;
    }

        if (header.type != PacketType::ACK || header.remaining != oend - obegin) {
            LOG(ERROR) << "malformed ACK";
    uint32_t ilen = iend - ibegin;
    if (args.msg_len > ilen) {
        LOG(ERROR) << AT << "response message too long to fit in return buffer";
        return -1;
    }

    memcpy(ibegin, shm_base_, args.msg_len);

    return args.msg_len;
}

    ssize_t remaining = 0;
    auto begin = ibegin;
    do {
        PacketHeader header = {
            .type = PacketType::RCV,
            .remaining = 0,
        };
TrustyApp::TrustyApp(const std::string& path, const std::string& appname)
    : handle_(kInvalidHandle) {
    unique_fd tipc_handle(tipc_connect(path.c_str(), appname.c_str()));
    if (tipc_handle < 0) {
        LOG(ERROR) << AT << "failed to connect to Trusty TA \"" << appname << "\" using dev:"
                   << "\"" << path << "\"";
        return;
    }

    uint32_t shm_len = RoundPageUp(CONFIRMATIONUI_MAX_MSG_SIZE);
    BufferAllocator allocator;
    unique_fd dma_buf(allocator.Alloc("system", shm_len));
    if (dma_buf < 0) {
        LOG(ERROR) << AT << "failed to allocate shared memory buffer";
        return;
    }

    if (dma_buf < 0) {
        LOG(ERROR) << AT << "failed to allocate shared memory buffer";
        return;
    }

    confirmationui_hdr hdr = {
        .cmd = CONFIRMATIONUI_CMD_INIT,
    };
    confirmationui_init_req args = {
        .shm_len = shm_len,
    };
    iovec iov[] = {
        {
                .iov_base = &header,
                .iov_len = kHeaderSize,
            .iov_base = &hdr,
            .iov_len = sizeof(hdr),
        },
        {
                .iov_base = begin,
                .iov_len = uint32_t(iend - begin),
            .iov_base = &args,
            .iov_len = sizeof(args),
        },
    };
    trusty_shm shm = {
        .fd = dma_buf,
        .transfer = TRUSTY_SHARE,
    };

        ssize_t rc = writev(handle, iov, 1);
        if (!rc) {
            PLOG(ERROR) << "Error sending RCV message. " << rc;
            return rc;
    int rc = tipc_send(tipc_handle, iov, 2, &shm, 1);
    if (rc != static_cast<int>(sizeof(hdr) + sizeof(args))) {
        LOG(ERROR) << AT << "failed to send INIT request";
        return;
    }

        rc = readv(handle, iov, 2);
        if (rc < 0) {
            PLOG(ERROR) << "Error reading response. " << rc;
            return rc;
    rc = read(tipc_handle, &hdr, sizeof(hdr));
    if (rc != static_cast<int>(sizeof(hdr))) {
        LOG(ERROR) << AT << "failed to receive INIT response";
        return;
    }

        uint32_t body_size = std::min(kPayloadSize, header.remaining);
        if (body_size != rc - kHeaderSize) {
            LOG(ERROR) << "Unexpected amount of data: " << rc;
            return -1;
    if (hdr.cmd != (CONFIRMATIONUI_CMD_INIT | CONFIRMATIONUI_RESP_BIT)) {
        LOG(ERROR) << AT << "unknown response command: " << hdr.cmd;
        return;
    }

        remaining = header.remaining - body_size;
        begin += body_size;
    } while (remaining);

    return begin - ibegin;
    void* shm_base = mmap(0, shm_len, PROT_READ | PROT_WRITE, MAP_SHARED, dma_buf, 0);
    if (shm_base == MAP_FAILED) {
        LOG(ERROR) << AT << "failed to mmap() shared memory buffer";
        return;
    }

TrustyApp::TrustyApp(const std::string& path, const std::string& appname)
    : handle_(kInvalidHandle) {
    handle_ = tipc_connect(path.c_str(), appname.c_str());
    if (handle_ == kInvalidHandle) {
        LOG(ERROR) << AT << "failed to connect to Trusty TA \"" << appname << "\" using dev:"
                   << "\"" << path << "\"";
    }
    handle_ = std::move(tipc_handle);
    shm_base_ = shm_base;
    shm_len_ = shm_len;

    LOG(INFO) << AT << "succeeded to connect to Trusty TA \"" << appname << "\"";
}

TrustyApp::~TrustyApp() {
    if (handle_ != kInvalidHandle) {
        tipc_close(handle_);
    }
    LOG(INFO) << "Done shutting down TrustyApp";
}

+14 −17
Original line number Diff line number Diff line
@@ -16,7 +16,10 @@

#pragma once

#include "TrustyIpc.h"

#include <android-base/logging.h>
#include <android-base/unique_fd.h>
#include <errno.h>
#include <poll.h>
#include <stdio.h>
@@ -60,19 +63,11 @@ enum class TrustyAppError : int32_t {
    MSG_TOO_LONG = -2,
};

/*
 * There is a hard limitation of 0x1800 bytes for the to-be-signed message size. The protocol
 * overhead is limited, so that 0x2000 is a buffer size that will be sufficient in any benign
 * mode of operation.
 */
static constexpr const size_t kSendBufferSize = 0x2000;

ssize_t TrustyRpc(int handle, const uint8_t* obegin, const uint8_t* oend, uint8_t* ibegin,
                  uint8_t* iend);

class TrustyApp {
  private:
    int handle_;
    android::base::unique_fd handle_;
    void* shm_base_;
    size_t shm_len_;
    static constexpr const int kInvalidHandle = -1;
    /*
     * This mutex serializes communication with the trusted app, not handle_.
@@ -84,6 +79,8 @@ class TrustyApp {
    TrustyApp(const std::string& path, const std::string& appname);
    ~TrustyApp();

    ssize_t TrustyRpc(const uint8_t* obegin, const uint8_t* oend, uint8_t* ibegin, uint8_t* iend);

    template <typename Request, typename Response, typename... T>
    std::tuple<TrustyAppError, msg2tuple_t<Response>> issueCmd(const T&... args) {
        std::lock_guard<std::mutex> lock(mutex_);
@@ -93,7 +90,7 @@ class TrustyApp {
            return {TrustyAppError::ERROR, {}};
        }

        uint8_t buffer[kSendBufferSize];
        uint8_t buffer[CONFIRMATIONUI_MAX_MSG_SIZE];
        WriteStream out(buffer);

        out = write(Request(), out, args...);
@@ -102,8 +99,8 @@ class TrustyApp {
            return {TrustyAppError::MSG_TOO_LONG, {}};
        }

        auto rc = TrustyRpc(handle_, &buffer[0], const_cast<const uint8_t*>(out.pos()), &buffer[0],
                            &buffer[kSendBufferSize]);
        auto rc = TrustyRpc(&buffer[0], const_cast<const uint8_t*>(out.pos()), &buffer[0],
                            &buffer[CONFIRMATIONUI_MAX_MSG_SIZE]);
        if (rc < 0) return {TrustyAppError::ERROR, {}};

        ReadStream in(&buffer[0], rc);
@@ -125,7 +122,7 @@ class TrustyApp {
            return TrustyAppError::ERROR;
        }

        uint8_t buffer[kSendBufferSize];
        uint8_t buffer[CONFIRMATIONUI_MAX_MSG_SIZE];
        WriteStream out(buffer);

        out = write(Request(), out, args...);
@@ -134,8 +131,8 @@ class TrustyApp {
            return TrustyAppError::MSG_TOO_LONG;
        }

        auto rc = TrustyRpc(handle_, &buffer[0], const_cast<const uint8_t*>(out.pos()), &buffer[0],
                            &buffer[kSendBufferSize]);
        auto rc = TrustyRpc(&buffer[0], const_cast<const uint8_t*>(out.pos()), &buffer[0],
                            &buffer[CONFIRMATIONUI_MAX_MSG_SIZE]);
        if (rc < 0) {
            LOG(ERROR) << "send command failed: " << strerror(errno) << " (" << errno << ")";
            return TrustyAppError::ERROR;
+1 −1
Original line number Diff line number Diff line
@@ -71,7 +71,7 @@ using ::std::tie;
using TeeuiRc = ::teeui::ResponseCode;

constexpr const char kTrustyDeviceName[] = "/dev/trusty-ipc-dev0";
constexpr const char kConfirmationuiAppName[] = "com.android.trusty.confirmationui";
constexpr const char kConfirmationuiAppName[] = CONFIRMATIONUI_PORT;

namespace {

+80 −0
Original line number Diff line number Diff line
/*
 * Copyright 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#pragma once

#include <stdint.h>

/*
 * This interface is shared between Android and Trusty. There is a copy in each
 * repository. They must be kept in sync.
 */

#define CONFIRMATIONUI_PORT "com.android.trusty.confirmationui"

/**
 * enum confirmationui_cmd - command identifiers for ConfirmationUI interface
 * @CONFIRMATIONUI_RESP_BIT:  response bit set as part of response
 * @CONFIRMATIONUI_REQ_SHIFT: number of bits used by response bit
 * @CONFIRMATIONUI_CMD_INIT:  command to initialize session
 * @CONFIRMATIONUI_CMD_MSG:   command to send ConfirmationUI messages
 */
enum confirmationui_cmd : uint32_t {
    CONFIRMATIONUI_RESP_BIT = 1,
    CONFIRMATIONUI_REQ_SHIFT = 1,

    CONFIRMATIONUI_CMD_INIT = (1 << CONFIRMATIONUI_REQ_SHIFT),
    CONFIRMATIONUI_CMD_MSG = (2 << CONFIRMATIONUI_REQ_SHIFT),
};

/**
 * struct confirmationui_hdr - header for ConfirmationUI messages
 * @cmd: command identifier
 *
 * Note that no messages return a status code. Any error on the server side
 * results in the connection being closed. So, operations can be assumed to be
 * successful if they return a response.
 */
struct confirmationui_hdr {
    uint32_t cmd;
};

/**
 * struct confirmationui_init_req - arguments for request to initialize a
 *                                  session
 * @shm_len: length of memory region being shared
 *
 * A handle to a memory region must be sent along with this message. This memory
 * is send to ConfirmationUI messages.
 */
struct confirmationui_init_req {
    uint32_t shm_len;
};

/**
 * struct confirmationui_msg_args - arguments for sending a message
 * @msg_len: length of message being sent
 *
 * Contents of the message are located in the shared memory region that is
 * established using %CONFIRMATIONUI_CMD_INIT.
 *
 * ConfirmationUI messages can travel both ways.
 */
struct confirmationui_msg_args {
    uint32_t msg_len;
};

#define CONFIRMATIONUI_MAX_MSG_SIZE 0x2000
Loading