init.c 12.5 KB
Newer Older
1
/*
M
Mupceet 已提交
2
 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "init.h"

#include <errno.h>
X
xionglei6 已提交
18
#include <poll.h>
19 20
#include <stdlib.h>
#include <signal.h>
21
#include <time.h>
22 23 24
#include <sys/sysmacros.h>
#include <sys/stat.h>
#include <sys/types.h>
X
xionglei6 已提交
25
#include <sys/socket.h>
4
411148299@qq.com 已提交
26
#include <linux/major.h>
Z
zhr758 已提交
27 28

#include "config_policy_utils.h"
29
#include "device.h"
X
xionglei6 已提交
30
#include "fd_holder_service.h"
31
#include "fs_manager/fs_manager.h"
M
Mupceet 已提交
32
#include "init_control_fd_service.h"
33 34
#include "init_log.h"
#include "init_mount.h"
X
xionglei6 已提交
35
#include "init_group_manager.h"
36
#include "init_param.h"
X
xionglei6 已提交
37 38
#include "init_service.h"
#include "init_service_manager.h"
39 40
#include "init_utils.h"
#include "securec.h"
41 42 43
#include "switch_root.h"
#include "ueventd.h"
#include "ueventd_socket.h"
X
xionglei6 已提交
44
#include "fd_holder_internal.h"
X
xionglei6 已提交
45 46
#include "sandbox.h"
#include "sandbox_namespace.h"
47
#include "bootstage.h"
48

X
xionglei6 已提交
49 50
static bool g_enableSandbox;

X
xionglei6 已提交
51 52 53 54
static int FdHolderSockInit(void)
{
    int sock = -1;
    int on = 1;
X
xionglei6 已提交
55 56
    int fdHolderBufferSize = FD_HOLDER_BUFFER_SIZE; // 4KiB
    sock = socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
X
xionglei6 已提交
57 58 59 60 61 62 63 64 65 66 67 68 69
    if (sock < 0) {
        INIT_LOGE("Failed to create fd holder socket, err = %d", errno);
        return -1;
    }

    setsockopt(sock, SOL_SOCKET, SO_RCVBUFFORCE, &fdHolderBufferSize, sizeof(fdHolderBufferSize));
    setsockopt(sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));

    if (access(INIT_HOLDER_SOCKET_PATH, F_OK) == 0) {
        INIT_LOGI("%s exist, remove it", INIT_HOLDER_SOCKET_PATH);
        unlink(INIT_HOLDER_SOCKET_PATH);
    }
    struct sockaddr_un addr;
X
xionglei6 已提交
70
    addr.sun_family = AF_UNIX;
X
xionglei6 已提交
71 72
    if (strncpy_s(addr.sun_path, sizeof(addr.sun_path),
        INIT_HOLDER_SOCKET_PATH, strlen(INIT_HOLDER_SOCKET_PATH)) != 0) {
73
        INIT_LOGE("Failed to copy fd hoder socket path");
X
xionglei6 已提交
74 75 76 77 78
        close(sock);
        return -1;
    }
    socklen_t len = (socklen_t)(offsetof(struct sockaddr_un, sun_path) + strlen(addr.sun_path) + 1);
    if (bind(sock, (struct sockaddr *)&addr, len) < 0) {
X
xionglei6 已提交
79
        INIT_LOGE("Failed to binder fd folder socket %d", errno);
X
xionglei6 已提交
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
        close(sock);
        return -1;
    }

    // Owned by root
    if (lchown(addr.sun_path, 0, 0)) {
        INIT_LOGW("Failed to change owner of fd holder socket, err = %d", errno);
    }
    mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
    if (fchmodat(AT_FDCWD, addr.sun_path, mode, AT_SYMLINK_NOFOLLOW)) {
        INIT_LOGW("Failed to change mode of fd holder socket, err = %d", errno);
    }
    INIT_LOGI("Init fd holder socket done");
    return sock;
}

96 97 98
void SystemInit(void)
{
    SignalInit();
X
xionglei6 已提交
99 100
    // umask call always succeeds and return the previous mask value which is not needed here
    (void)umask(DEFAULT_UMASK_INIT);
101
    MakeDirRecursive("/dev/unix/socket", S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
X
xionglei6 已提交
102 103 104 105
    int sock = FdHolderSockInit();
    if (sock >= 0) {
        RegisterFdHoldWatcher(sock);
    }
M
Mupceet 已提交
106
    InitControlFd();
X
xionglei6 已提交
107 108
}

109 110 111 112 113 114 115 116 117 118 119 120 121 122
static void EnableDevKmsg(void)
{
    /* printk_devkmsg default value is ratelimit, We need to set "on" and remove the restrictions */
    int fd = open("/proc/sys/kernel/printk_devkmsg", O_WRONLY | O_CLOEXEC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
    if (fd < 0) {
        return;
    }
    char *kmsgStatus = "on";
    write(fd, kmsgStatus, strlen(kmsgStatus) + 1);
    close(fd);
    fd = -1;
    return;
}

