1 /*
2 * Copyright (c) 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 <sys/socket.h>
16 #include <sys/un.h>
17
18 #include "fd_holder_internal.h"
19 #include "init_log.h"
20 #include "init_service.h"
21 #include "init_service_manager.h"
22 #include "init_utils.h"
23 #include "loop_event.h"
24 #include "securec.h"
25
26 #define MSG_ARRAY_INDEX 2
27
FreeFds(int * fds)28 static void FreeFds(int *fds)
29 {
30 if (fds != NULL) {
31 free(fds);
32 }
33 }
34
HandlerHoldFds(Service * service,int * fds,size_t fdCount,const char * pollStr)35 static int HandlerHoldFds(Service *service, int *fds, size_t fdCount, const char *pollStr)
36 {
37 if (service == NULL) {
38 INIT_LOGE("Request hold fds with invalid service");
39 return -1;
40 }
41
42 if (fds == NULL || fdCount == 0 || fdCount > MAX_HOLD_FDS) {
43 INIT_LOGE("Service %s request hold fds with invalid fds", service->name);
44 return -1;
45 }
46
47 INIT_LOGI("Hold service \' %s \' fds:", service->name);
48 for (size_t i = 0; i < fdCount; i++) {
49 INIT_LOGI("fd = %d", fds[i]);
50 }
51 if (UpdaterServiceFds(service, fds, fdCount) < 0) {
52 INIT_LOGE("Failed to update service \' %s \' fds", service->name);
53 return -1;
54 }
55
56 if (strcmp(pollStr, WITHPOLL) == 0) {
57 // poll service fds if service asked for
58 INIT_LOGI("Service \' %s \' asked init to poll fds, not implement yet.", service->name);
59 }
60 return 0;
61 }
62
SendErrorInfo(int sock,const char * errInfo,const char * serviceName)63 static void SendErrorInfo(int sock, const char *errInfo, const char *serviceName)
64 {
65 char errBuffer[MAX_FD_HOLDER_BUFFER] = {};
66 if (UNLIKELY(errInfo == NULL)) { // Should not happen.
67 char *defaultError = "Unknonw error";
68 (void)strncpy_s(errBuffer, MAX_FD_HOLDER_BUFFER, defaultError, strlen(defaultError));
69 } else {
70 (void)strncpy_s(errBuffer, MAX_FD_HOLDER_BUFFER, errInfo, strlen(errInfo));
71 }
72
73 struct iovec iovec = {
74 .iov_base = errBuffer,
75 .iov_len = strlen(errBuffer),
76 };
77
78 struct msghdr msghdr = {
79 .msg_iov = &iovec,
80 .msg_iovlen = 1,
81 .msg_control = NULL,
82 .msg_controllen = 0,
83 .msg_flags = 0,
84 };
85
86 if (TEMP_FAILURE_RETRY(sendmsg(sock, &msghdr, MSG_NOSIGNAL)) < 0) {
87 INIT_LOGE("Failed to send err info to service \' %s \', err = %d", serviceName, errno);
88 }
89 }
90
SendFdsInfo(int sock,Service * service)91 static void SendFdsInfo(int sock, Service *service)
92 {
93 // Sanity check
94 if (sock < 0 || service == NULL) {
95 INIT_LOGE("Try to send fd with invalid parameter");
96 return;
97 }
98 char sendBuffer[MAX_FD_HOLDER_BUFFER] = {};
99 (void)strncpy_s(sendBuffer, MAX_FD_HOLDER_BUFFER, "send done", strlen("send done"));
100 struct iovec iovec = {
101 .iov_base = sendBuffer,
102 .iov_len = strlen(sendBuffer),
103 };
104
105 struct msghdr msghdr = {
106 .msg_iov = &iovec,
107 .msg_iovlen = 1,
108 };
109
110 if (BuildControlMessage(&msghdr, service->fds, service->fdCount, false) < 0) {
111 SendErrorInfo(sock, "Faild to build send message", service->name);
112 } else {
113 if (TEMP_FAILURE_RETRY(sendmsg(sock, &msghdr, MSG_NOSIGNAL)) < 0) {
114 INIT_LOGE("Failed to send fd info to service \' %s \', err = %d", service->name, errno);
115 } else {
116 // Send fd to service OK, need to close fds in init.
117 CloseServiceFds(service, true);
118 }
119 }
120
121 if (msghdr.msg_control != NULL) {
122 free(msghdr.msg_control);
123 msghdr.msg_control = NULL;
124 msghdr.msg_controllen = 0;
125 }
126 }
127
HandlerGetFds(int sock,Service * service)128 static void HandlerGetFds(int sock, Service *service)
129 {
130 const char *errorInfo = NULL;
131 if (sock < 0 || service == NULL) {
132 INIT_LOGE("Get fd from init with invalid parameter");
133 errorInfo = "Invalid parameter";
134 }
135
136 if (service->fds == NULL || service->fdCount == 0) {
137 INIT_LOGE("Service \' %s \' does not have any held fds");
138 errorInfo = "Service without any fds";
139 }
140
141 if (errorInfo != NULL) {
142 SendErrorInfo(sock, errorInfo, service->name);
143 } else {
144 // Send fds back to service
145 SendFdsInfo(sock, service);
146 }
147 }
148
CheckFdHolderPermission(Service * service,pid_t requestPid)149 static int CheckFdHolderPermission(Service *service, pid_t requestPid)
150 {
151 if (service == NULL) {
152 INIT_LOGE("Invalid service");
153 return -1;
154 }
155
156 INIT_LOGI("received service pid = %d", requestPid);
157 if (service->pid < 0 || requestPid != service->pid) {
158 INIT_LOGE("Service \' %s \'(pid = %d) is not valid or request with unexpected process(pid = %d)",
159 service->name, service->pid, requestPid);
160 return -1;
161 }
162 INIT_LOGI("CheckFdHolderPermission done");
163 return 0;
164 }
165
CloseFds(int * fds,size_t fdCount)166 static inline void CloseFds(int *fds, size_t fdCount)
167 {
168 for (size_t i = 0; i < fdCount; i++) {
169 close(fds[i]);
170 }
171 }
172
HandlerFdHolder(int sock)173 static void HandlerFdHolder(int sock)
174 {
175 char buffer[MAX_FD_HOLDER_BUFFER + 1] = {};
176 size_t fdCount = 0;
177 pid_t requestPid = -1;
178 struct iovec iovec = {
179 .iov_base = buffer,
180 .iov_len = MAX_FD_HOLDER_BUFFER,
181 };
182 int *fds = ReceiveFds(sock, iovec, &fdCount, true, &requestPid);
183 // Check what client want, is it want init to hold fds or return fds.
184 INIT_LOGI("Received buffer: [%s]", buffer);
185 int msgCount = 0;
186 int maxMsgCount = 3;
187 char **msg = SplitStringExt(buffer, "|", &msgCount, maxMsgCount);
188 if (msg == NULL || msgCount != maxMsgCount) {
189 INIT_LOGE("Invalid message received: %s", buffer);
190 CloseFds(fds, fdCount);
191 FreeFds(fds);
192 }
193 char *serviceName = msg[0];
194 char *action = msg[1];
195 char *pollStr = msg[MSG_ARRAY_INDEX];
196
197 Service *service = GetServiceByName(serviceName);
198 if (CheckFdHolderPermission(service, requestPid) < 0) {
199 // Permission check failed.
200 // But fds may already dup to init, so close them.
201 CloseFds(fds, fdCount);
202 FreeFds(fds);
203 FreeStringVector(msg, msgCount);
204 return;
205 }
206 if (strcmp(action, ACTION_HOLD) == 0) {
207 INIT_LOGI("Service \' %s \' request init to %s fds", serviceName, action);
208 if (HandlerHoldFds(service, fds, fdCount, pollStr) < 0) {
209 CloseFds(fds, fdCount);
210 }
211 } else if (strcmp(action, ACTION_GET) == 0) {
212 // In this case, ignore fds, just close them if fd passed to init
213 CloseFds(fds, fdCount);
214 HandlerGetFds(sock, service);
215 } else {
216 INIT_LOGE("Unexpect action: %s", action);
217 }
218 FreeFds(fds);
219 FreeStringVector(msg, msgCount);
220 }
221
ProcessFdHoldEvent(const WatcherHandle taskHandle,int fd,uint32_t * events,const void * context)222 static void ProcessFdHoldEvent(const WatcherHandle taskHandle, int fd, uint32_t *events, const void *context)
223 {
224 HandlerFdHolder(fd);
225 *events = Event_Read;
226 }
227
RegisterFdHoldWatcher(int sock)228 void RegisterFdHoldWatcher(int sock)
229 {
230 if (sock < 0) {
231 INIT_LOGE("Invalid fd holder socket");
232 return;
233 }
234
235 WatcherHandle watcher = NULL;
236 LE_WatchInfo info = {};
237 info.fd = sock;
238 info.flags = 0; // WATCHER_ONCE;
239 info.events = Event_Read;
240 info.processEvent = ProcessFdHoldEvent;
241 LE_StartWatcher(LE_GetDefaultLoop(), &watcher, &info, NULL);
242 }
243