diff options
author | chiachangwang <chiachangwang@google.com> | 2022-05-17 05:16:16 +0000 |
---|---|---|
committer | Cherrypicker Worker <android-build-cherrypicker-worker@google.com> | 2022-06-02 12:45:54 +0000 |
commit | 776b68cecb611abb16cce0bf7a02bb939d271e3a (patch) | |
tree | e073fef85d9e4fbf95235cbacd949ace1006bc49 | |
parent | 8a03faaefe4858b848102ccb596b906e0194ef96 (diff) | |
download | netd-776b68cecb611abb16cce0bf7a02bb939d271e3a.tar.gz |
Add app default local rule
Add an app default local rule prior to the VPN local route rule
to route the per app default local traffic.
If the routes setting for system default and app default are
overlapped with each other, the traffic may be routed
unexpectedly becuase the VPN local rules do not contain the
uid range information. The rule will match first before app
default rule. Thus, add an default local rule piror to the
VPN local route rule to address the issue.
Sample rule after applying the change:
- App UID(99999)
- Default(iface0), app default(iface1), vpn(tun0)
25000: ... 0x0/0x10000 iif lo uidrange 99998-99999 lookup iface1_local
26000: ... 0x0/0x10000 iif lo lookup iface0_local
27000: ... 0x0/0x30000 iif lo uidrange 99997-99998 lookup tun0
28000: ... 0xffdf/0xffff lookup iface0
29000: ... 0x0/0xffff iif lo uidrange 99998-99999 lookup iface1
30000: ... 0x0/0xffff iif lo lookup iface0
Bug: 184750836
Test: cd system/netd ; atest
Change-Id: Ic092398a0d89b0104afcee8e1f22dfa93fa408ae
(cherry picked from commit 0d5ae9805b1dcad074dd171dca62d5e3893d6a72)
Merged-In: Ic092398a0d89b0104afcee8e1f22dfa93fa408ae
-rw-r--r-- | server/RouteController.cpp | 33 | ||||
-rw-r--r-- | server/RouteController.h | 22 | ||||
-rw-r--r-- | tests/binder_test.cpp | 8 |
3 files changed, 54 insertions, 9 deletions
diff --git a/server/RouteController.cpp b/server/RouteController.cpp index d63dbd2e..ea8baea8 100644 --- a/server/RouteController.cpp +++ b/server/RouteController.cpp @@ -859,6 +859,13 @@ int RouteController::modifyPhysicalNetwork(unsigned netId, const char* interface subPriority, add)) { return ret; } + + // Per-UID local network rules must always match per-app default network rules, + // because their purpose is to allow the UIDs to use the default network for + // local destinations within it. + if (int ret = modifyUidLocalNetworkRule(interface, range.start, range.stop, add)) { + return ret; + } } } } @@ -906,6 +913,32 @@ int RouteController::modifyPhysicalNetwork(unsigned netId, const char* interface return 0; } +int RouteController::modifyUidLocalNetworkRule(const char* interface, uid_t uidStart, uid_t uidEnd, + bool add) { + uint32_t table = getRouteTableForInterface(interface, true /* local */); + if (table == RT_TABLE_UNSPEC) { + return -ESRCH; + } + + if ((uidStart == INVALID_UID) || (uidEnd == INVALID_UID)) { + ALOGE("modifyUidLocalNetworkRule, invalid UIDs (%u, %u)", uidStart, uidEnd); + return -EUSERS; + } + + Fwmark fwmark; + Fwmark mask; + + fwmark.explicitlySelected = false; + mask.explicitlySelected = true; + + // Access to this network is controlled by UID rules, not permission bits. + fwmark.permission = PERMISSION_NONE; + mask.permission = PERMISSION_NONE; + + return modifyIpRule(add ? RTM_NEWRULE : RTM_DELRULE, RULE_PRIORITY_UID_LOCAL_ROUTES, table, + fwmark.intValue, mask.intValue, IIF_LOOPBACK, OIF_NONE, uidStart, uidEnd); +} + [[nodiscard]] static int modifyUidUnreachableRule(unsigned netId, uid_t uidStart, uid_t uidEnd, int32_t subPriority, bool add, bool explicitSelect) { diff --git a/server/RouteController.h b/server/RouteController.h index 9b04cfd2..887187c8 100644 --- a/server/RouteController.h +++ b/server/RouteController.h @@ -55,11 +55,17 @@ constexpr int32_t RULE_PRIORITY_TETHERING = 21000; constexpr int32_t RULE_PRIORITY_UID_IMPLICIT_NETWORK = 22000; constexpr int32_t RULE_PRIORITY_IMPLICIT_NETWORK = 23000; constexpr int32_t RULE_PRIORITY_BYPASSABLE_VPN_NO_LOCAL_EXCLUSION = 24000; -// Rules used for excluding local route in the VPN network. -constexpr int32_t RULE_PRIORITY_LOCAL_ROUTES = 25000; -constexpr int32_t RULE_PRIORITY_BYPASSABLE_VPN_LOCAL_EXCLUSION = 26000; -constexpr int32_t RULE_PRIORITY_VPN_FALLTHROUGH = 27000; -constexpr int32_t RULE_PRIORITY_UID_DEFAULT_NETWORK = 28000; +// Sets of rules used for excluding local routes from the VPN. Look up tables +// that contain directly-connected local routes taken from the default network. +// The first set is used for apps that have a per-UID default network. The rule +// UID ranges match those of the per-UID default network rule for that network. +// The second set has no UID ranges and is used for apps whose default network +// is the system default network network. +constexpr int32_t RULE_PRIORITY_UID_LOCAL_ROUTES = 25000; +constexpr int32_t RULE_PRIORITY_LOCAL_ROUTES = 26000; +constexpr int32_t RULE_PRIORITY_BYPASSABLE_VPN_LOCAL_EXCLUSION = 27000; +constexpr int32_t RULE_PRIORITY_VPN_FALLTHROUGH = 28000; +constexpr int32_t RULE_PRIORITY_UID_DEFAULT_NETWORK = 29000; // Rule used when framework wants to disable default network from specified applications. There will // be a small interval the same uid range exists in both UID_DEFAULT_UNREACHABLE and // UID_DEFAULT_NETWORK when framework is switching user preferences. @@ -74,8 +80,8 @@ constexpr int32_t RULE_PRIORITY_UID_DEFAULT_NETWORK = 28000; // The priority is lower than UID_DEFAULT_NETWORK. Otherwise, the app will be told by // ConnectivityService that it has a network in step 1 of the second case. But if it tries to use // the network, it will not work. That will potentially cause a user-visible error. -constexpr int32_t RULE_PRIORITY_UID_DEFAULT_UNREACHABLE = 29000; -constexpr int32_t RULE_PRIORITY_DEFAULT_NETWORK = 30000; +constexpr int32_t RULE_PRIORITY_UID_DEFAULT_UNREACHABLE = 30000; +constexpr int32_t RULE_PRIORITY_DEFAULT_NETWORK = 31000; constexpr int32_t RULE_PRIORITY_UNREACHABLE = 32000; // clang-format on @@ -221,6 +227,8 @@ public: bool modifyNonUidBasedRules, bool excludeLocalRoutes); static void updateTableNamesFile() EXCLUDES(sInterfaceToTableLock); static int modifyVpnLocalExclusionRule(bool add, const char* physicalInterface); + static int modifyUidLocalNetworkRule(const char* interface, uid_t uidStart, uid_t uidEnd, + bool add); }; // Public because they are called by by RouteControllerTest.cpp. diff --git a/tests/binder_test.cpp b/tests/binder_test.cpp index c01d78e9..5f5dff11 100644 --- a/tests/binder_test.cpp +++ b/tests/binder_test.cpp @@ -129,6 +129,7 @@ using android::net::RULE_PRIORITY_UID_DEFAULT_NETWORK; using android::net::RULE_PRIORITY_UID_DEFAULT_UNREACHABLE; using android::net::RULE_PRIORITY_UID_EXPLICIT_NETWORK; using android::net::RULE_PRIORITY_UID_IMPLICIT_NETWORK; +using android::net::RULE_PRIORITY_UID_LOCAL_ROUTES; using android::net::RULE_PRIORITY_VPN_FALLTHROUGH; using android::net::SockDiag; using android::net::TetherOffloadRuleParcel; @@ -3287,8 +3288,8 @@ void NetdBinderTest::createVpnNetworkWithUid(bool secure, uid_t uid, int vpnNetI INetd::PERMISSION_NONE, false, false); EXPECT_TRUE(mNetd->networkCreate(config).isOk()); EXPECT_TRUE(mNetd->networkAddInterface(fallthroughNetId, sTun.name()).isOk()); - // Create a physical network to test that local network access does not include the non-default - // networks. + // Create another physical network in order to test VPN behaviour with multiple networks + // connected, of which one may be the default. auto nonDefaultNetworkConfig = makeNativeNetworkConfig( nonDefaultNetId, NativeNetworkType::PHYSICAL, INetd::PERMISSION_NONE, false, false); EXPECT_TRUE(mNetd->networkCreate(nonDefaultNetworkConfig).isOk()); @@ -4025,6 +4026,7 @@ void verifyAppUidRules(std::vector<bool>&& expectedResults, std::vector<UidRange ASSERT_EQ(expectedResults.size(), uidRanges.size()); if (iface.size()) { std::string action = StringPrintf("lookup %s ", iface.c_str()); + std::string action_local = StringPrintf("lookup %s_local ", iface.c_str()); for (unsigned long i = 0; i < uidRanges.size(); i++) { EXPECT_EQ(expectedResults[i], ipRuleExistsForRange(RULE_PRIORITY_UID_EXPLICIT_NETWORK + subPriority, @@ -4035,6 +4037,8 @@ void verifyAppUidRules(std::vector<bool>&& expectedResults, std::vector<UidRange EXPECT_EQ(expectedResults[i], ipRuleExistsForRange(RULE_PRIORITY_UID_DEFAULT_NETWORK + subPriority, uidRanges[i], action)); + EXPECT_EQ(expectedResults[i], ipRuleExistsForRange(RULE_PRIORITY_UID_LOCAL_ROUTES, + uidRanges[i], action_local)); } } else { std::string action = "unreachable"; |