From 19b62a5182534ab43e37913d13080b055960b6db Mon Sep 17 00:00:00 2001 From: Tri Vo Date: Tue, 16 Feb 2021 11:51:26 -0800 Subject: [PATCH] trusty: ConfirmationUI HAL<->TA IPC using shared memory Bug: 148421469 Test: VtsHalConfirmationUIV1_0TargetTest Change-Id: I686150b64da3d3e95618f29e396990660f2054ba --- trusty/confirmationui/Android.bp | 3 +- trusty/confirmationui/TrustyApp.cpp | 225 ++++++++++-------- trusty/confirmationui/TrustyApp.h | 31 ++- .../confirmationui/TrustyConfirmationUI.cpp | 2 +- trusty/confirmationui/TrustyIpc.h | 80 +++++++ ...dware.confirmationui@1.0-service.trusty.rc | 4 +- 6 files changed, 219 insertions(+), 126 deletions(-) create mode 100644 trusty/confirmationui/TrustyIpc.h diff --git a/trusty/confirmationui/Android.bp b/trusty/confirmationui/Android.bp index 60e0e71b2..09d48ad3f 100644 --- a/trusty/confirmationui/Android.bp +++ b/trusty/confirmationui/Android.bp @@ -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", ], -} \ No newline at end of file +} diff --git a/trusty/confirmationui/TrustyApp.cpp b/trusty/confirmationui/TrustyApp.cpp index e4c68f955..0e84b19c6 100644 --- a/trusty/confirmationui/TrustyApp.cpp +++ b/trusty/confirmationui/TrustyApp.cpp @@ -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 #include +#include #include #include +#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(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(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(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(sizeof(hdr) + sizeof(args))) { + LOG(ERROR) << AT << "failed to send INIT request"; + return; + } + + rc = read(tipc_handle, &hdr, sizeof(hdr)); + if (rc != static_cast(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"; } diff --git a/trusty/confirmationui/TrustyApp.h b/trusty/confirmationui/TrustyApp.h index 05a25f61d..406f439be 100644 --- a/trusty/confirmationui/TrustyApp.h +++ b/trusty/confirmationui/TrustyApp.h @@ -16,7 +16,10 @@ #pragma once +#include "TrustyIpc.h" + #include +#include #include #include #include @@ -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 std::tuple> issueCmd(const T&... args) { std::lock_guard 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(out.pos()), &buffer[0], - &buffer[kSendBufferSize]); + auto rc = TrustyRpc(&buffer[0], const_cast(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(out.pos()), &buffer[0], - &buffer[kSendBufferSize]); + auto rc = TrustyRpc(&buffer[0], const_cast(out.pos()), &buffer[0], + &buffer[CONFIRMATIONUI_MAX_MSG_SIZE]); if (rc < 0) { LOG(ERROR) << "send command failed: " << strerror(errno) << " (" << errno << ")"; return TrustyAppError::ERROR; diff --git a/trusty/confirmationui/TrustyConfirmationUI.cpp b/trusty/confirmationui/TrustyConfirmationUI.cpp index 6b25893b5..c8b24e3fa 100644 --- a/trusty/confirmationui/TrustyConfirmationUI.cpp +++ b/trusty/confirmationui/TrustyConfirmationUI.cpp @@ -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 { diff --git a/trusty/confirmationui/TrustyIpc.h b/trusty/confirmationui/TrustyIpc.h new file mode 100644 index 000000000..eb764bc46 --- /dev/null +++ b/trusty/confirmationui/TrustyIpc.h @@ -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 + +/* + * 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 diff --git a/trusty/confirmationui/android.hardware.confirmationui@1.0-service.trusty.rc b/trusty/confirmationui/android.hardware.confirmationui@1.0-service.trusty.rc index dc7a03b6e..3ba6fc04b 100644 --- a/trusty/confirmationui/android.hardware.confirmationui@1.0-service.trusty.rc +++ b/trusty/confirmationui/android.hardware.confirmationui@1.0-service.trusty.rc @@ -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