2 * Copyright (c) 2013-2015 TRUSTONIC LIMITED
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the TRUSTONIC LIMITED nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 #include <stdlib.h> // malloc, free
38 #include <sys/mman.h> // mmap, munmap
40 #include "mc_user.h" // mc_ioctl_buffer
42 #pragma GCC diagnostic push
43 #pragma GCC diagnostic ignored "-Wconversion"
45 #pragma GCC diagnostic pop
47 #define SOCKET_PATH "@/com/trustonic/tee_proxy"
48 #define PROTOCOL_MAGIC "T7e3"
49 #define PROTOCOL_VERSION 1
52 * ProtoBuf gives us the serialisation mechanism, but that's not enough to send
53 * our RPC messages: we also need to pass the method we want to call, the total
54 * length of the data, and a magic number is usually welcome too. While at it,
55 * we'll throw a version number just in case.
58 * ----------------------
59 * | Magic number | 4 bytes (text)
60 * ----------------------
61 * | Method | Version | 2 + 2 bytes (LE)
62 * ----------------------
63 * | Message length | 4 bytes (LE)
64 * ----------------------
66 * | Message data | N bytes (text)
69 * ----------------------
76 struct RequestHeader
{
83 struct ResponseHeader
{
87 int32_t proto_rc
; // -errno if negative, length of data otherwise
88 uint32_t method_rc
; // errno from called method on server side
101 GP_REQUESTCANCELLATION
= 27,
109 CLIENT
, // Buffer managed by caller (client side)
110 SERVER
, // Buffer mmap'd (server side)
112 mc_ioctl_buffer info_
;
115 int alloc(size_t length
, uint32_t flags
= MC_IO_MAP_INPUT_OUTPUT
) {
116 // No posix_memalign, aligned_alloc, valloc, memalign, pvalloc in
117 // Android so we rely on mmap to give us page-aligned memory
118 size_t page_mask
= sysconf(_SC_PAGESIZE
) - 1;
119 size_t aligned_length
= (length
+ page_mask
) & ~page_mask
;
120 void* buf
= ::mmap(0, aligned_length
, PROT_READ
| PROT_WRITE
,
121 MAP_PRIVATE
| MAP_ANONYMOUS
, -1, 0);
122 if (buf
== MAP_FAILED
) {
123 LOG_E("Failed to allocate");
128 info_
.va
= reinterpret_cast<uintptr_t>(address_
);
129 info_
.len
= static_cast<uint32_t>(length
);
131 LOG_D("alloc'd buffer %p:%u:%x", address_
, info_
.len
, info_
.flags
);
135 Buffer(const Buffer
&) = delete;
136 Buffer
& operator=(const Buffer
&) = delete;
137 // Constructor from buffer: allocate and fill in
138 Buffer(std::string buffer
): address_(nullptr) {
139 if (!alloc(buffer
.length())) {
143 // Constructor for client TCI: pointer and length (can be null) given
144 Buffer(void* address
, size_t length
): address_(address
) {
146 info_
.va
= reinterpret_cast<uintptr_t>(address_
);
147 info_
.len
= static_cast<uint32_t>(length
);
148 info_
.flags
= MC_IO_MAP_INPUT_OUTPUT
;
150 LOG_D("use buffer %p:%u:%x", address_
, info_
.len
, info_
.flags
);
159 // Constructor for server buffer: allocate
160 Buffer(uint32_t length
, uint32_t flags
): address_(nullptr) {
161 alloc(length
, flags
);
163 // Constructor for client buffer: info given
164 Buffer(mc_ioctl_buffer info
): info_(info
) {
165 address_
= reinterpret_cast<void*>(
166 static_cast<uintptr_t>(info_
.va
));
168 LOG_D("use buffer %p:%u:%x", address_
, info_
.len
, info_
.flags
);
171 if (type_
== Buffer::SERVER
) {
172 LOG_D("unmap buffer %p:%u:%x", address_
, info_
.len
,
174 ::munmap(address_
, info_
.len
);
178 const mc_ioctl_buffer
& info() const {
181 void* address() const {
184 void setSva(uint64_t sva
) {
187 int update(const std::string
& buf
) {
188 if (buf
.length() != info_
.len
) {
189 LOG_E("Failed to update TCI");
193 ::memcpy(address_
, buf
.c_str(), info_
.len
);
201 std::mutex buffers_mutex_
;
202 std::vector
<Buffer
*> buffers_
;
204 Session(uint32_t id
, Buffer
* tci
): id_(id
), tci_(tci
) {}
207 for (auto& buf
: buffers_
) {
211 uint32_t id() const {
214 bool hasTci() const {
217 const void* tci() const {
218 return tci_
->address();
220 size_t tciLen() const {
221 return tci_
->info().len
;
223 int updateTci(const std::string
& buf
) {
224 return tci_
->update(buf
);
226 void addBuffer(Buffer
* buffer
) {
227 LOG_D("%p %s: 0x%llx", this, __FUNCTION__
, buffer
->info().sva
);
228 std::lock_guard
<std::mutex
> buffers_lock(buffers_mutex_
);
229 buffers_
.push_back(buffer
);
231 void addBuffer(mc_ioctl_buffer
& info
) {
232 LOG_D("%p %s: 0x%llx", this, __FUNCTION__
, info
.sva
);
233 std::lock_guard
<std::mutex
> buffers_lock(buffers_mutex_
);
234 auto buffer
= new Buffer(info
);
235 buffers_
.push_back(buffer
);
237 int removeBuffer(uint64_t sva
) {
238 LOG_D("%p %s: %jx", this, __FUNCTION__
, sva
);
239 std::lock_guard
<std::mutex
> buffers_lock(buffers_mutex_
);
240 auto it
= std::find_if(buffers_
.begin(), buffers_
.end(),
241 [this, sva
](Buffer
* buffer
) {
242 return buffer
->info().sva
== sva
;
244 if (it
== buffers_
.end()) {
252 // Must be called under buffers_mutex_
253 Buffer
* findBuffer(uint64_t sva
) {
254 for (auto& buf
: buffers_
) {
255 if (buf
->info().sva
== sva
) {
261 std::mutex
& buffersMutex() {
262 return buffers_mutex_
;
264 const std::vector
<Buffer
*>& buffers() {
269 static int recv_all(int sock
, const char* what
, void* buffer
, size_t length
,
270 bool may_close
= false) {
271 auto cbuffer
= static_cast<char*>(buffer
);
273 while (count
< length
) {
274 ssize_t rc
= ::recv(sock
, &cbuffer
[count
], length
- count
, 0);
278 LOG_D("socket closed");
280 LOG_E("socket closed while receiving %s", what
);
284 if (errno
!= EINTR
) {
288 LOG_D("signal ignored while sending %s", what
);
297 static const int32_t timeout_max
= 1000; // 1s
299 static int send_all(int sock
, const char* what
, const void* buffer
,
301 auto cbuffer
= static_cast<const char*>(buffer
);
303 while (count
< length
) {
304 ssize_t rc
= ::send(sock
, &cbuffer
[count
], length
- count
,
308 LOG_E("socket closed while sending %s", what
);
311 if (errno
!= EINTR
) {
315 LOG_D("signal ignored while sending %s", what
);
325 static const char* methodToString(enum RpcMethod method
) {
328 return "openSession";
330 return "openTruslet";
332 return "closeSession";
336 return "waitNotification";
345 case GP_REQUESTCANCELLATION
:
346 return "gpRequestCancellation";
352 } // namespace tee_proxy
353 } // namespace trustonic