/* * Copyright 2020, 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define AT __FILE__ ":" << __LINE__ << ": " namespace android { namespace trusty { namespace confirmationui { using ::teeui::Message; using ::teeui::msg2tuple_t; using ::teeui::ReadStream; using ::teeui::WriteStream; #ifndef TEEUI_USE_STD_VECTOR /* * TEEUI_USE_STD_VECTOR makes certain wire types like teeui::MsgString and * teeui::MsgVector be aliases for std::vector. This is required for thread safe * message serialization. Always compile this with -DTEEUI_USE_STD_VECTOR set in * CFLAGS of the HAL service. */ #error "Must be compiled with -DTEEUI_USE_STD_VECTOR." #endif enum class TrustyAppError : int32_t { OK, ERROR = -1, MSG_TOO_LONG = -2, }; class TrustyApp { private: 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_. * Calling issueCmd during construction or deletion is undefined behavior. */ std::mutex mutex_; public: 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_); if (handle_ == kInvalidHandle) { LOG(ERROR) << "TrustyApp not connected"; return {TrustyAppError::ERROR, {}}; } uint8_t buffer[CONFIRMATIONUI_MAX_MSG_SIZE]; WriteStream out(buffer); out = write(Request(), out, args...); if (!out) { LOG(ERROR) << AT << "send command failed: message formatting"; return {TrustyAppError::MSG_TOO_LONG, {}}; } 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); auto result = read(Response(), in); if (!std::get<0>(result)) { LOG(ERROR) << "send command failed: message parsing"; return {TrustyAppError::ERROR, {}}; } return {std::get<0>(result) ? TrustyAppError::OK : TrustyAppError::ERROR, tuple_tail(std::move(result))}; } template TrustyAppError issueCmd(const T&... args) { std::lock_guard lock(mutex_); if (handle_ == kInvalidHandle) { LOG(ERROR) << "TrustyApp not connected"; return TrustyAppError::ERROR; } uint8_t buffer[CONFIRMATIONUI_MAX_MSG_SIZE]; WriteStream out(buffer); out = write(Request(), out, args...); if (!out) { LOG(ERROR) << AT << "send command failed: message formatting"; return TrustyAppError::MSG_TOO_LONG; } 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; } if (rc > 0) { LOG(ERROR) << "Unexpected non zero length response"; return TrustyAppError::ERROR; } return TrustyAppError::OK; } operator bool() const { return handle_ != kInvalidHandle; } }; } // namespace confirmationui } // namespace trusty } // namespace android