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