summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLorenzo Colitti <lorenzo@google.com>2017-09-06 16:07:02 +0900
committerLorenzo Colitti <lorenzo@google.com>2017-09-06 18:35:49 +0900
commit6bd4a48ed735c7fc5c1143bf0b2f06b8a2879e61 (patch)
tree98c5e95466683d783b0214346c5a830980c47bab
parent7b0ab7a59ad1f28b8985cb673beb551b42c07059 (diff)
downloadnetd-6bd4a48ed735c7fc5c1143bf0b2f06b8a2879e61.tar.gz
Don't allow seamless handover to networks requiring permissions.
Currently, implicitly-marked sockets continue to work when the network changes permission. This makes it so that UDP sockets connected on a foreground network will continue to work even if the network moves into the background (e.g., when the linger timer fires on cell data with mobile data always on). Instead, make it so that sockets implicitly marked to a network become unroutable when the network starts requiring permissions. Explicitly-marked sockets will continue to be routed on the network, as usual. This is consistent with what we do for TCP: when a network changes permissions, all implicitly-marked sockets on that network are closed using SOCK_DESTROY. This change should not affect any other behaviour because: - Netd only ever implicitly marks sockets to the default network or to a bypassable VPN that applies to the caller. - In both cases, at the time of marking, the network does not require permissions because: - VPNs don't support permissions. - The default network never requires any permissions: - ConnectivityService's mDefaultRequest specifies NOT_RESTRICTED. - The only case where a NOT_RESTRICTED network can require a permission is if it's a background network, and the default network is, by definition, never a background network. - VPNs can't change permissions. - If the network is still the default network, the lack of this implicit rule doesn't matter. Therefore, the only case where this rule can alter routing is if a socket is implicitly marked on the default network and that network, after ceasing to be the default, changes permissions. Bug: 64103722 Test: builds Test: manually observed IP rules while changing network permissions Change-Id: I255a9d216c50aa47bb951be9bd6cce59a12c6165
-rw-r--r--server/RouteController.cpp33
1 files changed, 28 insertions, 5 deletions
diff --git a/server/RouteController.cpp b/server/RouteController.cpp
index aeed3e9e..87a56982 100644
--- a/server/RouteController.cpp
+++ b/server/RouteController.cpp
@@ -553,8 +553,7 @@ WARN_UNUSED_RESULT int modifyOutputInterfaceRules(const char* interface, uint32_
// This is for sockets that have not explicitly requested a particular network, but have been
// bound to one when they called connect(). This ensures that sockets connected on a particular
// network stay on that network even if the default network changes.
-WARN_UNUSED_RESULT int modifyImplicitNetworkRule(unsigned netId, uint32_t table,
- Permission permission, bool add) {
+WARN_UNUSED_RESULT int modifyImplicitNetworkRule(unsigned netId, uint32_t table, bool add) {
Fwmark fwmark;
Fwmark mask;
@@ -564,8 +563,8 @@ WARN_UNUSED_RESULT int modifyImplicitNetworkRule(unsigned netId, uint32_t table,
fwmark.explicitlySelected = false;
mask.explicitlySelected = true;
- fwmark.permission = permission;
- mask.permission = permission;
+ fwmark.permission = PERMISSION_NONE;
+ mask.permission = PERMISSION_NONE;
return modifyIpRule(add ? RTM_NEWRULE : RTM_DELRULE, RULE_PRIORITY_IMPLICIT_NETWORK, table,
fwmark.intValue, mask.intValue);
@@ -727,7 +726,31 @@ WARN_UNUSED_RESULT int modifyPhysicalNetwork(unsigned netId, const char* interfa
add)) {
return ret;
}
- return modifyImplicitNetworkRule(netId, table, permission, add);
+
+ // Only set implicit rules for networks that don't require permissions.
+ //
+ // This is so that if the default network ceases to be the default network and then switches
+ // from requiring no permissions to requiring permissions, we ensure that apps only use the
+ // network if they explicitly select it. This is consistent with destroySocketsLackingPermission
+ // - it closes all sockets on the network except sockets that are explicitly selected.
+ //
+ // The lack of this rule only affects the special case above, because:
+ // - The only cases where we implicitly bind a socket to a network are the default network and
+ // the bypassable VPN that applies to the app, if any.
+ // - This rule doesn't affect VPNs because they don't support permissions at all.
+ // - The default network doesn't require permissions. While we support doing this, the framework
+ // never does it (partly because we'd end up in the situation where we tell apps that there is
+ // a default network, but they can't use it).
+ // - If the network is still the default network, the presence or absence of this rule does not
+ // matter.
+ //
+ // Therefore, for the lack of this rule to affect a socket, the socket has to have been
+ // implicitly bound to a network because at the time of connect() it was the default, and that
+ // network must no longer be the default, and must now require permissions.
+ if (permission == PERMISSION_NONE) {
+ return modifyImplicitNetworkRule(netId, table, add);
+ }
+ return 0;
}
WARN_UNUSED_RESULT int modifyRejectNonSecureNetworkRule(const UidRanges& uidRanges, bool add) {