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 
39 static bool g_enableSandbox = false;
40 
WriteOomScoreAdjToService(Service * service)41 static 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 
NotifyServiceChange(Service * service,int status)67 void 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 
IsForbidden(const char * fieldStr)94 int IsForbidden(const char *fieldStr)
95 {
96     UNUSED(fieldStr);
97     return 0;
98 }
99 
SetImportantValue(Service * service,const char * attrName,int value,int flag)100 int 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 
ServiceExec(Service * service,const ServiceArgs * pathArgs)115 int 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 
SetAccessToken(const Service * service)136 int SetAccessToken(const Service *service)
137 {
138     INIT_ERROR_CHECK(service != NULL, return SERVICE_FAILURE, "service is null");
139     return SetSelfTokenID(service->tokenId);
140 }
141 
GetAccessToken(void)142 void 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 
IsEnableSandbox(void)174 void 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 
SetServiceEnterSandbox(const Service * service,const char * execPath)185 int 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