1 /*
2 * Copyright (C) 2021-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "ipc_dev_auth_stub.h"
17
18 #include "common_defs.h"
19 #include "hc_log.h"
20 #include "ipc_adapt.h"
21 #include "ipc_callback_stub.h"
22 #include "ipc_sdk_defines.h"
23 #include "permission_adapter.h"
24 #include "securec.h"
25 #include "system_ability_definition.h"
26 #include "hc_string_vector.h"
27 #include "hidump_adapter.h"
28 #include "string_ex.h"
29
30 #ifdef DEV_AUTH_SERVICE_BUILD
31 #include "account_task_manager.h"
32 #include "group_data_manager.h"
33 #include "hisysevent_adapter.h"
34 #endif
35
36 #ifdef DEV_AUTH_USE_JEMALLOC
37 #include "malloc.h"
38 #endif
39
40 using namespace std;
41 namespace OHOS {
42 static std::mutex g_cBMutex;
43
44 struct CbStubInfo {
45 sptr<IRemoteObject> cbStub;
46 bool inUse;
47 };
48 static struct CbStubInfo g_cbStub[MAX_CBSTUB_SIZE];
49 static bool g_cbStubInited = false;
50 static const uint32_t RESTORE_CODE = 14701;
51
52 #ifdef DEV_AUTH_SERVICE_BUILD
53 static const uint32_t DEFAULT_UPGRADE_OS_ACCOUNT_ID = 100;
54 #endif
55
56 #define MAX_DATA_LEN 102400
57
ServiceDevAuth(bool serialInvokeFlag)58 ServiceDevAuth::ServiceDevAuth(bool serialInvokeFlag) : IRemoteStub(serialInvokeFlag)
59 {}
60
~ServiceDevAuth()61 ServiceDevAuth::~ServiceDevAuth()
62 {
63 maxCallMapSz = MAX_CALLMAP_SIZE;
64 if (standardCallMapTable != nullptr) {
65 delete[] standardCallMapTable;
66 standardCallMapTable = nullptr;
67 }
68 callMapElemNum = 0;
69 }
70
Dump(int32_t fd,const std::vector<std::u16string> & args)71 int32_t ServiceDevAuth::Dump(int32_t fd, const std::vector<std::u16string> &args)
72 {
73 std::vector<std::string> strArgs;
74 for (auto arg : args) {
75 strArgs.emplace_back(Str16ToStr8(arg));
76 }
77 uint32_t argc = strArgs.size();
78 StringVector strArgVec = CreateStrVector();
79 for (uint32_t i = 0; i < argc; i++) {
80 HcString strArg = CreateString();
81 if (!StringSetPointer(&strArg, strArgs[i].c_str())) {
82 LOGE("Failed to set strArg!");
83 DeleteString(&strArg);
84 continue;
85 }
86 if (strArgVec.pushBackT(&strArgVec, strArg) == NULL) {
87 LOGE("Failed to push strArg to strArgVec!");
88 DeleteString(&strArg);
89 }
90 }
91 DEV_AUTH_DUMP(fd, &strArgVec);
92 DestroyStrVector(&strArgVec);
93 return 0;
94 }
95
GetCallMethodByMethodId(int32_t methodId)96 IpcServiceCall ServiceDevAuth::GetCallMethodByMethodId(int32_t methodId)
97 {
98 int32_t i;
99
100 if (standardCallMapTable == nullptr) {
101 return nullptr;
102 }
103
104 for (i = 0; i < maxCallMapSz; i++) {
105 if ((standardCallMapTable[i].methodId == methodId) && (standardCallMapTable[i].method != nullptr)) {
106 return standardCallMapTable[i].method;
107 }
108 }
109 return nullptr;
110 }
111
DecodeCallRequest(MessageParcel & data,IpcDataInfo * paramsCache,int32_t cacheNum,int32_t & inParamNum)112 static int32_t DecodeCallRequest(MessageParcel &data, IpcDataInfo *paramsCache, int32_t cacheNum, int32_t &inParamNum)
113 {
114 int32_t dataLen = 0;
115 int32_t i;
116 int32_t ret;
117
118 if (data.GetReadableBytes() == 0) {
119 return HC_SUCCESS;
120 }
121
122 if (data.GetReadableBytes() > MAX_DATA_LEN) {
123 LOGE("Data len over MAX_DATA_LEN");
124 return HC_ERR_IPC_BAD_MESSAGE_LENGTH;
125 }
126
127 if (data.GetReadableBytes() < sizeof(int32_t)) {
128 LOGE("Insufficient data available in IPC container. [Data]: dataLen");
129 return HC_ERR_IPC_BAD_MESSAGE_LENGTH;
130 }
131 data.ReadInt32(dataLen);
132 if (dataLen > static_cast<int32_t>(data.GetReadableBytes())) {
133 LOGE("Insufficient data available in IPC container. [Data]: data");
134 return HC_ERR_IPC_BAD_MESSAGE_LENGTH;
135 }
136
137 if (data.GetReadableBytes() < sizeof(int32_t)) {
138 LOGE("Insufficient data available in IPC container. [Data]: inParamNum");
139 return HC_ERR_IPC_BAD_MESSAGE_LENGTH;
140 }
141 data.ReadInt32(inParamNum);
142 if ((inParamNum < 0) || (inParamNum > cacheNum)) {
143 LOGE("param number invalid, inParamNum - %" LOG_PUB "d", inParamNum);
144 return HC_ERR_IPC_BAD_PARAM_NUM;
145 }
146
147 for (i = 0; i < inParamNum; i++) {
148 ret = DecodeIpcData(reinterpret_cast<uintptr_t>(&data), &(paramsCache[i].type),
149 &(paramsCache[i].val), &(paramsCache[i].valSz));
150 if (ret != HC_SUCCESS) {
151 LOGE("decode failed, ret %" LOG_PUB "d", ret);
152 return ret;
153 }
154 }
155 return HC_SUCCESS;
156 }
157
GetMethodId(MessageParcel & data,int32_t & methodId)158 static int32_t GetMethodId(MessageParcel &data, int32_t &methodId)
159 {
160 if (data.GetDataSize() < sizeof(int32_t)) {
161 LOGE("Insufficient data available in IPC container. [Data]: methodId");
162 return HC_ERR_IPC_CALL_DATA_LENGTH;
163 }
164 methodId = data.ReadInt32();
165 return HC_SUCCESS;
166 }
167
WithObject(int32_t methodId,MessageParcel & data,IpcDataInfo & ipcData,int32_t & cnt)168 static void WithObject(int32_t methodId, MessageParcel &data, IpcDataInfo &ipcData, int32_t &cnt)
169 {
170 if (!IsCallbackMethod(methodId)) {
171 return;
172 }
173 if (data.GetReadableBytes() < sizeof(int32_t)) {
174 LOGE("Insufficient data available in IPC container. [Data]: type");
175 return;
176 }
177 ipcData.type = data.ReadInt32();
178 ipcData.valSz = sizeof(StubDevAuthCb);
179 sptr<IRemoteObject> tmp = data.ReadRemoteObject();
180 if (!tmp) {
181 LOGE("should with remote object, but read failed");
182 return;
183 }
184 ipcData.idx = ServiceDevAuth::SetRemoteObject(tmp);
185 if (ipcData.idx >= 0) {
186 ipcData.val = reinterpret_cast<uint8_t *>(&(ipcData.idx));
187 LOGI("object trans success, set id %" LOG_PUB "d", ipcData.idx);
188 cnt++;
189 }
190 }
191
InitCbStubTable()192 static void InitCbStubTable()
193 {
194 int32_t i;
195 if (g_cbStubInited) {
196 return;
197 }
198 std::lock_guard<std::mutex> autoLock(g_cBMutex);
199 if (g_cbStubInited) { /* for first init at the same time */
200 return;
201 }
202 for (i = 0; i < MAX_CBSTUB_SIZE; i++) {
203 g_cbStub[i].inUse = false;
204 }
205 g_cbStubInited = true;
206 return;
207 }
208
HandleRestoreCall(MessageParcel & data,MessageParcel & reply)209 int32_t ServiceDevAuth::HandleRestoreCall(MessageParcel &data, MessageParcel &reply)
210 {
211 #ifdef DEV_AUTH_SERVICE_BUILD
212 int32_t osAccountId = DEFAULT_UPGRADE_OS_ACCOUNT_ID;
213 data.ReadInt32(osAccountId);
214 LOGI("Begin to upgrade data for osAccountId: %" LOG_PUB "d.", osAccountId);
215 int32_t res = ExecuteAccountAuthCmd(osAccountId, UPGRADE_DATA, nullptr, nullptr);
216 ReloadOsAccountDb(osAccountId);
217 if (res != HC_SUCCESS) {
218 LOGE("Failed to upgrade data!");
219 DEV_AUTH_REPORT_FAULT_EVENT_WITH_ERR_CODE(UPGRADE_DATA_EVENT, PROCESS_UPDATE, res);
220 }
221 reply.WriteInt32(res);
222 #else
223 (void)data;
224 (void)reply;
225 #endif
226 return 0;
227 }
228
HandleDeviceAuthCall(uint32_t code,MessageParcel & data,MessageParcel & reply,MessageOption & option)229 int32_t ServiceDevAuth::HandleDeviceAuthCall(uint32_t code, MessageParcel &data, MessageParcel &reply,
230 MessageOption &option)
231 {
232 SET_LOG_MODE(NORMAL_MODE);
233 int32_t ret = HC_ERR_IPC_UNKNOW_OPCODE;
234 uint32_t dataLen;
235 int32_t methodId = 0;
236 int32_t reqParamNum = 0;
237 MessageParcel replyCache;
238 IpcDataInfo reqParams[MAX_REQUEST_PARAMS_NUM] = { { 0 } };
239 IpcServiceCall serviceCall = nullptr;
240
241 switch (code) {
242 case static_cast<uint32_t>(DevAuthInterfaceCode::DEV_AUTH_CALL_REQUEST):
243 ret = GetMethodId(data, methodId);
244 if (ret != HC_SUCCESS) {
245 break;
246 }
247 if (CheckPermission(methodId) != HC_SUCCESS) {
248 return -1;
249 }
250 serviceCall = GetCallMethodByMethodId(methodId);
251 if (serviceCall == nullptr) {
252 LOGE("ServiceDevAuth::HandleDeviceAuthCall serviceCall is nullptr, methodId: %" LOG_PUB "d", methodId);
253 ret = HC_ERR_IPC_METHOD_ID_INVALID;
254 break;
255 }
256 ret = DecodeCallRequest(data, reqParams, MAX_REQUEST_PARAMS_NUM, reqParamNum);
257 if (ret != HC_SUCCESS) {
258 LOGE("ServiceDevAuth::HandleDeviceAuthCall DecodeCallRequest ret: %" LOG_PUB "d", ret);
259 break;
260 }
261 if (reqParamNum < (MAX_REQUEST_PARAMS_NUM - 1)) {
262 InitCbStubTable();
263 WithObject(methodId, data, reqParams[reqParamNum], reqParamNum);
264 }
265 ret = serviceCall(reqParams, reqParamNum, reinterpret_cast<uintptr_t>(&replyCache));
266 break;
267 default:
268 return IPCObjectStub::OnRemoteRequest(code, data, reply, option);
269 }
270 reply.WriteInt32(ret);
271 dataLen = replyCache.GetDataSize();
272 if (dataLen > 0) {
273 reply.WriteInt32(dataLen);
274 reply.WriteBuffer(reinterpret_cast<const void *>(replyCache.GetData()), dataLen);
275 }
276 return 0;
277 }
278
DevAuthInitMemoryPolicy(void)279 static void DevAuthInitMemoryPolicy(void)
280 {
281 #ifdef DEV_AUTH_USE_JEMALLOC
282 (void)mallopt(M_SET_THREAD_CACHE, M_THREAD_CACHE_DISABLE);
283 (void)mallopt(M_DELAYED_FREE, M_DELAYED_FREE_DISABLE);
284 #endif
285 }
286
OnRemoteRequest(uint32_t code,MessageParcel & data,MessageParcel & reply,MessageOption & option)287 int32_t ServiceDevAuth::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply,
288 MessageOption &option)
289 {
290 DevAuthInitMemoryPolicy();
291 std::u16string readToken = data.ReadInterfaceToken();
292 bool isRestoreCall = ((code == RESTORE_CODE) && (readToken == std::u16string(u"OHOS.Updater.RestoreData")));
293 if (readToken != GetDescriptor() && !isRestoreCall) {
294 LOGE("[IPC][C->S]: The proxy interface token is invalid!");
295 return -1;
296 }
297 if (isRestoreCall) {
298 return HandleRestoreCall(data, reply);
299 } else {
300 return HandleDeviceAuthCall(code, data, reply, option);
301 }
302 }
303
SetCallMap(IpcServiceCall method,int32_t methodId)304 int32_t ServiceDevAuth::SetCallMap(IpcServiceCall method, int32_t methodId)
305 {
306 int32_t len;
307 errno_t eno;
308 IpcServiceCallMap *callMapTmp = nullptr;
309
310 if ((1 + callMapElemNum) > maxCallMapSz) {
311 maxCallMapSz += MAX_CALLMAP_SIZE;
312 if (standardCallMapTable != nullptr) {
313 callMapTmp = standardCallMapTable;
314 standardCallMapTable = nullptr;
315 }
316 }
317 if (standardCallMapTable == nullptr) {
318 standardCallMapTable = new(std::nothrow) IpcServiceCallMap[maxCallMapSz];
319 if (standardCallMapTable == nullptr) {
320 return HC_ERR_ALLOC_MEMORY;
321 }
322 len = sizeof(IpcServiceCallMap) * maxCallMapSz;
323 (void)memset_s(standardCallMapTable, len, 0, len);
324 if (callMapTmp != nullptr) {
325 eno = memcpy_s(standardCallMapTable, len, callMapTmp, (sizeof(IpcServiceCallMap) * callMapElemNum));
326 if (eno != EOK) {
327 delete[] standardCallMapTable;
328 standardCallMapTable = callMapTmp;
329 maxCallMapSz -= MAX_CALLMAP_SIZE;
330 return HC_ERR_MEMORY_COPY;
331 }
332 delete[] callMapTmp;
333 callMapTmp = nullptr;
334 }
335 }
336
337 standardCallMapTable[callMapElemNum].method = method;
338 standardCallMapTable[callMapElemNum].methodId = methodId;
339 callMapElemNum++;
340 return HC_SUCCESS;
341 }
342
SetRemoteObject(sptr<IRemoteObject> & object)343 int32_t ServiceDevAuth::SetRemoteObject(sptr<IRemoteObject> &object)
344 {
345 int32_t idx = -1;
346 int32_t i;
347
348 std::lock_guard<std::mutex> autoLock(g_cBMutex);
349 for (i = 0; i < MAX_CBSTUB_SIZE; i++) {
350 if (!g_cbStub[i].inUse) {
351 idx = i;
352 break;
353 }
354 }
355 LOGI("remote object cache index %" LOG_PUB "d", idx);
356 if (idx == -1) {
357 return -1;
358 }
359 g_cbStub[idx].cbStub = object;
360 g_cbStub[idx].inUse = true;
361 return idx;
362 }
363
AddCbDeathRecipient(int32_t cbStubIdx,int32_t cbDataIdx)364 void ServiceDevAuth::AddCbDeathRecipient(int32_t cbStubIdx, int32_t cbDataIdx)
365 {
366 bool bRet = false;
367 if ((cbStubIdx < 0) || (cbStubIdx >= MAX_CBSTUB_SIZE) || (!g_cbStub[cbStubIdx].inUse)) {
368 return;
369 }
370
371 std::lock_guard<std::mutex> autoLock(g_cBMutex);
372 DevAuthDeathRecipient *deathRecipient = new(std::nothrow) DevAuthDeathRecipient(cbDataIdx);
373 if (deathRecipient == nullptr) {
374 LOGE("Failed to create death recipient");
375 return;
376 }
377 bRet = g_cbStub[cbStubIdx].cbStub->AddDeathRecipient(deathRecipient);
378 LOGI("AddDeathRecipient %" LOG_PUB "s, callback stub idx %" LOG_PUB "d", bRet ? "success" : "failed", cbStubIdx);
379 return;
380 }
381
ResetRemoteObject(int32_t idx)382 void ServiceDevAuth::ResetRemoteObject(int32_t idx)
383 {
384 if ((idx >= 0) && (idx < MAX_CBSTUB_SIZE)) {
385 LOGI("remote object used done, idx %" LOG_PUB "d", idx);
386 std::lock_guard<std::mutex> autoLock(g_cBMutex);
387 g_cbStub[idx].inUse = false;
388 }
389 return;
390 }
391
ActCallback(int32_t objIdx,int32_t callbackId,bool sync,uintptr_t cbHook,MessageParcel & dataParcel,MessageParcel & reply)392 void ServiceDevAuth::ActCallback(int32_t objIdx, int32_t callbackId, bool sync,
393 uintptr_t cbHook, MessageParcel &dataParcel, MessageParcel &reply)
394 {
395 if ((objIdx < 0) || (objIdx >= MAX_CBSTUB_SIZE) || (!g_cbStub[objIdx].inUse)) {
396 LOGW("nothing to do, callback id %" LOG_PUB "d, remote object id %" LOG_PUB "d", callbackId, objIdx);
397 return;
398 }
399 MessageOption option(MessageOption::TF_SYNC);
400 if (!sync) {
401 option.SetFlags(MessageOption::TF_ASYNC);
402 }
403 std::lock_guard<std::mutex> autoLock(g_cBMutex);
404 sptr<ICommIpcCallback> proxy = iface_cast<ICommIpcCallback>(g_cbStub[objIdx].cbStub);
405 proxy->DoCallBack(callbackId, cbHook, dataParcel, reply, option);
406 return;
407 }
408
DevAuthDeathRecipient(int32_t cbIdx)409 DevAuthDeathRecipient::DevAuthDeathRecipient(int32_t cbIdx)
410 {
411 callbackIdx = cbIdx;
412 }
413 }
414