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"
X
xionglei6 已提交
31
#include "fs_manager/fs_manager.h"
32 33
#include "init_log.h"
#include "init_mount.h"
X
xionglei6 已提交
34
#include "init_group_manager.h"
35
#include "init_param.h"
X
xionglei6 已提交
36 37
#include "init_service.h"
#include "init_service_manager.h"
38 39 40
#include "init_utils.h"
#include "securec.h"
#include "switch_root.h"
X
xionglei6 已提交
41 42
#include "ueventd.h"
#include "ueventd_socket.h"
X
xionglei6 已提交
43
#include "fd_holder_internal.h"
X
xionglei6 已提交
44 45
#include "sandbox.h"
#include "sandbox_namespace.h"
Q
Qin Fandong 已提交
46
#ifdef WITH_SELINUX
X
xionglei6 已提交
47
#include <policycoreutils.h>
R
renwei 已提交
48
#include <selinux/selinux.h>
Q
Qin Fandong 已提交
49
#endif // WITH_SELINUX
50
#include "bootstage.h"
51

X
xionglei6 已提交
52 53
static bool g_enableSandbox;

X
xionglei6 已提交
54 55 56 57
static int FdHolderSockInit(void)
{
    int sock = -1;
    int on = 1;
X
xionglei6 已提交
58 59
    int fdHolderBufferSize = FD_HOLDER_BUFFER_SIZE; // 4KiB
    sock = socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
X
xionglei6 已提交
60 61 62 63 64 65 66 67 68 69 70 71 72
    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 已提交
73
    addr.sun_family = AF_UNIX;
X
xionglei6 已提交
74 75 76 77 78 79 80 81
    if (strncpy_s(addr.sun_path, sizeof(addr.sun_path),
        INIT_HOLDER_SOCKET_PATH, strlen(INIT_HOLDER_SOCKET_PATH)) != 0) {
        INIT_LOGE("Faild to copy fd hoder socket path");
        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 已提交
82
        INIT_LOGE("Failed to binder fd folder socket %d", errno);
X
xionglei6 已提交
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
        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;
}

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

static void EnableDevKmsg(void)
{
    /* printk_devkmsg default value is ratelimit, We need to set "on" and remove the restrictions */
X
xionglei6 已提交
114
    int fd = open("/proc/sys/kernel/printk_devkmsg", O_WRONLY | O_CLOEXEC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
X
xionglei6 已提交
115 116 117 118 119 120 121 122
    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 132 133 134
}

void LogInit(void)
{
    CloseStdio();
    int ret = mknod("/dev/kmsg", S_IFCHR | S_IWUSR | S_IRUSR,
        makedev(MEM_MAJOR, DEV_KMSG_MINOR));
    if (ret == 0) {
        OpenLogDevice();
    }
}

X
xionglei6 已提交
135
static char **GetRequiredDevices(Fstab fstab, int *requiredNum)
136
{
X
xionglei6 已提交
137 138 139 140 141 142 143
    int num = 0;
    FstabItem *item = fstab.head;
    while (item != NULL) {
        if (FM_MANAGER_REQUIRED_ENABLED(item->fsManagerFlags)) {
            num++;
        }
        item = item->next;
144
    }
X
xionglei6 已提交
145 146 147 148 149 150 151 152 153 154 155
    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++;
156
        }
X
xionglei6 已提交
157
        item = item->next;
158
    }
X
xionglei6 已提交
159 160
    *requiredNum = num;
    return devices;
161 162
}

X
xionglei6 已提交
163
static int StartUeventd(char **requiredDevices, int num)
164
{
X
xionglei6 已提交
165 166 167 168 169
    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;
170
    }
X
xionglei6 已提交
171
    RetriggerUevent(ueventSockFd, requiredDevices, num);
X
xionglei6 已提交
172
    close(ueventSockFd);
X
xionglei6 已提交
173 174 175 176 177 178
    return 0;
}

