1 /*
2 * Copyright (C) 2021 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 "device_auth_defines.h"
20 #include "hc_log.h"
21 #include "hc_mutex.h"
22 #include "hc_types.h"
23 #include "ipc_skeleton.h"
24 #include "ipc_adapt.h"
25 #include "ipc_callback_proxy.h"
26 #include "ipc_sdk.h"
27 #include "securec.h"
28
29 #ifdef __cplusplus
30 extern "C" {
31 #endif
32
33 static HcMutex g_cBMutex;
34
35 struct CbStubInfo {
36 SvcIdentity cbStub;
37 uint32_t cbDieId;
38 bool inUse;
39 };
40 static struct CbStubInfo g_cbStub[MAX_CBSTUB_SIZE];
41
42 IpcServiceCallMap *g_callMapTable = NULL;
43 int32_t g_maxCallMapSz = MAX_CALLMAP_SIZE;
44 int32_t g_callMapElemNum = 0;
45
46 #define BINDER_TYPE_ACQUIRE 1
47 #define BINDER_TYPE_ACQUIRE_AND_FREE 2
48 #define BINDER_TYPE_RELEASE 3
49
50 #define IPC_IO_BUFF_SZ 1024
51
ResetCallMap(void)52 void ResetCallMap(void)
53 {
54 g_maxCallMapSz = MAX_CALLMAP_SIZE;
55 if (g_callMapTable != NULL) {
56 HcFree(g_callMapTable);
57 g_callMapTable = NULL;
58 }
59 g_callMapElemNum = 0;
60 }
61
GetCallMethodByMethodId(int32_t methodId)62 static IpcServiceCall GetCallMethodByMethodId(int32_t methodId)
63 {
64 int32_t i;
65
66 if (g_callMapTable == NULL) {
67 return NULL;
68 }
69
70 for (i = 0; i < g_maxCallMapSz; i++) {
71 if ((g_callMapTable[i].methodId == methodId) && (g_callMapTable[i].method != NULL)) {
72 return g_callMapTable[i].method;
73 }
74 }
75 return NULL;
76 }
77
DecodeCallRequest(IpcIo * data,IpcDataInfo * paramsCache,int32_t cacheNum,int32_t * inParamNum)78 static int32_t DecodeCallRequest(IpcIo *data, IpcDataInfo *paramsCache, int32_t cacheNum, int32_t *inParamNum)
79 {
80 int32_t dataLen;
81 int32_t i;
82 int32_t ret;
83
84 ReadInt32(data, &dataLen);
85 if (dataLen <= 0) {
86 return HC_ERR_IPC_BAD_MESSAGE_LENGTH;
87 }
88
89 ReadInt32(data, inParamNum);
90 if ((*inParamNum < 0) || (*inParamNum > cacheNum)) {
91 LOGE("param number invalid, inParamNum(%d)", *inParamNum);
92 return HC_ERR_IPC_BAD_PARAM_NUM;
93 }
94 LOGI("request data length(%d), param number: %d", dataLen - sizeof(int32_t), *inParamNum);
95
96 uint32_t len = 0;
97 ReadUint32(data, &len); /* skip flat object length information */
98 for (i = 0; i < *inParamNum; i++) {
99 ret = DecodeIpcData((uintptr_t)data, &(paramsCache[i].type), &(paramsCache[i].val), &(paramsCache[i].valSz));
100 if (ret != HC_SUCCESS) {
101 LOGE("decode failed, ret %d", ret);
102 return ret;
103 }
104 LOGI("decode success, param type %d, val size %d", paramsCache[i].type, paramsCache[i].valSz);
105 }
106 return HC_SUCCESS;
107 }
108
GetMethodId(IpcIo * data,int32_t * methodId)109 static int32_t GetMethodId(IpcIo *data, int32_t *methodId)
110 {
111 ReadInt32(data, methodId);
112 LOGI("GetMethodId, id code %d", *methodId);
113 return HC_SUCCESS;
114 }
115
WithObject(int32_t methodId,IpcIo * data,IpcDataInfo * ipcData,int32_t * cnt)116 static void WithObject(int32_t methodId, IpcIo *data, IpcDataInfo *ipcData, int32_t *cnt)
117 {
118 if (!IsCallbackMethod(methodId)) {
119 return;
120 }
121 ReadInt32(data, &(ipcData->type));
122 ipcData->valSz = 0;
123 SvcIdentity tmp;
124 bool ret = ReadRemoteObject(data, &tmp);
125 if (!ret || (ipcData->type != PARAM_TYPE_CB_OBJECT)) {
126 LOGE("should with remote object, but failed, param type %d", ipcData->type);
127 return;
128 }
129 ShowIpcSvcInfo(&tmp);
130 ipcData->idx = SetRemoteObject(&tmp);
131 if (ipcData->idx >= 0) {
132 ipcData->val = (uint8_t *)(&(ipcData->idx));
133 LOGI("object trans success, set id %d", ipcData->idx);
134 (*cnt)++;
135 }
136 }
137
InitCbStubTable()138 void InitCbStubTable()
139 {
140 (void)InitHcMutex(&g_cBMutex);
141 (void)memset_s(g_cbStub, sizeof(g_cbStub), 0, sizeof(g_cbStub));
142 return;
143 }
144
LockCbStubTable(void)145 static void LockCbStubTable(void)
146 {
147 (void)g_cBMutex.lock(&g_cBMutex);
148 return;
149 }
150
UnLockCbStubTable(void)151 static void UnLockCbStubTable(void)
152 {
153 g_cBMutex.unlock(&g_cBMutex);
154 return;
155 }
156
DevAuthRequestCall(void * origin,IpcIo * req,IpcIo * reply)157 static int32_t DevAuthRequestCall(void *origin, IpcIo *req, IpcIo *reply)
158 {
159 int32_t ret;
160 int32_t methodId = -1;
161 int32_t reqParamNum = 0;
162 IpcDataInfo reqParams[MAX_REQUEST_PARAMS_NUM] = { { 0 } };
163 IpcServiceCall serviceCall = NULL;
164
165 (void)origin;
166 ret = GetMethodId(req, &methodId);
167 LOGI("request method id %d", methodId);
168 if (ret != HC_SUCCESS || methodId <= 0) {
169 LOGE("GetMethodId failed, ret = %d", ret);
170 return HC_ERR_IPC_METHOD_ID_INVALID;
171 }
172 serviceCall = GetCallMethodByMethodId(methodId);
173 if (serviceCall == NULL) {
174 return HC_ERR_IPC_METHOD_ID_INVALID;
175 }
176 ret = DecodeCallRequest(req, reqParams, MAX_REQUEST_PARAMS_NUM, &reqParamNum);
177 if (ret != HC_SUCCESS) {
178 return ret;
179 }
180 if (reqParamNum < (MAX_REQUEST_PARAMS_NUM - 1)) {
181 WithObject(methodId, req, &reqParams[reqParamNum], &reqParamNum);
182 }
183 return serviceCall(reqParams, reqParamNum, (uintptr_t)(reply));
184 }
185
186 static struct {
187 int32_t (*callCtx)(void *origin, IpcIo *req, IpcIo *reply);
188 int32_t reqId;
189 } g_reqCallMaps[] = {
190 {DevAuthRequestCall, DEV_AUTH_CALL_REQUEST},
191 };
192
OnRemoteInvoke(IServerProxy * iProxy,int32_t reqId,void * origin,IpcIo * req,IpcIo * reply)193 int32_t OnRemoteInvoke(IServerProxy *iProxy, int32_t reqId, void *origin, IpcIo *req, IpcIo *reply)
194 {
195 int32_t i;
196 int32_t n;
197 int32_t (*callCtx)(void *origin, IpcIo *req, IpcIo *reply) = NULL;
198 IpcIo replyTmp;
199 uint8_t dataBuff[IPC_IO_BUFF_SZ] = { 0 };
200 int32_t ret = HC_ERR_IPC_UNKNOW_OPCODE;
201
202 (void)origin;
203 (void)iProxy;
204 LOGI("request code %u", reqId);
205 n = sizeof(g_reqCallMaps) / sizeof(g_reqCallMaps[0]);
206 for (i = 0; i < n; i++) {
207 if ((int32_t)reqId == g_reqCallMaps[i].reqId) {
208 callCtx = g_reqCallMaps[i].callCtx;
209 break;
210 }
211 }
212 (void)memset_s(&replyTmp, sizeof(IpcIo), 0, sizeof(IpcIo));
213 IpcIoInit(&replyTmp, dataBuff, sizeof(dataBuff), 0);
214 if (callCtx) {
215 ret = callCtx(origin, req, &replyTmp);
216 }
217 WriteInt32(reply, ret);
218 if (reply != NULL) {
219 n = GetIpcIoDataLength(&replyTmp);
220 if (n > 0) {
221 WriteUint32(reply, n);
222 if (!WriteBuffer(reply, (const void *)(replyTmp.bufferBase + IpcIoBufferOffset()), n)) {
223 LOGI("WriteBuffer faild");
224 return HC_ERROR;
225 }
226 LOGI("form service result done, result length(%d)", n);
227 }
228 }
229 LOGI("done, request code %d, call result %d", reqId, ret);
230 return 0;
231 }
232
SetCallMap(IpcServiceCall method,int32_t methodId)233 int32_t SetCallMap(IpcServiceCall method, int32_t methodId)
234 {
235 int32_t len;
236 IpcServiceCallMap *callMapTmp = NULL;
237
238 if ((1 + g_callMapElemNum) > g_maxCallMapSz) {
239 g_maxCallMapSz += MAX_CALLMAP_SIZE;
240 if (g_callMapTable != NULL) {
241 callMapTmp = g_callMapTable;
242 g_callMapTable = NULL;
243 }
244 }
245 if (g_callMapTable == NULL) {
246 len = sizeof(IpcServiceCallMap) * g_maxCallMapSz;
247 g_callMapTable = (IpcServiceCallMap *)HcMalloc(len, 0);
248 if (g_callMapTable == NULL) {
249 return HC_ERR_ALLOC_MEMORY;
250 }
251 (void)memset_s(g_callMapTable, len, 0, len);
252 if (callMapTmp != NULL) {
253 errno_t eno = memcpy_s(g_callMapTable, len, callMapTmp, (sizeof(IpcServiceCallMap) * g_callMapElemNum));
254 if (eno != EOK) {
255 HcFree((void *)g_callMapTable);
256 g_callMapTable = callMapTmp;
257 g_maxCallMapSz -= MAX_CALLMAP_SIZE;
258 return HC_ERR_MEMORY_COPY;
259 }
260 HcFree((void *)callMapTmp);
261 callMapTmp = NULL;
262 }
263 }
264 g_callMapTable[g_callMapElemNum].method = method;
265 g_callMapTable[g_callMapElemNum].methodId = methodId;
266 g_callMapElemNum++;
267 return HC_SUCCESS;
268 }
269
SetRemoteObject(const SvcIdentity * object)270 int32_t SetRemoteObject(const SvcIdentity *object)
271 {
272 int32_t idx = -1;
273 int32_t i;
274
275 LockCbStubTable();
276 for (i = 0; i < MAX_CBSTUB_SIZE; i++) {
277 if (!g_cbStub[i].inUse) {
278 idx = i;
279 break;
280 }
281 }
282 LOGI("remote object cache index %d", idx);
283 if (idx == -1) {
284 UnLockCbStubTable();
285 return -1;
286 }
287 g_cbStub[idx].cbStub = *object;
288 g_cbStub[idx].cbDieId = 0;
289 g_cbStub[idx].inUse = true;
290 UnLockCbStubTable();
291 ShowIpcSvcInfo(&(g_cbStub[idx].cbStub));
292 return idx;
293 }
294
ClientDeathCallback(void * arg)295 static void ClientDeathCallback(void *arg)
296 {
297 int32_t callbackIdx = (int32_t)arg;
298
299 LOGI("remote is not actively, to reset local resource");
300 ResetIpcCallBackNodeByNodeId(callbackIdx);
301 }
302
AddCbDeathRecipient(int32_t cbStubIdx,int32_t cbDataIdx)303 void AddCbDeathRecipient(int32_t cbStubIdx, int32_t cbDataIdx)
304 {
305 int32_t ret;
306 uint32_t cbId = 0;
307 if ((cbStubIdx < 0) || (cbStubIdx >= MAX_CBSTUB_SIZE)) {
308 return;
309 }
310
311 LockCbStubTable();
312 if (!g_cbStub[cbStubIdx].inUse) {
313 UnLockCbStubTable();
314 return;
315 }
316 ret = AddDeathRecipient(g_cbStub[cbStubIdx].cbStub, ClientDeathCallback, (void *)cbDataIdx, &cbId);
317 if (ret == 0) {
318 g_cbStub[cbStubIdx].cbDieId = cbId;
319 }
320 UnLockCbStubTable();
321 LOGI("done, ret %d, callback stub idx %d", ret, cbStubIdx);
322 return;
323 }
324
ResetRemoteObject(int32_t idx)325 void ResetRemoteObject(int32_t idx)
326 {
327 if ((idx >= 0) && (idx < MAX_CBSTUB_SIZE)) {
328 LOGI("object idx %d", idx);
329 LockCbStubTable();
330 if (!g_cbStub[idx].inUse) {
331 UnLockCbStubTable();
332 return;
333 }
334 RemoveDeathRecipient(g_cbStub[idx].cbStub, g_cbStub[idx].cbDieId);
335 (void)memset_s(&(g_cbStub[idx].cbStub), sizeof(g_cbStub[idx].cbStub), 0, sizeof(g_cbStub[idx].cbStub));
336 g_cbStub[idx].inUse = false;
337 UnLockCbStubTable();
338 LOGI("remote object used done, idx %d", idx);
339 }
340 return;
341 }
342
ActCallback(int32_t objIdx,int32_t callbackId,uintptr_t cbHook,IpcIo * dataParcel,IpcIo * reply)343 void ActCallback(int32_t objIdx, int32_t callbackId, uintptr_t cbHook, IpcIo *dataParcel, IpcIo *reply)
344 {
345 if ((objIdx < 0) || (objIdx >= MAX_CBSTUB_SIZE) || (!g_cbStub[objIdx].inUse)) {
346 LOGW("nothing to do, callback id %d, remote object id %d", callbackId, objIdx);
347 return;
348 }
349
350 ShowIpcSvcInfo(&g_cbStub[objIdx].cbStub);
351 LockCbStubTable();
352 CbProxySendRequest(g_cbStub[objIdx].cbStub, callbackId, cbHook, dataParcel, reply);
353 UnLockCbStubTable();
354 return;
355 }
356
357 #ifdef __cplusplus
358 }
359 #endif
360