From: Lorenzo Colitti Date: Sun, 24 Apr 2016 04:13:14 +0000 (+0900) Subject: Add a binder IPC to close socket connections. X-Git-Tag: android-x86-7.1-r1~39^2~12 X-Git-Url: http://git.osdn.net/view?p=android-x86%2Fsystem-netd.git;a=commitdiff_plain;h=563d98b27d02a1d694fc4ed82b5554fd534c9daf Add a binder IPC to close socket connections. Bug: 27824851 Bug: 27867653 Change-Id: I2e63ccfb268db763ec732594a73c2908838468b8 --- diff --git a/server/NetdNativeService.cpp b/server/NetdNativeService.cpp index 388b6b5..a8f5c3b 100644 --- a/server/NetdNativeService.cpp +++ b/server/NetdNativeService.cpp @@ -31,6 +31,7 @@ #include "NetdConstants.h" #include "NetdNativeService.h" #include "RouteController.h" +#include "SockDiag.h" #include "UidRanges.h" using android::base::StringPrintf; @@ -67,7 +68,6 @@ binder::Status checkPermission(const char *permission) { android::RWLock::AutoWLock _lock(lock); #define NETD_BIG_LOCK_RPC(permission) NETD_LOCKING_RPC((permission), gBigNetdLock) - } // namespace @@ -135,8 +135,7 @@ binder::Status NetdNativeService::networkRejectNonSecureVpn(bool add, // look at routes, but it's not enough here). NETD_BIG_LOCK_RPC(CONNECTIVITY_INTERNAL); - UidRanges uidRanges; - uidRanges.createFrom(uidRangeArray); + UidRanges uidRanges(uidRangeArray); int err; if (add) { @@ -152,5 +151,27 @@ binder::Status NetdNativeService::networkRejectNonSecureVpn(bool add, return binder::Status::ok(); } +binder::Status NetdNativeService::socketDestroy(const std::vector& uids, + const std::vector& skipUids) { + + ENFORCE_PERMISSION(CONNECTIVITY_INTERNAL); + + SockDiag sd; + if (!sd.open()) { + return binder::Status::fromServiceSpecificError(EIO, + String8("Could not open SOCK_DIAG socket")); + } + + UidRanges uidRanges(uids); + int err = sd.destroySockets(uidRanges, std::set(skipUids.begin(), skipUids.end())); + + if (err) { + return binder::Status::fromServiceSpecificError(-err, + String8::format("destroySockets: %s", strerror(-err))); + } + + return binder::Status::ok(); +} + } // namespace net } // namespace android diff --git a/server/NetdNativeService.h b/server/NetdNativeService.h index 96759e1..22c81fc 100644 --- a/server/NetdNativeService.h +++ b/server/NetdNativeService.h @@ -40,6 +40,8 @@ class NetdNativeService : public BinderService, public BnNetd binder::Status bandwidthEnableDataSaver(bool enable, bool *ret) override; binder::Status networkRejectNonSecureVpn(bool enable, const std::vector& uids) override; + binder::Status socketDestroy(const std::vector& uids, + const std::vector& skipUids) override; }; } // namespace net diff --git a/server/UidRanges.cpp b/server/UidRanges.cpp index a2b8dde..b7db616 100644 --- a/server/UidRanges.cpp +++ b/server/UidRanges.cpp @@ -75,7 +75,7 @@ bool UidRanges::parseFrom(int argc, char* argv[]) { return true; } -void UidRanges::createFrom(const std::vector& ranges) { +UidRanges::UidRanges(const std::vector& ranges) { mRanges.resize(ranges.size()); std::transform(ranges.begin(), ranges.end(), mRanges.begin(), [](const android::net::UidRange& range) { diff --git a/server/UidRanges.h b/server/UidRanges.h index 3cbbe80..293f53f 100644 --- a/server/UidRanges.h +++ b/server/UidRanges.h @@ -30,11 +30,13 @@ public: // a larger type first. typedef std::pair Range; + UidRanges() {} + UidRanges(const std::vector& ranges); + bool hasUid(uid_t uid) const; const std::vector& getRanges() const; bool parseFrom(int argc, char* argv[]); - void createFrom(const std::vector& ranges); std::string toString() const; void add(const UidRanges& other); diff --git a/server/binder/android/net/INetd.aidl b/server/binder/android/net/INetd.aidl index 63054f8..616842b 100644 --- a/server/binder/android/net/INetd.aidl +++ b/server/binder/android/net/INetd.aidl @@ -80,4 +80,9 @@ interface INetd { * unix errno. */ void networkRejectNonSecureVpn(boolean add, in UidRange[] uidRanges); + + /** + * Administratively closes sockets belonging to the specified UIDs. + */ + void socketDestroy(in UidRange[] uidRanges, in int[] exemptUids); } diff --git a/tests/binder_test.cpp b/tests/binder_test.cpp index 94cc535..bdc147a 100644 --- a/tests/binder_test.cpp +++ b/tests/binder_test.cpp @@ -21,8 +21,12 @@ #include #include #include +#include #include +#include +#include + #include #include #include @@ -291,3 +295,91 @@ TEST_F(BinderTest, TestNetworkRejectNonSecureVpn) { EXPECT_EQ(initialRulesV4, listIpRules(IP_RULE_V4)); EXPECT_EQ(initialRulesV6, listIpRules(IP_RULE_V6)); } + +void socketpair(int *clientSocket, int *serverSocket, int *acceptedSocket) { + *serverSocket = socket(AF_INET6, SOCK_STREAM, 0); + struct sockaddr_in6 server6 = { .sin6_family = AF_INET6 }; + ASSERT_EQ(0, bind(*serverSocket, (struct sockaddr *) &server6, sizeof(server6))); + + socklen_t addrlen = sizeof(server6); + ASSERT_EQ(0, getsockname(*serverSocket, (struct sockaddr *) &server6, &addrlen)); + ASSERT_EQ(0, listen(*serverSocket, 10)); + + *clientSocket = socket(AF_INET6, SOCK_STREAM, 0); + struct sockaddr_in6 client6; + ASSERT_EQ(0, connect(*clientSocket, (struct sockaddr *) &server6, sizeof(server6))); + ASSERT_EQ(0, getsockname(*clientSocket, (struct sockaddr *) &client6, &addrlen)); + + *acceptedSocket = accept(*serverSocket, (struct sockaddr *) &server6, &addrlen); + ASSERT_NE(-1, *acceptedSocket); + + ASSERT_EQ(0, memcmp(&client6, &server6, sizeof(client6))); +} + +void checkSocketpairOpen(int clientSocket, int acceptedSocket) { + char buf[4096]; + EXPECT_EQ(4, write(clientSocket, "foo", sizeof("foo"))); + EXPECT_EQ(4, read(acceptedSocket, buf, sizeof(buf))); + EXPECT_EQ(0, memcmp(buf, "foo", sizeof("foo"))); +} + +void checkSocketpairClosed(int clientSocket, int acceptedSocket) { + // Check that the client socket was closed with ECONNABORTED. + int ret = write(clientSocket, "foo", sizeof("foo")); + int err = errno; + EXPECT_EQ(-1, ret); + EXPECT_EQ(ECONNABORTED, err); + + // Check that it sent a RST to the server. + ret = write(acceptedSocket, "foo", sizeof("foo")); + err = errno; + EXPECT_EQ(-1, ret); + EXPECT_EQ(ECONNRESET, err); +} + +TEST_F(BinderTest, TestSocketDestroy) { + int clientSocket, serverSocket, acceptedSocket; + ASSERT_NO_FATAL_FAILURE(socketpair(&clientSocket, &serverSocket, &acceptedSocket)); + + // Pick a random UID in the system UID range. + constexpr int baseUid = AID_APP - 2000; + static_assert(baseUid > 0, "Not enough UIDs? Please fix this test."); + int uid = baseUid + 500 + arc4random_uniform(1000); + EXPECT_EQ(0, fchown(clientSocket, uid, -1)); + + // UID ranges that don't contain uid. + std::vector uidRanges = { + {baseUid + 42, baseUid + 449}, + {baseUid + 1536, AID_APP - 4}, + {baseUid + 498, uid - 1}, + {uid + 1, baseUid + 1520}, + }; + // A skip list that doesn't contain UID. + std::vector skipUids { baseUid + 123, baseUid + 1600 }; + + // Close sockets. Our test socket should be intact. + EXPECT_TRUE(mNetd->socketDestroy(uidRanges, skipUids).isOk()); + checkSocketpairOpen(clientSocket, acceptedSocket); + + // UID ranges that do contain uid. + uidRanges = { + {baseUid + 42, baseUid + 449}, + {baseUid + 1536, AID_APP - 4}, + {baseUid + 498, baseUid + 1520}, + }; + // Add uid to the skip list. + skipUids.push_back(uid); + + // Close sockets. Our test socket should still be intact because it's in the skip list. + EXPECT_TRUE(mNetd->socketDestroy(uidRanges, skipUids).isOk()); + checkSocketpairOpen(clientSocket, acceptedSocket); + + // Now remove uid from skipUids, and close sockets. Our test socket should have been closed. + skipUids.resize(skipUids.size() - 1); + EXPECT_TRUE(mNetd->socketDestroy(uidRanges, skipUids).isOk()); + checkSocketpairClosed(clientSocket, acceptedSocket); + + close(clientSocket); + close(serverSocket); + close(acceptedSocket); +}