1 /*
2  * Copyright (c) 2021-2022 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 "hks_samgr_client.h"
17 #include "hks_request.h"
18 #include "hks_template.h"
19 #include "huks_service_ipc_interface_code.h"
20 
21 #include "iproxy_client.h"
22 #include "registry.h"
23 
24 #include <unistd.h>
25 
SynchronizeOutput(const struct HksIpcHandle * reply,struct HksBlob * outBlob)26 static int32_t SynchronizeOutput(const struct HksIpcHandle *reply, struct HksBlob *outBlob)
27 {
28     if (reply->state != HKS_IPC_MSG_OK) {
29         HKS_LOG_E("ipc reply failed, ret = %d", reply->state);
30         return HKS_ERROR_IPC_MSG_FAIL;
31     }
32 
33     int32_t callBackResult = HKS_ERROR_IPC_MSG_FAIL;
34     do {
35         bool ipcRet = ReadInt32(reply->io, &callBackResult);
36         if (!ipcRet) {
37             callBackResult = HKS_ERROR_IPC_MSG_FAIL;
38             break;
39         }
40 
41         bool isNoneResponse = true;
42         ipcRet = ReadBool(reply->io, &isNoneResponse);
43         if (!ipcRet) {
44             callBackResult = HKS_ERROR_IPC_MSG_FAIL;
45             break;
46         }
47         if (isNoneResponse) {
48             break;
49         }
50 
51         if (outBlob != NULL) {
52             uint32_t buffSize = 0;
53             ipcRet = ReadUint32(reply->io, &buffSize);
54             if (!ipcRet) {
55                 callBackResult = HKS_ERROR_IPC_MSG_FAIL;
56                 break;
57             }
58             if (buffSize == 0) {
59                 HKS_LOG_I("ipc reply with no out data");
60                 break;
61             }
62 
63             // the ipc will ensure the validity of data-reading within limited and valid data size
64             const uint8_t *tmpUint8Array = ReadBuffer(reply->io, buffSize);
65             if (tmpUint8Array == NULL) {
66                 callBackResult = HKS_ERROR_IPC_MSG_FAIL;
67                 break;
68             }
69 
70             if (memcpy_s(outBlob->data, outBlob->size, tmpUint8Array, buffSize) != EOK) {
71                 callBackResult = HKS_ERROR_BUFFER_TOO_SMALL;
72                 break;
73             }
74             outBlob->size = buffSize;
75         }
76     } while (0);
77 
78     return callBackResult;
79 }
80 
CurrentCallback(IOwner owner,int code,IpcIo * reply)81 static int CurrentCallback(IOwner owner, int code, IpcIo *reply)
82 {
83     (void)code;
84     struct HksIpcHandle *curReply = (struct HksIpcHandle *)owner;
85     if (curReply == NULL || reply == NULL) {
86         return HKS_ERROR_NULL_POINTER;
87     }
88     if (memcpy_s(curReply->io->bufferCur, curReply->io->bufferLeft, reply->bufferCur, reply->bufferLeft) != EOK) {
89         HKS_LOG_E("data copy for curReply failed, cur size is %zu, reply size is %zu", curReply->io->bufferLeft,
90             reply->bufferLeft);
91         curReply->state = HKS_IPC_MSG_ERROR;
92         curReply->io->bufferLeft = 0;
93         return HKS_ERROR_IPC_MSG_FAIL;
94     }
95     curReply->state = HKS_IPC_MSG_OK;
96     curReply->io->bufferLeft = reply->bufferLeft;
97     return HKS_SUCCESS;
98 }
99 
WriteToIpcRequest(IpcIo * request,uint32_t outBlobSize,const struct HksBlob * inBlob)100 static int32_t WriteToIpcRequest(IpcIo *request, uint32_t outBlobSize, const struct HksBlob *inBlob)
101 {
102     bool ipcRet = WriteUint32(request, outBlobSize);
103     if (!ipcRet) {
104         return HKS_ERROR_IPC_MSG_FAIL;
105     }
106     ipcRet = WriteUint32(request, inBlob->size);
107     if (!ipcRet) {
108         return HKS_ERROR_IPC_MSG_FAIL;
109     }
110     ipcRet = WriteBuffer(request, inBlob->data, inBlob->size);
111     if (!ipcRet) {
112         return HKS_ERROR_IPC_MSG_FAIL;
113     }
114     return HKS_SUCCESS;
115 }
116 
HksIpcCall(IUnknown * iUnknown,enum HksIpcInterfaceCode type,const struct HksBlob * inBlob,struct HksBlob * outBlob)117 static int32_t HksIpcCall(IUnknown *iUnknown, enum HksIpcInterfaceCode type, const struct HksBlob *inBlob,
118     struct HksBlob *outBlob)
119 {
120     /* Check input and inBlob */
121     int32_t ret = CheckBlob(inBlob);
122     if ((ret != HKS_SUCCESS) || (iUnknown == NULL)) {
123         return HKS_ERROR_NULL_POINTER;
124     }
125 
126     IClientProxy *proxy = (IClientProxy *)iUnknown;
127 
128     uint32_t outBlobSize = 0;
129     if (outBlob != NULL) {
130         outBlobSize = outBlob->size;
131     }
132 
133     char *dataReq = NULL;
134     char *dataReply = NULL;
135     do {
136         dataReq = (char *)HksMalloc(MAX_IO_SIZE);
137         if (dataReq == NULL) {
138             ret = HKS_ERROR_MALLOC_FAIL;
139             break;
140         }
141         IpcIo request;
142         IpcIoInit(&request, dataReq, MAX_IO_SIZE, MAX_OBJ_NUM);
143 
144         ret = WriteToIpcRequest(&request, outBlobSize, inBlob);
145         HKS_IF_NOT_SUCC_LOGE_BREAK(ret, "write to ipc request failed!")
146 
147         dataReply = (char *)HksMalloc(MAX_IO_SIZE);
148         if (dataReply == NULL) {
149             ret = HKS_ERROR_MALLOC_FAIL;
150             break;
151         }
152         IpcIo reply;
153         IpcIoInit(&reply, dataReply, MAX_IO_SIZE, MAX_OBJ_NUM);
154 
155         struct HksIpcHandle replyHandle = { .io = &reply, .state = HKS_IPC_MSG_BASE };
156 
157         ret = (int32_t)proxy->Invoke((IClientProxy *)proxy, type, &request, (IOwner)&replyHandle, CurrentCallback);
158         HKS_IF_NOT_SUCC_BREAK(ret, HKS_ERROR_IPC_MSG_FAIL)
159 
160         ret = SynchronizeOutput(&replyHandle, outBlob);
161     } while (0);
162     HKS_FREE(dataReq);
163     HKS_FREE(dataReply);
164 
165     return ret;
166 }
167 
HksSendRequestSync(enum HksIpcInterfaceCode type,const struct HksBlob * inBlob,struct HksBlob * outBlob)168 static int32_t HksSendRequestSync(enum HksIpcInterfaceCode type, const struct HksBlob *inBlob, struct HksBlob *outBlob)
169 {
170     IClientProxy *clientProxy = NULL;
171     IUnknown *iUnknown = SAMGR_GetInstance()->GetFeatureApi(HKS_SAMGR_SERVICE, HKS_SAMGR_FEATRURE);
172     if (iUnknown == NULL) {
173         HKS_LOG_E("get HKS_SAMGR_FEATRURE api failed");
174         return HKS_ERROR_NULL_POINTER;
175     }
176 
177     int32_t ret = iUnknown->QueryInterface(iUnknown, DEFAULT_VERSION, (void **)&clientProxy);
178     if ((clientProxy == NULL) || (ret != 0)) {
179         HKS_LOG_E("get clientProxy failed");
180         return HKS_ERROR_NULL_POINTER;
181     }
182 
183     ret = HksIpcCall((IUnknown *)clientProxy, type, inBlob, outBlob);
184     (void)clientProxy->Release((IUnknown *)clientProxy);
185 
186     return ret;
187 }
188 
HksSendRequest(enum HksIpcInterfaceCode type,const struct HksBlob * inBlob,struct HksBlob * outBlob,const struct HksParamSet * paramSet)189 int32_t HksSendRequest(enum HksIpcInterfaceCode type, const struct HksBlob *inBlob, struct HksBlob *outBlob,
190     const struct HksParamSet *paramSet)
191 {
192     (void)paramSet;
193     return HksSendRequestSync(type, inBlob, outBlob);
194 }
195