• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "netlink/netlink_listener.h"
16 
17 #include <cerrno>
18 #include <memory>
19 #include <iostream>
20 
21 #include <sys/socket.h>
22 #include <sys/socket.h>
23 #include <unistd.h>
24 #include <linux/netlink.h>
25 
26 #include "securec.h"
27 #include "storage_service_errno.h"
28 #include "storage_service_log.h"
29 
30 constexpr int POLL_IDLE_TIME = 1000;
31 constexpr int UEVENT_MSG_LEN = 1024;
32 
33 namespace OHOS {
34 namespace StorageDaemon {
UeventKernelMulticastRecv(int32_t socket,char * buffer,size_t length)35 ssize_t UeventKernelMulticastRecv(int32_t socket, char *buffer, size_t length)
36 {
37     struct iovec iov = { buffer, length };
38     struct sockaddr_nl addr;
39     char control[CMSG_SPACE(sizeof(struct ucred))];
40     struct msghdr hdr = {
41         .msg_name = &addr,
42         .msg_namelen = sizeof(addr),
43         .msg_iov = &iov,
44         .msg_iovlen = 1,
45         .msg_control = control,
46         .msg_controllen = sizeof(control),
47         .msg_flags = 0,
48     };
49     struct cmsghdr *cmsg;
50 
51     ssize_t n = recvmsg(socket, &hdr, 0);
52     if (n <= 0) {
53         LOGE("Recvmsg failed, errno %{public}d", errno);
54         return n;
55     }
56 
57     if (addr.nl_groups == 0 || addr.nl_pid != 0) {
58         LOGE("Groups or pid check failed");
59         return E_ERR;
60     }
61 
62     cmsg = CMSG_FIRSTHDR(&hdr);
63     if (cmsg == nullptr || cmsg->cmsg_type != SCM_CREDENTIALS) {
64         LOGE("SCM_CREDENTIALS check failed");
65         return E_ERR;
66     }
67 
68     struct ucred cred;
69     if (memcpy_s(&cred, sizeof(cred), CMSG_DATA(cmsg), sizeof(struct ucred)) != 0 || cred.uid != 0) {
70         LOGE("Uid check failed");
71         return E_ERR;
72     }
73 
74     return n;
75 }
76 
RecvUeventMsg()77 void NetlinkListener::RecvUeventMsg()
78 {
79     auto msg = std::make_unique<char[]>(UEVENT_MSG_LEN + 1);
80     ssize_t count;
81 
82     while (1) {
83         count = UeventKernelMulticastRecv(socketFd_, msg.get(), UEVENT_MSG_LEN);
84         if (count <= 0) {
85             (void)memset_s(msg.get(), UEVENT_MSG_LEN + 1, 0, UEVENT_MSG_LEN + 1);
86             break;
87         }
88         if (count >= UEVENT_MSG_LEN) {
89             continue;
90         }
91 
92         msg.get()[count] = '\0';
93         OnEvent(msg.get());
94     }
95 }
96 
ReadMsg(int32_t fd_count,struct pollfd ufds[2])97 int32_t NetlinkListener::ReadMsg(int32_t fd_count, struct pollfd ufds[2])
98 {
99     int32_t i;
100     for (i = 0; i < fd_count; i++) {
101         if (ufds[i].revents == 0) {
102             continue;
103         }
104 
105         if (ufds[i].fd == socketPipe_[0]) {
106             int32_t msg;
107             if (read(socketPipe_[0], &msg, 1) < 0) {
108                 LOGE("Read socket pipe failed");
109                 return E_ERR;
110             }
111             if (msg == 0) {
112                 LOGI("Stop listener");
113                 break;
114             }
115         } else if (ufds[i].fd == socketFd_) {
116             if (ufds[i].revents & POLLIN) {
117                 RecvUeventMsg();
118                 continue;
119             }
120             if ((static_cast<uint32_t>(ufds[i].revents)) & (POLLERR | POLLHUP)) {
121                 LOGE("POLLERR | POLLHUP");
122                 return E_ERR;
123             }
124         }
125     }
126     return E_OK;
127 }
128 
RunListener()129 void NetlinkListener::RunListener()
130 {
131     struct pollfd ufds[2];
132     int32_t idle_time = POLL_IDLE_TIME;
133 
134     while (1) {
135         int32_t fd_count = 0;
136 
137         ufds[fd_count].fd = socketPipe_[0];
138         ufds[fd_count].events = POLLIN;
139         ufds[fd_count].revents = 0;
140         fd_count++;
141 
142         if (socketFd_ > -1) {
143             ufds[fd_count].fd = socketFd_;
144             ufds[fd_count].events = POLLIN;
145             ufds[fd_count].revents = 0;
146             fd_count++;
147         }
148 
149         int32_t n = poll(ufds, fd_count, idle_time);
150         if (n < 0) {
151             if (errno == EAGAIN || errno == EINTR) {
152                 continue;
153             }
154             break;
155         } else if (!n) {
156             continue;
157         }
158 
159         if (ReadMsg(fd_count, ufds) != 0) {
160             return;
161         }
162     }
163 }
164 
EventProcess(void * object)165 void *NetlinkListener::EventProcess(void *object)
166 {
167     NetlinkListener* me = reinterpret_cast<NetlinkListener *>(object);
168     me->RunListener();
169     return nullptr;
170 }
171 
StartListener()172 int32_t NetlinkListener::StartListener()
173 {
174     if (socketFd_ < 0) {
175         return E_ERR;
176     }
177 
178     if (pipe(socketPipe_) == -1) {
179         LOGE("Pipe error");
180         return E_ERR;
181     }
182     socketThread_ = std::make_unique<std::thread>(&NetlinkListener::EventProcess, this);
183     if (socketThread_ == nullptr) {
184         close(socketPipe_[0]);
185         close(socketPipe_[1]);
186         socketPipe_[0] = socketPipe_[1] = -1;
187         return E_ERR;
188     }
189 
190     return E_OK;
191 }
192 
StopListener()193 int32_t NetlinkListener::StopListener()
194 {
195     int32_t msg = 0;
196     write(socketPipe_[1], &msg, 1);
197 
198     if (socketThread_ != nullptr && socketThread_->joinable()) {
199         socketThread_->join();
200     }
201 
202     close(socketPipe_[0]);
203     close(socketPipe_[1]);
204     socketPipe_[0] = socketPipe_[1] = -1;
205 
206     return E_OK;
207 }
208 
NetlinkListener(int32_t socket)209 NetlinkListener::NetlinkListener(int32_t socket)
210 {
211     socketFd_ = socket;
212 }
213 } // StorageDaemon
214 } // OHOS
215