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