1 /*
2  * Copyright (c) 2021-2022 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.h"
16 
17 #include <errno.h>
18 #include <poll.h>
19 #include <stdarg.h>
20 #include <stdlib.h>
21 #include <signal.h>
22 #include <time.h>
23 #include <sys/sysmacros.h>
24 #include <sys/stat.h>
25 #include <sys/types.h>
26 #include <sys/socket.h>
27 #include <linux/major.h>
28 
29 #include "config_policy_utils.h"
30 #include "device.h"
31 #include "fd_holder_service.h"
32 #include "key_control.h"
33 #include "init_control_fd_service.h"
34 #include "init_log.h"
35 #include "init_mount.h"
36 #include "init_group_manager.h"
37 #include "init_param.h"
38 #include "init_service.h"
39 #include "init_service_manager.h"
40 #include "init_utils.h"
41 #include "securec.h"
42 #include "fd_holder_internal.h"
43 #include "bootstage.h"
44 
FdHolderSockInit(void)45 static int FdHolderSockInit(void)
46 {
47     int sock = -1;
48     int on = 1;
49     int fdHolderBufferSize = FD_HOLDER_BUFFER_SIZE; // 4KiB
50     sock = socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
51     if (sock < 0) {
52         INIT_LOGE("Failed to create fd holder socket, err = %d", errno);
53         return -1;
54     }
55 
56     setsockopt(sock, SOL_SOCKET, SO_RCVBUFFORCE, &fdHolderBufferSize, sizeof(fdHolderBufferSize));
57     setsockopt(sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
58 
59     if (access(INIT_HOLDER_SOCKET_PATH, F_OK) == 0) {
60         INIT_LOGI("%s exist, remove it", INIT_HOLDER_SOCKET_PATH);
61         unlink(INIT_HOLDER_SOCKET_PATH);
62     }
63     struct sockaddr_un addr;
64     addr.sun_family = AF_UNIX;
65     if (strncpy_s(addr.sun_path, sizeof(addr.sun_path),
66         INIT_HOLDER_SOCKET_PATH, strlen(INIT_HOLDER_SOCKET_PATH)) != 0) {
67         INIT_LOGE("Failed to copy fd hoder socket path");
68         close(sock);
69         return -1;
70     }
71     socklen_t len = (socklen_t)(offsetof(struct sockaddr_un, sun_path) + strlen(addr.sun_path) + 1);
72     if (bind(sock, (struct sockaddr *)&addr, len) < 0) {
73         INIT_LOGE("Failed to binder fd folder socket %d", errno);
74         close(sock);
75         return -1;
76     }
77 
78     // Owned by root
79     if (lchown(addr.sun_path, 0, 0)) {
80         INIT_LOGW("Failed to change owner of fd holder socket, err = %d", errno);
81     }
82     mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
83     if (fchmodat(AT_FDCWD, addr.sun_path, mode, AT_SYMLINK_NOFOLLOW)) {
84         INIT_LOGW("Failed to change mode of fd holder socket, err = %d", errno);
85     }
86     INIT_LOGI("Init fd holder socket done");
87     return sock;
88 }
89 
SystemInit(void)90 void SystemInit(void)
91 {
92     CloseStdio();
93 #ifndef STARTUP_INIT_TEST
94     // Set up a session keyring that all processes will have access to.
95     KeyCtrlGetKeyringId(KEY_SPEC_SESSION_KEYRING, 1);
96 #endif
97     // umask call always succeeds and return the previous mask value which is not needed here
98     (void)umask(DEFAULT_UMASK_INIT);
99     MakeDirRecursive("/dev/unix/socket", S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
100     int sock = FdHolderSockInit();
101     if (sock >= 0) {
102         RegisterFdHoldWatcher(sock);
103     }
104     InitControlFd();
105 
106     // sysclktz 0
107     struct timezone tz = { 0 };
108     if (settimeofday(NULL, &tz) == -1) {
109         INIT_LOGE("Set time of day failed, err = %d", errno);
110     }
111 }
112 
LogInit(void)113 void LogInit(void)
114 {
115     int ret = mknod("/dev/kmsg", S_IFCHR | S_IWUSR | S_IRUSR,
116         makedev(MEM_MAJOR, DEV_KMSG_MINOR));
117     if (ret == 0) {
118         OpenLogDevice();
119     }
120 }
121 
WriteUptimeSysParam(const char *param, const char *uptime)122 static void WriteUptimeSysParam(const char *param, const char *uptime)
123 {
124     char buf[64];
125 
126     if (uptime == NULL) {
127         snprintf_s(buf, sizeof(buf), sizeof(buf) - 1,
128                    "%lld", GetUptimeInMicroSeconds(NULL));
129         uptime = buf;
130     }
131     SystemWriteParam(param, uptime);
132 }
133 
134 INIT_TIMING_STAT g_bootJob = {{0}, {0}};
135 
RecordInitBootEvent(const char *initBootEvent)136 static void RecordInitBootEvent(const char *initBootEvent)
137 {
138     const char *bootEventArgv[] = {"init", initBootEvent};
139     PluginExecCmd("bootevent", ARRAY_LENGTH(bootEventArgv), bootEventArgv);
140     return;
141 }
142 
BootStateChange(int start, const char *content)143 INIT_STATIC void BootStateChange(int start, const char *content)
144 {
145     if (start == 0) {
146         clock_gettime(CLOCK_MONOTONIC, &(g_bootJob.startTime));
147         RecordInitBootEvent(content);
148         INIT_LOGI("boot job %s start.", content);
149     } else {
150         clock_gettime(CLOCK_MONOTONIC, &(g_bootJob.endTime));
151         RecordInitBootEvent(content);
152         long long diff = InitDiffTime(&g_bootJob);
153         INIT_LOGI("boot job %s finish diff %lld us.", content, diff);
154         if (strcmp(content, "boot") == 0) {
155             WriteUptimeSysParam("ohos.boot.time.init", NULL);
156         }
157     }
158 }
159 
InitLoadParamFiles(void)160 static void InitLoadParamFiles(void)
161 {
162     if (InUpdaterMode() != 0) {
163         LoadDefaultParams("/etc/param/ohos_const", LOAD_PARAM_NORMAL);
164         LoadDefaultParams("/etc/param", LOAD_PARAM_ONLY_ADD);
165         LoadDefaultParams("/vendor/etc/param", LOAD_PARAM_ONLY_ADD);
166         return;
167     }
168 
169     // Load developer mode param
170     LoadDefaultParams("/proc/dsmm/developer", LOAD_PARAM_NORMAL);
171 
172     // Load const params, these can't be override!
173     LoadDefaultParams("/system/etc/param/ohos_const", LOAD_PARAM_NORMAL);
174     CfgFiles *files = GetCfgFiles("etc/param");
175     for (int i = MAX_CFG_POLICY_DIRS_CNT - 1; files && i >= 0; i--) {
176         if (files->paths[i]) {
177             LoadDefaultParams(files->paths[i], LOAD_PARAM_ONLY_ADD);
178         }
179     }
180     FreeCfgFiles(files);
181 }
182 
InitPreHook(const HOOK_INFO *hookInfo, void *executionContext)183 INIT_STATIC void InitPreHook(const HOOK_INFO *hookInfo, void *executionContext)
184 {
185     INIT_TIMING_STAT *stat = (INIT_TIMING_STAT *)executionContext;
186     clock_gettime(CLOCK_MONOTONIC, &(stat->startTime));
187 }
188 
InitPostHook(const HOOK_INFO *hookInfo, void *executionContext, int executionRetVal)189 INIT_STATIC void InitPostHook(const HOOK_INFO *hookInfo, void *executionContext, int executionRetVal)
190 {
191     INIT_TIMING_STAT *stat = (INIT_TIMING_STAT *)executionContext;
192     clock_gettime(CLOCK_MONOTONIC, &(stat->endTime));
193     long long diff = InitDiffTime(stat);
194     INIT_LOGI("Executing hook [%d:%d] cost [%lld]us, result %d.",
195         hookInfo->stage, hookInfo->prio, diff, executionRetVal);
196 }
197 
InitSysAdj(void)198 static void InitSysAdj(void)
199 {
200     const char* path = "/proc/self/oom_score_adj";
201     const char* content = "-1000";
202     int fd = open(path, O_RDWR);
203     if (fd == -1) {
204         return;
205     }
206     if (write(fd, content, strlen(content)) < 0) {
207         close(fd);
208         return;
209     }
210     close(fd);
211     return;
212 }
213 
TriggerServices(int startMode)214 INIT_STATIC void TriggerServices(int startMode)
215 {
216     int index = 0;
217     int jobNum = 0;
218     char jobName[64] = {0}; // 64 job name
219     char cmd[64] = {0};  // 64 job name
220     const int maxServiceInJob = 4; // 4 service in job
221     InitGroupNode *node = GetNextGroupNode(NODE_TYPE_SERVICES, NULL);
222     while (node != NULL) {
223         Service *service = node->data.service;
224         if (service == NULL || service->startMode != startMode) {
225             node = GetNextGroupNode(NODE_TYPE_SERVICES, node);
226             continue;
227         }
228         if (IsOnDemandService(service)) {
229             if (CreateSocketForService(service) != 0) {
230                 INIT_LOGE("service %s exit! create socket failed!", service->name);
231             }
232             node = GetNextGroupNode(NODE_TYPE_SERVICES, node);
233             continue;
234         }
235         if (sprintf_s(cmd, sizeof(cmd), "start %s", service->name) <= 0) {
236             node = GetNextGroupNode(NODE_TYPE_SERVICES, node);
237             continue;
238         }
239         if (index == 0) {
240             if (sprintf_s(jobName, sizeof(jobName), "boot-service:service-%d-%03d", startMode, jobNum) <= 0) {
241                 node = GetNextGroupNode(NODE_TYPE_SERVICES, node);
242                 continue;
243             }
244             jobNum++;
245         }
246         index++;
247         AddCompleteJob(jobName, NULL, cmd);
248         INIT_LOGV("Add %s to job %s", service->name, jobName);
249         if (index == maxServiceInJob) {
250             PostTrigger(EVENT_TRIGGER_BOOT, jobName, strlen(jobName));
251             index = 0;
252         }
253         node = GetNextGroupNode(NODE_TYPE_SERVICES, node);
254     }
255     if (index > 0) {
256         PostTrigger(EVENT_TRIGGER_BOOT, jobName, strlen(jobName));
257     }
258 }
259 
ParseInitCfgByPriority(void)260 void ParseInitCfgByPriority(void)
261 {
262     CfgFiles *files = GetCfgFiles("etc/init");
263     for (int i = 0; files && i < MAX_CFG_POLICY_DIRS_CNT; i++) {
264         if (files->paths[i]) {
265             if (ReadFileInDir(files->paths[i], ".cfg", ParseInitCfg, NULL) < 0) {
266                 break;
267             }
268         }
269     }
270     FreeCfgFiles(files);
271 }
272 
SystemConfig(const char *uptime)273 void SystemConfig(const char *uptime)
274 {
275     INIT_TIMING_STAT timingStat;
276 
277     InitSysAdj();
278 
279     HOOK_EXEC_OPTIONS options;
280 
281     options.flags = 0;
282     options.preHook = InitPreHook;
283     options.postHook = InitPostHook;
284     InitServiceSpace();
285     HookMgrExecute(GetBootStageHookMgr(), INIT_GLOBAL_INIT, (void *)&timingStat, (void *)&options);
286     RecordInitBootEvent("init.prepare");
287 
288     HookMgrExecute(GetBootStageHookMgr(), INIT_PRE_PARAM_SERVICE, (void *)&timingStat, (void *)&options);
289     if (InitParamService() != 0) {
290         INIT_LOGE("[startup_failed]Init param service failed %d", SYS_PARAM_INIT_FAILED);
291         ExecReboot("panic");
292     }
293     InitParseGroupCfg();
294     RegisterBootStateChange(BootStateChange);
295 
296     INIT_LOGI("boot stage: init finish.");
297 
298     // The cgroupv1 hierarchy may be created asynchronously in the early stage,
299     // so make sure it has been done before loading SELinux.
300     struct stat sourceInfo = {0};
301     if (stat("/dev/cgroup", &sourceInfo) == 0) {
302         WaitForFile("/dev/memcg/procs", WAIT_MAX_SECOND);
303     }
304 
305     // load SELinux context and policy
306     // Do not move position!
307     PluginExecCmdByName("loadSelinuxPolicy", "");
308     RecordInitBootEvent("init.prepare");
309 
310     // after selinux loaded
311     SignalInit();
312 
313     RecordInitBootEvent("init.ParseCfg");
314     LoadSpecialParam();
315 
316     // parse parameters
317     HookMgrExecute(GetBootStageHookMgr(), INIT_PRE_PARAM_LOAD, (void *)&timingStat, (void *)&options);
318     InitLoadParamFiles();
319 
320     // Write kernel uptime into system parameter
321     WriteUptimeSysParam("ohos.boot.time.kernel", uptime);
322 
323     // read config
324     HookMgrExecute(GetBootStageHookMgr(), INIT_PRE_CFG_LOAD, (void *)&timingStat, (void *)&options);
325     ReadConfig();
326     RecordInitBootEvent("init.ParseCfg");
327     INIT_LOGI("boot stage: parse config file finish.");
328     HookMgrExecute(GetBootStageHookMgr(), INIT_POST_CFG_LOAD, (void *)&timingStat, (void *)&options);
329 
330     IsEnableSandbox();
331     // execute init
332     PostTrigger(EVENT_TRIGGER_BOOT, "pre-init", strlen("pre-init"));
333     PostTrigger(EVENT_TRIGGER_BOOT, "init", strlen("init"));
334     TriggerServices(START_MODE_BOOT);
335     PostTrigger(EVENT_TRIGGER_BOOT, "post-init", strlen("post-init"));
336     TriggerServices(START_MODE_NORMAL);
337     clock_gettime(CLOCK_MONOTONIC, &(g_bootJob.startTime));
338 }
339 
SystemRun(void)340 void SystemRun(void)
341 {
342     StartParamService();
343 }
344