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