1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "chre/platform/platform_nanoapp.h"
18 #include "chre/platform/shared/libc/dlfcn.h"
19 #include "chre/platform/shared/memory.h"
20 #include "chre/platform/shared/nanoapp_dso_util.h"
21 #include "chre/util/system/napp_permissions.h"
22 
23 #include <cinttypes>
24 
25 namespace chre {
26 
~PlatformNanoapp()27 PlatformNanoapp::~PlatformNanoapp() {}
28 
reserveBuffer(uint64_t appId,uint32_t appVersion,uint32_t appFlags,size_t appBinaryLen,uint32_t targetApiVersion)29 bool PlatformNanoappBase::reserveBuffer(uint64_t appId, uint32_t appVersion,
30                                         uint32_t appFlags, size_t appBinaryLen,
31                                         uint32_t targetApiVersion) {
32   CHRE_ASSERT(!isLoaded());
33 
34   bool success = false;
35   mAppBinary = memoryAlloc(appBinaryLen);
36 
37   // TODO(b/237819962): Check binary signature when authentication is
38   // implemented.
39   if (mAppBinary == nullptr) {
40     LOG_OOM();
41   } else {
42     mExpectedAppId = appId;
43     mExpectedAppVersion = appVersion;
44     mExpectedTargetApiVersion = targetApiVersion;
45     mAppBinaryLen = appBinaryLen;
46     success = true;
47   }
48 
49   return success;
50 }
51 
copyNanoappFragment(const void * buffer,size_t bufferLen)52 bool PlatformNanoappBase::copyNanoappFragment(const void *buffer,
53                                               size_t bufferLen) {
54   CHRE_ASSERT(!isLoaded());
55 
56   bool success = true;
57 
58   if ((mBytesLoaded + bufferLen) > mAppBinaryLen) {
59     LOGE("Overflow: cannot load %zu bytes to %zu/%zu nanoapp binary buffer",
60          bufferLen, mBytesLoaded, mAppBinaryLen);
61     success = false;
62   } else {
63     uint8_t *binaryBuffer = static_cast<uint8_t *>(mAppBinary) + mBytesLoaded;
64     memcpy(binaryBuffer, buffer, bufferLen);
65     mBytesLoaded += bufferLen;
66   }
67   return success;
68 }
69 
start()70 bool PlatformNanoapp::start() {
71   bool success = false;
72 
73   if (!openNanoapp()) {
74     LOGE("Failed to open the nanoapp");
75   } else if (mAppInfo != nullptr) {
76     success = mAppInfo->entryPoints.start();
77   } else {
78     LOGE("app info was null - unable to start nanoapp");
79   }
80 
81   return success;
82 }
83 
handleEvent(uint32_t senderInstanceId,uint16_t eventType,const void * eventData)84 void PlatformNanoapp::handleEvent(uint32_t senderInstanceId, uint16_t eventType,
85                                   const void *eventData) {
86   mAppInfo->entryPoints.handleEvent(senderInstanceId, eventType, eventData);
87 }
88 
end()89 void PlatformNanoapp::end() {
90   mAppInfo->entryPoints.end();
91 }
92 
getAppId() const93 uint64_t PlatformNanoapp::getAppId() const {
94   return mAppInfo->appId;
95 }
96 
getAppVersion() const97 uint32_t PlatformNanoapp::getAppVersion() const {
98   return mAppInfo->appVersion;
99 }
100 
getTargetApiVersion() const101 uint32_t PlatformNanoapp::getTargetApiVersion() const {
102   return mAppInfo->targetApiVersion;
103 }
isSystemNanoapp() const104 bool PlatformNanoapp::isSystemNanoapp() const {
105   return mAppInfo->isSystemNanoapp;
106 }
107 
getAppName() const108 const char *PlatformNanoapp::getAppName() const {
109   return (mAppInfo != nullptr) ? mAppInfo->name : "Unknown";
110 }
111 
isLoaded() const112 bool PlatformNanoappBase::isLoaded() const {
113   return (mIsStatic ||
114           (mAppBinary != nullptr && mBytesLoaded == mAppBinaryLen) ||
115           mDsoHandle != nullptr);
116 }
117 
loadStatic(const struct chreNslNanoappInfo * appInfo)118 void PlatformNanoappBase::loadStatic(const struct chreNslNanoappInfo *appInfo) {
119   CHRE_ASSERT(!isLoaded());
120   mIsStatic = true;
121   mAppInfo = appInfo;
122 }
123 
supportsAppPermissions() const124 bool PlatformNanoapp::supportsAppPermissions() const {
125   return (mAppInfo != nullptr) ? (mAppInfo->structMinorVersion >=
126                                   CHRE_NSL_NANOAPP_INFO_STRUCT_MINOR_VERSION_3)
127                                : false;
128 }
129 
getAppPermissions() const130 uint32_t PlatformNanoapp::getAppPermissions() const {
131   return (supportsAppPermissions())
132              ? mAppInfo->appPermissions
133              : static_cast<uint32_t>(chre::NanoappPermissions::CHRE_PERMS_NONE);
134 }
135 
verifyNanoappInfo()136 bool PlatformNanoappBase::verifyNanoappInfo() {
137   bool success = false;
138 
139   if (mDsoHandle == nullptr) {
140     LOGE("No nanoapp info to verify");
141   } else {
142     mAppInfo = static_cast<const struct chreNslNanoappInfo *>(
143         dlsym(mDsoHandle, CHRE_NSL_DSO_NANOAPP_INFO_SYMBOL_NAME));
144     if (mAppInfo == nullptr) {
145       LOGE("Failed to find app info symbol");
146     } else {
147       mAppUnstableId = mAppInfo->appVersionString;
148       if (mAppUnstableId == nullptr) {
149         LOGE("Failed to find unstable ID symbol");
150       } else {
151         success = validateAppInfo(mExpectedAppId, mExpectedAppVersion,
152                                   mExpectedTargetApiVersion, mAppInfo);
153         if (!success) {
154           mAppInfo = nullptr;
155         } else {
156           LOGI("Nanoapp loaded: %s (0x%016" PRIx64 ") version 0x%" PRIx32
157                " (%s) uimg %d system %d",
158                mAppInfo->name, mAppInfo->appId, mAppInfo->appVersion,
159                mAppInfo->appVersionString, mAppInfo->isTcmNanoapp,
160                mAppInfo->isSystemNanoapp);
161           if (mAppInfo->structMinorVersion >=
162               CHRE_NSL_NANOAPP_INFO_STRUCT_MINOR_VERSION_3) {
163             LOGI("Nanoapp permissions: 0x%" PRIx32, mAppInfo->appPermissions);
164           }
165         }
166       }
167     }
168   }
169   return success;
170 }
171 
openNanoapp()172 bool PlatformNanoappBase::openNanoapp() {
173   bool success = false;
174   if (mIsStatic) {
175     success = true;
176   } else if (mAppBinary != nullptr) {
177     if (mDsoHandle != nullptr) {
178       LOGE("Trying to reopen an existing buffer");
179     } else {
180       mDsoHandle = dlopenbuf(mAppBinary, false /* mapIntoTcm */);
181       success = verifyNanoappInfo();
182     }
183   }
184 
185   if (!success) {
186     closeNanoapp();
187   }
188 
189   if (mAppBinary != nullptr) {
190     nanoappBinaryDramFree(mAppBinary);
191     mAppBinary = nullptr;
192   }
193 
194   return success;
195 }
196 
closeNanoapp()197 void PlatformNanoappBase::closeNanoapp() {
198   if (mDsoHandle != nullptr) {
199     // Force DRAM access since dl* functions are only safe to call with DRAM
200     // available.
201     forceDramAccess();
202     mAppInfo = nullptr;
203     if (dlclose(mDsoHandle) != 0) {
204       LOGE("dlclose failed");
205     }
206     mDsoHandle = nullptr;
207   }
208 }
209 
210 }  // namespace chre
211