diff options
author | Ken Chen <cken@google.com> | 2022-12-25 12:01:59 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2022-12-25 12:01:59 +0000 |
commit | ad4f2f4faf45bdc5ca25466f2131e68ce1b85045 (patch) | |
tree | c373526f1965f7786a99b533af8aafab48024e2d | |
parent | 5b02e1224b5e697bcdef98889eeff6a3da954904 (diff) | |
parent | 0c209f8c6bab3513a1ec23077acefead8e0b4eea (diff) | |
download | netd-ad4f2f4faf45bdc5ca25466f2131e68ce1b85045.tar.gz |
Merge "Support per-uid explicit selected network permission control"
-rw-r--r-- | server/NetdNativeService.cpp | 6 | ||||
-rw-r--r-- | server/NetdNativeService.h | 2 | ||||
-rw-r--r-- | server/Network.cpp | 19 | ||||
-rw-r--r-- | server/Network.h | 11 | ||||
-rw-r--r-- | server/NetworkController.cpp | 37 | ||||
-rw-r--r-- | server/NetworkController.h | 3 | ||||
-rw-r--r-- | tests/binder_test.cpp | 128 |
7 files changed, 202 insertions, 4 deletions
diff --git a/server/NetdNativeService.cpp b/server/NetdNativeService.cpp index 2c0d7bce..dcfc6c2e 100644 --- a/server/NetdNativeService.cpp +++ b/server/NetdNativeService.cpp @@ -1247,5 +1247,11 @@ binder::Status NetdNativeService::tetherOffloadGetAndClearStats( return binder::Status::fromExceptionCode(binder::Status::EX_UNSUPPORTED_OPERATION); } +binder::Status NetdNativeService::setNetworkAllowlist( + const std::vector<NativeUidRangeConfig>& settings) { + ENFORCE_NETWORK_STACK_PERMISSIONS(); + return statusFromErrcode(gCtls->netCtrl.setNetworkAllowlist(settings)); +} + } // namespace net } // namespace android diff --git a/server/NetdNativeService.h b/server/NetdNativeService.h index b2571221..532acc3c 100644 --- a/server/NetdNativeService.h +++ b/server/NetdNativeService.h @@ -266,6 +266,8 @@ class NetdNativeService : public BinderService<NetdNativeService>, public BnNetd binder::Status getOemNetd(android::sp<android::IBinder>* listener) override; binder::Status getFwmarkForNetwork(int32_t netId, MarkMaskParcel* markmask); + binder::Status setNetworkAllowlist( + const std::vector<netd::aidl::NativeUidRangeConfig>& settings) override; private: std::vector<uid_t> intsToUids(const std::vector<int32_t>& intUids); diff --git a/server/Network.cpp b/server/Network.cpp index 156cfb3e..a3956419 100644 --- a/server/Network.cpp +++ b/server/Network.cpp @@ -83,6 +83,13 @@ std::string Network::uidRangesToString() const { return result.str(); } +std::string Network::allowedUidsToString() const { + if (!mUidsAbleToSelectThisNetwork) { + return "unrestricted"; + } + return mUidsAbleToSelectThisNetwork->toString(); +} + // Check if the user has been added to this network. If yes, the highest priority of matching // setting is returned by subPriority. Thus caller can make choice among several matching // networks. @@ -117,6 +124,18 @@ void Network::removeFromUidRangeMap(const UidRanges& uidRanges, int32_t subPrior } } +void Network::clearAllowedUids() { + mUidsAbleToSelectThisNetwork.reset(); +} + +void Network::setAllowedUids(const UidRanges& uidRanges) { + mUidsAbleToSelectThisNetwork = uidRanges; +} + +bool Network::isUidAllowed(uid_t uid) { + return !mUidsAbleToSelectThisNetwork || mUidsAbleToSelectThisNetwork->hasUid(uid); +} + bool Network::canAddUidRanges(const UidRanges& uidRanges) const { if (uidRanges.overlapsSelf()) { ALOGE("uid range %s overlaps self", uidRanges.toString().c_str()); diff --git a/server/Network.h b/server/Network.h index 6c3d01d3..bafa1948 100644 --- a/server/Network.h +++ b/server/Network.h @@ -48,6 +48,7 @@ public: std::string toString() const; std::string uidRangesToString() const; + std::string allowedUidsToString() const; bool appliesToUser(uid_t uid, int32_t* subPriority) const; virtual Permission getPermission() const = 0; [[nodiscard]] virtual int addUsers(const UidRanges&, int32_t /*subPriority*/) { @@ -64,8 +65,11 @@ public: virtual bool isValidSubPriority(int32_t /*priority*/) { return false; } virtual void addToUidRangeMap(const UidRanges& uidRanges, int32_t subPriority); virtual void removeFromUidRangeMap(const UidRanges& uidRanges, int32_t subPriority); + void clearAllowedUids(); + void setAllowedUids(const UidRanges& uidRanges); + bool isUidAllowed(uid_t uid); -protected: + protected: explicit Network(unsigned netId, bool secure = false); bool canAddUidRanges(const UidRanges& uidRanges) const; @@ -74,8 +78,11 @@ protected: // Each subsidiary priority maps to a set of UID ranges of a feature. std::map<int32_t, UidRanges> mUidRangeMap; const bool mSecure; + // UIDs that can explicitly select this network. It means no restriction for all UIDs if the + // optional variable has no value. + std::optional<UidRanges> mUidsAbleToSelectThisNetwork; -private: + private: enum Action { REMOVE, ADD, diff --git a/server/NetworkController.cpp b/server/NetworkController.cpp index f1aaeca8..0d716adf 100644 --- a/server/NetworkController.cpp +++ b/server/NetworkController.cpp @@ -749,7 +749,12 @@ void NetworkController::dump(DumpWriter& dw) { } if (const auto& str = network->uidRangesToString(); !str.empty()) { dw.incIndent(); - dw.println(str); + dw.println("Per-app UID ranges: %s", str.c_str()); + dw.decIndent(); + } + if (const auto& str = network->allowedUidsToString(); !str.empty()) { + dw.incIndent(); + dw.println("Allowed UID ranges: %s", str.c_str()); dw.decIndent(); } dw.blankline(); @@ -794,6 +799,32 @@ void NetworkController::dump(DumpWriter& dw) { dw.decIndent(); } +void NetworkController::clearAllowedUidsForAllNetworksLocked() { + for (const auto& [_, network] : mNetworks) { + if (!network->isPhysical()) continue; + + network->clearAllowedUids(); + } +} + +int NetworkController::setNetworkAllowlist( + const std::vector<netd::aidl::NativeUidRangeConfig>& settings) { + const ScopedWLock lock(mRWLock); + + clearAllowedUidsForAllNetworksLocked(); + for (const auto& setting : settings) { + Network* network = getNetworkLocked(setting.netId); + if (!network) return -ENONET; + if (!network->isPhysical()) return -EINVAL; + } + + for (const auto& setting : settings) { + Network* network = getNetworkLocked(setting.netId); + network->setAllowedUids(UidRanges(setting.uidRanges)); + } + return 0; +} + bool NetworkController::isValidNetworkLocked(unsigned netId) const { return getNetworkLocked(netId); } @@ -886,6 +917,10 @@ int NetworkController::checkUserNetworkAccessLocked(uid_t uid, unsigned netId) c if (network->isUnreachable()) { return network->appliesToUser(uid, &subPriority) ? 0 : -EPERM; } + + if (!network->isUidAllowed(uid)) { + return -EACCES; + } // Check whether the UID's permission bits are sufficient to use the network. // Because the permission of the system default network is PERMISSION_NONE(0x0), apps can always // pass the check here when using the system default network. diff --git a/server/NetworkController.h b/server/NetworkController.h index d4156f98..386733ad 100644 --- a/server/NetworkController.h +++ b/server/NetworkController.h @@ -19,7 +19,6 @@ #include <android-base/thread_annotations.h> #include <android/multinetwork.h> - #include "NetdConstants.h" #include "Permission.h" #include "PhysicalNetwork.h" @@ -148,6 +147,7 @@ public: void denyProtect(const std::vector<uid_t>& uids); void dump(netdutils::DumpWriter& dw); + int setNetworkAllowlist(const std::vector<netd::aidl::NativeUidRangeConfig>& settings); private: bool isValidNetworkLocked(unsigned netId) const; @@ -173,6 +173,7 @@ public: int mtu); [[nodiscard]] int modifyFallthroughLocked(unsigned vpnNetId, bool add); void updateTcpSocketMonitorPolling(); + void clearAllowedUidsForAllNetworksLocked(); class DelegateImpl; DelegateImpl* const mDelegateImpl; diff --git a/tests/binder_test.cpp b/tests/binder_test.cpp index 36a0d515..d4902bc8 100644 --- a/tests/binder_test.cpp +++ b/tests/binder_test.cpp @@ -4035,6 +4035,10 @@ namespace { #define APP_DEFAULT_NETID TEST_NETID2 #define VPN_NETID TEST_NETID3 +#define ENTERPRISE_NETID_1 TEST_NETID2 +#define ENTERPRISE_NETID_2 TEST_NETID3 +#define ENTERPRISE_NETID_3 TEST_NETID4 + void verifyAppUidRules(std::vector<bool>&& expectedResults, std::vector<UidRangeParcel>& uidRanges, const std::string& iface, int32_t subPriority) { ASSERT_EQ(expectedResults.size(), uidRanges.size()); @@ -5389,3 +5393,127 @@ TEST_F(MDnsBinderTest, EventListenerTest) { status = mMDns->unregisterEventListener(testListener); EXPECT_TRUE(status.isOk()) << status.exceptionMessage(); } + +// Creates a system default network and 3 enterprise networks for two profiles. Check if network +// selection in compliance with network allow list settings. +// +// +-----------+-----------------------+----------------------------------------+ +// | UID | UID's default network | UID can select networks | +// +-----------+-----------------------+----------------------------------------+ +// | TEST_UID1 | ENTERPRISE_NETID_1 | ENTERPRISE_NETID_1, ENTERPRISE_NETID_2 | +// | TEST_UID2 | ENTERPRISE_NETID_3 | ENTERPRISE_NETID_3 | +// +-----------+-----------------------+----------------------------------------+ +TEST_F(NetdBinderTest, PerProfileNetworkPermission) { + // creates 4 networks + createDefaultAndOtherPhysicalNetwork(SYSTEM_DEFAULT_NETID, ENTERPRISE_NETID_1); + createPhysicalNetwork(ENTERPRISE_NETID_2, sTun3.name()); + EXPECT_TRUE(mNetd->networkAddRoute(ENTERPRISE_NETID_2, sTun3.name(), "::/0", "").isOk()); + createPhysicalNetwork(ENTERPRISE_NETID_3, sTun4.name()); + EXPECT_TRUE(mNetd->networkAddRoute(ENTERPRISE_NETID_3, sTun4.name(), "::/0", "").isOk()); + + // profile#1 + NativeUidRangeConfig cfg1 = + makeNativeUidRangeConfig(ENTERPRISE_NETID_1, {makeUidRangeParcel(TEST_UID1, TEST_UID1)}, + UidRanges::SUB_PRIORITY_HIGHEST + 20); + EXPECT_TRUE(mNetd->networkAddUidRangesParcel(cfg1).isOk()); + + // profile#2 + NativeUidRangeConfig cfg2 = + makeNativeUidRangeConfig(ENTERPRISE_NETID_3, {makeUidRangeParcel(TEST_UID2, TEST_UID2)}, + UidRanges::SUB_PRIORITY_HIGHEST + 20); + EXPECT_TRUE(mNetd->networkAddUidRangesParcel(cfg2).isOk()); + + // setNetworkAllowlist at once + // all uids except for TEST_UID2 + NativeUidRangeConfig nw1UserConfig = makeNativeUidRangeConfig( + ENTERPRISE_NETID_1, + {makeUidRangeParcel(0, TEST_UID3), makeUidRangeParcel(TEST_UID1, TEST_UID1)}, + /*unused*/ 0); + NativeUidRangeConfig nw2UserConfig = makeNativeUidRangeConfig( + ENTERPRISE_NETID_2, + {makeUidRangeParcel(0, TEST_UID3), makeUidRangeParcel(TEST_UID1, TEST_UID1)}, + /*unused*/ 0); + // all uids except for TEST_UID1 + NativeUidRangeConfig nw3UserConfig = makeNativeUidRangeConfig( + ENTERPRISE_NETID_3, {makeUidRangeParcel(0, TEST_UID2)}, /*unused*/ 0); + // all uids except for TEST_UID1 and TEST_UID2 + NativeUidRangeConfig nwDefaultUserConfig = makeNativeUidRangeConfig( + SYSTEM_DEFAULT_NETID, {makeUidRangeParcel(0, TEST_UID3)}, /*unused*/ 0); + EXPECT_TRUE(mNetd->setNetworkAllowlist( + {nw1UserConfig, nw2UserConfig, nw3UserConfig, nwDefaultUserConfig}) + .isOk()); + + { // Can set network for process on allowed networks. + ScopedUidChange scopedUidChange(TEST_UID1); + EXPECT_EQ(0, setNetworkForProcess(ENTERPRISE_NETID_1)); + EXPECT_EQ(0, setNetworkForProcess(ENTERPRISE_NETID_2)); + // Can not set network for process on not allowed networks. + EXPECT_EQ(-EACCES, setNetworkForProcess(SYSTEM_DEFAULT_NETID)); + EXPECT_EQ(-EACCES, setNetworkForProcess(ENTERPRISE_NETID_3)); + } + { // Can set network for process on allowed networks. + ScopedUidChange scopedUidChange(TEST_UID2); + EXPECT_EQ(0, setNetworkForProcess(ENTERPRISE_NETID_3)); + // Can not set network for process on not allowed networks. + EXPECT_EQ(-EACCES, setNetworkForProcess(SYSTEM_DEFAULT_NETID)); + EXPECT_EQ(-EACCES, setNetworkForProcess(ENTERPRISE_NETID_1)); + EXPECT_EQ(-EACCES, setNetworkForProcess(ENTERPRISE_NETID_2)); + } + { // Root can use whatever network it wants. + ScopedUidChange scopedUidChange(AID_ROOT); + EXPECT_EQ(0, setNetworkForProcess(SYSTEM_DEFAULT_NETID)); + EXPECT_EQ(0, setNetworkForProcess(ENTERPRISE_NETID_1)); + EXPECT_EQ(0, setNetworkForProcess(ENTERPRISE_NETID_2)); + EXPECT_EQ(0, setNetworkForProcess(ENTERPRISE_NETID_3)); + } + + // Update setting: remove ENTERPRISE_NETID_2 from profile#1's allowed network list and add it to + // profile#2's allowed network list. + // +-----------+-----------------------+----------------------------------------+ + // | UID | UID's default network | UID can select networks | + // +-----------+-----------------------+----------------------------------------+ + // | TEST_UID1 | ENTERPRISE_NETID_1 | ENTERPRISE_NETID_1 | + // | TEST_UID2 | ENTERPRISE_NETID_3 | ENTERPRISE_NETID_2, ENTERPRISE_NETID_3 | + // +-----------+-----------------------+----------------------------------------+ + + // all uids except for TEST_UID2 + nw1UserConfig = makeNativeUidRangeConfig( + ENTERPRISE_NETID_1, + {makeUidRangeParcel(0, TEST_UID3), makeUidRangeParcel(TEST_UID1, TEST_UID1)}, + /*unused*/ 0); + // all uids except for TEST_UID1 + nw2UserConfig = makeNativeUidRangeConfig(ENTERPRISE_NETID_2, {makeUidRangeParcel(0, TEST_UID2)}, + /*unused*/ 0); + nw3UserConfig = makeNativeUidRangeConfig(ENTERPRISE_NETID_3, {makeUidRangeParcel(0, TEST_UID2)}, + /*unused*/ 0); + // all uids except for TEST_UID1 and TEST_UID2 + nwDefaultUserConfig = makeNativeUidRangeConfig( + SYSTEM_DEFAULT_NETID, {makeUidRangeParcel(0, TEST_UID3)}, /*unused*/ 0); + EXPECT_TRUE(mNetd->setNetworkAllowlist( + {nw1UserConfig, nw2UserConfig, nw3UserConfig, nwDefaultUserConfig}) + .isOk()); + + { + ScopedUidChange scopedUidChange(TEST_UID1); + EXPECT_EQ(0, setNetworkForProcess(ENTERPRISE_NETID_1)); + EXPECT_EQ(-EACCES, setNetworkForProcess(SYSTEM_DEFAULT_NETID)); + EXPECT_EQ(-EACCES, setNetworkForProcess(ENTERPRISE_NETID_2)); + EXPECT_EQ(-EACCES, setNetworkForProcess(ENTERPRISE_NETID_3)); + } + { + ScopedUidChange scopedUidChange(TEST_UID2); + EXPECT_EQ(0, setNetworkForProcess(ENTERPRISE_NETID_2)); + EXPECT_EQ(0, setNetworkForProcess(ENTERPRISE_NETID_3)); + EXPECT_EQ(-EACCES, setNetworkForProcess(SYSTEM_DEFAULT_NETID)); + EXPECT_EQ(-EACCES, setNetworkForProcess(ENTERPRISE_NETID_1)); + } + + // UID not restricted by allowed list can select all networks. + { + ScopedUidChange scopedUidChange(TEST_UID3); + EXPECT_EQ(0, setNetworkForProcess(ENTERPRISE_NETID_1)); + EXPECT_EQ(0, setNetworkForProcess(SYSTEM_DEFAULT_NETID)); + EXPECT_EQ(0, setNetworkForProcess(ENTERPRISE_NETID_2)); + EXPECT_EQ(0, setNetworkForProcess(ENTERPRISE_NETID_3)); + } +}
\ No newline at end of file |