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