123 124 125 126 127 128 129 130 131
void LogInit(void)
{
    int ret = mknod("/dev/kmsg", S_IFCHR | S_IWUSR | S_IRUSR,
        makedev(MEM_MAJOR, DEV_KMSG_MINOR));
    if (ret == 0) {
        OpenLogDevice();
    }
}

132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
static char **GetRequiredDevices(Fstab fstab, int *requiredNum)
{
    int num = 0;
    FstabItem *item = fstab.head;
    while (item != NULL) {
        if (FM_MANAGER_REQUIRED_ENABLED(item->fsManagerFlags)) {
            num++;
        }
        item = item->next;
    }
    char **devices = (char **)calloc(num, sizeof(char *));
    INIT_ERROR_CHECK(devices != NULL, return NULL, "Failed calloc err=%d", errno);

    int i = 0;
    item = fstab.head;
    while (item != NULL) {
        if (FM_MANAGER_REQUIRED_ENABLED(item->fsManagerFlags)) {
            devices[i] = strdup(item->deviceName);
            INIT_ERROR_CHECK(devices[i] != NULL, FreeStringVector(devices, num); return NULL,
                "Failed strdup err=%d", errno);
            i++;
        }
        item = item->next;
    }
    *requiredNum = num;
    return devices;
}

static int StartUeventd(char **requiredDevices, int num)
{
    INIT_ERROR_CHECK(requiredDevices != NULL && num > 0, return -1, "Failed parameters");
    int ueventSockFd = UeventdSocketInit();
    if (ueventSockFd < 0) {
        INIT_LOGE("Failed to create uevent socket");
        return -1;
    }
    RetriggerUevent(ueventSockFd, requiredDevices, num);
    close(ueventSockFd);
    return 0;
}

static void StartInitSecondStage(void)
{
    int requiredNum = 0;
    Fstab* fstab = LoadRequiredFstab();
    INIT_ERROR_CHECK(fstab != NULL, abort(), "Failed to load required fstab");
    char **devices = GetRequiredDevices(*fstab, &requiredNum);
    if (devices != NULL && requiredNum > 0) {
        int ret = StartUeventd(devices, requiredNum);
        if (ret == 0) {
            ret = MountRequriedPartitions(fstab);
        }
        FreeStringVector(devices, requiredNum);
        devices = NULL;
        ReleaseFstab(fstab);
        fstab = NULL;
        if (ret < 0) {
            // If mount required partitions failure.
            // There is no necessary to continue.
            // Just abort
192
            INIT_LOGE("Mount required partitions failed; please check fstab file");
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216
            // Execute sh for debugging
            execv("/bin/sh", NULL);
            abort();
        }
    }

    // It will panic if close stdio before execv("/bin/sh", NULL)
    CloseStdio();

#ifndef DISABLE_INIT_TWO_STAGES
    SwitchRoot("/usr");
    // Execute init second stage
    char * const args[] = {
        "/bin/init",
        "--second-stage",
        NULL,
    };
    if (execv("/bin/init", args) != 0) {
        INIT_LOGE("Failed to exec \"/bin/init\", err = %d", errno);
        exit(-1);
    }
#endif
}

217 218
void SystemPrepare(void)
{
219 220 221 222 223 224 225 226 227 228 229
    MountBasicFs();
    CreateDeviceNode();
    LogInit();
    // Make sure init log always output to /dev/kmsg.
    EnableDevKmsg();
    // Only ohos normal system support
    // two stages of init.
    // If we are in updater mode, only one stage of init,
    if (InUpdaterMode() == 0) {
        StartInitSecondStage();
    }
230 231
}

H
handyohos 已提交
232 233 234 235 236
#define INIT_BOOTSTAGE_HOOK_NAME "bootstage"
static HOOK_MGR *bootStageHookMgr = NULL;

