1 /*
2  * Copyright 2020, The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #pragma once
18 
19 #include <TrustyIpc.h>
20 
21 #include <android-base/logging.h>
22 #include <android-base/unique_fd.h>
23 #include <errno.h>
24 #include <poll.h>
25 #include <stdio.h>
26 #include <sys/eventfd.h>
27 #include <sys/stat.h>
28 #include <teeui/msg_formatting.h>
29 #include <trusty/tipc.h>
30 #include <unistd.h>
31 
32 #include <fstream>
33 #include <functional>
34 #include <future>
35 #include <iostream>
36 #include <sstream>
37 #include <thread>
38 #include <vector>
39 
40 #define AT __FILE__ ":" << __LINE__ << ": "
41 
42 namespace android {
43 namespace trusty {
44 namespace confirmationui {
45 
46 using ::teeui::Message;
47 using ::teeui::msg2tuple_t;
48 using ::teeui::ReadStream;
49 using ::teeui::WriteStream;
50 
51 #ifndef TEEUI_USE_STD_VECTOR
52 /*
53  * TEEUI_USE_STD_VECTOR makes certain wire types like teeui::MsgString and
54  * teeui::MsgVector be aliases for std::vector. This is required for thread safe
55  * message serialization. Always compile this with -DTEEUI_USE_STD_VECTOR set in
56  * CFLAGS of the HAL service.
57  */
58 #error "Must be compiled with -DTEEUI_USE_STD_VECTOR."
59 #endif
60 
61 enum class TrustyAppError : int32_t {
62     OK,
63     ERROR = -1,
64     MSG_TOO_LONG = -2,
65 };
66 
67 class TrustyApp {
68   private:
69     android::base::unique_fd handle_;
70     void* shm_base_;
71     size_t shm_len_;
72     static constexpr const int kInvalidHandle = -1;
73     /*
74      * This mutex serializes communication with the trusted app, not handle_.
75      * Calling issueCmd during construction or deletion is undefined behavior.
76      */
77     std::mutex mutex_;
78 
79   public:
80     TrustyApp(const std::string& path, const std::string& appname);
81     ~TrustyApp();
82 
83     ssize_t TrustyRpc(const uint8_t* obegin, const uint8_t* oend, uint8_t* ibegin, uint8_t* iend);
84 
85     template <typename Request, typename Response, typename... T>
issueCmd(const T &...args)86     std::tuple<TrustyAppError, msg2tuple_t<Response>> issueCmd(const T&... args) {
87         std::lock_guard<std::mutex> lock(mutex_);
88 
89         if (handle_ == kInvalidHandle) {
90             LOG(ERROR) << "TrustyApp not connected";
91             return {TrustyAppError::ERROR, {}};
92         }
93 
94         uint8_t buffer[CONFIRMATIONUI_MAX_MSG_SIZE];
95         WriteStream out(buffer);
96 
97         out = write(Request(), out, args...);
98         if (!out) {
99             LOG(ERROR) << AT << "send command failed: message formatting";
100             return {TrustyAppError::MSG_TOO_LONG, {}};
101         }
102 
103         auto rc = TrustyRpc(&buffer[0], const_cast<const uint8_t*>(out.pos()), &buffer[0],
104                             &buffer[CONFIRMATIONUI_MAX_MSG_SIZE]);
105         if (rc < 0) return {TrustyAppError::ERROR, {}};
106 
107         ReadStream in(&buffer[0], rc);
108         auto result = read(Response(), in);
109         if (!std::get<0>(result)) {
110             LOG(ERROR) << "send command failed: message parsing";
111             return {TrustyAppError::ERROR, {}};
112         }
113 
114         return {std::get<0>(result) ? TrustyAppError::OK : TrustyAppError::ERROR,
115                 tuple_tail(std::move(result))};
116     }
117 
issueCmd(const T &...args)118     template <typename Request, typename... T> TrustyAppError issueCmd(const T&... args) {
119         std::lock_guard<std::mutex> lock(mutex_);
120 
121         if (handle_ == kInvalidHandle) {
122             LOG(ERROR) << "TrustyApp not connected";
123             return TrustyAppError::ERROR;
124         }
125 
126         uint8_t buffer[CONFIRMATIONUI_MAX_MSG_SIZE];
127         WriteStream out(buffer);
128 
129         out = write(Request(), out, args...);
130         if (!out) {
131             LOG(ERROR) << AT << "send command failed: message formatting";
132             return TrustyAppError::MSG_TOO_LONG;
133         }
134 
135         auto rc = TrustyRpc(&buffer[0], const_cast<const uint8_t*>(out.pos()), &buffer[0],
136                             &buffer[CONFIRMATIONUI_MAX_MSG_SIZE]);
137         if (rc < 0) {
138             LOG(ERROR) << "send command failed: " << strerror(errno) << " (" << errno << ")";
139             return TrustyAppError::ERROR;
140         }
141 
142         if (rc > 0) {
143             LOG(ERROR) << "Unexpected non zero length response";
144             return TrustyAppError::ERROR;
145         }
146         return TrustyAppError::OK;
147     }
148 
149     operator bool() const { return handle_ != kInvalidHandle; }
150 };
151 
152 }  // namespace confirmationui
153 }  // namespace trusty
154 }  // namespace android
155