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
39 static SubInitInfo g_subInitInfo[INIT_CONTEXT_MAIN] = {};
40 static const char *g_subContext[INIT_CONTEXT_MAIN] = {
41 "u:r:chipset_init:s0"
42 };
43
44 static void SubInitMain(InitContextType type, int readFd, int writeFd);
45 static void HandleRecvMessage(SubInitInfo *subInfo, char *buffer, uint32_t size);
46 static int CreateSocketPair(int socket[2]);
47 static int SubInitSetSelinuxContext(InitContextType type);
48
SubInitRun(const SubInitForkArg * arg)49 static 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
SubInitFork(int (* childFunc)(const SubInitForkArg * arg),const SubInitForkArg * args)66 pid_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
SubInitStart(InitContextType type)76 static 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
SubInitStop(pid_t pid)106 static 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
SubInitExecuteCmd(InitContextType type,const char * name,const char * cmdContent)117 static 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
CreateSocketPair(int socket[2])156 static 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
CheckSocketPermission(const SubInitInfo * subInfo)178 static 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
HandleRecvMessage_(SubInitInfo * subInfo,char * buffer,uint32_t size)191 static 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
HandleRecvMessage(SubInitInfo * subInfo,char * buffer,uint32_t size)211 static 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
SubInitMain(InitContextType type,int readFd,int writeFd)221 static 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
SubInitSetSelinuxContext(InitContextType type)254 static 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
GetSubInitInfo(InitContextType type)266 SubInitInfo *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
MODULE_CONSTRUCTOR(void)273 MODULE_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