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