static void StartInitSecondStage(void)
{
    int requiredNum = 0;
M
Mupceet 已提交
179 180
    Fstab* fstab = LoadRequiredFstab();
    INIT_ERROR_CHECK(fstab != NULL, abort(), "Failed to load required fstab");
X
xionglei6 已提交
181 182 183 184 185 186 187 188 189 190 191 192 193 194
    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
X
xionglei6 已提交
195 196 197
            INIT_LOGE("Mount requried partitions failed; please check fstab file");
            // Execute sh for debugging
            execv("/bin/sh", NULL);
X
xionglei6 已提交
198 199
            abort();
        }
200
    }
X
xionglei6 已提交
201
#ifndef DISABLE_INIT_TWO_STAGES
202 203
    SwitchRoot("/usr");
    // Execute init second stage
X
xionglei6 已提交
204
    char * const args[] = {
205 206
        "/bin/init",
        "--second-stage",
S
sun_fan 已提交
207
        NULL,
208 209 210 211 212
    };
    if (execv("/bin/init", args) != 0) {
        INIT_LOGE("Failed to exec \"/bin/init\", err = %d", errno);
        exit(-1);
    }
S
sun_fan 已提交
213
#endif
X
xionglei6 已提交
214
}
215 216 217 218

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

Q
Qin Fandong 已提交
232 233 234 235
void SystemLoadSelinux(void)
{
#ifdef WITH_SELINUX
    // load selinux policy and context
R
renwei 已提交
236
    if (LoadPolicy() < 0) {
Q
Qin Fandong 已提交
237 238 239 240
        INIT_LOGE("main, load_policy failed.");
    } else {
        INIT_LOGI("main, load_policy success.");
    }
R
renwei 已提交
241 242

    setcon("u:r:init:s0");
R
renwei 已提交
243
    (void)RestoreconRecurse("/dev");
Q
Qin Fandong 已提交
244 245 246
#endif // WITH_SELINUX
}

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

#if defined(OHOS_SERVICE_DUMP)
X
xionglei6 已提交
261
static int SystemDump(int id, const char *name, int argc, const char **argv)
X
xionglei6 已提交
262
{
X
xionglei6 已提交
263
    INIT_ERROR_CHECK(argv != NULL && argc >= 1, return 0, "Invalid install parameter");
X
xionglei6 已提交
264 265
    INIT_LOGI("Dump system info %s", argv[0]);
    DumpAllServices();
M
Mupceet 已提交
266 267
    SystemDumpParameters(1);
    SystemDumpTriggers(1);
X
xionglei6 已提交
268
    return 0;
X
xionglei6 已提交
269 270 271
}
#endif

X
xionglei6 已提交
272 273 274 275 276 277 278 279 280 281
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 已提交
282
        INIT_LOGI("Enable sandbox.");
X
xionglei6 已提交
283 284
        g_enableSandbox = true;
    } else {
X
xionglei6 已提交
285
        INIT_LOGI("Disable sandbox.");
X
xionglei6 已提交
286 287 288 289
        g_enableSandbox = false;
    }
}

Z
zhr758 已提交
290 291 292 293 294 295 296 297 298 299 300 301 302
static void InitLoadParamFiles(void)
{
    // 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);
}

303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330
typedef struct HOOK_TIMING_STAT {
    struct timespec startTime;
    struct timespec endTime;
} HOOK_TIMING_STAT;

static void InitPreHook(const HOOK_INFO *hookInfo)
{
    HOOK_TIMING_STAT *stat = (HOOK_TIMING_STAT *)hookInfo->cookie;
    clock_gettime(CLOCK_MONOTONIC, &(stat->startTime));
}

static void InitPostHook(const HOOK_INFO *hookInfo)
{
    long long diff;
    HOOK_TIMING_STAT *stat = (HOOK_TIMING_STAT *)hookInfo->cookie;
    clock_gettime(CLOCK_MONOTONIC, &(stat->endTime));

    diff = (long long)((stat->endTime.tv_sec - stat->startTime.tv_sec) / 1000);
    if (stat->endTime.tv_nsec > stat->startTime.tv_nsec) {
        diff += (stat->endTime.tv_nsec - stat->startTime.tv_nsec) * 1000;
    } else {
        diff -= (stat->endTime.tv_nsec - stat->startTime.tv_nsec) * 1000;
    }

    INIT_LOGI("Executing hook [%d:%d:%p] cost [%lld]ms, return %d.",
                hookInfo->stage, hookInfo->prio, hookInfo->hook, diff, hookInfo->retVal);
}

331 332
void SystemConfig(void)
{
333 334 335 336 337 338 339 340 341
    HOOK_TIMING_STAT timingStat;
    HOOK_EXEC_ARGS args;

    args.flags = 0;
    args.cookie = (void *)&timingStat;
    args.preHook = InitPreHook;
    args.postHook = InitPostHook;

    HookMgrExecute(NULL, INIT_GLOBAL_INIT, (void *)&args);
X
xionglei6 已提交
342
    InitServiceSpace();
343 344

    HookMgrExecute(NULL, INIT_PRE_PARAM_SERVICE, (void *)&args);
Z
zhr758 已提交
345
    InitParamService();
X
xionglei6 已提交
346 347 348
    InitParseGroupCfg();
    RegisterBootStateChange(BootStateChange);

R
renwei 已提交
349 350 351
    // load SELinux context and policy
    // Do not move position!
    SystemLoadSelinux();
352
    // parse parameters
353
    HookMgrExecute(NULL, INIT_PRE_PARAM_LOAD, (void *)&args);
Z
zhr758 已提交
354
    InitLoadParamFiles();
355
    // read config
356
    HookMgrExecute(NULL, INIT_PRE_CFG_LOAD, (void *)&args);
357 358
    ReadConfig();
    INIT_LOGI("Parse init config file done.");
359 360 361 362
    HookMgrExecute(NULL, INIT_POST_CFG_LOAD, (void *)&args);

    // Destroy all hooks
    HookMgrDestroy(NULL);
363 364

    // dump config
X
xionglei6 已提交
365 366 367
#if defined(OHOS_SERVICE_DUMP)
    AddCmdExecutor("display", SystemDump);
    (void)AddCompleteJob("param:ohos.servicectrl.display", "ohos.servicectrl.display=*", "display system");
368
#endif
X
xionglei6 已提交
369
    IsEnableSandbox();
370 371 372 373 374 375 376 377 378 379
    // 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 已提交
380

X
xionglei6 已提交
381
void SetServiceEnterSandbox(const char *execPath, unsigned int attribute)
X
xionglei6 已提交
382 383
{
    if (g_enableSandbox == false) {
X
xionglei6 已提交
384
        return;
X
xionglei6 已提交
385
    }
X
xionglei6 已提交
386 387 388 389 390 391 392 393 394
    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 已提交
395
        } else {
X
xionglei6 已提交
396 397
            INIT_ERROR_CHECK(EnterSandbox("system") == 0, return,
                "Service %s failed enter sandbox system.", execPath);
X
xionglei6 已提交
398
        }
X
xionglei6 已提交
399 400 401 402
    } else if (strncmp(execPath, "/vendor/bin/", strlen("/vendor/bin/")) == 0) {
        // chipset sandbox will be implemented later.
        INIT_ERROR_CHECK(EnterSandbox("system") == 0, return,
            "Service %s failed enter sandbox system.", execPath);
X
xionglei6 已提交
403
    } else {
X
xionglei6 已提交
404
        INIT_LOGE("Service %s does not enter sandbox", execPath);
X
xionglei6 已提交
405
    }
X
xionglei6 已提交
406
    return;
X
xionglei6 已提交
407
}