• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     PLUGIN_CHECK(ret > 0, return errno, "Failed to send cmd %s to %d errno %d", name, subInfo->type, errno);
136 
137     // block and wait result
138     ssize_t rLen = TEMP_FAILURE_RETRY(read(subInfo->recvFd, buffer, sizeof(buffer)));
139     while ((rLen < 0) && (errno == EAGAIN)) {
140         rLen = TEMP_FAILURE_RETRY(read(subInfo->recvFd, buffer, sizeof(buffer)));
141     }
142     PLUGIN_CHECK(rLen >= 0 && rLen < sizeof(buffer), return errno,
143         "Failed to read result from %d for cmd %s errno %d", subInfo->type, name, errno);
144     // change to result
145     buffer[rLen] = '\0';
146     PLUGIN_LOGV("recv cmd result %s", buffer);
147     return atoi(buffer);
148 }
149 
CreateSocketPair(int socket[2])150 static int CreateSocketPair(int socket[2])
151 {
152     int ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, socket);
153     PLUGIN_CHECK(ret == 0, return -1, "Create socket fail errno %d", errno);
154 
155     int opt = 1;
156     struct timeval timeout = {TIMEOUT_DEF, 0};
157     do {
158         ret = setsockopt(socket[0], SOL_SOCKET, SO_PASSCRED, &opt, sizeof(opt));
159         PLUGIN_CHECK(ret == 0, break, "Failed to set opt for %d errno %d", socket[0], errno);
160         ret = setsockopt(socket[1], SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
161         PLUGIN_CHECK(ret == 0, break, "Failed to set opt for %d errno %d", socket[1], errno);
162         ret = setsockopt(socket[0], SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
163         PLUGIN_CHECK(ret == 0, break, "Failed to set opt for %d errno %d", socket[0], errno);
164     } while (0);
165     if (ret != 0) {
166         close(socket[0]);
167         close(socket[1]);
168     }
169     return ret;
170 }
171 
CheckSocketPermission(const SubInitInfo * subInfo)172 static int CheckSocketPermission(const SubInitInfo *subInfo)
173 {
174     struct ucred uc = {-1, -1, -1};
175     socklen_t len = sizeof(uc);
176     // Only root is permitted to use control fd of init.
177     if (getsockopt(subInfo->recvFd, SOL_SOCKET, SO_PEERCRED, &uc, &len) < 0 || uc.uid != 0) {
178         INIT_LOGE("Failed to get socket option. err = %d", errno);
179         errno = EPERM;
180         return -1;
181     }
182     return 0;
183 }
184 
HandleRecvMessage_(SubInitInfo * subInfo,char * buffer,uint32_t size)185 static int HandleRecvMessage_(SubInitInfo *subInfo, char *buffer, uint32_t size)
186 {
187     if (CheckSocketPermission(subInfo) != 0) {
188         return -1;
189     }
190     ssize_t rLen = TEMP_FAILURE_RETRY(read(subInfo->recvFd, buffer, size));
191     while ((rLen < 0) && (errno == EAGAIN)) {
192         rLen = TEMP_FAILURE_RETRY(read(subInfo->recvFd, buffer, size));
193     }
194     PLUGIN_CHECK(rLen >= 0, return errno, "Read message for %d fail errno %d", subInfo->type, errno);
195     buffer[rLen] = '\0';
196     PLUGIN_LOGI("Exec cmd '%s' in sub init %s", buffer, g_subContext[subInfo->type]);
197     int index = 0;
198     const char *cmd = GetMatchCmd(buffer, &index);
199     PLUGIN_CHECK(cmd != NULL, return -1, "Can not find cmd %s", buffer);
200     DoCmdByIndex(index, buffer + strlen(cmd) + 1, NULL);
201     return 0;
202 }
203 
HandleRecvMessage(SubInitInfo * subInfo,char * buffer,uint32_t size)204 static void HandleRecvMessage(SubInitInfo *subInfo, char *buffer, uint32_t size)
205 {
206     int ret = HandleRecvMessage_(subInfo, buffer, size);
207     int len = snprintf_s(buffer, size, size - 1, "%d", ret);
208     PLUGIN_CHECK(len > 0, return, "Failed to format result %d", ret);
209     buffer[len] = '\0';
210     ret = send(subInfo->sendFd, buffer, len, 0);
211     PLUGIN_CHECK(ret > 0, return, "Failed to send result to %d errno %d", subInfo->type, errno);
212 }
213 
SubInitMain(InitContextType type,int readFd,int writeFd)214 static void SubInitMain(InitContextType type, int readFd, int writeFd)
215 {
216     PLUGIN_LOGI("SubInitMain, sub init %s[%d] enter", g_subContext[type], getpid());
217 #ifndef STARTUP_INIT_TEST
218     (void)prctl(PR_SET_NAME, "chipset_init");
219     const int timeout = 30000; // 30000 30s
220 #else
221     const int timeout = 1000; // 1000 1s
222 #endif
223     char buffer[MAX_CMD_LEN] = {0};
224     struct pollfd pfd = {};
225     pfd.events = POLLIN;
226     pfd.fd = readFd;
227     SubInitInfo subInfo = {};
228     subInfo.type = type;
229     subInfo.recvFd = readFd;
230     subInfo.sendFd = writeFd;
231     while (1) {
232         pfd.revents = 0;
233         int ret = poll(&pfd, 1, timeout);
234         if (ret == 0) {
235             PLUGIN_LOGI("Poll sub init timeout, sub init %d exit", type);
236             return;
237         } else if (ret < 0) {
238             PLUGIN_LOGE("Failed to poll sub init socket!");
239             return;
240         }
241         if (pfd.revents & POLLIN) {
242             HandleRecvMessage(&subInfo, buffer, sizeof(buffer));
243         }
244     }
245 }
246 
SubInitSetSelinuxContext(InitContextType type)247 static int SubInitSetSelinuxContext(InitContextType type)
248 {
249     PLUGIN_CHECK(type < INIT_CONTEXT_MAIN, return -1, "Invalid type %d", type);
250 #ifdef INIT_SUPPORT_CHIPSET_INIT
251 #ifdef WITH_SELINUX
252     setcon(g_subContext[type]);
253 #endif
254 #endif
255     return 0;
256 }
257 
258 #ifdef STARTUP_INIT_TEST
GetSubInitInfo(InitContextType type)259 SubInitInfo *GetSubInitInfo(InitContextType type)
260 {
261     PLUGIN_CHECK(type < INIT_CONTEXT_MAIN, return NULL, "Invalid type %d", type);
262     return &g_subInitInfo[type];
263 }
264 #endif
265 
MODULE_CONSTRUCTOR(void)266 MODULE_CONSTRUCTOR(void)
267 {
268     for (size_t i = 0; i < ARRAY_LENGTH(g_subContext); i++) {
269         SubInitContext context = {
270             (InitContextType)i,
271             SubInitStart,
272             SubInitStop,
273             SubInitExecuteCmd,
274             SubInitSetSelinuxContext
275         };
276         InitSubInitContext((InitContextType)i, &context);
277     }
278 }
279