• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include <ctype.h>
16 #include <errno.h>
17 #include <stdio.h>
18 #include <string.h>
19 #include <sys/socket.h>
20 
21 #include "init_log.h"
22 #include "init_param.h"
23 #include "init_utils.h"
24 #include "loop_event.h"
25 #include "param_manager.h"
26 #include "param_message.h"
27 #include "trigger_manager.h"
28 #include "securec.h"
29 #ifdef PARAM_SUPPORT_SELINUX
30 #include "selinux_parameter.h"
31 #include <policycoreutils.h>
32 #include <selinux/selinux.h>
33 #endif
34 
35 static ParamService g_paramService = {};
36 
OnClose(ParamTaskPtr client)37 PARAM_STATIC void OnClose(ParamTaskPtr client)
38 {
39     ParamWatcher *watcher = (ParamWatcher *)ParamGetTaskUserData(client);
40     if (client == g_paramService.watcherTask) {
41         ClearWatchTrigger(watcher, TRIGGER_PARAM_WATCH);
42         g_paramService.watcherTask = NULL;
43     } else {
44         ClearWatchTrigger(watcher, TRIGGER_PARAM_WAIT);
45     }
46 }
47 
TimerCallback(const ParamTaskPtr timer,void * context)48 static void TimerCallback(const ParamTaskPtr timer, void *context)
49 {
50     UNUSED(context);
51     UNUSED(timer);
52     int ret = CheckWatchTriggerTimeout();
53     // no wait node
54     if (ret == 0 && g_paramService.timer != NULL) {
55         ParamTaskClose(g_paramService.timer);
56         g_paramService.timer = NULL;
57     }
58 }
59 
CheckAndSendTrigger(uint32_t dataIndex,const char * name,const char * value)60 static void CheckAndSendTrigger(uint32_t dataIndex, const char *name, const char *value)
61 {
62     ParamNode *entry = (ParamNode *)GetTrieNode(GetWorkSpaceByName(name), dataIndex);
63     PARAM_CHECK(entry != NULL, return, "Failed to get data %s ", name);
64     uint32_t trigger = 1;
65     if ((ATOMIC_LOAD_EXPLICIT(&entry->commitId, MEMORY_ORDER_RELAXED) & PARAM_FLAGS_TRIGGED) != PARAM_FLAGS_TRIGGED) {
66         trigger = (CheckAndMarkTrigger(TRIGGER_PARAM, name) != 0) ? 1 : 0;
67     }
68     if (trigger) {
69         ATOMIC_SYNC_OR_AND_FETCH(&entry->commitId, PARAM_FLAGS_TRIGGED, MEMORY_ORDER_RELEASE);
70         // notify event to process trigger
71         PostParamTrigger(EVENT_TRIGGER_PARAM, name, value);
72     }
73 
74     int wait = 1;
75     if ((ATOMIC_LOAD_EXPLICIT(&entry->commitId, MEMORY_ORDER_RELAXED) & PARAM_FLAGS_WAITED) != PARAM_FLAGS_WAITED) {
76         wait = (CheckAndMarkTrigger(TRIGGER_PARAM_WAIT, name) != 0) ? 1 : 0;
77     }
78     if (wait) {
79         ATOMIC_SYNC_OR_AND_FETCH(&entry->commitId, PARAM_FLAGS_WAITED, MEMORY_ORDER_RELEASE);
80         PostParamTrigger(EVENT_TRIGGER_PARAM_WAIT, name, value);
81     }
82     PostParamTrigger(EVENT_TRIGGER_PARAM_WATCH, name, value);
83 }
84 
SendResponseMsg(ParamTaskPtr worker,const ParamMessage * msg,int result)85 static int SendResponseMsg(ParamTaskPtr worker, const ParamMessage *msg, int result)
86 {
87     ParamResponseMessage *response = NULL;
88     response = (ParamResponseMessage *)CreateParamMessage(msg->type, msg->key, sizeof(ParamResponseMessage));
89     PARAM_CHECK(response != NULL, return PARAM_CODE_ERROR, "Failed to alloc memory for response");
90     response->msg.id.msgId = msg->id.msgId;
91     response->result = result;
92     response->msg.msgSize = sizeof(ParamResponseMessage);
93     ParamTaskSendMsg(worker, (ParamMessage *)response);
94     PARAM_LOGV("Send response msg msgId %d result %d", msg->id.msgId, result);
95     return 0;
96 }
97 
SendWatcherNotifyMessage(const TriggerExtInfo * extData,const char * content,uint32_t size)98 static int SendWatcherNotifyMessage(const TriggerExtInfo *extData, const char *content, uint32_t size)
99 {
100     PARAM_CHECK(content != NULL, return -1, "Invalid content");
101     PARAM_CHECK(extData != NULL && extData->stream != NULL, return -1, "Invalid extData");
102     uint32_t msgSize = sizeof(ParamMessage) + PARAM_ALIGN(strlen(content) + 1);
103     ParamMessage *msg = (ParamMessage *)CreateParamMessage(MSG_NOTIFY_PARAM, "*", msgSize);
104     PARAM_CHECK(msg != NULL, return -1, "Failed to create msg ");
105 
106     uint32_t offset = 0;
107     int ret;
108     char *tmp = strstr(content, "=");
109     if (tmp != NULL) {
110         ret = strncpy_s(msg->key, sizeof(msg->key) - 1, content, tmp - content);
111         PARAM_CHECK(ret == 0, free(msg);
112             return -1, "Failed to fill value");
113         tmp++;
114         ret = FillParamMsgContent(msg, &offset, PARAM_VALUE, tmp, strlen(tmp));
115         PARAM_CHECK(ret == 0, free(msg);
116             return -1, "Failed to fill value");
117     } else if (content != NULL && strlen(content) > 0) {
118         ret = FillParamMsgContent(msg, &offset, PARAM_VALUE, content, strlen(content));
119         PARAM_CHECK(ret == 0, free(msg);
120             return -1, "Failed to fill value");
121     }
122 
123     msg->id.msgId = 0;
124     if (extData->type == TRIGGER_PARAM_WAIT) {
125         msg->id.msgId = extData->info.waitInfo.waitId;
126     } else {
127         msg->id.msgId = extData->info.watchInfo.watchId;
128     }
129     msg->msgSize = sizeof(ParamMessage) + offset;
130     PARAM_LOGV("SendWatcherNotifyMessage cmd %s, id %d msgSize %d para: %s",
131         (extData->type == TRIGGER_PARAM_WAIT) ? "wait" : "watcher",
132         msg->id.msgId, msg->msgSize, content);
133     ParamTaskSendMsg(extData->stream, msg);
134     return 0;
135 }
136 
SystemSetParam(const char * name,const char * value,const ParamSecurityLabel * srcLabel)137 static int SystemSetParam(const char *name, const char *value, const ParamSecurityLabel *srcLabel)
138 {
139     PARAM_LOGV("SystemWriteParam name %s value: %s", name, value);
140     int ctrlService = 0;
141     int ret = CheckParameterSet(name, value, srcLabel, &ctrlService);
142     PARAM_CHECK(ret == 0, return ret, "Forbid to set parameter %s", name);
143 
144     if ((ctrlService & PARAM_CTRL_SERVICE) != PARAM_CTRL_SERVICE) { // ctrl param
145         uint32_t dataIndex = 0;
146         ret = WriteParam(name, value, &dataIndex, 0);
147         PARAM_CHECK(ret == 0, return ret, "Failed to set param %d name %s %s", ret, name, value);
148         ret = WritePersistParam(name, value);
149         PARAM_CHECK(ret == 0, return ret, "Failed to set persist param name %s", name);
150         CheckAndSendTrigger(dataIndex, name, value);
151     }
152     return ret;
153 }
154 
HandleParamSet(const ParamTaskPtr worker,const ParamMessage * msg)155 static int HandleParamSet(const ParamTaskPtr worker, const ParamMessage *msg)
156 {
157     uint32_t offset = 0;
158     ParamMsgContent *valueContent = GetNextContent(msg, &offset);
159     PARAM_CHECK(valueContent != NULL, return -1, "Invalid msg for %s", msg->key);
160     ParamSecurityLabel srcLabel = {0};
161     struct ucred cr = {-1, -1, -1};
162     socklen_t crSize = sizeof(cr);
163     if (getsockopt(LE_GetSocketFd(worker), SOL_SOCKET, SO_PEERCRED, &cr, &crSize) < 0) {
164         PARAM_LOGE("Failed to get opt %d", errno);
165 #ifndef STARTUP_INIT_TEST
166         return SendResponseMsg(worker, msg, -1);
167 #endif
168     }
169     srcLabel.sockFd = LE_GetSocketFd(worker);
170     srcLabel.cred.uid = cr.uid;
171     srcLabel.cred.pid = cr.pid;
172     srcLabel.cred.gid = cr.gid;
173     PARAM_LOGI("Handle set param msgId %d pid %d key: %s", msg->id.msgId, cr.pid, msg->key);
174     int ret = SystemSetParam(msg->key, valueContent->content, &srcLabel);
175     return SendResponseMsg(worker, msg, ret);
176 }
177 
AddWatchNode(struct tagTriggerNode_ * trigger,const struct TriggerExtInfo_ * extInfo)178 static int32_t AddWatchNode(struct tagTriggerNode_ *trigger, const struct TriggerExtInfo_ *extInfo)
179 {
180     ParamWatcher *watcher = NULL;
181     if (extInfo != NULL && extInfo->stream != NULL) {
182         watcher = (ParamWatcher *)ParamGetTaskUserData(extInfo->stream);
183     }
184     PARAM_CHECK(watcher != NULL, return -1, "Failed to get param watcher data");
185     if (extInfo->type == TRIGGER_PARAM_WAIT) {
186         WaitNode *node = (WaitNode *)trigger;
187         OH_ListInit(&node->item);
188         node->timeout = extInfo->info.waitInfo.timeout;
189         node->stream = extInfo->stream;
190         node->waitId = extInfo->info.waitInfo.waitId;
191         OH_ListAddTail(&watcher->triggerHead, &node->item);
192     } else {
193         WatchNode *node = (WatchNode *)trigger;
194         OH_ListInit(&node->item);
195         node->watchId = extInfo->info.watchInfo.watchId;
196         OH_ListAddTail(&watcher->triggerHead, &node->item);
197     }
198     return 0;
199 }
200 
AddWatcherTrigger(int triggerType,const char * condition,const TriggerExtInfo * extData)201 static TriggerNode *AddWatcherTrigger(int triggerType, const char *condition, const TriggerExtInfo *extData)
202 {
203     TriggerWorkSpace *workSpace = GetTriggerWorkSpace();
204     TriggerHeader *header = (TriggerHeader *)&workSpace->triggerHead[extData->type];
205     return header->addTrigger(workSpace, condition, extData);
206 }
207 
ExecuteWatchTrigger_(const struct tagTriggerNode_ * trigger,const char * content,uint32_t size)208 static int32_t ExecuteWatchTrigger_(const struct tagTriggerNode_ *trigger, const char *content, uint32_t size)
209 {
210     TriggerExtInfo extData = {};
211     extData.type = trigger->type;
212     if (trigger->type == TRIGGER_PARAM_WAIT) {
213         WaitNode *node = (WaitNode *)trigger;
214         extData.stream = node->stream;
215         extData.info.waitInfo.waitId = node->waitId;
216         extData.info.waitInfo.timeout = node->timeout;
217     } else {
218         WatchNode *node = (WatchNode *)trigger;
219         extData.stream = g_paramService.watcherTask;
220         extData.info.watchInfo.watchId = node->watchId;
221     }
222     if (content == NULL) {
223         return SendWatcherNotifyMessage(&extData, "", 0);
224     }
225     return SendWatcherNotifyMessage(&extData, content, size);
226 }
227 
HandleParamWaitAdd(const ParamTaskPtr worker,const ParamMessage * msg)228 static int HandleParamWaitAdd(const ParamTaskPtr worker, const ParamMessage *msg)
229 {
230     PARAM_CHECK(msg != NULL, return -1, "Invalid message");
231     uint32_t offset = 0;
232 #ifndef STARTUP_INIT_TEST
233     uint32_t timeout = DEFAULT_PARAM_WAIT_TIMEOUT;
234 #else
235     uint32_t timeout = 0;
236 #endif
237     ParamMsgContent *valueContent = GetNextContent(msg, &offset);
238     PARAM_CHECK(valueContent != NULL, return -1, "Invalid msg");
239     PARAM_CHECK(valueContent->contentSize <= PARAM_CONST_VALUE_LEN_MAX, return -1, "Invalid msg");
240     ParamMsgContent *timeoutContent = GetNextContent(msg, &offset);
241     if (timeoutContent != NULL) {
242         timeout = *((uint32_t *)(timeoutContent->content));
243     }
244 
245     PARAM_LOGV("HandleParamWaitAdd name %s timeout %d", msg->key, timeout);
246     TriggerExtInfo extData = {};
247     extData.addNode = AddWatchNode;
248     extData.type = TRIGGER_PARAM_WAIT;
249     extData.stream = worker;
250     extData.info.waitInfo.waitId = msg->id.watcherId;
251     extData.info.waitInfo.timeout = timeout;
252     // first check match, if match send response to client
253     ParamNode *param = SystemCheckMatchParamWait(msg->key, valueContent->content);
254     if (param != NULL) {
255         SendWatcherNotifyMessage(&extData, param->data, param->valueLength);
256         return 0;
257     }
258 
259     uint32_t buffSize = strlen(msg->key) + valueContent->contentSize + 1 + 1;
260     char *condition = calloc(1, buffSize);
261     PARAM_CHECK(condition != NULL, return -1, "Failed to create condition for %s", msg->key);
262     int ret = sprintf_s(condition, buffSize - 1, "%s=%s", msg->key, valueContent->content);
263     PARAM_CHECK(ret > EOK, free(condition);
264         return -1, "Failed to copy name for %s", msg->key);
265     TriggerNode *trigger = AddWatcherTrigger(TRIGGER_PARAM_WAIT, condition, &extData);
266     PARAM_CHECK(trigger != NULL, free(condition);
267         return -1, "Failed to add trigger for %s", msg->key);
268     free(condition);
269     if (g_paramService.timer == NULL) {
270         ret = ParamTimerCreate(&g_paramService.timer, TimerCallback, &g_paramService);
271         PARAM_CHECK(ret == 0, return 0, "Failed to create timer %s", msg->key);
272         ret = ParamTimerStart(g_paramService.timer, MS_UNIT, (uint64_t)-1);
273         PARAM_CHECK(ret == 0,
274             ParamTaskClose(g_paramService.timer);
275             g_paramService.timer = NULL;
276             return 0, "Failed to set timer %s", msg->key);
277     }
278     return 0;
279 }
280 
HandleParamWatcherAdd(const ParamTaskPtr worker,const ParamMessage * msg)281 static int HandleParamWatcherAdd(const ParamTaskPtr worker, const ParamMessage *msg)
282 {
283     PARAM_CHECK(msg != NULL, return -1, "Invalid message");
284     PARAM_CHECK((g_paramService.watcherTask == NULL) ||
285         (g_paramService.watcherTask == worker), return -1, "Invalid watcher worker");
286     g_paramService.watcherTask = worker;
287     TriggerExtInfo extData = {};
288     extData.type = TRIGGER_PARAM_WATCH;
289     extData.addNode = AddWatchNode;
290     extData.stream = worker;
291     extData.info.watchInfo.watchId = msg->id.watcherId;
292     TriggerNode *trigger = AddWatcherTrigger(TRIGGER_PARAM_WATCH, msg->key, &extData);
293     if (trigger == NULL) {
294         PARAM_LOGE("Failed to add trigger for %s", msg->key);
295         return SendResponseMsg(worker, msg, -1);
296     }
297     PARAM_LOGV("HandleParamWatcherAdd name %s watcher: %d", msg->key, msg->id.watcherId);
298     return SendResponseMsg(worker, msg, 0);
299 }
300 
HandleParamWatcherDel(const ParamTaskPtr worker,const ParamMessage * msg)301 static int HandleParamWatcherDel(const ParamTaskPtr worker, const ParamMessage *msg)
302 {
303     PARAM_CHECK(msg != NULL, return -1, "Invalid message");
304     PARAM_LOGV("HandleParamWatcherDel name %s watcher: %d", msg->key, msg->id.watcherId);
305     DelWatchTrigger(TRIGGER_PARAM_WATCH, (const void *)&msg->id.watcherId);
306     return SendResponseMsg(worker, msg, 0);
307 }
308 
HandleParamSave(const ParamTaskPtr worker,const ParamMessage * msg)309 static int HandleParamSave(const ParamTaskPtr worker, const ParamMessage *msg)
310 {
311     PARAM_CHECK(msg != NULL, return -1, "Invalid message");
312     struct ucred cr = {-1, -1, -1};
313     socklen_t crSize = sizeof(cr);
314     if (getsockopt(LE_GetSocketFd(worker), SOL_SOCKET, SO_PEERCRED, &cr, &crSize) < 0) {
315         PARAM_LOGE("Failed to get opt %d", errno);
316 #ifndef STARTUP_INIT_TEST
317         return SendResponseMsg(worker, msg, -1);
318 #endif
319     }
320     PARAM_LOGI("process info:pid = %d, uid = %d, gid = %d", cr.pid, cr.uid, cr.gid);
321     PARAM_CHECK(cr.uid != -1, return -1, "Invalid uid");
322     int ret = CheckIfUidInGroup(cr.uid, "servicectrl");
323     PARAM_CHECK(ret == 0, return SendResponseMsg(worker, msg, -1), "Failed to process save parameters : ret %d", ret);
324     CheckAndSavePersistParam();
325     return SendResponseMsg(worker, msg, 0);
326 }
327 
ProcessMessage(const ParamTaskPtr worker,const ParamMessage * msg)328 PARAM_STATIC int ProcessMessage(const ParamTaskPtr worker, const ParamMessage *msg)
329 {
330     PARAM_CHECK((msg != NULL) && (msg->msgSize >= sizeof(ParamMessage)), return -1, "Invalid msg");
331     PARAM_CHECK(worker != NULL, return -1, "Invalid worker");
332     int ret = PARAM_CODE_INVALID_PARAM;
333     switch (msg->type) {
334         case MSG_SET_PARAM:
335             ret = HandleParamSet(worker, msg);
336             break;
337         case MSG_WAIT_PARAM:
338             ret = HandleParamWaitAdd(worker, msg);
339             break;
340         case MSG_ADD_WATCHER:
341             ret = HandleParamWatcherAdd(worker, msg);
342             break;
343         case MSG_DEL_WATCHER:
344             ret = HandleParamWatcherDel(worker, msg);
345             break;
346         case MSG_SAVE_PARAM:
347             ret = HandleParamSave(worker, msg);
348             break;
349         default:
350             break;
351     }
352     PARAM_CHECK(ret == 0, return -1, "Failed to process message ret %d", ret);
353     return 0;
354 }
355 
OnIncomingConnect(LoopHandle loop,TaskHandle server)356 PARAM_STATIC int OnIncomingConnect(LoopHandle loop, TaskHandle server)
357 {
358     ParamStreamInfo info = {};
359 #ifdef STARTUP_INIT_TEST
360     info.flags = PARAM_TEST_FLAGS;
361 #endif
362     info.server = NULL;
363     info.close = OnClose;
364     info.recvMessage = ProcessMessage;
365     info.incomingConnect = NULL;
366     ParamTaskPtr client = NULL;
367     int ret = ParamStreamCreate(&client, server, &info, sizeof(ParamWatcher));
368     PARAM_CHECK(ret == 0, return -1, "Failed to create client");
369 
370     ParamWatcher *watcher = (ParamWatcher *)ParamGetTaskUserData(client);
371     PARAM_CHECK(watcher != NULL, return -1, "Failed to get watcher");
372     OH_ListInit(&watcher->triggerHead);
373     watcher->stream = client;
374 #ifdef STARTUP_INIT_TEST
375     g_paramService.watcherTask = client;
376 #endif
377     return 0;
378 }
379 
LoadSelinuxLabel(const char * op)380 static void LoadSelinuxLabel(const char *op)
381 {
382     // load security label
383 #ifdef PARAM_SUPPORT_SELINUX
384     ParamSecurityOps *ops = GetParamSecurityOps(PARAM_SECURITY_SELINUX);
385     if (ops != NULL && ops->securityGetLabel != NULL) {
386         ops->securityGetLabel(op);
387     }
388 #endif
389 }
390 
InitParamService(void)391 int InitParamService(void)
392 {
393     PARAM_LOGI("InitParamService pipe: %s.", PIPE_NAME);
394     CheckAndCreateDir(PIPE_NAME);
395     CheckAndCreateDir(PARAM_STORAGE_PATH"/");
396     // param space
397     PARAM_WORKSPACE_OPS ops = {0};
398     ops.updaterMode = InUpdaterMode();
399     // init open log
400     ops.logFunc = InitLog;
401     ops.getServiceGroupIdByPid = GetServiceGroupIdByPid;
402 #ifdef PARAM_SUPPORT_SELINUX
403     ops.setfilecon = setfilecon;
404 #endif
405     int ret = InitParamWorkSpace(0, &ops);
406     PARAM_CHECK(ret == 0, return ret, "Init parameter workspace fail");
407     ret = InitPersistParamWorkSpace();
408     PARAM_CHECK(ret == 0, return ret, "Init persist parameter workspace fail");
409     // param server
410     if (g_paramService.serverTask == NULL) {
411         ParamStreamInfo info = {};
412         info.server = PIPE_NAME;
413         info.close = NULL;
414         info.recvMessage = NULL;
415         info.incomingConnect = OnIncomingConnect;
416         ret = ParamServerCreate(&g_paramService.serverTask, &info);
417         PARAM_CHECK(ret == 0, return ret, "Failed to create server");
418     }
419 
420     // init trigger space
421     ret = InitTriggerWorkSpace();
422     PARAM_CHECK(ret == 0, return ret, "Failed to init trigger");
423     RegisterTriggerExec(TRIGGER_PARAM_WAIT, ExecuteWatchTrigger_);
424     RegisterTriggerExec(TRIGGER_PARAM_WATCH, ExecuteWatchTrigger_);
425 
426     return 0;
427 }
428 
LoadSpecialParam(void)429 void LoadSpecialParam(void)
430 {
431     // read param area size from cfg and save to dac
432     LoadParamAreaSize();
433     // read selinux label
434     LoadSelinuxLabel("init");
435     // from cmdline
436     LoadParamFromCmdLine();
437     // from build
438     LoadParamFromBuild();
439 }
440 
StartParamService(void)441 int StartParamService(void)
442 {
443     // read selinux label
444     LoadSelinuxLabel("permission");
445     return ParamServiceStart();
446 }
447 
StopParamService(void)448 void StopParamService(void)
449 {
450     PARAM_LOGI("StopParamService.");
451     ClosePersistParamWorkSpace();
452     CloseParamWorkSpace();
453     CloseTriggerWorkSpace();
454     ParamTaskClose(g_paramService.serverTask);
455     g_paramService.serverTask = NULL;
456     ParamServiceStop();
457 }
458 
SystemWriteParam(const char * name,const char * value)459 int SystemWriteParam(const char *name, const char *value)
460 {
461     return SystemSetParam(name, value, GetParamSecurityLabel());
462 }
463 
464 #ifdef STARTUP_INIT_TEST
GetParamService()465 ParamService *GetParamService()
466 {
467     return &g_paramService;
468 }
469 #endif
470