trusty: ConfirmationUI HAL<->TA IPC using shared memory
Bug: 148421469
Test: VtsHalConfirmationUIV1_0TargetTest
Change-Id: I686150b64da3d3e95618f29e396990660f2054ba
diff --git a/trusty/confirmationui/Android.bp b/trusty/confirmationui/Android.bp
index 60e0e71..09d48ad 100644
--- a/trusty/confirmationui/Android.bp
+++ b/trusty/confirmationui/Android.bp
@@ -54,6 +54,7 @@
"android.hardware.confirmationui@1.0",
"android.hardware.keymaster@4.0",
"libbase",
+ "libdmabufheap",
"libhidlbase",
"libteeui_hal_support",
"libtrusty",
@@ -92,4 +93,4 @@
"-Werror",
"-DTEEUI_USE_STD_VECTOR",
],
-}
\ No newline at end of file
+}
diff --git a/trusty/confirmationui/TrustyApp.cpp b/trusty/confirmationui/TrustyApp.cpp
index e4c68f9..0e84b19 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 <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";
}
diff --git a/trusty/confirmationui/TrustyApp.h b/trusty/confirmationui/TrustyApp.h
index 05a25f6..406f439 100644
--- a/trusty/confirmationui/TrustyApp.h
+++ b/trusty/confirmationui/TrustyApp.h
@@ -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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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;
diff --git a/trusty/confirmationui/TrustyConfirmationUI.cpp b/trusty/confirmationui/TrustyConfirmationUI.cpp
index 6b25893..c8b24e3 100644
--- a/trusty/confirmationui/TrustyConfirmationUI.cpp
+++ b/trusty/confirmationui/TrustyConfirmationUI.cpp
@@ -71,7 +71,7 @@
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 0000000..eb764bc
--- /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 <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
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 dc7a03b..3ba6fc0 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