19d5b500a223ef73560f0dce38f50b809bde5dd0dBrian Duddie/* 29d5b500a223ef73560f0dce38f50b809bde5dd0dBrian Duddie * Copyright (C) 2017 The Android Open Source Project 39d5b500a223ef73560f0dce38f50b809bde5dd0dBrian Duddie * 49d5b500a223ef73560f0dce38f50b809bde5dd0dBrian Duddie * Licensed under the Apache License, Version 2.0 (the "License"); 59d5b500a223ef73560f0dce38f50b809bde5dd0dBrian Duddie * you may not use this file except in compliance with the License. 69d5b500a223ef73560f0dce38f50b809bde5dd0dBrian Duddie * You may obtain a copy of the License at 79d5b500a223ef73560f0dce38f50b809bde5dd0dBrian Duddie * 89d5b500a223ef73560f0dce38f50b809bde5dd0dBrian Duddie * http://www.apache.org/licenses/LICENSE-2.0 99d5b500a223ef73560f0dce38f50b809bde5dd0dBrian Duddie * 109d5b500a223ef73560f0dce38f50b809bde5dd0dBrian Duddie * Unless required by applicable law or agreed to in writing, software 119d5b500a223ef73560f0dce38f50b809bde5dd0dBrian Duddie * distributed under the License is distributed on an "AS IS" BASIS, 129d5b500a223ef73560f0dce38f50b809bde5dd0dBrian Duddie * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139d5b500a223ef73560f0dce38f50b809bde5dd0dBrian Duddie * See the License for the specific language governing permissions and 149d5b500a223ef73560f0dce38f50b809bde5dd0dBrian Duddie * limitations under the License. 159d5b500a223ef73560f0dce38f50b809bde5dd0dBrian Duddie */ 169d5b500a223ef73560f0dce38f50b809bde5dd0dBrian Duddie 179d5b500a223ef73560f0dce38f50b809bde5dd0dBrian Duddie#include "chre/platform/platform_nanoapp.h" 189d5b500a223ef73560f0dce38f50b809bde5dd0dBrian Duddie 1947a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie#include "chre/platform/assert.h" 2047a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie#include "chre/platform/log.h" 2147a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie#include "chre/platform/memory.h" 2247a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie#include "chre/platform/shared/nanoapp_support_lib_dso.h" 2347a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie#include "chre_api/chre/version.h" 2447a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie 2547a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie#include "dlfcn.h" 2647a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie 2747a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie#include <inttypes.h> 2847a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie#include <string.h> 2947a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie 309d5b500a223ef73560f0dce38f50b809bde5dd0dBrian Duddienamespace chre { 319d5b500a223ef73560f0dce38f50b809bde5dd0dBrian Duddie 3247a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddienamespace { 3347a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie 3447a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie/** 3547a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie * Performs sanity checks on the app info structure included in a dynamically 3647a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie * loaded nanoapp. 3747a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie * 3847a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie * @param expectedAppId 3947a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie * @param expectedAppVersion 4047a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie * @param appInfo 4147a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie * 4247a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie * @return true if validation was successful 4347a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie */ 4447a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddiebool validateAppInfo(uint64_t expectedAppId, uint32_t expectedAppVersion, 4547a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie const struct chreNslNanoappInfo *appInfo) { 4647a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie uint32_t ourApiMajorVersion = CHRE_EXTRACT_MAJOR_VERSION(chreGetApiVersion()); 4747a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie uint32_t targetApiMajorVersion = CHRE_EXTRACT_MAJOR_VERSION( 4847a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie appInfo->targetApiVersion); 4947a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie 5047a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie bool success = false; 5147a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie if (appInfo->magic != CHRE_NSL_NANOAPP_INFO_MAGIC) { 5247a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie LOGE("Invalid app info magic: got 0x%08" PRIx32 " expected 0x%08" PRIx32, 5347a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie appInfo->magic, CHRE_NSL_NANOAPP_INFO_MAGIC); 5447a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie } else if (appInfo->appId == 0) { 5547a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie LOGE("Rejecting invalid app ID 0"); 5647a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie } else if (expectedAppId != appInfo->appId) { 5747a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie LOGE("Expected app ID (0x%016" PRIx64 ") doesn't match internal one (0x%016" 5847a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie PRIx64 ")", expectedAppId, appInfo->appId); 5947a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie } else if (expectedAppVersion != appInfo->appVersion) { 6047a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie LOGE("Expected app version (0x%" PRIx32 ") doesn't match internal one (0x%" 6147a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie PRIx32 ")", expectedAppVersion, appInfo->appVersion); 6247a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie } else if (targetApiMajorVersion != ourApiMajorVersion) { 6347a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie LOGE("App targets a different major API version (%" PRIu32 ") than what we " 6447a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie "provide (%" PRIu32 ")", targetApiMajorVersion, ourApiMajorVersion); 6547a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie } else if (strlen(appInfo->name) > CHRE_NSL_DSO_NANOAPP_STRING_MAX_LEN) { 6647a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie LOGE("App name is too long"); 6747a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie } else if (strlen(appInfo->name) > CHRE_NSL_DSO_NANOAPP_STRING_MAX_LEN) { 6847a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie LOGE("App vendor is too long"); 6947a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie } else { 7047a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie success = true; 7147a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie } 7247a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie 7347a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie return success; 7447a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie} 7547a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie 7647a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie} // anonymous namespace 7747a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie 7847a99dc3cacacb0418548609c0e2d3b2b70d821eBrian DuddiePlatformNanoapp::~PlatformNanoapp() { 7947a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie closeNanoapp(); 8047a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie if (mAppBinary != nullptr) { 8147a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie memoryFree(mAppBinary); 8247a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie } 8347a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie} 849d5b500a223ef73560f0dce38f50b809bde5dd0dBrian Duddie 859d5b500a223ef73560f0dce38f50b809bde5dd0dBrian Duddiebool PlatformNanoapp::start() { 8647a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie // Invoke the start entry point after successfully opening the app 8747a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie return (mIsStatic || openNanoapp()) ? mAppInfo->entryPoints.start() : false; 889d5b500a223ef73560f0dce38f50b809bde5dd0dBrian Duddie} 899d5b500a223ef73560f0dce38f50b809bde5dd0dBrian Duddie 909d5b500a223ef73560f0dce38f50b809bde5dd0dBrian Duddievoid PlatformNanoapp::handleEvent(uint32_t senderInstanceId, 919d5b500a223ef73560f0dce38f50b809bde5dd0dBrian Duddie uint16_t eventType, 929d5b500a223ef73560f0dce38f50b809bde5dd0dBrian Duddie const void *eventData) { 939d5b500a223ef73560f0dce38f50b809bde5dd0dBrian Duddie mAppInfo->entryPoints.handleEvent(senderInstanceId, eventType, eventData); 949d5b500a223ef73560f0dce38f50b809bde5dd0dBrian Duddie} 959d5b500a223ef73560f0dce38f50b809bde5dd0dBrian Duddie 962b9d71a9f6a9e8cc0e787957d022154231f29962Brian Duddievoid PlatformNanoapp::end() { 972b9d71a9f6a9e8cc0e787957d022154231f29962Brian Duddie mAppInfo->entryPoints.end(); 9847a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie closeNanoapp(); 9947a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie} 10047a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie 10147a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddiebool PlatformNanoappBase::loadFromBuffer(uint64_t appId, uint32_t appVersion, 10247a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie const void *appBinary, 10347a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie size_t appBinaryLen) { 10447a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie CHRE_ASSERT(!isLoaded()); 10547a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie bool success = false; 10647a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie constexpr size_t kMaxAppSize = 2 * 1024 * 1024; // 2 MiB 10747a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie 10847a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie if (appBinaryLen > kMaxAppSize) { 10947a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie LOGE("Rejecting app size %zu above limit %zu", appBinaryLen, kMaxAppSize); 11047a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie } else { 11147a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie mAppBinary = memoryAlloc(appBinaryLen); 11247a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie if (mAppBinary == nullptr) { 11347a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie LOGE("Couldn't allocate %zu byte buffer for nanoapp 0x%016" PRIx64, 11447a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie appBinaryLen, appId); 11547a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie } else { 11647a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie mExpectedAppId = appId; 11747a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie mExpectedAppVersion = appVersion; 11847a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie mAppBinaryLen = appBinaryLen; 11947a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie memcpy(mAppBinary, appBinary, appBinaryLen); 12047a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie success = true; 12147a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie } 12247a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie } 12347a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie 12447a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie return success; 1259d5b500a223ef73560f0dce38f50b809bde5dd0dBrian Duddie} 1269d5b500a223ef73560f0dce38f50b809bde5dd0dBrian Duddie 1279d5b500a223ef73560f0dce38f50b809bde5dd0dBrian Duddievoid PlatformNanoappBase::loadStatic(const struct chreNslNanoappInfo *appInfo) { 12847a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie CHRE_ASSERT(!isLoaded()); 12947a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie mIsStatic = true; 1309d5b500a223ef73560f0dce38f50b809bde5dd0dBrian Duddie mAppInfo = appInfo; 1319d5b500a223ef73560f0dce38f50b809bde5dd0dBrian Duddie} 1329d5b500a223ef73560f0dce38f50b809bde5dd0dBrian Duddie 13347a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddiebool PlatformNanoappBase::isLoaded() const { 13447a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie return (mIsStatic || mAppBinary != nullptr); 13547a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie} 13647a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie 13747a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddievoid PlatformNanoappBase::closeNanoapp() { 13847a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie if (mDsoHandle != nullptr) { 13947a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie if (dlclose(mDsoHandle) != 0) { 14047a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie const char *name = (mAppInfo != nullptr) ? mAppInfo->name : "unknown"; 14147a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie LOGE("dlclose of %s failed: %s", name, dlerror()); 14247a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie } 14347a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie mDsoHandle = nullptr; 14447a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie } 14547a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie} 14647a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie 14747a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddiebool PlatformNanoappBase::openNanoapp() { 14847a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie bool success = false; 14947a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie 15047a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie // Populate a filename string (just a requirement of the dlopenbuf API) 15147a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie constexpr size_t kMaxFilenameLen = 17; 15247a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie char filename[kMaxFilenameLen]; 15347a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie snprintf(filename, sizeof(filename), "%016" PRIx64, mExpectedAppId); 15447a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie 15547a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie CHRE_ASSERT(mAppBinary != nullptr); 15647a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie CHRE_ASSERT_LOG(mDsoHandle == nullptr, "Re-opening nanoapp"); 15747a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie mDsoHandle = dlopenbuf( 15847a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie filename, static_cast<const char *>(mAppBinary), 15947a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie static_cast<int>(mAppBinaryLen), RTLD_NOW); 16047a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie if (mDsoHandle == nullptr) { 16147a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie LOGE("Failed to load nanoapp: %s", dlerror()); 16247a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie } else { 16347a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie mAppInfo = static_cast<const struct chreNslNanoappInfo *>( 16447a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie dlsym(mDsoHandle, CHRE_NSL_DSO_NANOAPP_INFO_SYMBOL_NAME)); 16547a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie if (mAppInfo == nullptr) { 16647a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie LOGE("Failed to find app info symbol: %s", dlerror()); 16747a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie } else { 16847a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie success = validateAppInfo(mExpectedAppId, mExpectedAppVersion, mAppInfo); 16947a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie if (!success) { 17047a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie mAppInfo = nullptr; 17147a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie } else { 17247a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie LOGI("Successfully loaded nanoapp: %s (0x%016" PRIx64 ") version 0x%" 17347a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie PRIx32, mAppInfo->name, mAppInfo->appId, mAppInfo->appVersion); 17447a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie } 17547a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie } 17647a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie } 17747a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie 17847a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie return success; 17947a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie} 18047a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie 1819d5b500a223ef73560f0dce38f50b809bde5dd0dBrian Duddieuint64_t PlatformNanoapp::getAppId() const { 18247a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie return (mAppInfo != nullptr) ? mAppInfo->appId : mExpectedAppId; 1839d5b500a223ef73560f0dce38f50b809bde5dd0dBrian Duddie} 1849d5b500a223ef73560f0dce38f50b809bde5dd0dBrian Duddie 1859d5b500a223ef73560f0dce38f50b809bde5dd0dBrian Duddieuint32_t PlatformNanoapp::getAppVersion() const { 18647a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie return (mAppInfo != nullptr) ? mAppInfo->appVersion : mExpectedAppVersion; 1879d5b500a223ef73560f0dce38f50b809bde5dd0dBrian Duddie} 1889d5b500a223ef73560f0dce38f50b809bde5dd0dBrian Duddie 1899d5b500a223ef73560f0dce38f50b809bde5dd0dBrian Duddieuint32_t PlatformNanoapp::getTargetApiVersion() const { 19047a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie return (mAppInfo != nullptr) ? mAppInfo->targetApiVersion : 0; 1919d5b500a223ef73560f0dce38f50b809bde5dd0dBrian Duddie} 1929d5b500a223ef73560f0dce38f50b809bde5dd0dBrian Duddie 1939d5b500a223ef73560f0dce38f50b809bde5dd0dBrian Duddiebool PlatformNanoapp::isSystemNanoapp() const { 19447a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie // Right now, we assume that system nanoapps are always static nanoapps. Since 19547a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie // mAppInfo can only be null either prior to loading the app (in which case 19647a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie // this function is not expected to return a valid value anyway), or when a 19747a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie // dynamic nanoapp is not running, "false" is the correct return value in that 19847a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie // case. 19947a99dc3cacacb0418548609c0e2d3b2b70d821eBrian Duddie return (mAppInfo != nullptr) ? mAppInfo->isSystemNanoapp : false; 2009d5b500a223ef73560f0dce38f50b809bde5dd0dBrian Duddie} 2019d5b500a223ef73560f0dce38f50b809bde5dd0dBrian Duddie 2029d5b500a223ef73560f0dce38f50b809bde5dd0dBrian Duddie} // namespace chre 203