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