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