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.
40 #include <sys/ioctl.h>
42 #include <sys/types.h>
45 #include "Mci/mcimcp.h"
46 #include "mcVersionHelper.h"
53 #include "PrivateRegistry.h"
55 #include "SecureWorld.h"
57 MC_CHECK_VERSION(MCDRVMODULEAPI
, 2, 1);
58 #define MAX_SO_CONT_SIZE 512
59 #define CRASHDUMP_PATH "/sys/kernel/debug/trustonic_tee/crashdump"
61 #define MY_LOG_ERRNO(fmt, ...) \
62 LOG_E("%s: %s " fmt, __func__, strerror(errno), ##__VA_ARGS__)
64 struct SecureWorld::Impl
{
68 Impl(): device_fd(-1), command_id(0), keep_running(true) {}
71 SecureWorld::SecureWorld(): pimpl_(new Impl
) {}
73 SecureWorld::~SecureWorld() {
77 static void* getRootContainer(const struct mc_admin_request
*,
78 struct mc_admin_response
* response
,
80 void* data
= ::malloc(MAX_SO_CONT_SIZE
);
81 uint32_t length
= MAX_SO_CONT_SIZE
;
83 switch (mcRegistryReadRoot(data
, &length
)) {
85 response
->length
= length
;
86 response
->error_no
= 0;
88 case MC_DRV_ERR_INVALID_PARAMETER
:
89 response
->error_no
= EINVAL
;
91 case MC_DRV_ERR_INVALID_DEVICE_FILE
:
92 response
->error_no
= ENOENT
;
95 // Some kind of default
96 response
->error_no
= EPERM
;
99 if (response
->error_no
) {
104 LOG_D("Read root container, size: %u", response
->length
);
108 static void* getSpContainer(const struct mc_admin_request
* request
,
109 struct mc_admin_response
* response
,
111 void* data
= ::malloc(MAX_SO_CONT_SIZE
);
112 uint32_t length
= MAX_SO_CONT_SIZE
;
114 switch (mcRegistryReadSp(request
->spid
, data
, &length
)) {
116 response
->length
= length
;
117 response
->error_no
= 0;
119 case MC_DRV_ERR_INVALID_PARAMETER
:
120 response
->error_no
= EINVAL
;
122 case MC_DRV_ERR_INVALID_DEVICE_FILE
:
123 response
->error_no
= ENOENT
;
126 // Some kind of default
127 response
->error_no
= EPERM
;
130 if (response
->error_no
) {
135 LOG_D("Read SP container for %u, size: %u", request
->spid
, response
->length
);
139 static void* getTrustletContainer(const struct mc_admin_request
* request
,
140 struct mc_admin_response
* response
,
142 void* data
= ::malloc(MAX_SO_CONT_SIZE
);
143 uint32_t length
= MAX_SO_CONT_SIZE
;
145 const mcUuid_t
* uuid
= reinterpret_cast<const mcUuid_t
*>(&request
->uuid
);
146 switch (mcRegistryReadTrustletCon(uuid
, request
->spid
, data
, &length
)) {
148 response
->length
= length
;
149 response
->error_no
= 0;
151 case MC_DRV_ERR_INVALID_PARAMETER
:
152 response
->error_no
= EINVAL
;
154 case MC_DRV_ERR_INVALID_DEVICE_FILE
:
155 response
->error_no
= ENOENT
;
157 case MC_DRV_ERR_OUT_OF_RESOURCES
:
158 response
->error_no
= ENOMEM
;
161 // Some kind of default
162 response
->error_no
= EPERM
;
165 if (response
->error_no
) {
170 LOG_D("Read trustlet container for %u, size: %u", response
->spid
, response
->length
);
174 static void* mapTrustlet(const char* path
, uint32_t* length
,
175 uint32_t* service_type
) {
176 int fd
= ::open(path
, O_RDONLY
);
178 LOG_W("Cannot open trustlet %s (%d)", path
, errno
);
183 *service_type
= SERVICE_TYPE_ILLEGAL
;
186 if (::fstat(fd
, &stat
) < 0) {
187 MY_LOG_ERRNO("getting size for trustlet %s", path
);
191 data
= ::mmap(NULL
, stat
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0);
192 if (data
== MAP_FAILED
) {
194 MY_LOG_ERRNO("mapping file to memory");
198 /* Give service type to driver so it knows how to allocate and copy */
199 mclfHeaderV2_t
* header
= static_cast<mclfHeaderV2_t
*>(data
);
200 *service_type
= header
->serviceType
;
201 *length
= static_cast<uint32_t>(stat
.st_size
);
209 static void* getTrustlet(const struct mc_admin_request
* request
,
210 struct mc_admin_response
* response
,
213 const mcUuid_t
* uuid
= reinterpret_cast<const mcUuid_t
*>(&request
->uuid
);
216 mcResult_t res
= mcRegistryGetTrustletInfo(uuid
, request
->is_gp
, &response
->spid
, path
);
219 response
->error_no
= 0;
221 case MC_DRV_ERR_INVALID_PARAMETER
:
222 response
->error_no
= EINVAL
;
224 case MC_DRV_ERR_TRUSTLET_NOT_FOUND
:
225 response
->error_no
= ENOENT
;
228 // Some kind of default
229 response
->error_no
= EPERM
;
232 if (response
->error_no
) {
236 void* data
= mapTrustlet(path
.c_str(), &response
->length
,
237 &response
->service_type
);
239 response
->error_no
= errno
;
241 LOG_D("Read spid %u and mmap'd trustlet from %s, total size: %u", response
->spid
, path
.c_str(), response
->length
);
246 static void* logCrashDump(const struct mc_admin_request
*,
247 struct mc_admin_response
* response
,
249 std::ifstream
crashdump(CRASHDUMP_PATH
);
250 if (!crashdump
.is_open()) {
251 MY_LOG_ERRNO("opening crash dump");
252 response
->error_no
= errno
;
256 LOG_E("<t-base halted. Status dump:");
258 while (std::getline(crashdump
, line
)) {
259 LOG_I("%s", line
.c_str());
265 int SecureWorld::open() {
266 pimpl_
->device_fd
= ::open("/dev/" MC_ADMIN_DEVNODE
, O_RDWR
);
267 if (pimpl_
->device_fd
< 0) {
268 MY_LOG_ERRNO("opening admin device");
272 LOG_D("Check version of <t-base driver");
273 struct mc_admin_driver_info info
;
274 if (ioctl(pimpl_
->device_fd
, MC_ADMIN_IO_GET_INFO
, &info
) != 0) {
275 LOG_ERRNO("ioctl MC_ADMIN_IO_GET_INFO");
276 ::close(pimpl_
->device_fd
);
281 if (!checkVersionOkMCDRVMODULEAPI(info
.drv_version
, &errmsg
)) {
283 ::close(pimpl_
->device_fd
);
288 pimpl_
->command_id
= info
.initial_cmd_id
;
290 // We wait 10 times 100ms for the device file to appear
295 int ret
= ::stat("/dev/" MC_USER_DEVNODE
, &st
);
300 if (errno
!= ENOENT
) {
301 MY_LOG_ERRNO("stat'ing user device");
305 /* Device driver didn't appear yet: give some time */
310 LOG_E("timed out while waiting for user device to appear");
314 LOG_D("TEE is ready");
318 void SecureWorld::close() {
319 ::close(pimpl_
->device_fd
);
322 int SecureWorld::loadDriver(const char* path
) {
323 struct mc_admin_load_info info
;
324 uint32_t service_type
;
326 void* data
= mapTrustlet(path
, &info
.length
, &service_type
);
331 LOG_D("Load secure driver %s of size %d", path
, info
.length
);
332 info
.address
= reinterpret_cast<uintptr_t>(data
);
335 int ret
= ioctl(pimpl_
->device_fd
, MC_ADMIN_IO_LOAD_DRIVER
, &info
);
337 LOG_ERRNO("ioctl MC_ADMIN_IO_LOAD_DRIVER");
340 // Free memory occupied by Trustlet data
341 ::munmap(data
, info
.length
);
345 int SecureWorld::loadToken(const void *data
, uint32_t length
) {
346 struct mc_admin_load_info token
;
348 LOG_D("Load authentication token %p of size %u", data
, length
);
349 token
.address
= reinterpret_cast<uintptr_t>(data
);
350 token
.length
= length
;
352 int rc
= ioctl(pimpl_
->device_fd
, MC_ADMIN_IO_LOAD_TOKEN
, &token
);
354 LOG_ERRNO("ioctl MC_ADMIN_IO_LOAD_TOKEN");
361 int SecureWorld::LoadCheck(mcSpid_t spid
, const void *data
, uint32_t length
) {
362 struct mc_admin_load_info info
;
364 LOG_D("Load secure object %p, length %u, spid %x", data
, length
, spid
);
366 info
.address
= reinterpret_cast<uintptr_t>(data
);
367 info
.length
= length
;
369 int rc
= ioctl(pimpl_
->device_fd
, MC_ADMIN_IO_LOAD_CHECK
, &info
);
371 LOG_ERRNO("ioctl MC_ADMIN_IO_LOAD_CHECK");
378 int SecureWorld::listen()
382 while (pimpl_
->keep_running
) {
383 struct mc_admin_request request
;
385 rc
= ioctl(pimpl_
->device_fd
, MC_ADMIN_IO_GET_DRIVER_REQUEST
, &request
);
387 if (errno
== EINTR
) {
388 LOG_D("Giving up on signal");
390 LOG_ERRNO("Getting request from driver");
395 LOG_D("Request %d received (ID %u)", request
.command
, request
.request_id
);
396 if (pimpl_
->command_id
!= request
.request_id
) {
397 LOG_E("Request ID counters are not synchronised (expected %u, got %u)", pimpl_
->command_id
, request
.request_id
);
401 struct mc_admin_response response
;
402 memset(&response
, 0, sizeof(response
));
403 response
.request_id
= pimpl_
->command_id
++;
404 void* response_data
= NULL
;
405 bool is_mmapped
= false; // Response data needs freeing
406 switch (request
.command
) {
407 case MC_DRV_GET_ROOT_CONTAINER
:
408 response_data
= getRootContainer(&request
, &response
, &is_mmapped
);
410 case MC_DRV_GET_SP_CONTAINER
:
411 response_data
= getSpContainer(&request
, &response
, &is_mmapped
);
413 case MC_DRV_GET_TRUSTLET_CONTAINER
:
414 response_data
= getTrustletContainer(&request
, &response
, &is_mmapped
);
416 case MC_DRV_GET_TRUSTLET
:
417 response_data
= getTrustlet(&request
, &response
, &is_mmapped
);
419 case MC_DRV_SIGNAL_CRASH
:
420 logCrashDump(&request
, &response
, &is_mmapped
);
423 LOG_E("Unknown command");
424 response
.error_no
= EBADRQC
;
427 ssize_t ret
= ::write(pimpl_
->device_fd
, &response
, sizeof(response
));
428 if (ret
!= sizeof(response
)) {
429 LOG_ERRNO("Sending response to driver");
431 } else if (response
.length
> 0) {
432 ssize_t expected_length
= response
.length
;
433 ret
= ::write(pimpl_
->device_fd
, response_data
, response
.length
);
434 if (ret
!= expected_length
) {
435 LOG_ERRNO("Sending response data to driver");
440 if (response_data
&& is_mmapped
) {
441 ::munmap(response_data
, response
.length
);
443 ::free(response_data
);
450 void SecureWorld::stopListening() {
451 pimpl_
->keep_running
= false;