1d9f0492fSopenharmony_ci/* 2d9f0492fSopenharmony_ci * Copyright (c) 2023 Huawei Device Co., Ltd. 3d9f0492fSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 4d9f0492fSopenharmony_ci * you may not use this file except in compliance with the License. 5d9f0492fSopenharmony_ci * You may obtain a copy of the License at 6d9f0492fSopenharmony_ci * 7d9f0492fSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 8d9f0492fSopenharmony_ci * 9d9f0492fSopenharmony_ci * Unless required by applicable law or agreed to in writing, software 10d9f0492fSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 11d9f0492fSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12d9f0492fSopenharmony_ci * See the License for the specific language governing permissions and 13d9f0492fSopenharmony_ci * limitations under the License. 14d9f0492fSopenharmony_ci */ 15d9f0492fSopenharmony_ci#include "init_context.h" 16d9f0492fSopenharmony_ci 17d9f0492fSopenharmony_ci#include <poll.h> 18d9f0492fSopenharmony_ci#ifdef WITH_SELINUX 19d9f0492fSopenharmony_ci#include <policycoreutils.h> 20d9f0492fSopenharmony_ci#include <selinux/selinux.h> 21d9f0492fSopenharmony_ci#endif 22d9f0492fSopenharmony_ci#include <sys/prctl.h> 23d9f0492fSopenharmony_ci#include <sys/types.h> 24d9f0492fSopenharmony_ci#include <sys/socket.h> 25d9f0492fSopenharmony_ci#include <unistd.h> 26d9f0492fSopenharmony_ci 27d9f0492fSopenharmony_ci#include "init_module_engine.h" 28d9f0492fSopenharmony_ci#include "plugin_adapter.h" 29d9f0492fSopenharmony_ci#include "init_cmds.h" 30d9f0492fSopenharmony_ci#include "init_utils.h" 31d9f0492fSopenharmony_ci#include "securec.h" 32d9f0492fSopenharmony_ci 33d9f0492fSopenharmony_ci#ifdef STARTUP_INIT_TEST 34d9f0492fSopenharmony_ci#define TIMEOUT_DEF 2 35d9f0492fSopenharmony_ci#else 36d9f0492fSopenharmony_ci#define TIMEOUT_DEF 5 37d9f0492fSopenharmony_ci#endif 38d9f0492fSopenharmony_ci 39d9f0492fSopenharmony_cistatic SubInitInfo g_subInitInfo[INIT_CONTEXT_MAIN] = {}; 40d9f0492fSopenharmony_cistatic const char *g_subContext[INIT_CONTEXT_MAIN] = { 41d9f0492fSopenharmony_ci "u:r:chipset_init:s0" 42d9f0492fSopenharmony_ci}; 43d9f0492fSopenharmony_ci 44d9f0492fSopenharmony_cistatic void SubInitMain(InitContextType type, int readFd, int writeFd); 45d9f0492fSopenharmony_cistatic void HandleRecvMessage(SubInitInfo *subInfo, char *buffer, uint32_t size); 46d9f0492fSopenharmony_cistatic int CreateSocketPair(int socket[2]); 47d9f0492fSopenharmony_cistatic int SubInitSetSelinuxContext(InitContextType type); 48d9f0492fSopenharmony_ci 49d9f0492fSopenharmony_cistatic int SubInitRun(const SubInitForkArg *arg) 50d9f0492fSopenharmony_ci{ 51d9f0492fSopenharmony_ci PLUGIN_LOGW("SubInitRun %d ", arg->type); 52d9f0492fSopenharmony_ci SubInitSetSelinuxContext(arg->type); 53d9f0492fSopenharmony_ci#ifndef STARTUP_INIT_TEST 54d9f0492fSopenharmony_ci close(arg->socket[0]); 55d9f0492fSopenharmony_ci#endif 56d9f0492fSopenharmony_ci SubInitMain(arg->type, arg->socket[1], arg->socket[1]); 57d9f0492fSopenharmony_ci close(arg->socket[1]); 58d9f0492fSopenharmony_ci#ifndef STARTUP_INIT_TEST 59d9f0492fSopenharmony_ci _exit(PROCESS_EXIT_CODE); 60d9f0492fSopenharmony_ci#else 61d9f0492fSopenharmony_ci return 0; 62d9f0492fSopenharmony_ci#endif 63d9f0492fSopenharmony_ci} 64d9f0492fSopenharmony_ci 65d9f0492fSopenharmony_ci#ifndef STARTUP_INIT_TEST 66d9f0492fSopenharmony_cipid_t SubInitFork(int (*childFunc)(const SubInitForkArg *arg), const SubInitForkArg *args) 67d9f0492fSopenharmony_ci{ 68d9f0492fSopenharmony_ci pid_t pid = fork(); 69d9f0492fSopenharmony_ci if (pid == 0) { 70d9f0492fSopenharmony_ci childFunc(args); 71d9f0492fSopenharmony_ci } 72d9f0492fSopenharmony_ci return pid; 73d9f0492fSopenharmony_ci} 74d9f0492fSopenharmony_ci#endif 75d9f0492fSopenharmony_ci 76d9f0492fSopenharmony_cistatic int SubInitStart(InitContextType type) 77d9f0492fSopenharmony_ci{ 78d9f0492fSopenharmony_ci PLUGIN_CHECK(type < INIT_CONTEXT_MAIN, return -1, "Invalid type %d", type); 79d9f0492fSopenharmony_ci SubInitInfo *subInfo = &g_subInitInfo[type]; 80d9f0492fSopenharmony_ci if (subInfo->state != SUB_INIT_STATE_IDLE) { 81d9f0492fSopenharmony_ci return 0; 82d9f0492fSopenharmony_ci } 83d9f0492fSopenharmony_ci SubInitForkArg arg = { 0 }; 84d9f0492fSopenharmony_ci arg.type = type; 85d9f0492fSopenharmony_ci int ret = CreateSocketPair(arg.socket); 86d9f0492fSopenharmony_ci PLUGIN_CHECK(ret == 0, return -1, "Failed to create socket for %d", type); 87d9f0492fSopenharmony_ci 88d9f0492fSopenharmony_ci subInfo->state = SUB_INIT_STATE_STARTING; 89d9f0492fSopenharmony_ci pid_t pid = SubInitFork(SubInitRun, &arg); 90d9f0492fSopenharmony_ci if (pid < 0) { 91d9f0492fSopenharmony_ci close(arg.socket[0]); 92d9f0492fSopenharmony_ci close(arg.socket[1]); 93d9f0492fSopenharmony_ci subInfo->state = SUB_INIT_STATE_IDLE; 94d9f0492fSopenharmony_ci return -1; 95d9f0492fSopenharmony_ci } 96d9f0492fSopenharmony_ci#ifndef STARTUP_INIT_TEST 97d9f0492fSopenharmony_ci close(arg.socket[1]); 98d9f0492fSopenharmony_ci#endif 99d9f0492fSopenharmony_ci subInfo->sendFd = arg.socket[0]; 100d9f0492fSopenharmony_ci subInfo->recvFd = arg.socket[0]; 101d9f0492fSopenharmony_ci subInfo->state = SUB_INIT_STATE_RUNNING; 102d9f0492fSopenharmony_ci subInfo->subPid = pid; 103d9f0492fSopenharmony_ci return 0; 104d9f0492fSopenharmony_ci} 105d9f0492fSopenharmony_ci 106d9f0492fSopenharmony_cistatic void SubInitStop(pid_t pid) 107d9f0492fSopenharmony_ci{ 108d9f0492fSopenharmony_ci for (size_t i = 0; i < ARRAY_LENGTH(g_subInitInfo); i++) { 109d9f0492fSopenharmony_ci if (g_subInitInfo[i].subPid == pid) { 110d9f0492fSopenharmony_ci close(g_subInitInfo[i].sendFd); 111d9f0492fSopenharmony_ci g_subInitInfo[i].subPid = 0; 112d9f0492fSopenharmony_ci g_subInitInfo[i].state = SUB_INIT_STATE_IDLE; 113d9f0492fSopenharmony_ci } 114d9f0492fSopenharmony_ci } 115d9f0492fSopenharmony_ci} 116d9f0492fSopenharmony_ci 117d9f0492fSopenharmony_cistatic int SubInitExecuteCmd(InitContextType type, const char *name, const char *cmdContent) 118d9f0492fSopenharmony_ci{ 119d9f0492fSopenharmony_ci static char buffer[MAX_CMD_LEN] = {0}; 120d9f0492fSopenharmony_ci PLUGIN_CHECK(type < INIT_CONTEXT_MAIN, return -1, "Invalid type %d", type); 121d9f0492fSopenharmony_ci PLUGIN_CHECK(name != NULL, return -1, "Invalid cmd name"); 122d9f0492fSopenharmony_ci SubInitInfo *subInfo = &g_subInitInfo[type]; 123d9f0492fSopenharmony_ci PLUGIN_CHECK(subInfo->state == SUB_INIT_STATE_RUNNING, return -1, "Sub init %d is not running ", type); 124d9f0492fSopenharmony_ci 125d9f0492fSopenharmony_ci int len = 0; 126d9f0492fSopenharmony_ci if (cmdContent != NULL) { 127d9f0492fSopenharmony_ci len = snprintf_s(buffer, sizeof(buffer), sizeof(buffer) - 1, "%s %s", name, cmdContent); 128d9f0492fSopenharmony_ci } else { 129d9f0492fSopenharmony_ci len = snprintf_s(buffer, sizeof(buffer), sizeof(buffer) - 1, "%s ", name); 130d9f0492fSopenharmony_ci } 131d9f0492fSopenharmony_ci PLUGIN_CHECK(len > 0, return -1, "Failed to format cmd %s", name); 132d9f0492fSopenharmony_ci buffer[len] = '\0'; 133d9f0492fSopenharmony_ci PLUGIN_LOGV("send cmd '%s'", buffer); 134d9f0492fSopenharmony_ci int ret = send(subInfo->sendFd, buffer, len, 0); 135d9f0492fSopenharmony_ci if (ret < 0 && errno == EPIPE) { 136d9f0492fSopenharmony_ci PLUGIN_LOGI("Failed to send cmd %s to %d, need fork new chip init process", name, subInfo->type); 137d9f0492fSopenharmony_ci SubInitStop(subInfo->subPid); 138d9f0492fSopenharmony_ci SubInitStart(type); 139d9f0492fSopenharmony_ci ret = send(subInfo->sendFd, buffer, len, 0); 140d9f0492fSopenharmony_ci } 141d9f0492fSopenharmony_ci PLUGIN_CHECK(ret > 0, return errno, "Failed to send cmd %s to %d errno %d", name, subInfo->type, errno); 142d9f0492fSopenharmony_ci 143d9f0492fSopenharmony_ci // block and wait result 144d9f0492fSopenharmony_ci ssize_t rLen = TEMP_FAILURE_RETRY(read(subInfo->recvFd, buffer, sizeof(buffer))); 145d9f0492fSopenharmony_ci while ((rLen < 0) && (errno == EAGAIN)) { 146d9f0492fSopenharmony_ci rLen = TEMP_FAILURE_RETRY(read(subInfo->recvFd, buffer, sizeof(buffer))); 147d9f0492fSopenharmony_ci } 148d9f0492fSopenharmony_ci PLUGIN_CHECK(rLen >= 0 && (size_t)rLen < sizeof(buffer), return errno, 149d9f0492fSopenharmony_ci "Failed to read result from %d for cmd %s errno %d", subInfo->type, name, errno); 150d9f0492fSopenharmony_ci // change to result 151d9f0492fSopenharmony_ci buffer[rLen] = '\0'; 152d9f0492fSopenharmony_ci PLUGIN_LOGV("recv cmd result %s", buffer); 153d9f0492fSopenharmony_ci return atoi(buffer); 154d9f0492fSopenharmony_ci} 155d9f0492fSopenharmony_ci 156d9f0492fSopenharmony_cistatic int CreateSocketPair(int socket[2]) 157d9f0492fSopenharmony_ci{ 158d9f0492fSopenharmony_ci int ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, socket); 159d9f0492fSopenharmony_ci PLUGIN_CHECK(ret == 0, return -1, "Create socket fail errno %d", errno); 160d9f0492fSopenharmony_ci 161d9f0492fSopenharmony_ci int opt = 1; 162d9f0492fSopenharmony_ci struct timeval timeout = {TIMEOUT_DEF, 0}; 163d9f0492fSopenharmony_ci do { 164d9f0492fSopenharmony_ci ret = setsockopt(socket[0], SOL_SOCKET, SO_PASSCRED, &opt, sizeof(opt)); 165d9f0492fSopenharmony_ci PLUGIN_CHECK(ret == 0, break, "Failed to set opt for %d errno %d", socket[0], errno); 166d9f0492fSopenharmony_ci ret = setsockopt(socket[1], SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); 167d9f0492fSopenharmony_ci PLUGIN_CHECK(ret == 0, break, "Failed to set opt for %d errno %d", socket[1], errno); 168d9f0492fSopenharmony_ci ret = setsockopt(socket[0], SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)); 169d9f0492fSopenharmony_ci PLUGIN_CHECK(ret == 0, break, "Failed to set opt for %d errno %d", socket[0], errno); 170d9f0492fSopenharmony_ci } while (0); 171d9f0492fSopenharmony_ci if (ret != 0) { 172d9f0492fSopenharmony_ci close(socket[0]); 173d9f0492fSopenharmony_ci close(socket[1]); 174d9f0492fSopenharmony_ci } 175d9f0492fSopenharmony_ci return ret; 176d9f0492fSopenharmony_ci} 177d9f0492fSopenharmony_ci 178d9f0492fSopenharmony_cistatic int CheckSocketPermission(const SubInitInfo *subInfo) 179d9f0492fSopenharmony_ci{ 180d9f0492fSopenharmony_ci struct ucred uc = {-1, -1, -1}; 181d9f0492fSopenharmony_ci socklen_t len = sizeof(uc); 182d9f0492fSopenharmony_ci // Only root is permitted to use control fd of init. 183d9f0492fSopenharmony_ci if (getsockopt(subInfo->recvFd, SOL_SOCKET, SO_PEERCRED, &uc, &len) < 0 || uc.uid != 0) { 184d9f0492fSopenharmony_ci INIT_LOGE("Failed to get socket option. err = %d", errno); 185d9f0492fSopenharmony_ci errno = EPERM; 186d9f0492fSopenharmony_ci return -1; 187d9f0492fSopenharmony_ci } 188d9f0492fSopenharmony_ci return 0; 189d9f0492fSopenharmony_ci} 190d9f0492fSopenharmony_ci 191d9f0492fSopenharmony_cistatic int HandleRecvMessage_(SubInitInfo *subInfo, char *buffer, uint32_t size) 192d9f0492fSopenharmony_ci{ 193d9f0492fSopenharmony_ci if (CheckSocketPermission(subInfo) != 0) { 194d9f0492fSopenharmony_ci return -1; 195d9f0492fSopenharmony_ci } 196d9f0492fSopenharmony_ci ssize_t rLen = TEMP_FAILURE_RETRY(read(subInfo->recvFd, buffer, size)); 197d9f0492fSopenharmony_ci while ((rLen < 0) && (errno == EAGAIN)) { 198d9f0492fSopenharmony_ci rLen = TEMP_FAILURE_RETRY(read(subInfo->recvFd, buffer, size)); 199d9f0492fSopenharmony_ci } 200d9f0492fSopenharmony_ci PLUGIN_CHECK(rLen >= 0 && rLen < size, return errno, 201d9f0492fSopenharmony_ci "Read message for %d fail errno %d rLen %d", subInfo->type, errno, rLen); 202d9f0492fSopenharmony_ci buffer[rLen] = '\0'; 203d9f0492fSopenharmony_ci PLUGIN_LOGI("Exec cmd '%s' in sub init %s", buffer, g_subContext[subInfo->type]); 204d9f0492fSopenharmony_ci int index = 0; 205d9f0492fSopenharmony_ci const char *cmd = GetMatchCmd(buffer, &index); 206d9f0492fSopenharmony_ci PLUGIN_CHECK(cmd != NULL, return -1, "Can not find cmd %s", buffer); 207d9f0492fSopenharmony_ci DoCmdByIndex(index, buffer + strlen(cmd) + 1, NULL); 208d9f0492fSopenharmony_ci return 0; 209d9f0492fSopenharmony_ci} 210d9f0492fSopenharmony_ci 211d9f0492fSopenharmony_cistatic void HandleRecvMessage(SubInitInfo *subInfo, char *buffer, uint32_t size) 212d9f0492fSopenharmony_ci{ 213d9f0492fSopenharmony_ci int ret = HandleRecvMessage_(subInfo, buffer, size); 214d9f0492fSopenharmony_ci int len = snprintf_s(buffer, size, size - 1, "%d", ret); 215d9f0492fSopenharmony_ci PLUGIN_CHECK(len > 0, return, "Failed to format result %d", ret); 216d9f0492fSopenharmony_ci buffer[len] = '\0'; 217d9f0492fSopenharmony_ci ret = send(subInfo->sendFd, buffer, len, 0); 218d9f0492fSopenharmony_ci PLUGIN_CHECK(ret > 0, return, "Failed to send result to %d errno %d", subInfo->type, errno); 219d9f0492fSopenharmony_ci} 220d9f0492fSopenharmony_ci 221d9f0492fSopenharmony_cistatic void SubInitMain(InitContextType type, int readFd, int writeFd) 222d9f0492fSopenharmony_ci{ 223d9f0492fSopenharmony_ci PLUGIN_LOGI("SubInitMain, sub init %s[%d] enter", g_subContext[type], getpid()); 224d9f0492fSopenharmony_ci#ifndef STARTUP_INIT_TEST 225d9f0492fSopenharmony_ci (void)prctl(PR_SET_NAME, "chipset_init"); 226d9f0492fSopenharmony_ci const int timeout = 30000; // 30000 30s 227d9f0492fSopenharmony_ci#else 228d9f0492fSopenharmony_ci const int timeout = 1000; // 1000 1s 229d9f0492fSopenharmony_ci#endif 230d9f0492fSopenharmony_ci char buffer[MAX_CMD_LEN] = {0}; 231d9f0492fSopenharmony_ci struct pollfd pfd = {}; 232d9f0492fSopenharmony_ci pfd.events = POLLIN; 233d9f0492fSopenharmony_ci pfd.fd = readFd; 234d9f0492fSopenharmony_ci SubInitInfo subInfo = {}; 235d9f0492fSopenharmony_ci subInfo.type = type; 236d9f0492fSopenharmony_ci subInfo.recvFd = readFd; 237d9f0492fSopenharmony_ci subInfo.sendFd = writeFd; 238d9f0492fSopenharmony_ci while (1) { 239d9f0492fSopenharmony_ci pfd.revents = 0; 240d9f0492fSopenharmony_ci int ret = poll(&pfd, 1, timeout); 241d9f0492fSopenharmony_ci if (ret == 0) { 242d9f0492fSopenharmony_ci PLUGIN_LOGI("Poll sub init timeout, sub init %d exit", type); 243d9f0492fSopenharmony_ci return; 244d9f0492fSopenharmony_ci } else if (ret < 0) { 245d9f0492fSopenharmony_ci PLUGIN_LOGE("Failed to poll sub init socket!"); 246d9f0492fSopenharmony_ci return; 247d9f0492fSopenharmony_ci } 248d9f0492fSopenharmony_ci if ((unsigned int)pfd.revents & POLLIN) { 249d9f0492fSopenharmony_ci HandleRecvMessage(&subInfo, buffer, sizeof(buffer)); 250d9f0492fSopenharmony_ci } 251d9f0492fSopenharmony_ci } 252d9f0492fSopenharmony_ci} 253d9f0492fSopenharmony_ci 254d9f0492fSopenharmony_cistatic int SubInitSetSelinuxContext(InitContextType type) 255d9f0492fSopenharmony_ci{ 256d9f0492fSopenharmony_ci PLUGIN_CHECK(type < INIT_CONTEXT_MAIN, return -1, "Invalid type %d", type); 257d9f0492fSopenharmony_ci#ifdef INIT_SUPPORT_CHIPSET_INIT 258d9f0492fSopenharmony_ci#ifdef WITH_SELINUX 259d9f0492fSopenharmony_ci setcon(g_subContext[type]); 260d9f0492fSopenharmony_ci#endif 261d9f0492fSopenharmony_ci#endif 262d9f0492fSopenharmony_ci return 0; 263d9f0492fSopenharmony_ci} 264d9f0492fSopenharmony_ci 265d9f0492fSopenharmony_ci#ifdef STARTUP_INIT_TEST 266d9f0492fSopenharmony_ciSubInitInfo *GetSubInitInfo(InitContextType type) 267d9f0492fSopenharmony_ci{ 268d9f0492fSopenharmony_ci PLUGIN_CHECK(type < INIT_CONTEXT_MAIN, return NULL, "Invalid type %d", type); 269d9f0492fSopenharmony_ci return &g_subInitInfo[type]; 270d9f0492fSopenharmony_ci} 271d9f0492fSopenharmony_ci#endif 272d9f0492fSopenharmony_ci 273d9f0492fSopenharmony_ciMODULE_CONSTRUCTOR(void) 274d9f0492fSopenharmony_ci{ 275d9f0492fSopenharmony_ci for (size_t i = 0; i < ARRAY_LENGTH(g_subContext); i++) { 276d9f0492fSopenharmony_ci SubInitContext context = { 277d9f0492fSopenharmony_ci (InitContextType)i, 278d9f0492fSopenharmony_ci SubInitStart, 279d9f0492fSopenharmony_ci SubInitStop, 280d9f0492fSopenharmony_ci SubInitExecuteCmd, 281d9f0492fSopenharmony_ci SubInitSetSelinuxContext 282d9f0492fSopenharmony_ci }; 283d9f0492fSopenharmony_ci InitSubInitContext((InitContextType)i, &context); 284d9f0492fSopenharmony_ci } 285d9f0492fSopenharmony_ci} 286