HOOK_MGR *GetBootStageHookMgr()
{
237 238 239 240 241 242 243 244 245
    if (bootStageHookMgr != NULL) {
        return bootStageHookMgr;
    }

    /*
     * Create bootstage hook manager for booting only.
     * When boot completed, this manager will be destroyed.
     */
    bootStageHookMgr = HookMgrCreate(INIT_BOOTSTAGE_HOOK_NAME);
H
handyohos 已提交
246 247 248
    return bootStageHookMgr;
}

X
xionglei6 已提交
249 250 251 252
static void BootStateChange(const char *content)
{
    INIT_LOGI("boot start %s finish.", content);
    if (strcmp("init", content) == 0) {
X
xionglei6 已提交
253
        StartAllServices(START_MODE_BOOT);
X
xionglei6 已提交
254 255 256
        return;
    }
    if (strcmp("post-init", content) == 0) {
M
Mupceet 已提交
257
        StartAllServices(START_MODE_NORMAL);
X
xionglei6 已提交
258 259 260 261
        return;
    }
}

X
xionglei6 已提交
262 263 264 265 266 267 268 269 270 271
static void IsEnableSandbox(void)
{
    const char *name = "const.sandbox";
    char value[MAX_BUFFER_LEN] = {0};
    unsigned int len = MAX_BUFFER_LEN;
    if (SystemReadParam(name, value, &len) != 0) {
        INIT_LOGE("Failed read param.");
        g_enableSandbox = false;
    }
    if (strcmp(value, "enable") == 0) {
X
xionglei6 已提交
272
        INIT_LOGI("Enable sandbox.");
X
xionglei6 已提交
273 274
        g_enableSandbox = true;
    } else {
X
xionglei6 已提交
275
        INIT_LOGI("Disable sandbox.");
X
xionglei6 已提交
276 277 278 279
        g_enableSandbox = false;
    }
}

Z
zhr758 已提交
280 281
static void InitLoadParamFiles(void)
{
Y
yichengzhao 已提交
282 283 284 285 286 287
    if (InUpdaterMode() != 0) {
        LoadDefaultParams("/etc/param/ohos_const", LOAD_PARAM_NORMAL);
        LoadDefaultParams("/etc/param", LOAD_PARAM_ONLY_ADD);
        return;
    }

Z
zhr758 已提交
288 289 290 291 292 293 294 295 296 297 298
    // Load const params, these can't be override!
    LoadDefaultParams("/system/etc/param/ohos_const", LOAD_PARAM_NORMAL);
    CfgFiles *files = GetCfgFiles("etc/param");
    for (int i = MAX_CFG_POLICY_DIRS_CNT - 1; files && i >= 0; i--) {
        if (files->paths[i]) {
            LoadDefaultParams(files->paths[i], LOAD_PARAM_ONLY_ADD);
        }
    }
    FreeCfgFiles(files);
}

299 300 301 302 303
typedef struct HOOK_TIMING_STAT {
    struct timespec startTime;
    struct timespec endTime;
} HOOK_TIMING_STAT;

304
static void InitPreHook(const HOOK_INFO *hookInfo, void *executionContext)
305
{
306
    HOOK_TIMING_STAT *stat = (HOOK_TIMING_STAT *)executionContext;
307 308 309
    clock_gettime(CLOCK_MONOTONIC, &(stat->startTime));
}

310
static void InitPostHook(const HOOK_INFO *hookInfo, void *executionContext, int executionRetVal)
311 312
{
    long long diff;
M
Mupceet 已提交
313
    const long long baseTime = 1000;
314
    HOOK_TIMING_STAT *stat = (HOOK_TIMING_STAT *)executionContext;
315 316
    clock_gettime(CLOCK_MONOTONIC, &(stat->endTime));

M
Mupceet 已提交
317
    diff = (long long)((stat->endTime.tv_sec - stat->startTime.tv_sec) / baseTime);
318
    if (stat->endTime.tv_nsec > stat->startTime.tv_nsec) {
M
Mupceet 已提交
319
        diff += (stat->endTime.tv_nsec - stat->startTime.tv_nsec) * baseTime;
320
    } else {
M
Mupceet 已提交
321
        diff -= (stat->endTime.tv_nsec - stat->startTime.tv_nsec) * baseTime;
322 323
    }

M
Mupceet 已提交
324
    INIT_LOGV("Executing hook [%d:%d:%p] cost [%lld]ms, return %d.",
325
        hookInfo->stage, hookInfo->prio, hookInfo->hook, diff, executionRetVal);
326 327
}

