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
16 #include "lmks_server.h"
17
18 #include <sys/socket.h>
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <thread>
22 #include <unistd.h>
23
24 #include "securec.h"
25 #include "hilog/log.h"
26
27 namespace OHOS {
28 namespace LMKS {
29
30 namespace {
31 #ifdef __MUSL__
32 const std::string LMKS_SOCKET_NAME = "/dev/unix/socket/lmks";
33 #else
34 const std::string LMKS_SOCKET_NAME = "/dev/socket/lmks";
35 #endif
36 constexpr uint32_t LISTEN_CLIENTS = 5; // 5: max num of clients
37 constexpr uint32_t WAIT_DELAY_US = 100 * 1000; // 100ms
38
39 constexpr int LMKS_CMD_TARGET = 0;
40 constexpr int LMKS_CMD_PROCPRIO = 1;
41 constexpr int LMKS_CMD_PROCREMOVE = 2;
42 constexpr int LMKS_CMD_PROCPURGE = 3;
43 constexpr uid_t LMKS_ID_ROOT = 0; // chown owner
44 constexpr gid_t LMKS_ID_SYSTEM = 1000; // chown group
45 constexpr mode_t SOCKET_PERM = 0666; // root system can read and write lmks socket
46 constexpr struct timeval SOCKET_TIMEOUT = {5, 0}; // 5, 0: { 5 sec, 0 msec } for timeout
47 } // namespace
48
49 using namespace OHOS::HiviewDFX;
50 static constexpr HiLogLabel LABEL = {LOG_CORE, 0, "LmksServer"};
51
LmksServer()52 LmksServer::LmksServer() : isStart_(false), socketFd_(-1), socketAddrLen_(0), lmksUtils_(nullptr)
53 {
54 memset_s(&socketAddr_, sizeof(socketAddr_), 0, sizeof(socketAddr_));
55 }
56
~LmksServer()57 LmksServer::~LmksServer()
58 {
59 CloseSocket();
60 }
61
StartServer()62 void LmksServer::StartServer()
63 {
64 if (isStart_) {
65 HiLog::Error(LABEL, "Lmks server has started.");
66 return;
67 }
68
69 if (RegisterSocket() != 0) {
70 HiLog::Error(LABEL, "Register error.");
71 return;
72 }
73
74 isStart_ = true;
75 if (lmksUtils_ == nullptr) {
76 lmksUtils_ = std::make_shared<LmksUtils>();
77 }
78
79 while (1) {
80 int connectFd = WaitConnection();
81 if (connectFd < 0) {
82 usleep(WAIT_DELAY_US);
83 continue;
84 }
85
86 LMKS_PACKET cmds;
87 int len = RecvSocketMessage(connectFd, (void *)cmds, sizeof(cmds));
88 if (len <= 0) {
89 HiLog::Error(LABEL, "Failed to read socket message, len %{public}d", len);
90 close(connectFd);
91 continue;
92 }
93
94 ProcessMessage(connectFd, cmds, len);
95 }
96
97 // close socket
98 CloseSocket();
99 }
100
RegisterSocket()101 int LmksServer::RegisterSocket()
102 {
103 if (socketFd_ > 0) {
104 HiLog::Error(LABEL, "Lmks server has already register.");
105 return -1;
106 }
107
108 socketFd_ = socket(AF_LOCAL, SOCK_SEQPACKET, 0);
109 if (socketFd_ < 0) {
110 HiLog::Error(LABEL, "Failed to create socket, err %{public}s", strerror(errno));
111 return (-errno);
112 }
113
114 if (memset_s(&socketAddr_, sizeof(socketAddr_), 0, sizeof(socketAddr_)) != 0) {
115 HiLog::Error(LABEL, "Failed to memset socket addr, err %{public}s", strerror(errno));
116 return (-errno);
117 }
118
119 if (strcpy_s(socketAddr_.sun_path, sizeof(socketAddr_.sun_path), LMKS_SOCKET_NAME.c_str()) != 0) {
120 HiLog::Error(LABEL, "Failed to snprint32_tf_s socket addr, err %{public}s", strerror(errno));
121 return (-errno);
122 }
123
124 socketAddr_.sun_family = AF_LOCAL;
125 socketAddrLen_ = offsetof(struct sockaddr_un, sun_path) + LMKS_SOCKET_NAME.length() + 1;
126
127 if ((unlink(socketAddr_.sun_path) != 0) && (errno != ENOENT)) {
128 HiLog::Error(LABEL, "Failed to unlink, err %{public}s", strerror(errno));
129 return (-errno);
130 }
131
132 int reuseAddr = 0;
133 if ((setsockopt(socketFd_, SOL_SOCKET, SO_REUSEADDR, &reuseAddr, sizeof(reuseAddr)) != 0) ||
134 (setsockopt(socketFd_, SOL_SOCKET, SO_RCVTIMEO, &SOCKET_TIMEOUT, sizeof(SOCKET_TIMEOUT)) != 0) ||
135 (setsockopt(socketFd_, SOL_SOCKET, SO_SNDTIMEO, &SOCKET_TIMEOUT, sizeof(SOCKET_TIMEOUT)) != 0)) {
136 HiLog::Error(LABEL, "Failed to set opt of socket %d, err %{public}s", socketFd_, strerror(errno));
137 return (-errno);
138 }
139
140 if (bind(socketFd_, reinterpret_cast<struct sockaddr *>(&socketAddr_), socketAddrLen_) < 0) {
141 HiLog::Error(LABEL, "Failed to bind socket fd %d, err %{public}s", socketFd_, strerror(errno));
142 return (-errno);
143 }
144
145 if (chown(socketAddr_.sun_path, LMKS_ID_ROOT, LMKS_ID_SYSTEM)) {
146 HiLog::Error(LABEL, "Failed to chown socket. err %{public}s", strerror(errno));
147 return (-errno);
148 }
149
150 if (chmod(socketAddr_.sun_path, SOCKET_PERM)) {
151 HiLog::Error(LABEL, "Failed to chmod socket. err %{public}s", strerror(errno));
152 if ((unlink(socketAddr_.sun_path) != 0) && (errno != ENOENT)) {
153 HiLog::Error(LABEL, "Failed to unlink, err %{public}s", strerror(errno));
154 }
155 return (-errno);
156 }
157
158 if (listen(socketFd_, LISTEN_CLIENTS) != 0) {
159 HiLog::Error(LABEL, "Failed to listen socket fd %d, err %{public}s", socketFd_, strerror(errno));
160 return (-errno);
161 }
162
163 return 0;
164 }
165
WaitConnection()166 int LmksServer::WaitConnection()
167 {
168 if (socketFd_ < 0) {
169 HiLog::Error(LABEL, "lmks server not register.");
170 return -1;
171 }
172
173 struct sockaddr_un clientAddr;
174 socklen_t clientLen = sizeof(clientAddr);
175
176 if (memset_s(&clientAddr, clientLen, 0, clientLen) != 0) {
177 HiLog::Warn(LABEL, "Failed to memset client addr, err %{public}s", strerror(errno));
178 }
179
180 int connFd = accept(socketFd_, reinterpret_cast<struct sockaddr *>(&clientAddr), &clientLen);
181 if (connFd < 0) {
182 HiLog::Warn(LABEL, "Accept warning %{public}s", strerror(errno));
183 return (-errno);
184 }
185
186 if ((setsockopt(connFd, SOL_SOCKET, SO_RCVTIMEO, &SOCKET_TIMEOUT, sizeof(SOCKET_TIMEOUT)) < 0) ||
187 (setsockopt(connFd, SOL_SOCKET, SO_SNDTIMEO, &SOCKET_TIMEOUT, sizeof(SOCKET_TIMEOUT)) < 0)) {
188 HiLog::Error(LABEL, "Failed to set opt of Connection %d, err %{public}s", connFd, strerror(errno));
189 close(connFd);
190 return (-errno);
191 }
192
193 return connFd;
194 }
195
CloseSocket()196 void LmksServer::CloseSocket()
197 {
198 if (socketFd_ >= 0) {
199 HiLog::Debug(LABEL, "Closed socket with fd %d", socketFd_);
200 close(socketFd_);
201 socketFd_ = -1;
202 }
203 }
204
SendSocketMessage(int connectFd,const void * buf,int len)205 int LmksServer::SendSocketMessage(int connectFd, const void *buf, int len)
206 {
207 if (connectFd < 0 || len <= 0 || buf == nullptr) {
208 HiLog::Error(LABEL, "Invalid args: connect %d, len %d, buf might be nullptr", connectFd, len);
209 return -1;
210 }
211
212 ssize_t rLen = TEMP_FAILURE_RETRY(send(connectFd, buf, len, 0));
213 if (rLen < 0) {
214 HiLog::Error(LABEL, "Send message from fd %d error %zd: %s", connectFd, rLen, strerror(errno));
215 return (-errno);
216 }
217
218 return rLen;
219 }
220
RecvSocketMessage(int connectFd,void * buf,int len)221 int LmksServer::RecvSocketMessage(int connectFd, void *buf, int len)
222 {
223 if (connectFd < 0 || len <= 0 || buf == nullptr) {
224 HiLog::Error(LABEL, "Invalid args: connect %d, len %d, buf might be nullptr", connectFd, len);
225 return -1;
226 }
227
228 if (memset_s(buf, len, 0, len) != 0) {
229 HiLog::Error(LABEL, "Failed to memset read buf err %{public}s", strerror(errno));
230 return (-errno);
231 }
232
233 ssize_t rLen = TEMP_FAILURE_RETRY(recv(connectFd, buf, len, 0));
234 if (rLen < 0) {
235 HiLog::Error(LABEL, "Read message from fd %d error %zd: %s", connectFd, rLen, strerror(errno));
236 return (-errno);
237 }
238
239 return rLen;
240 }
241
ProcessMessage(int connectFd,LMKS_PACKET cmds,int len)242 void LmksServer::ProcessMessage(int connectFd, LMKS_PACKET cmds, int len)
243 {
244 if (!isStart_ || (lmksUtils_ == nullptr)) {
245 HiLog::Error(
246 LABEL, "Lmks server not start isStart_ %{public}d lmksUtils_%{public}p", isStart_, lmksUtils_.get());
247 close(connectFd);
248 return;
249 }
250
251 if (connectFd < 0 || len <= 0) {
252 HiLog::Error(LABEL, "Invalid args: len %d, connectFd %d", len, connectFd);
253 close(connectFd);
254 return;
255 }
256
257 int ret = -1;
258 pid_t pid = 0;
259
260 switch (cmds[0]) {
261 case LMKS_CMD_TARGET:
262 HiLog::Info(LABEL, "ProcessMessage LMKS_CMD_TARGET ");
263 break;
264 case LMKS_CMD_PROCPRIO:
265 HiLog::Info(LABEL, "ProcessMessage LMKS_CMD_PROCPRIO");
266 break;
267 case LMKS_CMD_PROCREMOVE:
268 HiLog::Info(LABEL, "ProcessMessage LMKS_CMD_PROCREMOVE");
269 pid = cmds[1];
270 ret = lmksUtils_->RemoveProcess(pid);
271 if (SendSocketMessage(connectFd, &ret, sizeof(ret)) <= 0) {
272 HiLog::Error(LABEL, "Failed to return the result of remove process");
273 }
274 break;
275 case LMKS_CMD_PROCPURGE:
276 HiLog::Info(LABEL, "ProcessMessage LMKS_CMD_PROCPURGE");
277 break;
278 default:
279 HiLog::Error(LABEL, "Wrong cmd %d", cmds[0]);
280 break;
281 }
282
283 // close connect fd.
284 close(connectFd);
285 }
286 } // namespace LMKS
287 } // namespace OHOS
288