1 /*
2 * Copyright (c) 2021-2022 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_param.h"
16
17 #include <errno.h>
18 #include <stddef.h>
19 #include <string.h>
20 #include <sys/socket.h>
21 #include <unistd.h>
22
23 #include "init_log.h"
24 #include "init_utils.h"
25 #include "param_atomic.h"
26 #include "param_manager.h"
27 #include "param_message.h"
28 #include "param_security.h"
29
30 #define INVALID_SOCKET (-1)
31 static const uint32_t RECV_BUFFER_MAX = 5 * 1024;
32 static ATOMIC_UINT32 g_requestId;
33 static int g_clientFd = INVALID_SOCKET;
34 static pthread_mutex_t g_clientMutex = PTHREAD_MUTEX_INITIALIZER;
35
ParameterInit(void)36 __attribute__((constructor)) static void ParameterInit(void)
37 {
38 ATOMIC_INIT(&g_requestId, 1);
39 EnableInitLog(INIT_INFO);
40
41 PARAM_WORKSPACE_OPS ops = {0};
42 ops.updaterMode = 0;
43 ops.logFunc = InitLog;
44 #ifdef PARAM_SUPPORT_SELINUX
45 ops.setfilecon = NULL;
46 #endif
47 InitParamWorkSpace(1, &ops);
48
49 // modify log level
50 char logLevel[2] = {0}; // 2 is set param "persist.init.debug.loglevel" value length.
51 uint32_t len = sizeof(logLevel);
52 int ret = SystemReadParam(INIT_DEBUG_LEVEL, logLevel, &len);
53 if (ret == 0) {
54 errno = 0;
55 int level = atoi(logLevel);
56 if (errno != 0) {
57 return;
58 }
59 SetInitLogLevel((InitLogLevel)level);
60 }
61 }
62
ParameterDeinit(void)63 __attribute__((destructor)) static void ParameterDeinit(void)
64 {
65 if (g_clientFd != INVALID_SOCKET) {
66 close(g_clientFd);
67 g_clientFd = INVALID_SOCKET;
68 }
69 pthread_mutex_destroy(&g_clientMutex);
70 }
71
ProcessRecvMsg(const ParamMessage * recvMsg)72 static int ProcessRecvMsg(const ParamMessage *recvMsg)
73 {
74 PARAM_LOGV("ProcessRecvMsg type: %u msgId: %u name %s", recvMsg->type, recvMsg->id.msgId, recvMsg->key);
75 int result = PARAM_CODE_INVALID_PARAM;
76 switch (recvMsg->type) {
77 case MSG_SET_PARAM:
78 result = ((ParamResponseMessage *)recvMsg)->result;
79 break;
80 case MSG_NOTIFY_PARAM: {
81 uint32_t offset = 0;
82 ParamMsgContent *valueContent = GetNextContent(recvMsg, &offset);
83 PARAM_CHECK(valueContent != NULL, return PARAM_CODE_TIMEOUT, "Invalid msg");
84 result = 0;
85 break;
86 }
87 default:
88 break;
89 }
90 return result;
91 }
92
ReadMessage(int fd,char * buffer,uint32_t timeout)93 static int ReadMessage(int fd, char *buffer, uint32_t timeout)
94 {
95 int ret = 0;
96 uint32_t diff = 0;
97 struct timespec startTime = {0};
98 (void)clock_gettime(CLOCK_MONOTONIC, &startTime);
99 do {
100 ssize_t recvLen = recv(fd, (char *)buffer, RECV_BUFFER_MAX, 0);
101 if (recvLen > 0) {
102 break;
103 }
104 struct timespec finishTime = {0};
105 (void)clock_gettime(CLOCK_MONOTONIC, &finishTime);
106 diff = IntervalTime(&finishTime, &startTime);
107 if (diff >= timeout) {
108 ret = PARAM_CODE_TIMEOUT;
109 break;
110 }
111 if (errno == EAGAIN || errno == EINTR) {
112 usleep(10*1000); // 10*1000 wait 10ms
113 continue;
114 }
115 } while (1);
116 if (ret != 0) {
117 PARAM_LOGE("ReadMessage errno %d diff %u timeout %d ret %d", errno, diff, timeout, ret);
118 }
119 return ret;
120 }
121
GetClientSocket(int timeout)122 static int GetClientSocket(int timeout)
123 {
124 struct timeval time = {0};
125 time.tv_sec = timeout;
126 time.tv_usec = 0;
127 int clientFd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
128 PARAM_CHECK(clientFd >= 0, return -1, "Failed to create socket");
129 int ret = ConnectServer(clientFd, CLIENT_PIPE_NAME);
130 if (ret == 0) {
131 setsockopt(clientFd, SOL_SOCKET, SO_SNDTIMEO, (char *)&time, sizeof(struct timeval));
132 setsockopt(clientFd, SOL_SOCKET, SO_RCVTIMEO, (char *)&time, sizeof(struct timeval));
133 } else {
134 close(clientFd);
135 clientFd = INVALID_SOCKET;
136 }
137 return clientFd;
138 }
139
StartRequest(int clientFd,ParamMessage * request,int timeout)140 static int StartRequest(int clientFd, ParamMessage *request, int timeout)
141 {
142 errno = 0;
143 ssize_t sendLen = send(clientFd, (char *)request, request->msgSize, 0);
144 if (errno == EINVAL || errno == EACCES) {
145 return PARAM_CODE_INVALID_SOCKET;
146 }
147 PARAM_CHECK(sendLen >= 0, return PARAM_CODE_FAIL_CONNECT, "Failed to send message err: %d", errno);
148 PARAM_LOGV("sendMessage sendLen fd %d %zd", clientFd, sendLen);
149 if (timeout <= 0) {
150 return 0;
151 }
152 int ret = ReadMessage(clientFd, (char *)request, timeout);
153 if (ret == 0) {
154 ret = ProcessRecvMsg(request);
155 }
156 return ret;
157 }
158
SystemSetParameter_(const char * name,const char * value,int timeout)159 static int SystemSetParameter_(const char *name, const char *value, int timeout)
160 {
161 PARAM_CHECK(name != NULL && value != NULL, return -1, "Invalid name or value");
162 int ret = CheckParamName(name, 0);
163 PARAM_CHECK(ret == 0, return ret, "Illegal param name %s", name);
164 ret = CheckParamValue(NULL, name, value, GetParamValueType(name));
165 PARAM_CHECK(ret == 0, return ret, "Illegal param value %s", value);
166
167 size_t msgSize = sizeof(ParamMsgContent);
168 msgSize = (msgSize < RECV_BUFFER_MAX) ? RECV_BUFFER_MAX : msgSize;
169
170 ParamMessage *request = (ParamMessage *)CreateParamMessage(MSG_SET_PARAM, name, msgSize);
171 PARAM_CHECK(request != NULL, return -1, "Failed to malloc for connect");
172 uint32_t offset = 0;
173 ret = FillParamMsgContent(request, &offset, PARAM_VALUE, value, strlen(value));
174 PARAM_CHECK(ret == 0, free(request);
175 return -1, "Failed to fill value");
176 request->msgSize = offset + sizeof(ParamMessage);
177 request->id.msgId = ATOMIC_SYNC_ADD_AND_FETCH(&g_requestId, 1, MEMORY_ORDER_RELAXED);
178
179 PARAM_LOGI("SystemSetParameter name %s msgid:%d ", name, request->id.msgId);
180 pthread_mutex_lock(&g_clientMutex);
181 int retryCount = 0;
182 while (retryCount < 2) { // max retry 2
183 if (g_clientFd == INVALID_SOCKET) {
184 g_clientFd = GetClientSocket(DEFAULT_PARAM_SET_TIMEOUT);
185 }
186 if (g_clientFd < 0) {
187 ret = DAC_RESULT_FORBIDED;
188 break;
189 }
190 ret = StartRequest(g_clientFd, request, timeout);
191 if (ret == PARAM_CODE_INVALID_SOCKET) {
192 close(g_clientFd);
193 g_clientFd = INVALID_SOCKET;
194 retryCount++;
195 ret = DAC_RESULT_FORBIDED;
196 } else {
197 break;
198 }
199 }
200 PARAM_LOGI("SystemSetParameter name %s msgid:%d ret: %d ", name, request->id.msgId, ret);
201 pthread_mutex_unlock(&g_clientMutex);
202 free(request);
203 return ret;
204 }
205
SystemSetParameter(const char * name,const char * value)206 int SystemSetParameter(const char *name, const char *value)
207 {
208 return SystemSetParameter_(name, value, DEFAULT_PARAM_SET_TIMEOUT);
209 }
210
SystemSetParameterNoWait(const char * name,const char * value)211 int SystemSetParameterNoWait(const char *name, const char *value)
212 {
213 return SystemSetParameter_(name, value, 0);
214 }
215
SystemWaitParameter(const char * name,const char * value,int32_t timeout)216 int SystemWaitParameter(const char *name, const char *value, int32_t timeout)
217 {
218 PARAM_CHECK(name != NULL, return -1, "Invalid name");
219 int ret = CheckParamName(name, 0);
220 PARAM_CHECK(ret == 0, return ret, "Illegal param name %s", name);
221 ret = CheckParamPermission(GetParamSecurityLabel(), name, DAC_READ);
222 PARAM_CHECK(ret == 0, return ret, "Forbid to wait parameter %s", name);
223 if (timeout <= 0) {
224 timeout = DEFAULT_PARAM_WAIT_TIMEOUT;
225 }
226 uint32_t msgSize = sizeof(ParamMessage) + sizeof(ParamMsgContent) + sizeof(ParamMsgContent) + sizeof(uint32_t);
227 msgSize = (msgSize < RECV_BUFFER_MAX) ? RECV_BUFFER_MAX : msgSize;
228 uint32_t offset = 0;
229 ParamMessage *request = NULL;
230 if (value != NULL && strlen(value) > 0) {
231 msgSize += PARAM_ALIGN(strlen(value) + 1);
232 request = (ParamMessage *)CreateParamMessage(MSG_WAIT_PARAM, name, msgSize);
233 PARAM_CHECK(request != NULL, return -1, "Failed to malloc for wait");
234 ret = FillParamMsgContent(request, &offset, PARAM_VALUE, value, strlen(value));
235 } else {
236 msgSize += PARAM_ALIGN(1);
237 request = (ParamMessage *)CreateParamMessage(MSG_WAIT_PARAM, name, msgSize);
238 PARAM_CHECK(request != NULL, return -1, "Failed to malloc for wait");
239 ret = FillParamMsgContent(request, &offset, PARAM_VALUE, "*", 1);
240 }
241 PARAM_CHECK(ret == 0, free(request);
242 return -1, "Failed to fill value");
243 ParamMsgContent *content = (ParamMsgContent *)(request->data + offset);
244 content->type = PARAM_WAIT_TIMEOUT;
245 content->contentSize = sizeof(uint32_t);
246 *((uint32_t *)(content->content)) = timeout;
247 offset += sizeof(ParamMsgContent) + sizeof(uint32_t);
248
249 request->msgSize = offset + sizeof(ParamMessage);
250 request->id.waitId = ATOMIC_SYNC_ADD_AND_FETCH(&g_requestId, 1, MEMORY_ORDER_RELAXED);
251 #ifdef STARTUP_INIT_TEST
252 timeout = 1;
253 #endif
254 int fd = GetClientSocket(timeout);
255 PARAM_CHECK(fd >= 0, return -1, "Failed to connect server for wait %s", name);
256 ret = StartRequest(fd, request, timeout);
257 close(fd);
258 free(request);
259 PARAM_LOGI("SystemWaitParameter %s value %s result %d ", name, value, ret);
260 return ret;
261 }
262
SystemCheckParamExist(const char * name)263 int SystemCheckParamExist(const char *name)
264 {
265 return SysCheckParamExist(name);
266 }
267
WatchParamCheck(const char * keyprefix)268 int WatchParamCheck(const char *keyprefix)
269 {
270 PARAM_CHECK(keyprefix != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid keyprefix");
271 int ret = CheckParamName(keyprefix, 0);
272 PARAM_CHECK(ret == 0, return ret, "Illegal param name %s", keyprefix);
273 ret = CheckParamPermission(GetParamSecurityLabel(), keyprefix, DAC_WATCH);
274 PARAM_CHECK(ret == 0, return ret, "Forbid to watcher parameter %s", keyprefix);
275 return 0;
276 }
277
ResetParamSecurityLabel(void)278 void ResetParamSecurityLabel(void)
279 {
280 #ifdef RESET_CHILD_FOR_VERIFY
281 ParamWorkSpace *paramSpace = GetParamWorkSpace();
282 PARAM_CHECK(paramSpace != NULL, return, "Invalid paramSpace");
283 #if !(defined __LITEOS_A__ || defined __LITEOS_M__)
284 paramSpace->securityLabel.cred.pid = getpid();
285 paramSpace->securityLabel.cred.uid = geteuid();
286 paramSpace->securityLabel.cred.gid = getegid();
287 paramSpace->flags |= WORKSPACE_FLAGS_NEED_ACCESS;
288 #endif
289 #endif
290 PARAM_LOGI("ResetParamSecurityLabel g_clientFd: %d ", g_clientFd);
291 pthread_mutex_lock(&g_clientMutex);
292 if (g_clientFd != INVALID_SOCKET) {
293 close(g_clientFd);
294 g_clientFd = INVALID_SOCKET;
295 }
296 pthread_mutex_unlock(&g_clientMutex);
297 }
298