1 /*
2  * Copyright (c) 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 #include "samgr_ipc_adapter.h"
16 
17 typedef struct IRegisterEpArg IRegisterEpArg;
18 struct IRegisterEpArg {
19     Endpoint *endpoint;
20     int token;
21     char *service;
22     char *feature;
23 };
24 static int Dispatch(uint32_t code, IpcIo *data, IpcIo *reply, MessageOption option);
25 static void HandleIpc(const Request *request, const Response *response);
26 static void *Receive(void *argv);
27 static int RegisterRemoteFeatures(Endpoint *endpoint);
28 static void OnSamgrServerExit(void *argv);
29 static void GetRemotePolicy(IpcIo *reply, PolicyTrans **policy, uint32 *policyNum);
30 static boolean JudgePolicy(uid_t callingUid, const PolicyTrans *policy, uint32 policyNum);
31 static boolean SearchFixedPolicy(uid_t callingUid, PolicyTrans policy);
ClientRegisterRemoteEndpoint(SvcIdentity * identity,int token,const char * service,const char * feature)32 int ClientRegisterRemoteEndpoint(SvcIdentity *identity, int token, const char *service, const char *feature)
33 {
34     IpcIo req;
35     uint8 data[MAX_DATA_LEN];
36     IpcIoInit(&req, data, MAX_DATA_LEN, 1);
37     // add samgr server token
38     WriteInt32(&req, 0);
39     WriteUint32(&req, RES_ENDPOINT);
40     WriteUint32(&req, OP_POST);
41     bool ret = WriteRemoteObject(&req, identity);
42     if (!ret) {
43         return EC_FAILURE;
44     }
45     uint32 retry = 0;
46     while (retry < MAX_RETRY_TIMES) {
47         ++retry;
48         IpcIo reply;
49         void *replyBuf = NULL;
50         MessageOption option;
51         MessageOptionInit(&option);
52         SvcIdentity *samgr = GetContextObject();
53 
54         int err = SendRequest(*samgr, INVALID_INDEX, &req, &reply, option, (uintptr_t *)&replyBuf);
55         if (err == EC_SUCCESS) {
56             ret = ReadInt32(&reply, &identity->handle);
57             if (!ret || identity->handle == INVALID_INDEX) {
58                 continue;
59             }
60             if (replyBuf != NULL) {
61                 FreeBuffer(replyBuf);
62             }
63             return EC_SUCCESS;
64         }
65         usleep(RETRY_INTERVAL);
66     }
67     return EC_FAILURE;
68 }
69 
Listen(Endpoint * endpoint,int token,const char * service,const char * feature)70 void Listen(Endpoint *endpoint, int token, const char *service, const char *feature)
71 {
72     if (endpoint->boss != NULL) {
73         return;
74     }
75     ThreadAttr attr = {endpoint->name, MAX_STACK_SIZE, PRI_ABOVE_NORMAL, 0, 0};
76     IRegisterEpArg *registerEpArg = SAMGR_Malloc(sizeof(IRegisterEpArg));
77     if (registerEpArg == NULL) {
78         HILOG_ERROR(HILOG_MODULE_SAMGR, "IRegisterEpArg Memory is not enough!");
79         return;
80     }
81     IpcObjectStub *objectStubOne = (IpcObjectStub *)calloc(1, sizeof(IpcObjectStub));
82     if (objectStubOne == NULL) {
83         HILOG_ERROR(HILOG_MODULE_SAMGR, "IpcObjectStub Memory is not enough!");
84         return;
85     }
86 
87     objectStubOne->func = Dispatch;
88     objectStubOne->args = endpoint;
89     objectStubOne->isRemote = false;
90     endpoint->identity.cookie = objectStubOne;
91     // handle must -1
92     endpoint->identity.handle = INVALID_INDEX;
93     endpoint->identity.token = SERVICE_TYPE_NORMAL;
94 
95     registerEpArg->endpoint = endpoint;
96     registerEpArg->token = token;
97     registerEpArg->service = service;
98     registerEpArg->feature = feature;
99     endpoint->boss = (ThreadId)THREAD_Create(Receive, registerEpArg, &attr);
100 }
101 
Receive(void * argv)102 static void *Receive(void *argv)
103 {
104     IRegisterEpArg *registerEpArg = (IRegisterEpArg *)argv;
105     if (registerEpArg == NULL || registerEpArg->endpoint->registerEP == NULL) {
106         return NULL;
107     }
108     int ret = EC_INVALID;
109     uint32 retry = 0;
110     while (retry < MAX_RETRY_TIMES) {
111         ret = registerEpArg->endpoint->registerEP(&registerEpArg->endpoint->identity,
112             registerEpArg->token, registerEpArg->service, registerEpArg->feature);
113         if (ret == EC_SUCCESS) {
114             SvcIdentity *samgr = GetContextObject();
115             (void)RemoveDeathRecipient(*samgr, registerEpArg->endpoint->deadId);
116             (void)AddDeathRecipient(*samgr, OnSamgrServerExit, registerEpArg->endpoint,
117                 &registerEpArg->endpoint->deadId);
118             break;
119         }
120         ++retry;
121         usleep(RETRY_INTERVAL);
122     }
123     if (ret != EC_SUCCESS) {
124         HILOG_FATAL(HILOG_MODULE_SAMGR, "Register endpoint<%s>, handle<%u> failed! will exit to recover!",
125                     registerEpArg->endpoint->name, registerEpArg->endpoint->identity.handle);
126         SAMGR_Free(registerEpArg);
127         return NULL;
128     }
129     registerEpArg->endpoint->running = TRUE;
130     if (strcmp(registerEpArg->endpoint->name, SAMGR_SERVICE) != 0) {
131         int remain = RegisterRemoteFeatures(registerEpArg->endpoint);
132         HILOG_INFO(HILOG_MODULE_SAMGR, "Register endpoint<%s> and iunknown finished! remain<%d> iunknown!",
133             registerEpArg->endpoint->name, remain);
134     }
135     SAMGR_Free(registerEpArg);
136     JoinWorkThread();
137     return NULL;
138 }
139 
RegisterRemoteFeatures(Endpoint * endpoint)140 static int RegisterRemoteFeatures(Endpoint *endpoint)
141 {
142     int nums = 0;
143     int size = VECTOR_Size(&endpoint->routers);
144     int i;
145     SvcIdentity identity;
146     for (i = 0; i < size; ++i) {
147         Router *router = VECTOR_At(&endpoint->routers, i);
148         if (router == NULL) {
149             continue;
150         }
151         identity.handle = endpoint->identity.handle;
152         identity.token = i;
153         int ret = RegisterIdentity(&(router->saName), &identity, &(router->policy),
154                                    &(router->policyNum));
155         if (ret == EC_SUCCESS) {
156             ++nums;
157         }
158         HILOG_DEBUG(HILOG_MODULE_SAMGR, "RegisterRemoteFeatures<%s, %s> ret:%d",
159                     router->saName.service, router->saName.feature,  ret);
160     }
161     return VECTOR_Num(&endpoint->routers) - nums;
162 }
163 
RegisterIdentity(const SaName * saName,SvcIdentity * saInfo,PolicyTrans ** policy,uint32 * policyNum)164 int RegisterIdentity(const SaName *saName, SvcIdentity *saInfo, PolicyTrans **policy, uint32 *policyNum)
165 {
166     IpcIo req;
167     uint8 data[MAX_DATA_LEN];
168     IpcIoInit(&req, data, MAX_DATA_LEN, 0);
169     WriteInt32(&req, 0);
170     WriteUint32(&req, RES_FEATURE);
171     WriteUint32(&req, OP_PUT);
172     WriteString(&req, saName->service);
173     WriteBool(&req, saName->feature == NULL);
174     if (saName->feature != NULL) {
175         WriteString(&req, saName->feature);
176     }
177     WriteUint32(&req, saInfo->token);
178     IpcIo reply;
179     void *replyBuf = NULL;
180     SvcIdentity *samgr = GetContextObject();
181     MessageOption option;
182     MessageOptionInit(&option);
183     int ret = SendRequest(*samgr, INVALID_INDEX, &req, &reply, option,
184                           (uintptr_t *)&replyBuf);
185     ret = -ret;
186     int32_t ipcRet = EC_FAILURE;
187     if (ret == EC_SUCCESS) {
188         ReadInt32(&reply, &ipcRet);
189     }
190     if (ipcRet == EC_SUCCESS) {
191         SvcIdentity target;
192         (void)ReadRemoteObject(&reply, &target);
193         GetRemotePolicy(&reply, policy, policyNum);
194     }
195     if (replyBuf != NULL) {
196         FreeBuffer(replyBuf);
197     }
198     return ipcRet;
199 }
Dispatch(uint32_t code,IpcIo * data,IpcIo * reply,MessageOption option)200 static int Dispatch(uint32_t code, IpcIo *data, IpcIo *reply, MessageOption option)
201 {
202     Endpoint *endpoint = (Endpoint *)option.args;
203     int token = GetRemoteToken(data);
204     if (token == EC_INVALID) {
205         goto ERROR;
206     }
207     if (TB_CheckMessage(&endpoint->bucket) == BUCKET_BUSY) {
208         HILOG_WARN(HILOG_MODULE_SAMGR, "Flow Control <%u> is NULL", token);
209         goto ERROR;
210     }
211     Router *router = VECTOR_At(&endpoint->routers, token);
212     if (router == NULL) {
213         HILOG_ERROR(HILOG_MODULE_SAMGR, "Router <%s, %u> is NULL", endpoint->name, token);
214         goto ERROR;
215     }
216 
217     Response resp = {0};
218     resp.data = endpoint;
219     resp.reply = reply;
220     Request request = {0};
221     request.msgId = token;
222     request.data = data;
223     request.msgValue = code;
224 
225     HandleIpc(&request, &resp);
226     return EC_SUCCESS;
227 ERROR:
228     return EC_INVALID;
229 }
230 
HandleIpc(const Request * request,const Response * response)231 static void HandleIpc(const Request *request, const Response *response)
232 {
233     Endpoint *endpoint = (Endpoint *)response->data;
234     Router *router = VECTOR_At(&endpoint->routers, request->msgId);
235     if (router == NULL || router->proxy == NULL || router->proxy->Invoke == NULL) {
236         HILOG_ERROR(HILOG_MODULE_SAMGR, "Invalid IPC router!");
237         return;
238     }
239     uid_t uid = GetCallingUid();
240     if ((strcmp(router->saName.service, SAMGR_SERVICE) != 0) &&
241         !JudgePolicy(uid, (const PolicyTrans *)(router->policy), router->policyNum)) {
242         HILOG_ERROR(HILOG_MODULE_SAMGR, "Consumer uid<%d> has no permission to access<%s, %d, %d>!",
243                     uid, router->saName.service, router->identity.serviceId, router->identity.featureId);
244         return;
245     }
246     router->proxy->Invoke(router->proxy, request->msgValue, NULL, request->data, response->reply);
247 }
248 
JudgePolicy(uid_t callingUid,const PolicyTrans * policy,uint32 policyNum)249 static boolean JudgePolicy(uid_t callingUid, const PolicyTrans *policy, uint32 policyNum)
250 {
251     if (policy == NULL) {
252         HILOG_ERROR(HILOG_MODULE_SAMGR, "Policy is NULL! Num is %u", policyNum);
253         return FALSE;
254     }
255     uint32 i;
256     for (i = 0; i < policyNum; i++) {
257         if (policy[i].type == RANGE && callingUid >= policy[i].uidMin && callingUid <= policy[i].uidMax) {
258             return TRUE;
259         }
260         if (policy[i].type == FIXED && SearchFixedPolicy(callingUid, policy[i])) {
261             return TRUE;
262         }
263     }
264     return FALSE;
265 }
SearchFixedPolicy(uid_t callingUid,PolicyTrans policy)266 static boolean SearchFixedPolicy(uid_t callingUid, PolicyTrans policy)
267 {
268     int i;
269     for (i = 0; i < UID_SIZE; i++) {
270         if (callingUid == policy.fixedUid[i]) {
271             return TRUE;
272         }
273     }
274     return FALSE;
275 }
OnSamgrServerExit(void * argv)276 static void OnSamgrServerExit(void *argv)
277 {
278     HILOG_ERROR(HILOG_MODULE_SAMGR, "Disconnect to samgr server!");
279     Endpoint *endpoint = (Endpoint *)argv;
280     if (endpoint == NULL || endpoint->registerEP == NULL) {
281         return;
282     }
283     int size = VECTOR_Size(&endpoint->routers);
284     int i;
285     for (i = 0; i < size; i++) {
286         Router *router = VECTOR_At(&endpoint->routers, i);
287         if (router == NULL) {
288             continue;
289         }
290         SAMGR_Free(router->policy);
291         router->policy = NULL;
292         router->policyNum = 0;
293     }
294 
295     SvcIdentity old = endpoint->identity;
296     while (endpoint->registerEP(&endpoint->identity, 0, "", "") != EC_SUCCESS) {
297         HILOG_ERROR(HILOG_MODULE_SAMGR, "Reconnect to samgr server failed!");
298         usleep(RETRY_INTERVAL);
299     }
300     SvcIdentity new = endpoint->identity;
301     if (old.handle != new.handle || old.cookie != new.cookie || old.token != new.token) {
302         HILOG_ERROR(HILOG_MODULE_SAMGR, "Samgr server identity error!");
303         exit(-1);
304     }
305 
306     SvcIdentity identity = {SAMGR_HANDLE, SAMGR_TOKEN, SAMGR_COOKIE};
307     ReleaseSvc(identity);
308     (void)AddDeathRecipient(identity, OnSamgrServerExit, endpoint, &endpoint->deadId);
309     int remain = RegisterRemoteFeatures(endpoint);
310     HILOG_INFO(HILOG_MODULE_SAMGR, "Reconnect and register finished! remain<%d> iunknown!", remain);
311 }
312 
GetRemoteToken(IpcIo * data)313 int GetRemoteToken(IpcIo *data)
314 {
315     int32_t token;
316     if (ReadInt32(data, &token)) {
317         return token;
318     }
319     return EC_INVALID;
320 }
321 
GetRemotePolicy(IpcIo * reply,PolicyTrans ** policy,uint32 * policyNum)322 static void GetRemotePolicy(IpcIo *reply, PolicyTrans **policy, uint32 *policyNum)
323 {
324     if (reply == NULL) {
325         return;
326     }
327     uint32 i;
328     uint32 j;
329     ReadUint32(reply, policyNum);
330     if (*policyNum > MAX_POLICY_NUM) {
331         *policyNum = MAX_POLICY_NUM;
332     }
333     SAMGR_Free(*policy);
334     if (*policyNum == 0) {
335         *policy = NULL;
336         return;
337     }
338     *policy = (PolicyTrans *)SAMGR_Malloc(sizeof(PolicyTrans) * (*policyNum));
339     if (*policy == NULL) {
340         return;
341     }
342     for (i = 0; i < *policyNum; i++) {
343         if (!ReadInt32(reply, &(*policy)[i].type)) {
344             continue;
345         }
346         switch ((*policy)[i].type) {
347             case RANGE:
348                 ReadInt32(reply, &((*policy)[i].uidMin));
349                 ReadInt32(reply, &((*policy)[i].uidMax));
350                 break;
351             case FIXED:
352                 for (j = 0; j < UID_SIZE; j++) {
353                     ReadInt32(reply, &((*policy)[i].fixedUid[j]));
354                 }
355                 break;
356             case BUNDLENAME:
357                 ReadInt32(reply, &((*policy)[i].fixedUid[0]));
358                 break;
359             default:
360                 break;
361         }
362     }
363 }