Merge "trusty: ConfirmationUI HAL<->TA IPC using shared memory" am: 09cbde252c
am: 2302e2122f
am: c6c2304270
Original change: https://android-review.googlesource.com/c/platform/system/core/+/1590278 MUST ONLY BE SUBMITTED BY AUTOMERGER Change-Id: I62ee3fbe3ae948ca1182a6a7b42ce37027b8e08f
This commit is contained in:
commit
b279febaf3
6 changed files with 219 additions and 126 deletions
|
@ -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",
|
||||
],
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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";
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
trusty/confirmationui/TrustyIpc.h
Normal file
80
trusty/confirmationui/TrustyIpc.h
Normal 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
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue