1/*
2 * Copyright (c) 2020-2021 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_service.h"
16
17#include <dlfcn.h>
18#include <stdlib.h>
19#include <string.h>
20#include <sys/param.h>
21#include <sys/resource.h>
22#include <unistd.h>
23
24#include "init_group_manager.h"
25#include "init.h"
26#include "init_log.h"
27#include "init_param.h"
28#include "init_utils.h"
29#include "securec.h"
30#include "token_setproc.h"
31#include "nativetoken_kit.h"
32#include "sandbox.h"
33#include "sandbox_namespace.h"
34#include "service_control.h"
35
36#define MIN_IMPORTANT_LEVEL (-20)
37#define MAX_IMPORTANT_LEVEL 19
38
39static bool g_enableSandbox = false;
40
41static void WriteOomScoreAdjToService(Service *service)
42{
43    if (service == NULL) {
44        return;
45    }
46    if (IsOnDemandService(service)) {
47        char pidAdjPath[30];
48        const char* content = "-900";
49        int len = sprintf_s(pidAdjPath, sizeof(pidAdjPath), "/proc/%d/oom_score_adj", service->pid);
50        if (len <= 0) {
51            INIT_LOGE("Service(%s): format pidAdjPath (pid:%d) failed.", service->name, service->pid);
52            return;
53        }
54        int fd = open(pidAdjPath, O_RDWR);
55        if (fd < 0) {
56            INIT_LOGE("Service(%s): open path %s failed.", service->name, pidAdjPath);
57            return;
58        }
59        int ret = write(fd, content, strlen(content));
60        if (ret < 0) {
61            INIT_LOGE("Service(%s): write content(%s) to path(%s) failed.", service->name, content, pidAdjPath);
62        }
63        close(fd);
64    }
65}
66
67void NotifyServiceChange(Service *service, int status)
68{
69    INIT_LOGV("Notify service %s change from %d to %d", service->name, service->status, status);
70    service->status = status;
71    INIT_CHECK(status != SERVICE_IDLE, return);
72    char paramName[PARAM_NAME_LEN_MAX] = { 0 };
73    int ret = snprintf_s(paramName, sizeof(paramName), sizeof(paramName) - 1,
74        "%s.%s", STARTUP_SERVICE_CTL, service->name);
75    INIT_ERROR_CHECK(ret > 0, return, "Failed to format service name %s.", service->name);
76    char statusStr[MAX_INT_LEN] = {0};
77    ret = snprintf_s(statusStr, sizeof(statusStr), sizeof(statusStr) - 1, "%d", status);
78    INIT_ERROR_CHECK(ret > 0, return, "Failed to format service status %s.", service->name);
79    SystemWriteParam(paramName, statusStr);
80
81    // write pid
82    ret = snprintf_s(paramName, sizeof(paramName), sizeof(paramName) - 1,
83        "%s.%s.pid", STARTUP_SERVICE_CTL, service->name);
84    INIT_ERROR_CHECK(ret > 0, return, "Failed to format service pid name %s.", service->name);
85    ret = snprintf_s(statusStr, sizeof(statusStr), sizeof(statusStr) - 1,
86        "%d", (service->pid == -1) ? 0 : service->pid);
87    INIT_ERROR_CHECK(ret > 0, return, "Failed to format service pid %s.", service->name);
88    if (status == SERVICE_STARTED) {
89        WriteOomScoreAdjToService(service);
90    }
91    SystemWriteParam(paramName, statusStr);
92}
93
94int IsForbidden(const char *fieldStr)
95{
96    UNUSED(fieldStr);
97    return 0;
98}
99
100int SetImportantValue(Service *service, const char *attrName, int value, int flag)
101{
102    UNUSED(attrName);
103    UNUSED(flag);
104    INIT_ERROR_CHECK(service != NULL, return SERVICE_FAILURE, "Set service attr failed! null ptr.");
105    if (value >= MIN_IMPORTANT_LEVEL && value <= MAX_IMPORTANT_LEVEL) { // -20~19
106        service->attribute |= SERVICE_ATTR_IMPORTANT;
107        service->importance = value;
108    } else {
109        INIT_LOGE("Importance level = %d, is not between -20 and 19, error", value);
110        return SERVICE_FAILURE;
111    }
112    return SERVICE_SUCCESS;
113}
114
115int ServiceExec(Service *service, const ServiceArgs *pathArgs)
116{
117    INIT_ERROR_CHECK(service != NULL, return SERVICE_FAILURE, "Exec service failed! null ptr.");
118    INIT_LOGI("ServiceExec %s", service->name);
119    INIT_ERROR_CHECK(pathArgs != NULL && pathArgs->count > 0,
120        return SERVICE_FAILURE, "Exec service failed! null ptr.");
121
122    if (service->importance != 0) {
123        INIT_ERROR_CHECK(setpriority(PRIO_PROCESS, 0, service->importance) == 0,
124            service->lastErrno = INIT_EPRIORITY;
125            return SERVICE_FAILURE,
126            "Service error %d %s, failed to set priority %d.", errno, service->name, service->importance);
127    }
128    OpenHidebug(service->name);
129    int isCritical = (service->attribute & SERVICE_ATTR_CRITICAL);
130    INIT_ERROR_CHECK(execv(pathArgs->argv[0], pathArgs->argv) == 0,
131        service->lastErrno = INIT_EEXEC;
132        return errno, "[startup_failed]failed to execv %d %d %s", isCritical, errno, service->name);
133    return SERVICE_SUCCESS;
134}
135
136int SetAccessToken(const Service *service)
137{
138    INIT_ERROR_CHECK(service != NULL, return SERVICE_FAILURE, "service is null");
139    return SetSelfTokenID(service->tokenId);
140}
141
142void GetAccessToken(void)
143{
144    InitGroupNode *node = GetNextGroupNode(NODE_TYPE_SERVICES, NULL);
145    while (node != NULL) {
146        Service *service = node->data.service;
147        if (service != NULL) {
148            if (service->capsArgs.count == 0) {
149                service->capsArgs.argv = NULL;
150            }
151            const char *apl = "system_basic";
152            if (service->apl != NULL) {
153                apl = service->apl;
154            }
155            NativeTokenInfoParams nativeTokenInfoParams = {
156                service->capsArgs.count,
157                service->permArgs.count,
158                service->permAclsArgs.count,
159                (const char **)service->capsArgs.argv,
160                (const char **)service->permArgs.argv,
161                (const char **)service->permAclsArgs.argv,
162                service->name,
163                apl,
164            };
165            uint64_t tokenId = GetAccessTokenId(&nativeTokenInfoParams);
166            INIT_CHECK_ONLY_ELOG(tokenId  != 0,
167                "gettotkenid failed, service \' %s \'", service->name);
168            service->tokenId = tokenId;
169        }
170        node = GetNextGroupNode(NODE_TYPE_SERVICES, node);
171    }
172}
173
174void IsEnableSandbox(void)
175{
176    char value[MAX_BUFFER_LEN] = {0};
177    unsigned int len = MAX_BUFFER_LEN;
178    if (SystemReadParam("const.sandbox", value, &len) == 0) {
179        if (strcmp(value, "enable") == 0) {
180            g_enableSandbox = true;
181        }
182    }
183}
184
185int SetServiceEnterSandbox(const Service *service, const char *execPath)
186{
187    if ((service->attribute & SERVICE_ATTR_WITHOUT_SANDBOX) == SERVICE_ATTR_WITHOUT_SANDBOX) {
188        return 0;
189    }
190    if (g_enableSandbox == false) {
191        return 0;
192    }
193    INIT_ERROR_CHECK(execPath != NULL, return INIT_EPARAMETER, "Service path is null.");
194    int ret = 0;
195    if (strncmp(execPath, "/system/bin/", strlen("/system/bin/")) == 0) {
196        ret = EnterSandbox("system");
197    } else if (strncmp(execPath, "/vendor/bin/", strlen("/vendor/bin/")) == 0) {
198        ret = EnterSandbox("chipset");
199    }
200    return ret;
201}
202