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

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

MUST ONLY BE SUBMITTED BY AUTOMERGER

Change-Id: I5e3bec99e1068e12ee021ec7471af4852aa9c5c5
This commit is contained in:
Tri Vo 2021-02-17 22:41:02 +00:00 committed by Automerger Merge Worker
commit c6c2304270
6 changed files with 219 additions and 126 deletions

View file

@ -54,6 +54,7 @@ cc_library {
"android.hardware.confirmationui@1.0",
"android.hardware.keymaster@4.0",
"libbase",
"libdmabufheap",
"libhidlbase",
"libteeui_hal_support",
"libtrusty",
@ -92,4 +93,4 @@ cc_library {
"-Werror",
"-DTEEUI_USE_STD_VECTOR",
],
}
}

View file

@ -1,5 +1,5 @@
/*
* 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,
};
struct PacketHeader {
PacketType type;
uint32_t remaining;
};
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";
}
static inline uintptr_t RoundPageUp(uintptr_t val) {
return (val + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
}
static constexpr const uint32_t kHeaderSize = sizeof(PacketHeader);
static constexpr const uint32_t kPayloadSize = kPacketSize - kHeaderSize;
ssize_t TrustyApp::TrustyRpc(const uint8_t* obegin, const uint8_t* oend, uint8_t* ibegin,
uint8_t* iend) {
uint32_t olen = oend - obegin;
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),
};
uint32_t body_size = std::min(kPayloadSize, header.remaining);
iovec iov[] = {
{
.iov_base = &header,
.iov_len = kHeaderSize,
},
{
.iov_base = const_cast<uint8_t*>(obegin),
.iov_len = body_size,
},
};
int rc = writev(handle, iov, 2);
if (!rc) {
PLOG(ERROR) << "Error sending SND message. " << rc;
return rc;
}
obegin += body_size;
rc = read(handle, &header, kHeaderSize);
if (!rc) {
PLOG(ERROR) << "Error reading ACK. " << rc;
return rc;
}
if (header.type != PacketType::ACK || header.remaining != oend - obegin) {
LOG(ERROR) << "malformed ACK";
return -1;
}
if (olen > shm_len_) {
LOG(ERROR) << AT << "request message too long to fit in shared memory";
return -1;
}
ssize_t remaining = 0;
auto begin = ibegin;
do {
PacketHeader header = {
.type = PacketType::RCV,
.remaining = 0,
};
memcpy(shm_base_, obegin, olen);
iovec iov[] = {
{
.iov_base = &header,
.iov_len = kHeaderSize,
},
{
.iov_base = begin,
.iov_len = uint32_t(iend - begin),
},
};
confirmationui_hdr hdr = {
.cmd = CONFIRMATIONUI_CMD_MSG,
};
confirmationui_msg_args args = {
.msg_len = olen,
};
iovec iov[] = {
{
.iov_base = &hdr,
.iov_len = sizeof(hdr),
},
{
.iov_base = &args,
.iov_len = sizeof(args),
},
};
ssize_t rc = writev(handle, iov, 1);
if (!rc) {
PLOG(ERROR) << "Error sending RCV 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;
}
rc = readv(handle, iov, 2);
if (rc < 0) {
PLOG(ERROR) << "Error reading response. " << rc;
return rc;
}
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;
}
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_MSG | CONFIRMATIONUI_RESP_BIT)) {
LOG(ERROR) << AT << "unknown response command: " << hdr.cmd;
return -1;
}
remaining = header.remaining - body_size;
begin += body_size;
} while (remaining);
uint32_t ilen = iend - ibegin;
if (args.msg_len > ilen) {
LOG(ERROR) << AT << "response message too long to fit in return buffer";
return -1;
}
return begin - ibegin;
memcpy(ibegin, shm_base_, args.msg_len);
return args.msg_len;
}
TrustyApp::TrustyApp(const std::string& path, const std::string& appname)
: handle_(kInvalidHandle) {
handle_ = tipc_connect(path.c_str(), appname.c_str());
if (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 = &hdr,
.iov_len = sizeof(hdr),
},
{
.iov_base = &args,
.iov_len = sizeof(args),
},
};
trusty_shm shm = {
.fd = dma_buf,
.transfer = TRUSTY_SHARE,
};
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 = read(tipc_handle, &hdr, sizeof(hdr));
if (rc != static_cast<int>(sizeof(hdr))) {
LOG(ERROR) << AT << "failed to receive INIT response";
return;
}
if (hdr.cmd != (CONFIRMATIONUI_CMD_INIT | CONFIRMATIONUI_RESP_BIT)) {
LOG(ERROR) << AT << "unknown response command: " << hdr.cmd;
return;
}
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;
}
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";
}

View file

@ -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;

View file

@ -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 {

View file

@ -0,0 +1,80 @@
/*
* 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

View file

@ -1,4 +1,4 @@
service confirmationui-1-0 /vendor/bin/hw/android.hardware.confirmationui@1.0-service.trusty
class hal
user nobody
group drmrpc input
user system
group drmrpc input system