blob: 44bda3b08c090ac0d960b352f0d711a16f235ea3 [file] [log] [blame]
Lorenzo Colitti8464e1e2016-02-05 00:57:26 +09001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Bernie Innocenti196f1b82019-05-20 16:34:16 +090017#define LOG_TAG "Netd"
18
19#include "SockDiag.h"
20
Lorenzo Colitti8464e1e2016-02-05 00:57:26 +090021#include <errno.h>
Bernie Innocenti196f1b82019-05-20 16:34:16 +090022#include <linux/inet_diag.h>
23#include <linux/netlink.h>
24#include <linux/sock_diag.h>
Lorenzo Colitti8464e1e2016-02-05 00:57:26 +090025#include <netdb.h>
Lorenzo Colitti8464e1e2016-02-05 00:57:26 +090026#include <netinet/in.h>
27#include <netinet/tcp.h>
Bernie Innocenti196f1b82019-05-20 16:34:16 +090028#include <string.h>
Lorenzo Colitti8464e1e2016-02-05 00:57:26 +090029#include <sys/socket.h>
30#include <sys/uio.h>
31
Bernie Innocenti196f1b82019-05-20 16:34:16 +090032#include <cinttypes>
Lorenzo Colitti8464e1e2016-02-05 00:57:26 +090033
Lorenzo Colittifff4bd32016-04-14 00:56:01 +090034#include <android-base/strings.h>
Logan Chien3f461482018-04-23 14:31:32 +080035#include <log/log.h>
Luke Huang25599322019-06-14 00:34:05 +080036#include <netdutils/InternetAddresses.h>
Mike Yue7e332f2019-03-13 17:15:48 +080037#include <netdutils/Stopwatch.h>
Lorenzo Colitti8464e1e2016-02-05 00:57:26 +090038
Lorenzo Colittifbe76b92016-09-14 02:25:05 +090039#include "Permission.h"
Lorenzo Colittif32fc592016-02-15 01:09:14 +090040
Lorenzo Colitti8464e1e2016-02-05 00:57:26 +090041#ifndef SOCK_DESTROY
42#define SOCK_DESTROY 21
43#endif
44
Lorenzo Colittifbe76b92016-09-14 02:25:05 +090045#define INET_DIAG_BC_MARK_COND 10
46
Lorenzo Colitti7035f222017-02-13 18:29:00 +090047namespace android {
Lorenzo Colitti7035f222017-02-13 18:29:00 +090048
Luke Huang25599322019-06-14 00:34:05 +080049using netdutils::ScopedAddrinfo;
Mike Yue7e332f2019-03-13 17:15:48 +080050using netdutils::Stopwatch;
51
52namespace net {
Lorenzo Colitti8464e1e2016-02-05 00:57:26 +090053namespace {
54
Lorenzo Colitti8464e1e2016-02-05 00:57:26 +090055int checkError(int fd) {
56 struct {
57 nlmsghdr h;
58 nlmsgerr err;
59 } __attribute__((__packed__)) ack;
60 ssize_t bytesread = recv(fd, &ack, sizeof(ack), MSG_DONTWAIT | MSG_PEEK);
61 if (bytesread == -1) {
62 // Read failed (error), or nothing to read (good).
63 return (errno == EAGAIN) ? 0 : -errno;
64 } else if (bytesread == (ssize_t) sizeof(ack) && ack.h.nlmsg_type == NLMSG_ERROR) {
65 // We got an error. Consume it.
66 recv(fd, &ack, sizeof(ack), 0);
67 return ack.err.error;
68 } else {
69 // The kernel replied with something. Leave it to the caller.
70 return 0;
71 }
72}
73
74} // namespace
75
76bool SockDiag::open() {
77 if (hasSocks()) {
78 return false;
79 }
80
Nick Kralevichaf02b552016-12-20 08:40:35 -080081 mSock = socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_INET_DIAG);
82 mWriteSock = socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_INET_DIAG);
Lorenzo Colitti8464e1e2016-02-05 00:57:26 +090083 if (!hasSocks()) {
84 closeSocks();
85 return false;
86 }
87
88 sockaddr_nl nl = { .nl_family = AF_NETLINK };
89 if ((connect(mSock, reinterpret_cast<sockaddr *>(&nl), sizeof(nl)) == -1) ||
90 (connect(mWriteSock, reinterpret_cast<sockaddr *>(&nl), sizeof(nl)) == -1)) {
91 closeSocks();
92 return false;
93 }
94
95 return true;
96}
97
Hugo Benichidee94812018-01-12 14:47:00 +090098int SockDiag::sendDumpRequest(uint8_t proto, uint8_t family, uint8_t extensions, uint32_t states,
Lorenzo Colitti94a7b432016-03-24 16:47:12 +090099 iovec *iov, int iovcnt) {
100 struct {
101 nlmsghdr nlh;
102 inet_diag_req_v2 req;
103 } __attribute__((__packed__)) request = {
104 .nlh = {
105 .nlmsg_type = SOCK_DIAG_BY_FAMILY,
106 .nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP,
107 },
108 .req = {
109 .sdiag_family = family,
110 .sdiag_protocol = proto,
Hugo Benichidee94812018-01-12 14:47:00 +0900111 .idiag_ext = extensions,
Lorenzo Colitti94a7b432016-03-24 16:47:12 +0900112 .idiag_states = states,
113 },
114 };
115
116 size_t len = 0;
117 iov[0].iov_base = &request;
118 iov[0].iov_len = sizeof(request);
119 for (int i = 0; i < iovcnt; i++) {
120 len += iov[i].iov_len;
121 }
122 request.nlh.nlmsg_len = len;
123
124 if (writev(mSock, iov, iovcnt) != (ssize_t) len) {
125 return -errno;
126 }
127
128 return checkError(mSock);
129}
130
131int SockDiag::sendDumpRequest(uint8_t proto, uint8_t family, uint32_t states) {
132 iovec iov[] = {
133 { nullptr, 0 },
134 };
Hugo Benichidee94812018-01-12 14:47:00 +0900135 return sendDumpRequest(proto, family, 0, states, iov, ARRAY_SIZE(iov));
Lorenzo Colitti94a7b432016-03-24 16:47:12 +0900136}
137
Lorenzo Colitti8464e1e2016-02-05 00:57:26 +0900138int SockDiag::sendDumpRequest(uint8_t proto, uint8_t family, const char *addrstr) {
139 addrinfo hints = { .ai_flags = AI_NUMERICHOST };
140 addrinfo *res;
141 in6_addr mapped = { .s6_addr32 = { 0, 0, htonl(0xffff), 0 } };
Lorenzo Colitti8464e1e2016-02-05 00:57:26 +0900142
143 // TODO: refactor the netlink parsing code out of system/core, bring it into netd, and stop
144 // doing string conversions when they're not necessary.
Maciej Żenczykowski07f03ac2020-05-01 01:30:14 +0000145 int ret = getaddrinfo(addrstr, nullptr, &hints, &res);
146 if (ret != 0) return -EINVAL;
Lorenzo Colitti8464e1e2016-02-05 00:57:26 +0900147
148 // So we don't have to call freeaddrinfo on every failure path.
149 ScopedAddrinfo resP(res);
150
151 void *addr;
152 uint8_t addrlen;
153 if (res->ai_family == AF_INET && family == AF_INET) {
154 in_addr& ina = reinterpret_cast<sockaddr_in*>(res->ai_addr)->sin_addr;
155 addr = &ina;
156 addrlen = sizeof(ina);
157 } else if (res->ai_family == AF_INET && family == AF_INET6) {
158 in_addr& ina = reinterpret_cast<sockaddr_in*>(res->ai_addr)->sin_addr;
159 mapped.s6_addr32[3] = ina.s_addr;
160 addr = &mapped;
161 addrlen = sizeof(mapped);
162 } else if (res->ai_family == AF_INET6 && family == AF_INET6) {
163 in6_addr& in6a = reinterpret_cast<sockaddr_in6*>(res->ai_addr)->sin6_addr;
164 addr = &in6a;
165 addrlen = sizeof(in6a);
166 } else {
167 return -EAFNOSUPPORT;
168 }
169
170 uint8_t prefixlen = addrlen * 8;
171 uint8_t yesjump = sizeof(inet_diag_bc_op) + sizeof(inet_diag_hostcond) + addrlen;
172 uint8_t nojump = yesjump + 4;
Lorenzo Colitti8464e1e2016-02-05 00:57:26 +0900173
174 struct {
Lorenzo Colitti8464e1e2016-02-05 00:57:26 +0900175 nlattr nla;
176 inet_diag_bc_op op;
177 inet_diag_hostcond cond;
Lorenzo Colitti94a7b432016-03-24 16:47:12 +0900178 } __attribute__((__packed__)) attrs = {
Lorenzo Colitti8464e1e2016-02-05 00:57:26 +0900179 .nla = {
180 .nla_type = INET_DIAG_REQ_BYTECODE,
181 },
182 .op = {
183 INET_DIAG_BC_S_COND,
184 yesjump,
185 nojump,
186 },
187 .cond = {
188 family,
189 prefixlen,
190 -1,
191 {}
192 },
193 };
194
Lorenzo Colitti94a7b432016-03-24 16:47:12 +0900195 attrs.nla.nla_len = sizeof(attrs) + addrlen;
Lorenzo Colitti8464e1e2016-02-05 00:57:26 +0900196
Lorenzo Colitti94a7b432016-03-24 16:47:12 +0900197 iovec iov[] = {
Lorenzo Colittifbe76b92016-09-14 02:25:05 +0900198 { nullptr, 0 },
199 { &attrs, sizeof(attrs) },
200 { addr, addrlen },
Lorenzo Colitti8464e1e2016-02-05 00:57:26 +0900201 };
202
Lorenzo Colitti94a7b432016-03-24 16:47:12 +0900203 uint32_t states = ~(1 << TCP_TIME_WAIT);
Hugo Benichidee94812018-01-12 14:47:00 +0900204 return sendDumpRequest(proto, family, 0, states, iov, ARRAY_SIZE(iov));
Lorenzo Colitti8464e1e2016-02-05 00:57:26 +0900205}
206
Lorenzo Colitti0b733e42017-02-13 16:29:00 +0900207int SockDiag::readDiagMsg(uint8_t proto, const SockDiag::DestroyFilter& shouldDestroy) {
208 NetlinkDumpCallback callback = [this, proto, shouldDestroy] (nlmsghdr *nlh) {
Lorenzo Colitti0b733e42017-02-13 16:29:00 +0900209 const inet_diag_msg *msg = reinterpret_cast<inet_diag_msg *>(NLMSG_DATA(nlh));
210 if (shouldDestroy(proto, msg)) {
211 sockDestroy(proto, msg);
Lorenzo Colitti8464e1e2016-02-05 00:57:26 +0900212 }
Lorenzo Colitti0b733e42017-02-13 16:29:00 +0900213 };
Lorenzo Colitti8464e1e2016-02-05 00:57:26 +0900214
Lorenzo Colitti0b733e42017-02-13 16:29:00 +0900215 return processNetlinkDump(mSock, callback);
Lorenzo Colitti8464e1e2016-02-05 00:57:26 +0900216}
217
Hugo Benichidee94812018-01-12 14:47:00 +0900218int SockDiag::readDiagMsgWithTcpInfo(const TcpInfoReader& tcpInfoReader) {
219 NetlinkDumpCallback callback = [tcpInfoReader] (nlmsghdr *nlh) {
Hugo Benichi321b22c2018-01-30 11:37:27 +0900220 if (nlh->nlmsg_type != SOCK_DIAG_BY_FAMILY) {
221 ALOGE("expected nlmsg_type=SOCK_DIAG_BY_FAMILY, got nlmsg_type=%d", nlh->nlmsg_type);
222 return;
223 }
Hugo Benichicbaa36b2018-01-17 12:11:43 +0900224 Fwmark mark;
Hugo Benichidee94812018-01-12 14:47:00 +0900225 struct tcp_info *tcpinfo = nullptr;
Hugo Benichi54bfc7c2018-01-23 14:16:52 +0900226 uint32_t tcpinfoLength = 0;
Hugo Benichidee94812018-01-12 14:47:00 +0900227 inet_diag_msg *msg = reinterpret_cast<inet_diag_msg *>(NLMSG_DATA(nlh));
228 uint32_t attr_len = nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*msg));
229 struct rtattr *attr = reinterpret_cast<struct rtattr*>(msg+1);
230 while (RTA_OK(attr, attr_len)) {
231 if (attr->rta_type == INET_DIAG_INFO) {
232 tcpinfo = reinterpret_cast<struct tcp_info*>(RTA_DATA(attr));
Hugo Benichi54bfc7c2018-01-23 14:16:52 +0900233 tcpinfoLength = RTA_PAYLOAD(attr);
Hugo Benichicbaa36b2018-01-17 12:11:43 +0900234 }
235 if (attr->rta_type == INET_DIAG_MARK) {
236 mark.intValue = *reinterpret_cast<uint32_t*>(RTA_DATA(attr));
Hugo Benichidee94812018-01-12 14:47:00 +0900237 }
238 attr = RTA_NEXT(attr, attr_len);
239 }
240
Hugo Benichi54bfc7c2018-01-23 14:16:52 +0900241 tcpInfoReader(mark, msg, tcpinfo, tcpinfoLength);
Hugo Benichidee94812018-01-12 14:47:00 +0900242 };
243
244 return processNetlinkDump(mSock, callback);
245}
246
Lorenzo Colittie5c3c992016-07-26 17:53:50 +0900247// Determines whether a socket is a loopback socket. Does not check socket state.
248bool SockDiag::isLoopbackSocket(const inet_diag_msg *msg) {
249 switch (msg->idiag_family) {
250 case AF_INET:
251 // Old kernels only copy the IPv4 address and leave the other 12 bytes uninitialized.
252 return IN_LOOPBACK(htonl(msg->id.idiag_src[0])) ||
253 IN_LOOPBACK(htonl(msg->id.idiag_dst[0])) ||
254 msg->id.idiag_src[0] == msg->id.idiag_dst[0];
255
256 case AF_INET6: {
257 const struct in6_addr *src = (const struct in6_addr *) &msg->id.idiag_src;
258 const struct in6_addr *dst = (const struct in6_addr *) &msg->id.idiag_dst;
259 return (IN6_IS_ADDR_V4MAPPED(src) && IN_LOOPBACK(src->s6_addr32[3])) ||
260 (IN6_IS_ADDR_V4MAPPED(dst) && IN_LOOPBACK(dst->s6_addr32[3])) ||
261 IN6_IS_ADDR_LOOPBACK(src) || IN6_IS_ADDR_LOOPBACK(dst) ||
262 !memcmp(src, dst, sizeof(*src));
263 }
264 default:
265 return false;
266 }
267}
268
Lorenzo Colitti8464e1e2016-02-05 00:57:26 +0900269int SockDiag::sockDestroy(uint8_t proto, const inet_diag_msg *msg) {
Lorenzo Colittif32fc592016-02-15 01:09:14 +0900270 if (msg == nullptr) {
271 return 0;
272 }
273
Lorenzo Colitti8464e1e2016-02-05 00:57:26 +0900274 DestroyRequest request = {
275 .nlh = {
276 .nlmsg_type = SOCK_DESTROY,
277 .nlmsg_flags = NLM_F_REQUEST,
278 },
279 .req = {
280 .sdiag_family = msg->idiag_family,
281 .sdiag_protocol = proto,
282 .idiag_states = (uint32_t) (1 << msg->idiag_state),
283 .id = msg->id,
284 },
285 };
286 request.nlh.nlmsg_len = sizeof(request);
287
288 if (write(mWriteSock, &request, sizeof(request)) < (ssize_t) sizeof(request)) {
289 return -errno;
290 }
291
Lorenzo Colittif32fc592016-02-15 01:09:14 +0900292 int ret = checkError(mWriteSock);
293 if (!ret) mSocketsDestroyed++;
294 return ret;
295}
296
297int SockDiag::destroySockets(uint8_t proto, int family, const char *addrstr) {
298 if (!hasSocks()) {
299 return -EBADFD;
300 }
301
302 if (int ret = sendDumpRequest(proto, family, addrstr)) {
303 return ret;
304 }
305
Lorenzo Colittifff4bd32016-04-14 00:56:01 +0900306 auto destroyAll = [] (uint8_t, const inet_diag_msg*) { return true; };
Lorenzo Colittif32fc592016-02-15 01:09:14 +0900307
Lorenzo Colittifff4bd32016-04-14 00:56:01 +0900308 return readDiagMsg(proto, destroyAll);
Lorenzo Colittif32fc592016-02-15 01:09:14 +0900309}
310
311int SockDiag::destroySockets(const char *addrstr) {
Lorenzo Colitti94a7b432016-03-24 16:47:12 +0900312 Stopwatch s;
Lorenzo Colittif32fc592016-02-15 01:09:14 +0900313 mSocketsDestroyed = 0;
Lorenzo Colitti94a7b432016-03-24 16:47:12 +0900314
Lorenzo Colittif32fc592016-02-15 01:09:14 +0900315 if (!strchr(addrstr, ':')) {
316 if (int ret = destroySockets(IPPROTO_TCP, AF_INET, addrstr)) {
317 ALOGE("Failed to destroy IPv4 sockets on %s: %s", addrstr, strerror(-ret));
318 return ret;
319 }
320 }
321 if (int ret = destroySockets(IPPROTO_TCP, AF_INET6, addrstr)) {
322 ALOGE("Failed to destroy IPv6 sockets on %s: %s", addrstr, strerror(-ret));
323 return ret;
324 }
Lorenzo Colittif32fc592016-02-15 01:09:14 +0900325
326 if (mSocketsDestroyed > 0) {
Bernie Innocenti196f1b82019-05-20 16:34:16 +0900327 ALOGI("Destroyed %d sockets on %s in %" PRId64 "us", mSocketsDestroyed, addrstr,
328 s.timeTakenUs());
Lorenzo Colittif32fc592016-02-15 01:09:14 +0900329 }
330
331 return mSocketsDestroyed;
Lorenzo Colitti8464e1e2016-02-05 00:57:26 +0900332}
Lorenzo Colitti94a7b432016-03-24 16:47:12 +0900333
Bernie Innocenti15bb55c2018-06-03 16:19:51 +0900334int SockDiag::destroyLiveSockets(const DestroyFilter& destroyFilter, const char *what,
Lorenzo Colittifbe76b92016-09-14 02:25:05 +0900335 iovec *iov, int iovcnt) {
Hugo Benichidee94812018-01-12 14:47:00 +0900336 const int proto = IPPROTO_TCP;
337 const uint32_t states = (1 << TCP_ESTABLISHED) | (1 << TCP_SYN_SENT) | (1 << TCP_SYN_RECV);
Lorenzo Colittifff4bd32016-04-14 00:56:01 +0900338
339 for (const int family : {AF_INET, AF_INET6}) {
340 const char *familyName = (family == AF_INET) ? "IPv4" : "IPv6";
Hugo Benichidee94812018-01-12 14:47:00 +0900341 if (int ret = sendDumpRequest(proto, family, 0, states, iov, iovcnt)) {
Lorenzo Colittifbe76b92016-09-14 02:25:05 +0900342 ALOGE("Failed to dump %s sockets for %s: %s", familyName, what, strerror(-ret));
Lorenzo Colittifff4bd32016-04-14 00:56:01 +0900343 return ret;
344 }
345 if (int ret = readDiagMsg(proto, destroyFilter)) {
Lorenzo Colittifbe76b92016-09-14 02:25:05 +0900346 ALOGE("Failed to destroy %s sockets for %s: %s", familyName, what, strerror(-ret));
Lorenzo Colittifff4bd32016-04-14 00:56:01 +0900347 return ret;
348 }
349 }
350
351 return 0;
352}
353
Hugo Benichidee94812018-01-12 14:47:00 +0900354int SockDiag::getLiveTcpInfos(const TcpInfoReader& tcpInfoReader) {
355 const int proto = IPPROTO_TCP;
356 const uint32_t states = (1 << TCP_ESTABLISHED) | (1 << TCP_SYN_SENT) | (1 << TCP_SYN_RECV);
357 const uint8_t extensions = (1 << INET_DIAG_MEMINFO); // flag for dumping struct tcp_info.
358
359 iovec iov[] = {
360 { nullptr, 0 },
361 };
362
363 for (const int family : {AF_INET, AF_INET6}) {
364 const char *familyName = (family == AF_INET) ? "IPv4" : "IPv6";
365 if (int ret = sendDumpRequest(proto, family, extensions, states, iov, ARRAY_SIZE(iov))) {
366 ALOGE("Failed to dump %s sockets struct tcp_info: %s", familyName, strerror(-ret));
367 return ret;
368 }
369 if (int ret = readDiagMsgWithTcpInfo(tcpInfoReader)) {
370 ALOGE("Failed to read %s sockets struct tcp_info: %s", familyName, strerror(-ret));
371 return ret;
372 }
373 }
374
375 return 0;
376}
377
Lorenzo Colittie5c3c992016-07-26 17:53:50 +0900378int SockDiag::destroySockets(uint8_t proto, const uid_t uid, bool excludeLoopback) {
Lorenzo Colitti94a7b432016-03-24 16:47:12 +0900379 mSocketsDestroyed = 0;
380 Stopwatch s;
381
Lorenzo Colittie5c3c992016-07-26 17:53:50 +0900382 auto shouldDestroy = [uid, excludeLoopback] (uint8_t, const inet_diag_msg *msg) {
383 return msg != nullptr &&
384 msg->idiag_uid == uid &&
385 !(excludeLoopback && isLoopbackSocket(msg));
Lorenzo Colitti94a7b432016-03-24 16:47:12 +0900386 };
387
388 for (const int family : {AF_INET, AF_INET6}) {
389 const char *familyName = family == AF_INET ? "IPv4" : "IPv6";
390 uint32_t states = (1 << TCP_ESTABLISHED) | (1 << TCP_SYN_SENT) | (1 << TCP_SYN_RECV);
391 if (int ret = sendDumpRequest(proto, family, states)) {
392 ALOGE("Failed to dump %s sockets for UID: %s", familyName, strerror(-ret));
393 return ret;
394 }
Lorenzo Colittifff4bd32016-04-14 00:56:01 +0900395 if (int ret = readDiagMsg(proto, shouldDestroy)) {
Lorenzo Colitti94a7b432016-03-24 16:47:12 +0900396 ALOGE("Failed to destroy %s sockets for UID: %s", familyName, strerror(-ret));
397 return ret;
398 }
399 }
400
401 if (mSocketsDestroyed > 0) {
Bernie Innocenti196f1b82019-05-20 16:34:16 +0900402 ALOGI("Destroyed %d sockets for UID in %" PRId64 "us", mSocketsDestroyed, s.timeTakenUs());
Lorenzo Colitti94a7b432016-03-24 16:47:12 +0900403 }
404
405 return 0;
406}
Lorenzo Colittifff4bd32016-04-14 00:56:01 +0900407
Lorenzo Colittie5c3c992016-07-26 17:53:50 +0900408int SockDiag::destroySockets(const UidRanges& uidRanges, const std::set<uid_t>& skipUids,
409 bool excludeLoopback) {
Lorenzo Colittifff4bd32016-04-14 00:56:01 +0900410 mSocketsDestroyed = 0;
411 Stopwatch s;
412
413 auto shouldDestroy = [&] (uint8_t, const inet_diag_msg *msg) {
414 return msg != nullptr &&
415 uidRanges.hasUid(msg->idiag_uid) &&
Lorenzo Colittie5c3c992016-07-26 17:53:50 +0900416 skipUids.find(msg->idiag_uid) == skipUids.end() &&
417 !(excludeLoopback && isLoopbackSocket(msg));
Lorenzo Colittifff4bd32016-04-14 00:56:01 +0900418 };
419
Lorenzo Colittifbe76b92016-09-14 02:25:05 +0900420 iovec iov[] = {
421 { nullptr, 0 },
422 };
423
424 if (int ret = destroyLiveSockets(shouldDestroy, "UID", iov, ARRAY_SIZE(iov))) {
Lorenzo Colittifff4bd32016-04-14 00:56:01 +0900425 return ret;
426 }
427
Lorenzo Colittifff4bd32016-04-14 00:56:01 +0900428 if (mSocketsDestroyed > 0) {
Bernie Innocenti196f1b82019-05-20 16:34:16 +0900429 ALOGI("Destroyed %d sockets for %s skip={%s} in %" PRId64 "us", mSocketsDestroyed,
430 uidRanges.toString().c_str(), android::base::Join(skipUids, " ").c_str(),
431 s.timeTakenUs());
Lorenzo Colittifff4bd32016-04-14 00:56:01 +0900432 }
433
434 return 0;
435}
Lorenzo Colittifbe76b92016-09-14 02:25:05 +0900436
437// Destroys all "live" (CONNECTED, SYN_SENT, SYN_RECV) TCP sockets on the specified netId where:
438// 1. The opening app no longer has permission to use this network, or:
439// 2. The opening app does have permission, but did not explicitly select this network.
440//
441// We destroy sockets without the explicit bit because we want to avoid the situation where a
442// privileged app uses its privileges without knowing it is doing so. For example, a privileged app
443// might have opened a socket on this network just because it was the default network at the
444// time. If we don't kill these sockets, those apps could continue to use them without realizing
445// that they are now sending and receiving traffic on a network that is now restricted.
446int SockDiag::destroySocketsLackingPermission(unsigned netId, Permission permission,
447 bool excludeLoopback) {
448 struct markmatch {
449 inet_diag_bc_op op;
450 // TODO: switch to inet_diag_markcond
451 __u32 mark;
452 __u32 mask;
453 } __attribute__((packed));
454 constexpr uint8_t matchlen = sizeof(markmatch);
455
456 Fwmark netIdMark, netIdMask;
457 netIdMark.netId = netId;
458 netIdMask.netId = 0xffff;
459
460 Fwmark controlMark;
461 controlMark.explicitlySelected = true;
462 controlMark.permission = permission;
463
464 // A SOCK_DIAG bytecode program that accepts the sockets we intend to destroy.
465 struct bytecode {
466 markmatch netIdMatch;
467 markmatch controlMatch;
468 inet_diag_bc_op controlJump;
469 } __attribute__((packed)) bytecode;
470
471 // The length of the INET_DIAG_BC_JMP instruction.
472 constexpr uint8_t jmplen = sizeof(inet_diag_bc_op);
473 // Jump exactly this far past the end of the program to reject.
474 constexpr uint8_t rejectoffset = sizeof(inet_diag_bc_op);
475 // Total length of the program.
476 constexpr uint8_t bytecodelen = sizeof(bytecode);
477
478 bytecode = (struct bytecode) {
479 // If netId matches, continue, otherwise, reject (i.e., leave socket alone).
480 { { INET_DIAG_BC_MARK_COND, matchlen, bytecodelen + rejectoffset },
481 netIdMark.intValue, netIdMask.intValue },
482
483 // If explicit and permission bits match, go to the JMP below which rejects the socket
484 // (i.e., we leave it alone). Otherwise, jump to the end of the program, which accepts the
485 // socket (so we destroy it).
486 { { INET_DIAG_BC_MARK_COND, matchlen, matchlen + jmplen },
487 controlMark.intValue, controlMark.intValue },
488
489 // This JMP unconditionally rejects the packet by jumping to the reject target. It is
490 // necessary to keep the kernel bytecode verifier happy. If we don't have a JMP the bytecode
491 // is invalid because the target of every no jump must always be reachable by yes jumps.
492 // Without this JMP, the accept target is not reachable by yes jumps and the program will
493 // be rejected by the validator.
494 { INET_DIAG_BC_JMP, jmplen, jmplen + rejectoffset },
495
496 // We have reached the end of the program. Accept the socket, and destroy it below.
497 };
498
499 struct nlattr nla = {
Nick Desaulniers6b357502019-10-11 09:26:44 -0700500 .nla_len = sizeof(struct nlattr) + bytecodelen,
501 .nla_type = INET_DIAG_REQ_BYTECODE,
Lorenzo Colittifbe76b92016-09-14 02:25:05 +0900502 };
503
504 iovec iov[] = {
505 { nullptr, 0 },
506 { &nla, sizeof(nla) },
507 { &bytecode, bytecodelen },
508 };
509
510 mSocketsDestroyed = 0;
511 Stopwatch s;
512
513 auto shouldDestroy = [&] (uint8_t, const inet_diag_msg *msg) {
514 return msg != nullptr && !(excludeLoopback && isLoopbackSocket(msg));
515 };
516
517 if (int ret = destroyLiveSockets(shouldDestroy, "permission change", iov, ARRAY_SIZE(iov))) {
518 return ret;
519 }
520
521 if (mSocketsDestroyed > 0) {
Bernie Innocenti196f1b82019-05-20 16:34:16 +0900522 ALOGI("Destroyed %d sockets for netId %d permission=%d in %" PRId64 "us", mSocketsDestroyed,
523 netId, permission, s.timeTakenUs());
Lorenzo Colittifbe76b92016-09-14 02:25:05 +0900524 }
525
526 return 0;
527}
Lorenzo Colitti7035f222017-02-13 18:29:00 +0900528
529} // namespace net
530} // namespace android