blob: 885db91f019557c985ebf1943b2c8469c45115b3 [file] [log] [blame]
Sreeram Ramachandran030b36e2014-05-11 21:04:03 -07001/*
2 * Copyright (C) 2014 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
17#include "FwmarkServer.h"
18
Hugo Benichi456c9062017-01-04 12:19:16 +090019#include <netinet/in.h>
Lorenzo Colitti09175be2017-11-17 14:01:21 +090020#include <selinux/selinux.h>
Sreeram Ramachandran030b36e2014-05-11 21:04:03 -070021#include <sys/socket.h>
22#include <unistd.h>
Michal Karpinski7d374532016-10-06 19:33:55 +010023#include <utils/String16.h>
Sreeram Ramachandran030b36e2014-05-11 21:04:03 -070024
Josh Gaoba76bd62020-01-06 17:22:41 -080025#include <android-base/cmsg.h>
26#include <android-base/logging.h>
Chenbo Feng9944ba82017-10-10 17:33:20 -070027#include <binder/IServiceManager.h>
Bernie Innocenti189eb502018-10-01 23:10:18 +090028#include <netd_resolv/resolv.h> // NETID_UNSET
29
30#include "Fwmark.h"
31#include "FwmarkCommand.h"
32#include "NetdConstants.h"
33#include "NetworkController.h"
34#include "TrafficController.h"
Chenbo Feng9944ba82017-10-10 17:33:20 -070035
Michal Karpinski7d374532016-10-06 19:33:55 +010036using android::String16;
Josh Gaoba76bd62020-01-06 17:22:41 -080037using android::base::ReceiveFileDescriptorVector;
38using android::base::unique_fd;
Michal Karpinski7d374532016-10-06 19:33:55 +010039using android::net::metrics::INetdEventListener;
40
Lorenzo Colitti7035f222017-02-13 18:29:00 +090041namespace android {
42namespace net {
43
Lorenzo Colitti09175be2017-11-17 14:01:21 +090044constexpr const char *SYSTEM_SERVER_CONTEXT = "u:r:system_server:s0";
45
46bool isSystemServer(SocketClient* client) {
47 if (client->getUid() != AID_SYSTEM) {
48 return false;
49 }
50
51 char *context;
52 if (getpeercon(client->getSocket(), &context)) {
53 return false;
54 }
55
56 // We can't use context_new and context_type_get as they're private to libselinux. So just do
57 // a string match instead.
58 bool ret = !strcmp(context, SYSTEM_SERVER_CONTEXT);
59 freecon(context);
60
61 return ret;
62}
Chenbo Feng9944ba82017-10-10 17:33:20 -070063
Chenbo Feng9944ba82017-10-10 17:33:20 -070064FwmarkServer::FwmarkServer(NetworkController* networkController, EventReporter* eventReporter,
65 TrafficController* trafficCtrl)
66 : SocketListener(SOCKET_NAME, true),
67 mNetworkController(networkController),
68 mEventReporter(eventReporter),
69 mTrafficCtrl(trafficCtrl) {}
70
Sreeram Ramachandran030b36e2014-05-11 21:04:03 -070071bool FwmarkServer::onDataAvailable(SocketClient* client) {
Sreeram Ramachandrane09b20a2014-07-05 17:15:14 -070072 int socketFd = -1;
73 int error = processClient(client, &socketFd);
74 if (socketFd >= 0) {
75 close(socketFd);
Sreeram Ramachandran030b36e2014-05-11 21:04:03 -070076 }
77
78 // Always send a response even if there were connection errors or read errors, so that we don't
79 // inadvertently cause the client to hang (which always waits for a response).
80 client->sendData(&error, sizeof(error));
81
82 // Always close the client connection (by returning false). This prevents a DoS attack where
83 // the client issues multiple commands on the same connection, never reading the responses,
84 // causing its receive buffer to fill up, and thus causing our client->sendData() to block.
85 return false;
86}
87
Praveen Moongalam Thyagarajanf24eb882019-12-18 11:59:47 -080088static bool hasDestinationAddress(FwmarkCommand::CmdId cmdId) {
89 if (cmdId == FwmarkCommand::ON_SENDTO || cmdId == FwmarkCommand::ON_CONNECT ||
90 cmdId == FwmarkCommand::ON_SENDMSG || cmdId == FwmarkCommand::ON_SENDMMSG ||
91 cmdId == FwmarkCommand::ON_CONNECT_COMPLETE) {
92 return true;
93 }
94 return false;
95}
96
Sreeram Ramachandrane09b20a2014-07-05 17:15:14 -070097int FwmarkServer::processClient(SocketClient* client, int* socketFd) {
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -070098 FwmarkCommand command;
Michal Karpinski7d374532016-10-06 19:33:55 +010099 FwmarkConnectInfo connectInfo;
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700100
Josh Gaoba76bd62020-01-06 17:22:41 -0800101 char buf[sizeof(command) + sizeof(connectInfo)];
102 std::vector<unique_fd> received_fds;
103 ssize_t messageLength =
104 ReceiveFileDescriptorVector(client->getSocket(), buf, sizeof(buf), 1, &received_fds);
Sreeram Ramachandran030b36e2014-05-11 21:04:03 -0700105
Josh Gaoba76bd62020-01-06 17:22:41 -0800106 if (messageLength < 0) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700107 return -errno;
Josh Gaoba76bd62020-01-06 17:22:41 -0800108 } else if (messageLength == 0) {
109 return -ESHUTDOWN;
Sreeram Ramachandran030b36e2014-05-11 21:04:03 -0700110 }
111
Josh Gaoba76bd62020-01-06 17:22:41 -0800112 memcpy(&command, buf, sizeof(command));
113 memcpy(&connectInfo, buf + sizeof(command), sizeof(connectInfo));
114
Praveen Moongalam Thyagarajanf24eb882019-12-18 11:59:47 -0800115 size_t expected_len = sizeof(command);
116 if (hasDestinationAddress(command.cmdId)) {
117 expected_len += sizeof(connectInfo);
118 }
119
120 if (messageLength != static_cast<ssize_t>(expected_len)) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700121 return -EBADMSG;
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700122 }
123
Paul Jensend1df5972015-05-06 07:29:56 -0400124 Permission permission = mNetworkController->getPermissionForUser(client->getUid());
125
126 if (command.cmdId == FwmarkCommand::QUERY_USER_ACCESS) {
127 if ((permission & PERMISSION_SYSTEM) != PERMISSION_SYSTEM) {
128 return -EPERM;
129 }
130 return mNetworkController->checkUserNetworkAccess(command.uid, command.netId);
131 }
132
Chenbo Feng9944ba82017-10-10 17:33:20 -0700133 if (command.cmdId == FwmarkCommand::SET_COUNTERSET) {
Chenbo Fengb4a4fa12019-01-09 17:20:45 -0800134 return mTrafficCtrl->setCounterSet(command.trafficCtrlInfo, command.uid, client->getUid());
Chenbo Feng9944ba82017-10-10 17:33:20 -0700135 }
136
137 if (command.cmdId == FwmarkCommand::DELETE_TAGDATA) {
Chenbo Fengb4a4fa12019-01-09 17:20:45 -0800138 return mTrafficCtrl->deleteTagData(command.trafficCtrlInfo, command.uid, client->getUid());
Chenbo Feng9944ba82017-10-10 17:33:20 -0700139 }
140
Josh Gaoba76bd62020-01-06 17:22:41 -0800141 if (received_fds.size() != 1) {
142 LOG(ERROR) << "FwmarkServer received " << received_fds.size() << " fds from client?";
143 return -EBADF;
144 } else if (received_fds[0] < 0) {
145 LOG(ERROR) << "FwmarkServer received fd -1 from ReceiveFileDescriptorVector?";
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700146 return -EBADF;
Sreeram Ramachandran030b36e2014-05-11 21:04:03 -0700147 }
148
Josh Gaoba76bd62020-01-06 17:22:41 -0800149 *socketFd = received_fds[0].release();
150
Remi NGUYEN VANeabc5da2018-04-24 18:54:58 +0900151 int family;
152 socklen_t familyLen = sizeof(family);
153 if (getsockopt(*socketFd, SOL_SOCKET, SO_DOMAIN, &family, &familyLen) == -1) {
154 return -errno;
155 }
156 if (!FwmarkCommand::isSupportedFamily(family)) {
157 return -EAFNOSUPPORT;
158 }
159
Sreeram Ramachandran030b36e2014-05-11 21:04:03 -0700160 Fwmark fwmark;
Sreeram Ramachandran5ff58d42014-05-14 09:57:31 -0700161 socklen_t fwmarkLen = sizeof(fwmark.intValue);
Sreeram Ramachandrane09b20a2014-07-05 17:15:14 -0700162 if (getsockopt(*socketFd, SOL_SOCKET, SO_MARK, &fwmark.intValue, &fwmarkLen) == -1) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700163 return -errno;
Sreeram Ramachandran030b36e2014-05-11 21:04:03 -0700164 }
165
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700166 switch (command.cmdId) {
167 case FwmarkCommand::ON_ACCEPT: {
Sreeram Ramachandran070b2d22014-07-11 17:06:12 -0700168 // Called after a socket accept(). The kernel would've marked the NetId and necessary
Sreeram Ramachandrana675b002014-07-05 11:00:55 -0700169 // permissions bits, so we just add the rest of the user's permissions here.
170 permission = static_cast<Permission>(permission | fwmark.permission);
Sreeram Ramachandran030b36e2014-05-11 21:04:03 -0700171 break;
172 }
173
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700174 case FwmarkCommand::ON_CONNECT: {
Sreeram Ramachandran1011b492014-07-24 19:04:32 -0700175 // Called before a socket connect() happens. Set an appropriate NetId into the fwmark so
176 // that the socket routes consistently over that network. Do this even if the socket
177 // already has a NetId, so that calling connect() multiple times still works.
Sreeram Ramachandran070b2d22014-07-11 17:06:12 -0700178 //
Sreeram Ramachandran1011b492014-07-24 19:04:32 -0700179 // But if the explicit bit was set, the existing NetId was explicitly preferred (and not
180 // a case of connect() being called multiple times). Don't reset the NetId in that case.
181 //
182 // An "appropriate" NetId is the NetId of a bypassable VPN that applies to the user, or
183 // failing that, the default network. We'll never set the NetId of a secure VPN here.
184 // See the comments in the implementation of getNetworkForConnect() for more details.
185 //
186 // If the protect bit is set, this could be either a system proxy (e.g.: the dns proxy
187 // or the download manager) acting on behalf of another user, or a VPN provider. If it's
188 // a proxy, we shouldn't reset the NetId. If it's a VPN provider, we should set the
189 // default network's NetId.
190 //
191 // There's no easy way to tell the difference between a proxy and a VPN app. We can't
192 // use PERMISSION_SYSTEM to identify the proxy because a VPN app may also have those
193 // permissions. So we use the following heuristic:
194 //
195 // If it's a proxy, but the existing NetId is not a VPN, that means the user (that the
196 // proxy is acting on behalf of) is not subject to a VPN, so the proxy must have picked
197 // the default network's NetId. So, it's okay to replace that with the current default
198 // network's NetId (which in all likelihood is the same).
199 //
200 // Conversely, if it's a VPN provider, the existing NetId cannot be a VPN. The only time
201 // we set a VPN's NetId into a socket without setting the explicit bit is here, in
202 // ON_CONNECT, but we won't do that if the socket has the protect bit set. If the VPN
203 // provider connect()ed (and got the VPN NetId set) and then called protect(), we
204 // would've unset the NetId in PROTECT_FROM_VPN below.
205 //
206 // So, overall (when the explicit bit is not set but the protect bit is set), if the
207 // existing NetId is a VPN, don't reset it. Else, set the default network's NetId.
208 if (!fwmark.explicitlySelected) {
209 if (!fwmark.protectedFromVpn) {
210 fwmark.netId = mNetworkController->getNetworkForConnect(client->getUid());
211 } else if (!mNetworkController->isVirtualNetwork(fwmark.netId)) {
212 fwmark.netId = mNetworkController->getDefaultNetwork();
213 }
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700214 }
215 break;
216 }
217
Michal Karpinski7d374532016-10-06 19:33:55 +0100218 case FwmarkCommand::ON_CONNECT_COMPLETE: {
219 // Called after a socket connect() completes.
220 // This reports connect event including netId, destination IP address, destination port,
Hugo Benichi7dfaa782016-10-31 15:07:23 +0900221 // uid, connect latency, and connect errno if any.
Hugo Benichi456c9062017-01-04 12:19:16 +0900222
223 // Skip reporting if connect() happened on a UDP socket.
224 int socketProto;
225 socklen_t intSize = sizeof(socketProto);
226 const int ret = getsockopt(*socketFd, SOL_SOCKET, SO_PROTOCOL, &socketProto, &intSize);
227 if ((ret != 0) || (socketProto == IPPROTO_UDP)) {
228 break;
229 }
230
Michal Karpinski7d374532016-10-06 19:33:55 +0100231 android::sp<android::net::metrics::INetdEventListener> netdEventListener =
232 mEventReporter->getNetdEventListener();
233
234 if (netdEventListener != nullptr) {
235 char addrstr[INET6_ADDRSTRLEN];
236 char portstr[sizeof("65536")];
237 const int ret = getnameinfo((sockaddr*) &connectInfo.addr, sizeof(connectInfo.addr),
238 addrstr, sizeof(addrstr), portstr, sizeof(portstr),
239 NI_NUMERICHOST | NI_NUMERICSERV);
240
Hugo Benichi7dfaa782016-10-31 15:07:23 +0900241 netdEventListener->onConnectEvent(fwmark.netId, connectInfo.error,
242 connectInfo.latencyMs,
Michal Karpinski7d374532016-10-06 19:33:55 +0100243 (ret == 0) ? String16(addrstr) : String16(""),
Yi Kongbdfd57e2018-07-25 13:26:10 -0700244 (ret == 0) ? strtoul(portstr, nullptr, 10) : 0, client->getUid());
Michal Karpinski7d374532016-10-06 19:33:55 +0100245 }
246 break;
247 }
248
Praveen Moongalam Thyagarajanf24eb882019-12-18 11:59:47 -0800249 case FwmarkCommand::ON_SENDMMSG: {
250 return 0;
251 }
252
253 case FwmarkCommand::ON_SENDMSG: {
254 return 0;
255 }
256
257 case FwmarkCommand::ON_SENDTO: {
258 return 0;
259 }
260
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700261 case FwmarkCommand::SELECT_NETWORK: {
Sreeram Ramachandranec008842014-05-21 14:01:16 -0700262 fwmark.netId = command.netId;
263 if (command.netId == NETID_UNSET) {
264 fwmark.explicitlySelected = false;
Sreeram Ramachandrane09b20a2014-07-05 17:15:14 -0700265 fwmark.protectedFromVpn = false;
266 permission = PERMISSION_NONE;
Lorenzo Colittia1067c82014-10-02 22:47:41 +0900267 } else {
268 if (int ret = mNetworkController->checkUserNetworkAccess(client->getUid(),
269 command.netId)) {
270 return ret;
271 }
Sreeram Ramachandranec008842014-05-21 14:01:16 -0700272 fwmark.explicitlySelected = true;
Sreeram Ramachandrane09b20a2014-07-05 17:15:14 -0700273 fwmark.protectedFromVpn = mNetworkController->canProtect(client->getUid());
Sreeram Ramachandranec008842014-05-21 14:01:16 -0700274 }
Sreeram Ramachandran030b36e2014-05-11 21:04:03 -0700275 break;
276 }
277
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700278 case FwmarkCommand::PROTECT_FROM_VPN: {
Sreeram Ramachandrane09b20a2014-07-05 17:15:14 -0700279 if (!mNetworkController->canProtect(client->getUid())) {
280 return -EPERM;
281 }
Sreeram Ramachandran1011b492014-07-24 19:04:32 -0700282 // If a bypassable VPN's provider app calls connect() and then protect(), it will end up
283 // with a socket that looks like that of a system proxy but is not (see comments for
284 // ON_CONNECT above). So, reset the NetId.
285 //
286 // In any case, it's appropriate that if the socket has an implicit VPN NetId mark, the
287 // PROTECT_FROM_VPN command should unset it.
288 if (!fwmark.explicitlySelected && mNetworkController->isVirtualNetwork(fwmark.netId)) {
289 fwmark.netId = mNetworkController->getDefaultNetwork();
290 }
Sreeram Ramachandrane09b20a2014-07-05 17:15:14 -0700291 fwmark.protectedFromVpn = true;
292 permission = static_cast<Permission>(permission | fwmark.permission);
Sreeram Ramachandran030b36e2014-05-11 21:04:03 -0700293 break;
294 }
295
Sreeram Ramachandrana69d9472014-07-11 16:27:02 -0700296 case FwmarkCommand::SELECT_FOR_USER: {
297 if ((permission & PERMISSION_SYSTEM) != PERMISSION_SYSTEM) {
298 return -EPERM;
299 }
Sreeram Ramachandran1011b492014-07-24 19:04:32 -0700300 fwmark.netId = mNetworkController->getNetworkForUser(command.uid);
Sreeram Ramachandrana69d9472014-07-11 16:27:02 -0700301 fwmark.protectedFromVpn = true;
302 break;
303 }
304
Chenbo Feng9944ba82017-10-10 17:33:20 -0700305 case FwmarkCommand::TAG_SOCKET: {
306 // If the UID is -1, tag as the caller's UID:
307 // - TrafficStats and NetworkManagementSocketTagger use -1 to indicate "use the
308 // caller's UID".
309 // - xt_qtaguid will see -1 on the command line, fail to parse it as a uint32_t, and
310 // fall back to current_fsuid().
311 if (static_cast<int>(command.uid) == -1) {
312 command.uid = client->getUid();
313 }
Chenbo Fengb4a4fa12019-01-09 17:20:45 -0800314 return mTrafficCtrl->tagSocket(*socketFd, command.trafficCtrlInfo, command.uid,
315 client->getUid());
Chenbo Feng9944ba82017-10-10 17:33:20 -0700316 }
317
318 case FwmarkCommand::UNTAG_SOCKET: {
319 // Any process can untag a socket it has an fd for.
320 return mTrafficCtrl->untagSocket(*socketFd);
321 }
322
Sreeram Ramachandran030b36e2014-05-11 21:04:03 -0700323 default: {
324 // unknown command
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700325 return -EPROTO;
Sreeram Ramachandran030b36e2014-05-11 21:04:03 -0700326 }
327 }
328
Sreeram Ramachandrana675b002014-07-05 11:00:55 -0700329 fwmark.permission = permission;
330
Sreeram Ramachandrane09b20a2014-07-05 17:15:14 -0700331 if (setsockopt(*socketFd, SOL_SOCKET, SO_MARK, &fwmark.intValue,
332 sizeof(fwmark.intValue)) == -1) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700333 return -errno;
Sreeram Ramachandran030b36e2014-05-11 21:04:03 -0700334 }
335
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700336 return 0;
Sreeram Ramachandran030b36e2014-05-11 21:04:03 -0700337}
Lorenzo Colitti7035f222017-02-13 18:29:00 +0900338
339} // namespace net
340} // namespace android