summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKen Chen <cken@google.com>2022-12-25 13:26:29 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2022-12-25 13:26:29 +0000
commit4295cc6916e265a5e5c72ee99407a3da39152e66 (patch)
treec373526f1965f7786a99b533af8aafab48024e2d
parented93056e0dd2f86508f219e8b037f05a9b595db1 (diff)
parent3755dbfd1271224199b778783b7a81abab676b4e (diff)
downloadnetd-4295cc6916e265a5e5c72ee99407a3da39152e66.tar.gz
Merge "Support per-uid explicit selected network permission control" am: ad4f2f4faf am: 1dc0589e0a am: 3755dbfd12
Original change: https://android-review.googlesource.com/c/platform/system/netd/+/2367328 Change-Id: I71d6fb99d8e7895598405ecb7bba7cbe9d35f937 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r--server/NetdNativeService.cpp6
-rw-r--r--server/NetdNativeService.h2
-rw-r--r--server/Network.cpp19
-rw-r--r--server/Network.h11
-rw-r--r--server/NetworkController.cpp37
-rw-r--r--server/NetworkController.h3
-rw-r--r--tests/binder_test.cpp128
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