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