328 329
void SystemConfig(void)
{
330
    HOOK_TIMING_STAT timingStat;
331
    HOOK_EXEC_OPTIONS options;
332

333 334 335
    options.flags = 0;
    options.preHook = InitPreHook;
    options.postHook = InitPostHook;
336

X
xionglei6 已提交
337
    InitServiceSpace();
M
Mupceet 已提交
338
    HookMgrExecute(GetBootStageHookMgr(), INIT_GLOBAL_INIT, (void *)&timingStat, (void *)&options);
339

H
handyohos 已提交
340
    HookMgrExecute(GetBootStageHookMgr(), INIT_PRE_PARAM_SERVICE, (void *)&timingStat, (void *)&options);
Z
zhr758 已提交
341
    InitParamService();
X
xionglei6 已提交
342 343 344
    InitParseGroupCfg();
    RegisterBootStateChange(BootStateChange);

R
renwei 已提交
345 346
    // load SELinux context and policy
    // Do not move position!
C
cheng_jinsong 已提交
347
    PluginExecCmdByName("loadSelinuxPolicy", "");
M
Mupceet 已提交
348 349 350

    LoadSpecialParam();

351
    // parse parameters
H
handyohos 已提交
352
    HookMgrExecute(GetBootStageHookMgr(), INIT_PRE_PARAM_LOAD, (void *)&timingStat, (void *)&options);
Z
zhr758 已提交
353
    InitLoadParamFiles();
354
    // read config
H
handyohos 已提交
355
    HookMgrExecute(GetBootStageHookMgr(), INIT_PRE_CFG_LOAD, (void *)&timingStat, (void *)&options);
356 357
    ReadConfig();
    INIT_LOGI("Parse init config file done.");
H
handyohos 已提交
358
    HookMgrExecute(GetBootStageHookMgr(), INIT_POST_CFG_LOAD, (void *)&timingStat, (void *)&options);
359

X
xionglei6 已提交
360
    IsEnableSandbox();
361 362 363 364 365 366 367 368 369 370
    // execute init
    PostTrigger(EVENT_TRIGGER_BOOT, "pre-init", strlen("pre-init"));
    PostTrigger(EVENT_TRIGGER_BOOT, "init", strlen("init"));
    PostTrigger(EVENT_TRIGGER_BOOT, "post-init", strlen("post-init"));
}

void SystemRun(void)
{
    StartParamService();
}
X
xionglei6 已提交
371

X
xionglei6 已提交
372
void SetServiceEnterSandbox(const char *execPath, unsigned int attribute)
X
xionglei6 已提交
373 374
{
    if (g_enableSandbox == false) {
X
xionglei6 已提交
375
        return;
X
xionglei6 已提交
376
    }
X
xionglei6 已提交
377 378 379 380 381 382 383 384 385
    if ((attribute & SERVICE_ATTR_SANDBOX) != SERVICE_ATTR_SANDBOX) {
        return;
    }
    INIT_ERROR_CHECK(execPath != NULL, return, "Service path is null.");
    if (strncmp(execPath, "/system/bin/", strlen("/system/bin/")) == 0) {
        if (strcmp(execPath, "/system/bin/appspawn") == 0) {
            INIT_LOGI("Appspawn skip enter sandbox.");
        } else if (strcmp(execPath, "/system/bin/hilogd") == 0) {
            INIT_LOGI("Hilogd skip enter sandbox.");
X
xionglei6 已提交
386
        } else {
M
Mupceet 已提交
387 388
            INIT_INFO_CHECK(EnterSandbox("system") == 0, return,
                "Service %s skip enter sandbox system.", execPath);
X
xionglei6 已提交
389
        }
X
xionglei6 已提交
390 391
    } else if (strncmp(execPath, "/vendor/bin/", strlen("/vendor/bin/")) == 0) {
        // chipset sandbox will be implemented later.
M
Mupceet 已提交
392
        INIT_INFO_CHECK(EnterSandbox("chipset") == 0, return,
M
Mupceet 已提交
393
            "Service %s skip enter sandbox system.", execPath);
X
xionglei6 已提交
394
    } else {
M
Mupceet 已提交
395
        INIT_LOGI("Service %s does not enter sandbox", execPath);
X
xionglei6 已提交
396
    }
X
xionglei6 已提交
397
    return;
X
xionglei6 已提交
398
}