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-15 15:58:22 +0900
commit050085a56162dff203979e8c62cb57449f5f7a26 (patch)
tree9eb99a0afa3c549b62c5265998f0caa827e84747
parentab9c653aaf67575ba22c5e6d3eebe3f2fa8191d6 (diff)
downloadnetd-050085a56162dff203979e8c62cb57449f5f7a26.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 Merged-In: 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 f2894cb3..d7ab7960 100644
--- a/server/RouteController.cpp
+++ b/server/RouteController.cpp
@@ -550,8 +550,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;
@@ -561,8 +560,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);
@@ -724,7 +723,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) {