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 35static ParamService g_paramService = {}; 36 37PARAM_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 48static 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 60static 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 87static 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 100static 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 139static 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 161static 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 184static 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 207static 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 214static 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 234static 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 287static 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 307static 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 315static 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 333PARAM_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 361PARAM_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 385static 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 396int 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 434void 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 446int 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 456void 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 467int SystemWriteParam(const char *name, const char *value) 468{ 469 return SystemSetParam(name, value, GetParamSecurityLabel()); 470} 471 472#ifdef STARTUP_INIT_TEST 473ParamService *GetParamService() 474{ 475 return &g_paramService; 476} 477#endif 478