summaryrefslogtreecommitdiff
path: root/mobicore/MobiCoreDriverLib/Daemon/MobiCoreDriverDaemon.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'mobicore/MobiCoreDriverLib/Daemon/MobiCoreDriverDaemon.cpp')
-rw-r--r--mobicore/MobiCoreDriverLib/Daemon/MobiCoreDriverDaemon.cpp1546
1 files changed, 1546 insertions, 0 deletions
diff --git a/mobicore/MobiCoreDriverLib/Daemon/MobiCoreDriverDaemon.cpp b/mobicore/MobiCoreDriverLib/Daemon/MobiCoreDriverDaemon.cpp
new file mode 100644
index 0000000..f3e0b72
--- /dev/null
+++ b/mobicore/MobiCoreDriverLib/Daemon/MobiCoreDriverDaemon.cpp
@@ -0,0 +1,1546 @@
+/*
+ * Copyright (c) 2013-2014 TRUSTONIC LIMITED
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the TRUSTONIC LIMITED nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * Entry of the MobiCore Driver.
+ */
+#include <cstdlib>
+#include <signal.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+#include "mcVersion.h"
+#include "mcVersionHelper.h"
+#include "mc_linux.h"
+#include "log.h"
+#include "Mci/mci.h"
+
+#include "MobiCoreDriverApi.h"
+#include "MobiCoreDriverCmd.h"
+#include "MobiCoreDriverDaemon.h"
+#include "PrivateRegistry.h"
+#include "MobiCoreDevice.h"
+#include "NetlinkServer.h"
+#include "FSD.h"
+
+#define DRIVER_TCI_LEN 4096
+
+MC_CHECK_VERSION(MCI, 0, 2);
+MC_CHECK_VERSION(SO, 2, 0);
+MC_CHECK_VERSION(MCLF, 2, 0);
+MC_CHECK_VERSION(CONTAINER, 2, 0);
+
+static void checkMobiCoreVersion(MobiCoreDevice *mobiCoreDevice);
+
+#define LOG_I_RELEASE(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
+
+//------------------------------------------------------------------------------
+MobiCoreDriverDaemon::MobiCoreDriverDaemon(
+ bool enableScheduler,
+ bool loadDriver,
+ std::vector<std::string> drivers)
+{
+ mobiCoreDevice = NULL;
+
+ this->enableScheduler = enableScheduler;
+ this->loadDriver = loadDriver;
+ this->drivers = drivers;
+
+ for (int i = 0; i < MAX_SERVERS; i++) {
+ servers[i] = NULL;
+ }
+}
+
+//------------------------------------------------------------------------------
+MobiCoreDriverDaemon::~MobiCoreDriverDaemon(
+ void
+)
+{
+ // Unload any device drivers might have been loaded
+ driverResourcesList_t::iterator it;
+ for (it = driverResources.begin(); it != driverResources.end(); it++) {
+ MobicoreDriverResources *res = *it;
+ mobiCoreDevice->closeSession(res->conn, res->sessionId);
+ (void)mobiCoreDevice->unregisterWsmL2(res->pTciWsm);
+ res->pTciWsm = NULL;
+ }
+ delete mobiCoreDevice;
+ for (int i = 0; i < MAX_SERVERS; i++) {
+ delete servers[i];
+ servers[i] = NULL;
+ }
+}
+
+
+//------------------------------------------------------------------------------
+void MobiCoreDriverDaemon::run(
+ void
+)
+{
+ LOG_I_RELEASE("Daemon starting up...");
+ LOG_I_RELEASE("Socket interface version is %u.%u", DAEMON_VERSION_MAJOR, DAEMON_VERSION_MINOR);
+
+#ifdef MOBICORE_COMPONENT_BUILD_TAG
+ LOG_I_RELEASE("%s", MOBICORE_COMPONENT_BUILD_TAG);
+#else
+#warning "MOBICORE_COMPONENT_BUILD_TAG is not defined!"
+#endif
+
+ LOG_I_RELEASE("Build timestamp is %s %s", __DATE__, __TIME__);
+
+ int i;
+
+ mobiCoreDevice = getDeviceInstance();
+
+ LOG_I("Initializing Device, Daemon sheduler is %s",
+ enableScheduler ? "enabled" : "disabled");
+
+ // initialize device (setupo MCI)
+ if (!mobiCoreDevice->initDevice(
+ "/dev/" MC_ADMIN_DEVNODE,
+ enableScheduler)) {
+ LOG_E("Could not initialize <t-base!");
+ return;
+ }
+
+ // start device (scheduler)
+ mobiCoreDevice->start();
+
+ LOG_I_RELEASE("Checking version of <t-base");
+ checkMobiCoreVersion(mobiCoreDevice);
+
+ // Load device driver if requested
+ if (loadDriver) {
+ for (unsigned int i = 0; i < drivers.size(); i++)
+ loadDeviceDriver(drivers[i]);
+ }
+
+ // Look for tokens and send it to <t-base if any
+ installEndorsementToken();
+
+ LOG_I("Creating socket servers");
+ // Start listening for incoming TLC connections
+ servers[0] = new NetlinkServer(this);
+ servers[1] = new Server(this, SOCK_PATH);
+ LOG_I("Successfully created servers");
+
+ // Start all the servers
+ for (i = 0; i < MAX_SERVERS; i++) {
+ servers[i]->start(i ? "McDaemon.Server" : "NetlinkServer");
+ }
+
+ // then wait for them to exit
+ for (i = 0; i < MAX_SERVERS; i++) {
+ servers[i]->join();
+ }
+}
+
+//------------------------------------------------------------------------------
+bool MobiCoreDriverDaemon::checkPermission(Connection *connection)
+{
+#ifdef REGISTRY_CHECK_PERMISSIONS
+ struct ucred cred;
+ if (!connection)
+ return true;
+
+ if (connection->getPeerCredentials(cred)) {
+ gid_t gid = getegid();
+ uid_t uid = geteuid();
+ LOG_I("Peer connection has pid = %u and uid = %u gid = %u", cred.pid, cred.uid, cred.gid);
+ LOG_I("Daemon has uid = %u gid = %u", cred.uid, cred.gid);
+ // If the daemon and the peer have the same uid or gid then we're good
+ if (gid == cred.gid || uid == cred.uid) {
+ return true;
+ }
+ return false;
+
+ }
+ return false;
+#else
+ return true;
+#endif
+}
+
+//------------------------------------------------------------------------------
+MobiCoreDevice *MobiCoreDriverDaemon::getDevice(
+ uint32_t deviceId
+)
+{
+ // Always return the trustZoneDevice as it is currently the only one supported
+ if (MC_DEVICE_ID_DEFAULT != deviceId)
+ return NULL;
+ return mobiCoreDevice;
+}
+
+
+//------------------------------------------------------------------------------
+void MobiCoreDriverDaemon::dropConnection(
+ Connection *connection
+)
+{
+ // Check if a Device has already been registered with the connection
+ MobiCoreDevice *device = (MobiCoreDevice *) (connection->connectionData);
+
+ if (device != NULL) {
+ // A connection has been found and has to be closed
+ LOG_I("dropConnection(): closing still open device.");
+
+ // Make sure nobody else writes the MCP, e.g. netlink/socket server, cleanup of TAs
+ device->mutex_mcp.lock();
+ device->close(connection);
+ device->mutex_mcp.unlock();
+ }
+}
+
+
+//------------------------------------------------------------------------------
+size_t MobiCoreDriverDaemon::writeResult(
+ Connection *connection,
+ mcResult_t code
+)
+{
+ if (0 != code) {
+ LOG_V(" sending error code %d", code);
+ }
+ return connection->writeData(&code, sizeof(mcResult_t));
+}
+
+//------------------------------------------------------------------------------
+bool MobiCoreDriverDaemon::loadDeviceDriver(
+ std::string driverPath
+)
+{
+ bool ret = false;
+ CWsm_ptr pWsm = NULL, pTciWsm = NULL;
+ regObject_t *regObj = NULL;
+ Connection *conn = NULL;
+ mcDrvRspOpenSession_t rspOpenSession;
+
+ do {
+ //mobiCoreDevice
+ LOG_I("%s: loading %s", __FUNCTION__, driverPath.c_str());
+
+ regObj = mcRegistryGetDriverBlob(driverPath.c_str());
+ if (regObj == NULL) {
+ break;;
+ }
+
+ LOG_I("registering L2 in kmod, p=%p, len=%i",
+ regObj->value, regObj->len);
+
+ pWsm = mobiCoreDevice->registerWsmL2(
+ (addr_t)(regObj->value), regObj->len, 0);
+ if (pWsm == NULL) {
+ LOG_E("allocating WSM for Trustlet failed");
+ break;
+ }
+ // Initialize information data of open session command
+ loadDataOpenSession_t loadDataOpenSession;
+ loadDataOpenSession.baseAddr = pWsm->physAddr;
+ loadDataOpenSession.offs = ((uintptr_t) regObj->value) & 0xFFF;
+ loadDataOpenSession.len = regObj->len;
+ loadDataOpenSession.tlHeader = (mclfHeader_ptr) (regObj->value + regObj->tlStartOffset);
+
+ pTciWsm = mobiCoreDevice->allocateContiguousPersistentWsm(DRIVER_TCI_LEN);
+ if (pTciWsm == NULL) {
+ LOG_E("allocating WSM TCI for Trustlet failed");
+ break;
+ }
+
+ conn = new Connection();
+ uint32_t mcRet = mobiCoreDevice->openSession(
+ conn,
+ &loadDataOpenSession,
+ pTciWsm->handle,
+ pTciWsm->len,
+ 0,
+ &(rspOpenSession.payload));
+
+ // Unregister physical memory from kernel module.
+ // This will also destroy the WSM object.
+ if (!mobiCoreDevice->unregisterWsmL2(pWsm))
+ {
+ pWsm = NULL;
+ LOG_E("unregistering of WsmL2 failed.");
+ break;
+ }
+ pWsm = NULL;
+
+ // Free memory occupied by Trustlet data
+ free(regObj);
+ regObj = NULL;
+
+ if (mcRet != MC_MCP_RET_OK) {
+ LOG_E("open session error %d", mcRet);
+ break;
+ }
+
+ ret = true;
+ } while (false);
+ // Free all allocated resources
+ if (ret == false) {
+ LOG_I("%s: Freeing previously allocated resources!", __FUNCTION__);
+ if (pWsm != NULL) {
+ if (!mobiCoreDevice->unregisterWsmL2(pWsm)) {
+ LOG_E("unregisterWsmL2 failed");
+ }
+ pWsm = NULL;
+ }
+ // No matter if we free NULL objects
+ free(regObj);
+
+ if (conn != NULL) {
+ delete conn;
+ }
+ } else if (conn != NULL) {
+ driverResources.push_back(new MobicoreDriverResources(
+ conn, pTciWsm, rspOpenSession.payload.sessionId));
+ }
+
+ return ret;
+}
+
+#define RECV_PAYLOAD_FROM_CLIENT(CONNECTION, CMD_BUFFER) \
+{ \
+ void *payload = (void*)((uintptr_t)CMD_BUFFER + sizeof(mcDrvCommandHeader_t)); \
+ uint32_t payload_len = sizeof(*CMD_BUFFER) - sizeof(mcDrvCommandHeader_t); \
+ int32_t rlen = CONNECTION->readData(payload, payload_len); \
+ if (rlen < 0) { \
+ LOG_E("reading from Client failed"); \
+ /* it is questionable, if writing to broken socket has any effect here. */ \
+ writeResult(CONNECTION, MC_DRV_ERR_DAEMON_SOCKET); \
+ return; \
+ } \
+ if ((uint32_t)rlen != payload_len) {\
+ LOG_E("wrong buffer length %i received from Client", rlen); \
+ writeResult(CONNECTION, MC_DRV_ERR_DAEMON_SOCKET); \
+ return; \
+ } \
+}
+
+#define CHECK_DEVICE(DEVICE, CONNECTION) \
+ if (DEVICE == NULL) \
+ { \
+ LOG_V("%s: no device associated with connection",__FUNCTION__); \
+ writeResult(CONNECTION, MC_DRV_ERR_DAEMON_DEVICE_NOT_OPEN); \
+ return; \
+ }
+
+//------------------------------------------------------------------------------
+inline bool getData(Connection *con, void *buf, uint32_t len)
+{
+ uint32_t rlen = con->readData(buf, len);
+ if (rlen < len || (int32_t)rlen < 0) {
+ LOG_E("reading from Client failed");
+ return false;
+ }
+ return true;
+}
+
+//------------------------------------------------------------------------------
+void MobiCoreDriverDaemon::processOpenDevice(Connection *connection)
+{
+ MC_DRV_CMD_OPEN_DEVICE_struct cmdOpenDevice;
+ RECV_PAYLOAD_FROM_CLIENT(connection, &cmdOpenDevice);
+
+ // Check if device has been registered to the connection
+ MobiCoreDevice *device = (MobiCoreDevice *) (connection->connectionData);
+ if (NULL != device) {
+ LOG_E("processOpenDevice(): device already set");
+ writeResult(connection, MC_DRV_ERR_DEVICE_ALREADY_OPEN);
+ return;
+ }
+
+ LOG_I(" Opening deviceId %d ", cmdOpenDevice.deviceId);
+
+ // Get device for device ID
+ device = getDevice(cmdOpenDevice.deviceId);
+
+ // Check if a device for the given name has been found
+ if (device == NULL) {
+ LOG_E("invalid deviceId");
+ writeResult(connection, MC_DRV_ERR_UNKNOWN_DEVICE);
+ return;
+ }
+
+ // Register device object with connection
+ device->open(connection);
+
+ // Return result code to client lib (no payload)
+ writeResult(connection, MC_DRV_OK);
+}
+
+
+//------------------------------------------------------------------------------
+void MobiCoreDriverDaemon::processCloseDevice(
+ Connection *connection
+)
+{
+ // there is no payload to read
+
+ // Device required
+ MobiCoreDevice *device = (MobiCoreDevice *) (connection->connectionData);
+ CHECK_DEVICE(device, connection);
+
+ // No command data will be read
+ // Unregister device object with connection
+ device->close(connection);
+
+ // there is no payload
+ writeResult(connection, MC_DRV_OK);
+}
+
+
+//------------------------------------------------------------------------------
+void MobiCoreDriverDaemon::processOpenSession(Connection *connection, bool isGpUuid)
+{
+ MC_DRV_CMD_OPEN_SESSION_struct cmdOpenSession;
+ RECV_PAYLOAD_FROM_CLIENT(connection, &cmdOpenSession);
+
+ // Device required
+ MobiCoreDevice *device = (MobiCoreDevice *) (connection->connectionData);
+ CHECK_DEVICE(device, connection);
+
+ // Get service blob from registry
+ regObject_t *regObj = mcRegistryGetServiceBlob(&cmdOpenSession.uuid, isGpUuid);
+ if (NULL == regObj) {
+ writeResult(connection, MC_DRV_ERR_TRUSTLET_NOT_FOUND);
+ return;
+ }
+ if (regObj->len == 0) {
+ free(regObj);
+ writeResult(connection, MC_DRV_ERR_TRUSTLET_NOT_FOUND);
+ return;
+ }
+ LOG_I(" Sharing Service loaded at %p with Secure World", (addr_t)(regObj->value));
+
+ CWsm_ptr pWsm = device->registerWsmL2((addr_t)(regObj->value), regObj->len, 0);
+ if (pWsm == NULL) {
+ // Free memory occupied by Trustlet data
+ free(regObj);
+ LOG_E("allocating WSM for Trustlet failed");
+ writeResult(connection, MC_DRV_ERR_DAEMON_KMOD_ERROR);
+ return;
+ }
+ // Initialize information data of open session command
+ loadDataOpenSession_t loadDataOpenSession;
+ loadDataOpenSession.baseAddr = pWsm->physAddr;
+ loadDataOpenSession.offs = ((uintptr_t) regObj->value) & 0xFFF;
+ loadDataOpenSession.len = regObj->len;
+ loadDataOpenSession.tlHeader = (mclfHeader_ptr) (regObj->value + regObj->tlStartOffset);
+
+ mcDrvRspOpenSession_t rspOpenSession;
+ mcResult_t ret = device->openSession(
+ connection,
+ &loadDataOpenSession,
+ cmdOpenSession.handle,
+ cmdOpenSession.len,
+ cmdOpenSession.tci,
+ &rspOpenSession.payload);
+
+ // Unregister physical memory from kernel module.
+ LOG_I(" Service buffer was copied to Secure world and processed. Stop sharing of buffer.");
+
+ // This will also destroy the WSM object.
+ if (!device->unregisterWsmL2(pWsm)) {
+ pWsm = NULL;
+ // TODO-2012-07-02-haenellu: Can this ever happen? And if so, we should assert(), also TL might still be running.
+ free(regObj);
+ writeResult(connection, MC_DRV_ERR_DAEMON_KMOD_ERROR);
+ return;
+ }
+ pWsm = NULL;
+ // Free memory occupied by Trustlet data
+ free(regObj);
+
+ if (ret != MC_DRV_OK) {
+ LOG_E("Service could not be loaded.");
+ writeResult(connection, ret);
+ } else {
+ rspOpenSession.header.responseId = ret;
+ connection->writeData(
+ &rspOpenSession,
+ sizeof(rspOpenSession));
+ }
+}
+
+//------------------------------------------------------------------------------
+mcResult_t MobiCoreDriverDaemon::processLoadCheck(mcSpid_t spid, void *blob, uint32_t size)
+{
+
+ // Device required
+ MobiCoreDevice *device = getDevice(MC_DEVICE_ID_DEFAULT);
+
+ if (device == NULL) {
+ LOG_E(" No device found");
+ return MC_DRV_ERR_DAEMON_DEVICE_NOT_OPEN;
+ }
+
+ // Get service blob from registry
+ regObject_t *regObj = mcRegistryMemGetServiceBlob(spid, blob, size);
+ if (NULL == regObj) {
+ LOG_E(" mcRegistryMemGetServiceBlob failed");
+ return MC_DRV_ERR_TRUSTLET_NOT_FOUND;
+ }
+ if (regObj->len == 0) {
+ free(regObj);
+ LOG_E("mcRegistryMemGetServiceBlob returned registry object with length equal to zero");
+ return MC_DRV_ERR_TRUSTLET_NOT_FOUND;
+ }
+ LOG_I(" Sharing Service loaded at %p with Secure World", (addr_t)(regObj->value));
+
+ CWsm_ptr pWsm = device->registerWsmL2((addr_t)(regObj->value), regObj->len, 0);
+ if (pWsm == NULL) {
+ // Free memory occupied by Trustlet data
+ free(regObj);
+ LOG_E("allocating WSM for Trustlet failed");
+ return MC_DRV_ERR_DAEMON_KMOD_ERROR;
+ }
+ // Initialize information data of open session command
+ loadDataOpenSession_t loadDataOpenSession;
+ loadDataOpenSession.baseAddr = pWsm->physAddr;
+ loadDataOpenSession.offs = ((uintptr_t) regObj->value) & 0xFFF;
+ loadDataOpenSession.len = regObj->len;
+ loadDataOpenSession.tlHeader = (mclfHeader_ptr) (regObj->value + regObj->tlStartOffset);
+
+ mcDrvRspOpenSession_t rspOpenSession;
+ mcResult_t ret = device->checkLoad(
+ &loadDataOpenSession,
+ &rspOpenSession.payload);
+
+ // Unregister physical memory from kernel module.
+ LOG_I(" Service buffer was copied to Secure world and processed. Stop sharing of buffer.");
+
+ // This will also destroy the WSM object.
+ if (!device->unregisterWsmL2(pWsm)) {
+ pWsm = NULL;
+ // Free memory occupied by Trustlet data
+ free(regObj);
+ LOG_E("deallocating WSM for Trustlet failed");
+ return MC_DRV_ERR_DAEMON_KMOD_ERROR;
+ }
+ pWsm = NULL;
+
+ // Free memory occupied by Trustlet data
+ free(regObj);
+
+ if (ret != MC_DRV_OK) {
+ LOG_E("TA could not be loaded.");
+ return ret;
+ } else {
+ return MC_DRV_OK;
+ }
+}
+
+
+//------------------------------------------------------------------------------
+void MobiCoreDriverDaemon::processOpenTrustlet(Connection *connection)
+{
+ MC_DRV_CMD_OPEN_TRUSTLET_struct cmdOpenTrustlet;
+ RECV_PAYLOAD_FROM_CLIENT(connection, &cmdOpenTrustlet);
+
+ // Device required
+ MobiCoreDevice *device = (MobiCoreDevice *) (connection->connectionData);
+ CHECK_DEVICE(device, connection);
+
+ uint32_t total_len, rlen, len = cmdOpenTrustlet.trustlet_len;
+ uint8_t *payload = (uint8_t *)malloc(len);
+ uint8_t *p = payload;
+ if (payload == NULL) {
+ LOG_E("failed to allocate payload buffer");
+ writeResult(connection, MC_DRV_ERR_DAEMON_SOCKET);
+ return;
+ }
+ total_len = 0;
+ while (total_len < len) {
+ rlen = connection->readData(p, len - total_len);
+ if ((int32_t)rlen < 0) {
+ LOG_E("reading from Client failed");
+ /* it is questionable, if writing to broken socket has any effect here. */
+ writeResult(connection, MC_DRV_ERR_DAEMON_SOCKET);
+ free(payload);
+ return;
+ }
+ total_len += rlen;
+ p += rlen;
+ }
+
+ // Get service blob from registry
+ regObject_t *regObj = mcRegistryMemGetServiceBlob(cmdOpenTrustlet.spid, (uint8_t *)payload, len);
+
+ // Free the payload object no matter what
+ free(payload);
+ if (regObj == NULL) {
+ writeResult(connection, MC_DRV_ERR_TRUSTLET_NOT_FOUND);
+ return;
+ }
+
+ if (regObj->len == 0) {
+ free(regObj);
+ writeResult(connection, MC_DRV_ERR_TRUSTLET_NOT_FOUND);
+ return;
+ }
+ LOG_I(" Sharing Service loaded at %p with Secure World", (addr_t)(regObj->value));
+
+ CWsm_ptr pWsm = device->registerWsmL2((addr_t)(regObj->value), regObj->len, 0);
+ if (pWsm == NULL) {
+ free(regObj);
+ LOG_E("allocating WSM for Trustlet failed");
+ writeResult(connection, MC_DRV_ERR_DAEMON_KMOD_ERROR);
+ return;
+ }
+ // Initialize information data of open session command
+ loadDataOpenSession_t loadDataOpenSession;
+ loadDataOpenSession.baseAddr = pWsm->physAddr;
+ loadDataOpenSession.offs = ((uintptr_t) regObj->value) & 0xFFF;
+ loadDataOpenSession.len = regObj->len;
+ loadDataOpenSession.tlHeader = (mclfHeader_ptr) (regObj->value + regObj->tlStartOffset);
+
+ mcDrvRspOpenSession_t rspOpenSession;
+ mcResult_t ret = device->openSession(
+ connection,
+ &loadDataOpenSession,
+ cmdOpenTrustlet.handle,
+ cmdOpenTrustlet.len,
+ cmdOpenTrustlet.tci,
+ &rspOpenSession.payload);
+
+ // Unregister physical memory from kernel module.
+ LOG_I(" Service buffer was copied to Secure world and processed. Stop sharing of buffer.");
+
+ // This will also destroy the WSM object.
+ if (!device->unregisterWsmL2(pWsm)) {
+ pWsm = NULL;
+ free(regObj);
+ // TODO-2012-07-02-haenellu: Can this ever happen? And if so, we should assert(), also TL might still be running.
+ writeResult(connection, MC_DRV_ERR_DAEMON_KMOD_ERROR);
+ return;
+ }
+ pWsm = NULL;
+
+ // Free memory occupied by Trustlet data
+ free(regObj);
+
+ if (ret != MC_DRV_OK) {
+ LOG_E("Service could not be loaded.");
+ writeResult(connection, ret);
+ } else {
+ rspOpenSession.header.responseId = ret;
+ connection->writeData(
+ &rspOpenSession,
+ sizeof(rspOpenSession));
+ }
+}
+
+//------------------------------------------------------------------------------
+void MobiCoreDriverDaemon::processCloseSession(Connection *connection)
+{
+ MC_DRV_CMD_CLOSE_SESSION_struct cmdCloseSession;
+ RECV_PAYLOAD_FROM_CLIENT(connection, &cmdCloseSession)
+
+ // Device required
+ MobiCoreDevice *device = (MobiCoreDevice *) (connection->connectionData);
+ CHECK_DEVICE(device, connection);
+
+ mcResult_t ret = device->closeSession(connection, cmdCloseSession.sessionId);
+
+ // there is no payload
+ writeResult(connection, ret);
+}
+
+
+//------------------------------------------------------------------------------
+void MobiCoreDriverDaemon::processNqConnect(Connection *connection)
+{
+ // Set up the channel for sending SWd notifications to the client
+ // MC_DRV_CMD_NQ_CONNECT is only allowed on new connections not
+ // associated with a device. If a device is registered to the
+ // connection NQ_CONNECT is not allowed.
+
+ // Read entire command data
+ MC_DRV_CMD_NQ_CONNECT_struct cmd;
+ RECV_PAYLOAD_FROM_CLIENT(connection, &cmd);
+
+ // device must be empty since this is a new connection
+ MobiCoreDevice *device = (MobiCoreDevice *)(connection->connectionData);
+ if (device != NULL) {
+ LOG_E("device already set\n");
+ writeResult(connection, MC_DRV_ERR_NQ_FAILED);
+ return;
+ }
+
+ // Remove the connection from the list of known client connections
+ for (int i = 0; i < MAX_SERVERS; i++) {
+ servers[i]->detachConnection(connection);
+ }
+
+ device = getDevice(cmd.deviceId);
+ // Check if a device for the given name has been found
+ if (NULL == device) {
+ LOG_E("invalid deviceId");
+ writeResult(connection, MC_DRV_ERR_UNKNOWN_DEVICE);
+ return;
+ }
+
+ /*
+ * The fix extends the range of the trustlet_session_list mutex over the
+ * sending of the nq-socket message that confirms the creation of the session.
+ * That way an arriving SSIQ/notification-from-driver will not use the nq-socket before the ok message was sent.
+ */
+ device->mutex_tslist.lock();
+ TrustletSession *ts = device->registerTrustletConnection(
+ connection,
+ &cmd);
+ if (!ts) {
+ LOG_E("registerTrustletConnection() failed!");
+ writeResult(connection, MC_DRV_ERR_UNKNOWN);
+ device->mutex_tslist.unlock();
+ return;
+ }
+
+ writeResult(connection, MC_DRV_OK);
+ device->mutex_tslist.unlock();
+
+ ts->processQueuedNotifications();
+}
+
+
+//------------------------------------------------------------------------------
+void MobiCoreDriverDaemon::processNotify(Connection *connection)
+{
+ // Read entire command data
+ MC_DRV_CMD_NOTIFY_struct cmd;
+ //RECV_PAYLOAD_FROM_CLIENT(connection, &cmd);
+ void *payload = (void *)((uintptr_t)&cmd + sizeof(mcDrvCommandHeader_t));
+ uint32_t payload_len = sizeof(cmd) - sizeof(mcDrvCommandHeader_t);
+ uint32_t rlen = connection->readData(payload, payload_len);
+ if ((int) rlen < 0) {
+ LOG_E("reading from Client failed");
+ /* it is questionable, if writing to broken socket has any effect here. */
+ // NOTE: notify fails silently
+ //writeResult(connection, MC_DRV_RSP_SOCKET_ERROR);
+ return;
+ }
+ if (rlen != payload_len) {
+ LOG_E("wrong buffer length %i received from Client", rlen);
+ // NOTE: notify fails silently
+ //writeResult(connection, MC_DRV_RSP_PAYLOAD_LENGTH_ERROR);
+ return;
+ }
+
+ // Device required
+ MobiCoreDevice *device = (MobiCoreDevice *) (connection->connectionData);
+ if (NULL == device) {
+ LOG_V("%s: no device associated with connection", __FUNCTION__);
+ // NOTE: notify fails silently
+ // writeResult(connection,MC_DRV_RSP_DEVICE_NOT_OPENED);
+ return;
+ }
+
+ device->notify(connection, cmd.sessionId);
+ // NOTE: for notifications there is no response at all
+}
+
+
+//------------------------------------------------------------------------------
+void MobiCoreDriverDaemon::processMapBulkBuf(Connection *connection)
+{
+ MC_DRV_CMD_MAP_BULK_BUF_struct cmd;
+
+ RECV_PAYLOAD_FROM_CLIENT(connection, &cmd);
+
+ // Device required
+ MobiCoreDevice *device = (MobiCoreDevice *) (connection->connectionData);
+ CHECK_DEVICE(device, connection);
+
+ if (!device->lockWsmL2(cmd.handle)) {
+ LOG_E("Couldn't lock the buffer!");
+ writeResult(connection, MC_DRV_ERR_DAEMON_WSM_HANDLE_NOT_FOUND);
+ return;
+ }
+
+ uint32_t secureVirtualAdr = (uint32_t)NULL;
+ uint64_t pAddrL2 = device->findWsmL2(cmd.handle, connection->socketDescriptor);
+
+ if (pAddrL2 == 0) {
+ LOG_E("Failed to resolve WSM with handle %u", cmd.handle);
+ writeResult(connection, MC_DRV_ERR_DAEMON_WSM_HANDLE_NOT_FOUND);
+ return;
+ }
+
+ // Map bulk memory to secure world
+ mcResult_t mcResult = device->mapBulk(connection, cmd.sessionId, cmd.handle, pAddrL2,
+ cmd.offsetPayload, cmd.lenBulkMem, &secureVirtualAdr);
+
+ if (mcResult != MC_DRV_OK) {
+ writeResult(connection, mcResult);
+ return;
+ }
+
+ mcDrvRspMapBulkMem_t rsp;
+ rsp.header.responseId = MC_DRV_OK;
+ rsp.payload.sessionId = cmd.sessionId;
+ rsp.payload.secureVirtualAdr = secureVirtualAdr;
+ connection->writeData(&rsp, sizeof(mcDrvRspMapBulkMem_t));
+}
+
+
+//------------------------------------------------------------------------------
+void MobiCoreDriverDaemon::processUnmapBulkBuf(Connection *connection)
+{
+ MC_DRV_CMD_UNMAP_BULK_BUF_struct cmd;
+ RECV_PAYLOAD_FROM_CLIENT(connection, &cmd)
+
+ // Device required
+ MobiCoreDevice *device = (MobiCoreDevice *) (connection->connectionData);
+ CHECK_DEVICE(device, connection);
+
+ // Unmap bulk memory from secure world
+ uint32_t mcResult = device->unmapBulk(connection, cmd.sessionId, cmd.handle,
+ cmd.secureVirtualAdr, cmd.lenBulkMem);
+
+ if (mcResult != MC_DRV_OK) {
+ LOG_V("MCP UNMAP returned code %d", mcResult);
+ writeResult(connection, mcResult);
+ return;
+ }
+
+ // TODO-2012-09-06-haenellu: Think about not ignoring the error case.
+ device->unlockWsmL2(cmd.handle);
+
+ writeResult(connection, MC_DRV_OK);
+}
+
+
+//------------------------------------------------------------------------------
+void MobiCoreDriverDaemon::processGetVersion(
+ Connection *connection
+)
+{
+ // there is no payload to read
+
+ mcDrvRspGetVersion_t rspGetVersion;
+ rspGetVersion.version = MC_MAKE_VERSION(DAEMON_VERSION_MAJOR, DAEMON_VERSION_MINOR);
+ rspGetVersion.responseId = MC_DRV_OK;
+
+ connection->writeData(&rspGetVersion, sizeof(mcDrvRspGetVersion_t));
+}
+
+//------------------------------------------------------------------------------
+void MobiCoreDriverDaemon::processGetMobiCoreVersion(
+ Connection *connection
+)
+{
+ // there is no payload to read
+
+ // Device required
+ MobiCoreDevice *device = (MobiCoreDevice *) (connection->connectionData);
+ CHECK_DEVICE(device, connection);
+
+ // Get <t-base version info from secure world.
+ mcDrvRspGetMobiCoreVersion_t rspGetMobiCoreVersion;
+
+ mcResult_t mcResult = device->getMobiCoreVersion(&rspGetMobiCoreVersion.payload);
+
+ if (mcResult != MC_DRV_OK) {
+ LOG_V("MC GET_MOBICORE_VERSION returned code %d", mcResult);
+ writeResult(connection, mcResult);
+ return;
+ }
+
+ rspGetMobiCoreVersion.header.responseId = MC_DRV_OK;
+ connection->writeData(
+ &rspGetMobiCoreVersion,
+ sizeof(rspGetMobiCoreVersion));
+}
+
+//------------------------------------------------------------------------------
+void MobiCoreDriverDaemon::processRegistryReadData(uint32_t commandId, Connection *connection)
+{
+#define MAX_DATA_SIZE 512
+mcDrvResponseHeader_t rspRegistry = { responseId :
+ MC_DRV_ERR_INVALID_OPERATION
+ };
+ void *buf = alloca(MAX_DATA_SIZE);
+ uint32_t len = MAX_DATA_SIZE;
+ mcSoAuthTokenCont_t auth;
+ mcSpid_t spid;
+ mcUuid_t uuid;
+
+ memset(&spid, 0, sizeof(spid));
+
+ if (!checkPermission(connection)) {
+ connection->writeData(&rspRegistry, sizeof(rspRegistry));
+ return;
+ }
+
+ switch (commandId) {
+ case MC_DRV_REG_READ_AUTH_TOKEN:
+ rspRegistry.responseId = mcRegistryReadAuthToken(&auth);
+ buf = &auth;
+ len = sizeof(mcSoAuthTokenCont_t);
+ break;
+ case MC_DRV_REG_READ_ROOT_CONT:
+ rspRegistry.responseId = mcRegistryReadRoot(buf, &len);
+ break;
+ case MC_DRV_REG_READ_SP_CONT:
+ if (!getData(connection, &spid, sizeof(spid)))
+ break;
+ rspRegistry.responseId = mcRegistryReadSp(spid, buf, &len);
+ break;
+ case MC_DRV_REG_READ_TL_CONT:
+ if (!getData(connection, &uuid, sizeof(uuid)))
+ break;
+ if (!getData(connection, &spid, sizeof(spid)))
+ break;
+ rspRegistry.responseId = mcRegistryReadTrustletCon(&uuid, spid, buf, &len);
+ break;
+ default:
+ break;
+ }
+ connection->writeData(&rspRegistry, sizeof(rspRegistry));
+ if (rspRegistry.responseId != MC_DRV_ERR_INVALID_OPERATION)
+ connection->writeData(buf, len);
+}
+
+//------------------------------------------------------------------------------
+void MobiCoreDriverDaemon::processRegistryWriteData(uint32_t commandId, Connection *connection)
+{
+mcDrvResponseHeader_t rspRegistry = { responseId :
+ MC_DRV_ERR_INVALID_OPERATION
+ };
+ uint32_t soSize = 0;
+ void *so;
+
+ if (!checkPermission(connection)) {
+ connection->writeData(&rspRegistry, sizeof(rspRegistry));
+ return;
+ }
+
+ // First read the SO data size
+ if (!getData(connection, &soSize, sizeof(soSize))) {
+ LOG_E("Failed to read SO data size");
+ connection->writeData(&rspRegistry, sizeof(rspRegistry));
+ return;
+ }
+ so = malloc(soSize);
+ if (so == NULL) {
+ LOG_E("Allocation failure");
+ rspRegistry.responseId = MC_DRV_ERR_NO_FREE_MEMORY;
+ connection->writeData(&rspRegistry, sizeof(rspRegistry));
+ return;
+ }
+
+ switch (commandId) {
+ case MC_DRV_REG_STORE_AUTH_TOKEN: {
+ if (!getData(connection, so, soSize))
+ break;
+ rspRegistry.responseId = mcRegistryStoreAuthToken(so, soSize);
+ if (rspRegistry.responseId != MC_DRV_OK) {
+ LOG_E("mcRegistryStoreAuthToken() failed");
+ break;
+ }
+ /* Load authentication token. Need to update <t-base to avoid
+ * reboot */
+ LOG_I("Auth Token stored. Updating <t-base.");
+ if (!loadToken((uint8_t *)so, sizeof(mcSoAuthTokenCont_t))) {
+ LOG_E("Failed to pass Auth Token to <t-base.");
+ }
+ break;
+ }
+ case MC_DRV_REG_WRITE_ROOT_CONT: {
+ if (!getData(connection, so, soSize))
+ break;
+ rspRegistry.responseId = mcRegistryStoreRoot(so, soSize);
+ if (rspRegistry.responseId != MC_DRV_OK) {
+ LOG_E("mcRegistryStoreRoot() failed");
+ break;
+ }
+ /* Load Root container. Need to update <t-base to avoid
+ * reboot */
+ LOG_I("Root container stored. Updating <t-base.");
+ if (!loadToken((uint8_t *)so, sizeof(mcSoRootCont_t))) {
+ LOG_E("Failed to pass Root container to <t-base.");
+ }
+ break;
+ }
+ case MC_DRV_REG_WRITE_SP_CONT: {
+ mcSpid_t spid;
+ if (!getData(connection, &spid, sizeof(spid)))
+ break;
+ if (!getData(connection, so, soSize))
+ break;
+ rspRegistry.responseId = mcRegistryStoreSp(spid, so, soSize);
+ break;
+ }
+ case MC_DRV_REG_WRITE_TL_CONT: {
+ mcUuid_t uuid;
+ mcSpid_t spid;
+ memset(&spid, 0, sizeof(spid));
+ if (!getData(connection, &uuid, sizeof(uuid)))
+ break;
+ if (!getData(connection, &spid, sizeof(spid)))
+ break;
+ if (!getData(connection, so, soSize))
+ break;
+ rspRegistry.responseId = mcRegistryStoreTrustletCon(&uuid, spid, so, soSize);
+ break;
+ }
+ case MC_DRV_REG_WRITE_SO_DATA: {
+ if (!getData(connection, so, soSize))
+ break;
+ rspRegistry.responseId = mcRegistryStoreData(so, soSize);
+ break;
+ }
+ case MC_DRV_REG_STORE_TA_BLOB: {
+ uint32_t blobSize = soSize;
+ mcSpid_t spid;
+ void *blob;
+ memset(&spid, 0, sizeof(spid));
+ if (!getData(connection, &spid, sizeof(spid)))
+ break;
+ blob = malloc(blobSize);
+ if (blob == NULL) {
+ LOG_E("Allocation failure");
+ rspRegistry.responseId = MC_DRV_ERR_NO_FREE_MEMORY;
+ break;
+ }
+ if (!getData(connection, blob, blobSize)) {
+ free(blob);
+ break;
+ }
+ //LOG_I("processLoadCheck");
+ rspRegistry.responseId = processLoadCheck(spid, blob, blobSize);
+ if (rspRegistry.responseId != MC_DRV_OK){
+ LOG_I("processLoadCheck failed");
+ free(blob);
+ break;
+ }
+ //LOG_I("mcRegistryStoreTABlob");
+ rspRegistry.responseId = mcRegistryStoreTABlob(spid, blob, blobSize);
+ free(blob);
+ break;
+ }
+ default:
+ break;
+ }
+ free(so);
+ connection->writeData(&rspRegistry, sizeof(rspRegistry));
+}
+
+//------------------------------------------------------------------------------
+void MobiCoreDriverDaemon::processRegistryDeleteData(uint32_t commandId, Connection *connection)
+{
+mcDrvResponseHeader_t rspRegistry = { responseId :
+ MC_DRV_ERR_INVALID_OPERATION
+ };
+ mcSpid_t spid = MC_SPID_RESERVED; /* MC_SPID_RESERVED = 0 */
+
+ if (!checkPermission(connection)) {
+ connection->writeData(&rspRegistry, sizeof(rspRegistry));
+ return;
+ }
+
+ switch (commandId) {
+ case MC_DRV_REG_DELETE_AUTH_TOKEN:
+ rspRegistry.responseId = mcRegistryDeleteAuthToken();
+ break;
+ case MC_DRV_REG_DELETE_ROOT_CONT: {
+ rspRegistry.responseId = mcRegistryCleanupRoot();
+ if (rspRegistry.responseId != MC_DRV_OK) {
+ LOG_E("mcRegistryCleanupRoot() failed");
+ break;
+ }
+ // Look for tokens and send it to <t-base if any
+ installEndorsementToken();
+ break;
+ }
+ case MC_DRV_REG_DELETE_SP_CONT:
+ if (!getData(connection, &spid, sizeof(spid)))
+ break;
+ rspRegistry.responseId = mcRegistryCleanupSp(spid);
+ break;
+ case MC_DRV_REG_DELETE_TL_CONT:
+ mcUuid_t uuid;
+ if (!getData(connection, &uuid, sizeof(uuid)))
+ break;
+ if (!getData(connection, &spid, sizeof(spid)))
+ break;
+ rspRegistry.responseId = mcRegistryCleanupTrustlet(&uuid, spid);
+ break;
+ default:
+ break;
+ }
+
+ connection->writeData(&rspRegistry, sizeof(rspRegistry));
+}
+
+//------------------------------------------------------------------------------
+bool MobiCoreDriverDaemon::handleConnection(
+ Connection *connection
+)
+{
+ bool ret = false;
+
+ // This is the big lock around everything the Daemon does, including socket and MCI access
+ static CMutex reg_mutex;
+ static CMutex siq_mutex;
+
+ /* In case of RTM fault do not try to signal anything to MobiCore
+ * just answer NO to all incoming connections! */
+ if (mobiCoreDevice->getMcFault()) {
+ LOG_I("Ignore request, <t-base has faulted before.");
+ return false;
+ }
+
+ LOG_I("handleConnection()==== %p", connection);
+ do {
+ // Read header
+ mcDrvCommandHeader_t mcDrvCommandHeader;
+ ssize_t rlen = connection->readData(
+ &(mcDrvCommandHeader),
+ sizeof(mcDrvCommandHeader));
+
+ if (rlen == 0) {
+ LOG_V(" handleConnection(): Connection closed.");
+ break;
+ }
+ if (rlen == -1) {
+ LOG_E("Socket error.");
+ break;
+ }
+ if (rlen == -2) {
+ LOG_E("Timeout.");
+ break;
+ }
+ ret = true;
+
+ switch (mcDrvCommandHeader.commandId) {
+ //-----------------------------------------
+ case MC_DRV_CMD_OPEN_DEVICE:
+ mobiCoreDevice->mutex_mcp.lock();
+ processOpenDevice(connection);
+ mobiCoreDevice->mutex_mcp.unlock();
+ break;
+ //-----------------------------------------
+ case MC_DRV_CMD_CLOSE_DEVICE:
+ mobiCoreDevice->mutex_mcp.lock();
+ processCloseDevice(connection);
+ mobiCoreDevice->mutex_mcp.unlock();
+ break;
+ //-----------------------------------------
+ case MC_DRV_CMD_OPEN_SESSION:
+ mobiCoreDevice->mutex_mcp.lock();
+ processOpenSession(connection, false);
+ mobiCoreDevice->mutex_mcp.unlock();
+ break;
+ //-----------------------------------------
+ case MC_DRV_CMD_OPEN_TRUSTLET:
+ mobiCoreDevice->mutex_mcp.lock();
+ processOpenTrustlet(connection);
+ mobiCoreDevice->mutex_mcp.unlock();
+ break;
+ //-----------------------------------------
+ case MC_DRV_CMD_OPEN_TRUSTED_APP:
+ mobiCoreDevice->mutex_mcp.lock();
+ processOpenSession(connection, true);
+ mobiCoreDevice->mutex_mcp.unlock();
+ break;
+ //-----------------------------------------
+ case MC_DRV_CMD_CLOSE_SESSION:
+ mobiCoreDevice->mutex_mcp.lock();
+ processCloseSession(connection);
+ mobiCoreDevice->mutex_mcp.unlock();
+ break;
+ //-----------------------------------------
+ case MC_DRV_CMD_NQ_CONNECT:
+ siq_mutex.lock();
+ processNqConnect(connection);
+ siq_mutex.unlock();
+ break;
+ //-----------------------------------------
+ case MC_DRV_CMD_NOTIFY:
+ siq_mutex.lock();
+ processNotify(connection);
+ siq_mutex.unlock();
+ break;
+ //-----------------------------------------
+ case MC_DRV_CMD_MAP_BULK_BUF:
+ mobiCoreDevice->mutex_mcp.lock();
+ processMapBulkBuf(connection);
+ mobiCoreDevice->mutex_mcp.unlock();
+ break;
+ //-----------------------------------------
+ case MC_DRV_CMD_UNMAP_BULK_BUF:
+ mobiCoreDevice->mutex_mcp.lock();
+ processUnmapBulkBuf(connection);
+ mobiCoreDevice->mutex_mcp.unlock();
+ break;
+ //-----------------------------------------
+ case MC_DRV_CMD_GET_VERSION:
+ processGetVersion(connection);
+ break;
+ //-----------------------------------------
+ case MC_DRV_CMD_GET_MOBICORE_VERSION:
+ mobiCoreDevice->mutex_mcp.lock();
+ processGetMobiCoreVersion(connection);
+ mobiCoreDevice->mutex_mcp.unlock();
+ break;
+ //-----------------------------------------
+ /* Registry functionality */
+ // Write Registry Data
+ case MC_DRV_REG_STORE_AUTH_TOKEN:
+ case MC_DRV_REG_WRITE_ROOT_CONT:
+ case MC_DRV_REG_WRITE_SP_CONT:
+ case MC_DRV_REG_WRITE_TL_CONT:
+ case MC_DRV_REG_WRITE_SO_DATA:
+ case MC_DRV_REG_STORE_TA_BLOB:
+ reg_mutex.lock();
+ processRegistryWriteData(mcDrvCommandHeader.commandId, connection);
+ reg_mutex.unlock();
+ break;
+ //-----------------------------------------
+ // Read Registry Data
+ case MC_DRV_REG_READ_AUTH_TOKEN:
+ case MC_DRV_REG_READ_ROOT_CONT:
+ case MC_DRV_REG_READ_SP_CONT:
+ case MC_DRV_REG_READ_TL_CONT:
+ reg_mutex.lock();
+ processRegistryReadData(mcDrvCommandHeader.commandId, connection);
+ reg_mutex.unlock();
+ break;
+ //-----------------------------------------
+ // Delete registry data
+ case MC_DRV_REG_DELETE_AUTH_TOKEN:
+ case MC_DRV_REG_DELETE_ROOT_CONT:
+ case MC_DRV_REG_DELETE_SP_CONT:
+ case MC_DRV_REG_DELETE_TL_CONT:
+ reg_mutex.lock();
+ processRegistryDeleteData(mcDrvCommandHeader.commandId, connection);
+ reg_mutex.unlock();
+ break;
+ //-----------------------------------------
+ default:
+ LOG_E("Unknown command: %d=0x%x",
+ mcDrvCommandHeader.commandId,
+ mcDrvCommandHeader.commandId);
+ ret = false;
+ break;
+ }
+ } while (0);
+
+ LOG_I("handleConnection()<-------");
+
+ return ret;
+}
+
+//------------------------------------------------------------------------------
+/**
+ * Print daemon command line options
+ */
+
+void printUsage(
+ int argc,
+ char *args[]
+)
+{
+#ifdef MOBICORE_COMPONENT_BUILD_TAG
+ fprintf(stderr, "<t-base Driver Daemon %u.%u. \"%s\" %s %s\n", DAEMON_VERSION_MAJOR, DAEMON_VERSION_MINOR, MOBICORE_COMPONENT_BUILD_TAG, __DATE__, __TIME__);
+#else
+#warning "MOBICORE_COMPONENT_BUILD_TAG is not defined!"
+#endif
+
+ fprintf(stderr, "usage: %s [-mdsbhp]\n", args[0]);
+ fprintf(stderr, "Start <t-base Daemon\n\n");
+ fprintf(stderr, "-h\t\tshow this help\n");
+ fprintf(stderr, "-b\t\tfork to background\n");
+ fprintf(stderr, "-s\t\tdisable daemon scheduler(default enabled)\n");
+ fprintf(stderr, "-r DRIVER\t<t-base driver to load at start-up\n");
+}
+
+//------------------------------------------------------------------------------
+/**
+ * Signal handler for daemon termination
+ * Using this handler instead of the standard libc one ensures the daemon
+ * can cleanup everything -> read() on a FD will now return EINTR
+ */
+void terminateDaemon(
+ int signum
+)
+{
+ LOG_E("Signal %d received\n", signum);
+}
+
+//------------------------------------------------------------------------------
+/**
+ * Main entry of the <t-base Driver Daemon.
+ */
+int main(int argc, char *args[])
+{
+ // Create the <t-base Driver Singleton
+ MobiCoreDriverDaemon *mobiCoreDriverDaemon = NULL;
+ // Process signal action
+ struct sigaction action;
+
+ // Read the Command line options
+ extern char *optarg;
+ extern int optopt;
+ int c, errFlag = 0;
+ // Scheduler enabled by default
+ int schedulerFlag = 1;
+ // Autoload driver at start-up
+ int driverLoadFlag = 0;
+ std::vector<std::string> drivers;
+ // By default don't fork
+ bool forkDaemon = false;
+
+ while ((c = getopt(argc, args, "r:sbhp:")) != -1) {
+ switch (c) {
+ case 'h': /* Help */
+ errFlag++;
+ break;
+ case 's': /* Disable Scheduler */
+ schedulerFlag = 0;
+ break;
+ case 'b': /* Fork to background */
+ forkDaemon = true;
+ break;
+ case 'r': /* Load <t-base driver at start-up */
+ driverLoadFlag = 1;
+ drivers.push_back(optarg);
+ break;
+ case ':': /* -r operand */
+ fprintf(stderr, "Option -%c requires an operand\n", optopt);
+ errFlag++;
+ break;
+ case '?':
+ fprintf(stderr, "Unrecognized option: -%c\n", optopt);
+ errFlag++;
+ }
+ }
+ if (errFlag) {
+ printUsage(argc, args);
+ exit(2);
+ }
+
+ // We should fork the daemon to background
+ if (forkDaemon == true) {
+
+ /* ignore terminal has been closed signal */
+ signal(SIGHUP, SIG_IGN);
+
+ /* become a daemon */
+ if (daemon(0, 0) < 0) {
+ fprintf(stderr, "Fork failed, exiting.\n");
+ return 1;
+ }
+
+ /* ignore tty signals */
+ signal(SIGTSTP, SIG_IGN);
+ signal(SIGTTOU, SIG_IGN);
+ signal(SIGTTIN, SIG_IGN);
+ }
+
+ // Set up the structure to specify the new action.
+ action.sa_handler = terminateDaemon;
+ sigemptyset (&action.sa_mask);
+ action.sa_flags = 0;
+ sigaction (SIGINT, &action, NULL);
+ sigaction (SIGTERM, &action, NULL);
+ signal(SIGPIPE, SIG_IGN);
+
+ mobiCoreDriverDaemon = new MobiCoreDriverDaemon(
+ /* Scheduler status */
+ schedulerFlag,
+ /* Auto Driver loading */
+ driverLoadFlag,
+ drivers);
+
+ // Start the driver
+ mobiCoreDriverDaemon->run();
+
+ delete mobiCoreDriverDaemon;
+
+ // This should not happen
+ LOG_E("Exiting <t-base Daemon");
+
+ return EXIT_FAILURE;
+}
+
+//------------------------------------------------------------------------------
+static void checkMobiCoreVersion(
+ MobiCoreDevice *mobiCoreDevice
+)
+{
+ bool failed = false;
+
+ // Get MobiCore version info.
+ mcDrvRspGetMobiCoreVersionPayload_t versionPayload;
+ mcResult_t mcResult = mobiCoreDevice->getMobiCoreVersion(&versionPayload);
+
+ if (mcResult != MC_DRV_OK) {
+ LOG_E("Failed to obtain <t-base version info. MCP return code: %u", mcResult);
+ failed = true;
+ } else {
+ LOG_I_RELEASE("Product ID is %s", versionPayload.versionInfo.productId);
+
+ // Check <t-base version info.
+ char *msg;
+ if (!checkVersionOkMCI(versionPayload.versionInfo.versionMci, &msg)) {
+ LOG_E("%s", msg);
+ failed = true;
+ }
+ LOG_I_RELEASE("%s", msg);
+ if (!checkVersionOkSO(versionPayload.versionInfo.versionSo, &msg)) {
+ LOG_E("%s", msg);
+ failed = true;
+ }
+ LOG_I_RELEASE("%s", msg);
+ if (!checkVersionOkMCLF(versionPayload.versionInfo.versionMclf, &msg)) {
+ LOG_E("%s", msg);
+ failed = true;
+ }
+ LOG_I_RELEASE("%s", msg);
+ if (!checkVersionOkCONTAINER(versionPayload.versionInfo.versionContainer, &msg)) {
+ LOG_E("%s", msg);
+ failed = true;
+ }
+ LOG_I_RELEASE("%s", msg);
+ }
+
+ if (failed) {
+ exit(1);
+ }
+}
+
+//------------------------------------------------------------------------------
+bool MobiCoreDriverDaemon::loadToken(uint8_t *token, uint32_t sosize)
+{
+ bool ret = false;
+ CWsm_ptr pWsm = NULL;
+ Connection *conn = NULL;
+
+ do {
+ LOG_I("registering L2 in kmod, p=%p, len=%i", token, sosize);
+
+ pWsm = mobiCoreDevice->registerWsmL2((addr_t) (token), sosize, 0);
+ if (pWsm == NULL) {
+ LOG_E("allocating WSM for Token failed");
+ break;
+ }
+
+ /* Initialize information data of LOAD_TOKEN command */
+ loadTokenData_t loadTokenData;
+ loadTokenData.addr = pWsm->physAddr;
+ loadTokenData.offs = ((uintptr_t) token) & 0xFFF;
+ loadTokenData.len = sosize;
+
+ conn = new Connection();
+ uint32_t mcRet = mobiCoreDevice->loadToken(conn, &loadTokenData);
+
+ /* Unregister physical memory from kernel module. This will also destroy
+ * the WSM object.
+ */
+ if (!mobiCoreDevice->unregisterWsmL2(pWsm)) {
+ LOG_E("Unregistering of WsmL2 failed.");
+ pWsm = NULL;
+ break;
+ }
+ pWsm = NULL;
+
+ if (mcRet != MC_MCP_RET_OK) {
+ LOG_E("LOAD_TOKEN error 0x%x", mcRet);
+ break;
+ }
+ ret = true;
+
+ } while (false);
+
+ delete pWsm;
+ delete conn;
+
+ return ret;
+}
+
+//------------------------------------------------------------------------------
+void MobiCoreDriverDaemon::installEndorsementToken(void)
+{
+ /* Look for tokens in the registry and pass them to <t-base for endorsement
+ * purposes.
+ */
+ LOG_I("Looking for suitable tokens");
+
+ mcSoAuthTokenCont_t authtoken;
+ mcSoAuthTokenCont_t authtokenbackup;
+ mcSoRootCont_t rootcont;
+ uint32_t sosize;
+ uint8_t *p = NULL;
+
+ // Search order: 1. authtoken 2. authtoken backup 3. root container
+ sosize = 0;
+ mcResult_t ret = mcRegistryReadAuthToken(&authtoken);
+ if (ret != MC_DRV_OK) {
+ LOG_I("Failed to read AuthToken (ret=%u). Trying AuthToken backup", ret);
+
+ ret = mcRegistryReadAuthTokenBackup(&authtokenbackup);
+ if (ret != MC_DRV_OK) {
+ LOG_I("Failed to read AuthToken backup (ret=%u). Trying Root Cont", ret);
+
+ sosize = sizeof(rootcont);
+ ret = mcRegistryReadRoot(&rootcont, &sosize);
+ if (ret != MC_DRV_OK) {
+ LOG_I("Failed to read Root Cont, (ret=%u).", ret);
+ LOG_W("Device endorsements not supported!");
+ sosize = 0;
+ } else {
+ LOG_I("Found Root Cont.");
+ p = (uint8_t *) &rootcont;
+ }
+
+ } else {
+ LOG_I("Found AuthToken backup.");
+ p = (uint8_t *) &authtokenbackup;
+ sosize = sizeof(authtokenbackup);
+ }
+
+ } else {
+ LOG_I("Found AuthToken.");
+ p = (uint8_t *) &authtoken;
+ sosize = sizeof(authtoken);
+ }
+
+ if (sosize) {
+ LOG_I("Found token of size: %u", sosize);
+ if (!loadToken(p, sosize)) {
+ LOG_E("Failed to pass token to <t-base. "
+ "Device endorsements disabled");
+ }
+ }
+}