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 (fds == NULL || fdCount == 0 || fdCount > MAX_HOLD_FDS) {
38         INIT_LOGE("Service %s request hold fds with invalid fds", service->name);
39         return -1;
40     }
41 
42     INIT_LOGI("Hold service \' %s \' fds:", service->name);
43     for (size_t i = 0; i < fdCount; i++) {
44         INIT_LOGI("fd = %d", fds[i]);
45     }
46     if (UpdaterServiceFds(service, fds, fdCount) < 0) {
47         INIT_LOGE("Failed to update service \' %s \' fds", service->name);
48         return -1;
49     }
50 
51     if (strcmp(pollStr, WITHPOLL) == 0) {
52         // poll service fds if service asked for
53         INIT_LOGI("Service \' %s \' asked init to poll fds, not implement yet.", service->name);
54     }
55     return 0;
56 }
57 
SendErrorInfo(int sock,const char * errInfo,const char * serviceName)58 static void SendErrorInfo(int sock, const char *errInfo, const char *serviceName)
59 {
60     int ret = 0;
61     char errBuffer[MAX_FD_HOLDER_BUFFER] = {};
62     if (UNLIKELY(errInfo == NULL)) { // Should not happen.
63         char *defaultError = "Unknonw error";
64         ret = strncpy_s(errBuffer, MAX_FD_HOLDER_BUFFER, defaultError, strlen(defaultError));
65     } else {
66         ret = strncpy_s(errBuffer, MAX_FD_HOLDER_BUFFER, errInfo, strlen(errInfo));
67     }
68     if (ret != 0) {
69         INIT_LOGE("Failed to copy, err = %d", errno);
70         return;
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 
CheckFdHolderPermission(Service * service,pid_t requestPid)91 static int CheckFdHolderPermission(Service *service, pid_t requestPid)
92 {
93     if (service == NULL) {
94         INIT_LOGE("Invalid service");
95         return -1;
96     }
97 
98     INIT_LOGI("received service pid = %d", requestPid);
99     if (service->pid < 0 || requestPid != service->pid) {
100         INIT_LOGE("Service \' %s \'(pid = %d) is not valid or request with unexpected process(pid = %d)",
101             service->name, service->pid, requestPid);
102         return -1;
103     }
104     INIT_LOGI("CheckFdHolderPermission done");
105     return 0;
106 }
107 
CloseFds(int * fds,size_t fdCount)108 static inline void CloseFds(int *fds, size_t fdCount)
109 {
110     if (fds == NULL) {
111         return;
112     }
113     for (size_t i = 0; i < fdCount; i++) {
114         close(fds[i]);
115     }
116 }
117 
HandlerFdHolder(int sock)118 static void HandlerFdHolder(int sock)
119 {
120     char buffer[MAX_FD_HOLDER_BUFFER + 1] = {0};
121     size_t fdCount = 0;
122     pid_t requestPid = -1;
123     struct iovec iovec = {
124         .iov_base = buffer,
125         .iov_len = MAX_FD_HOLDER_BUFFER,
126     };
127     int *fds = ReceiveFds(sock, iovec, &fdCount, true, &requestPid);
128     // Check what client want, is it want init to hold fds or return fds.
129     INIT_LOGI("Received buffer: [%s]", buffer);
130     int msgCount = 0;
131     int maxMsgCount = 3;
132     char **msg = SplitStringExt(buffer, "|", &msgCount, maxMsgCount);
133     if (msg == NULL || msgCount != maxMsgCount) {
134         INIT_LOGE("Invalid message received: %s", buffer);
135         CloseFds(fds, fdCount);
136         FreeFds(fds);
137         return;
138     }
139     char *serviceName = msg[0];
140     char *action = msg[1];
141     char *pollStr = msg[MSG_ARRAY_INDEX];
142 
143     Service *service = GetServiceByName(serviceName);
144     if (CheckFdHolderPermission(service, requestPid) < 0) {
145         SendErrorInfo(sock, "Invalid service", serviceName);
146         // Permission check failed.
147         // But fds may already dup to init, so close them.
148         CloseFds(fds, fdCount);
149         FreeFds(fds);
150         FreeStringVector(msg, msgCount);
151         return;
152     }
153     if (strcmp(action, ACTION_HOLD) == 0) {
154         INIT_LOGI("Service \' %s \' request init to %s fds", serviceName, action);
155         if (HandlerHoldFds(service, fds, fdCount, pollStr) < 0) {
156             CloseFds(fds, fdCount);
157         }
158     } else {
159         INIT_LOGE("Unexpected action: %s", action);
160         CloseFds(fds, fdCount);
161     }
162     FreeFds(fds);
163     FreeStringVector(msg, msgCount);
164 }
165 
ProcessFdHoldEvent(const WatcherHandle taskHandle,int fd,uint32_t * events,const void * context)166 void ProcessFdHoldEvent(const WatcherHandle taskHandle, int fd, uint32_t *events, const void *context)
167 {
168     HandlerFdHolder(fd);
169     *events = EVENT_READ;
170 }
171 
RegisterFdHoldWatcher(int sock)172 void RegisterFdHoldWatcher(int sock)
173 {
174     if (sock < 0) {
175         INIT_LOGE("Invalid fd holder socket");
176         return;
177     }
178 
179     WatcherHandle watcher = NULL;
180     LE_WatchInfo info = {};
181     info.fd = sock;
182     info.flags = 0; // WATCHER_ONCE;
183     info.events = EVENT_READ;
184     info.processEvent = ProcessFdHoldEvent;
185     LE_StartWatcher(LE_GetDefaultLoop(), &watcher, &info, NULL);
186 }
187