diff options
author | Luke Huang <huangluke@google.com> | 2020-06-18 14:46:02 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2020-06-18 14:46:02 +0000 |
commit | 06869ded2a372dafefe4f9247233abaa5de95594 (patch) | |
tree | ac16144b2380c0b91aa7e1e63ca599e7315822cd | |
parent | 08d39283c75799bd76e5d475601b4acf64a170ff (diff) | |
parent | 86983208a199d147d63033aec7794666e55d27a8 (diff) | |
download | netd-06869ded2a372dafefe4f9247233abaa5de95594.tar.gz |
Provide a way to disable socket() and DNS lookups in libnetd_client. am: 86983208a1
Original change: https://googleplex-android-review.googlesource.com/c/platform/system/netd/+/11881839
Change-Id: I3855120fd96b362d730901d6032d4d039573d9e5
-rw-r--r-- | client/NetdClient.cpp | 17 | ||||
-rw-r--r-- | include/NetdClient.h | 2 | ||||
-rw-r--r-- | tests/Android.bp | 1 | ||||
-rw-r--r-- | tests/netd_client_test.cpp | 113 |
4 files changed, 133 insertions, 0 deletions
diff --git a/client/NetdClient.cpp b/client/NetdClient.cpp index 74a441ae..0105a047 100644 --- a/client/NetdClient.cpp +++ b/client/NetdClient.cpp @@ -60,6 +60,7 @@ constexpr char PROPERTY_REDIRECT_SOCKET_CALLS_HOOKED[] = "net.redirect_socket_ca std::atomic_uint netIdForProcess(NETID_UNSET); std::atomic_uint netIdForResolv(NETID_UNSET); +std::atomic_bool allowNetworkingForProcess(true); typedef int (*Accept4FunctionType)(int, sockaddr*, socklen_t*, int); typedef int (*ConnectFunctionType)(int, const sockaddr*, socklen_t); @@ -182,6 +183,11 @@ int netdClientConnect(int sockfd, const sockaddr* addr, socklen_t addrlen) { } int netdClientSocket(int domain, int type, int protocol) { + // Block creating AF_INET/AF_INET6 socket if networking is not allowed. + if (FwmarkCommand::isSupportedFamily(domain) && !allowNetworkingForProcess.load()) { + errno = EPERM; + return -1; + } int socketFd = libcSocket(domain, type, protocol); if (socketFd == -1) { return -1; @@ -285,6 +291,13 @@ int dns_open_proxy() { return -1; } + // If networking is not allowed, dns_open_proxy should just fail here. + // Then eventually, the DNS related functions in local mode will get + // EPERM while creating socket. + if (!allowNetworkingForProcess.load()) { + errno = EPERM; + return -1; + } const auto socketFunc = libcSocket ? libcSocket : socket; int s = socketFunc(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); if (s == -1) { @@ -593,6 +606,10 @@ extern "C" void resNetworkCancel(int fd) { close(fd); } +extern "C" void setAllowNetworkingForProcess(bool allowNetworking) { + allowNetworkingForProcess.store(allowNetworking); +} + extern "C" int getNetworkForDns(unsigned* dnsNetId) { if (dnsNetId == nullptr) return -EFAULT; int fd = dns_open_proxy(); diff --git a/include/NetdClient.h b/include/NetdClient.h index 89f0a41a..cc835ede 100644 --- a/include/NetdClient.h +++ b/include/NetdClient.h @@ -40,6 +40,8 @@ int setNetworkForUser(uid_t uid, int socketFd); int queryUserAccess(uid_t uid, unsigned netId); +void setAllowNetworkingForProcess(bool allowNetworking); + int tagSocket(int socketFd, uint32_t tag, uid_t uid); int untagSocket(int socketFd); diff --git a/tests/Android.bp b/tests/Android.bp index f696bab6..3baaa184 100644 --- a/tests/Android.bp +++ b/tests/Android.bp @@ -71,6 +71,7 @@ cc_test { ":netd_integration_test_shared", "binder_test.cpp", "bpf_base_test.cpp", + "netd_client_test.cpp", "netd_test.cpp", "netlink_listener_test.cpp", ], diff --git a/tests/netd_client_test.cpp b/tests/netd_client_test.cpp new file mode 100644 index 00000000..c8af408b --- /dev/null +++ b/tests/netd_client_test.cpp @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <netdb.h> +#include <netinet/in.h> +#include <poll.h> /* poll */ +#include <sys/socket.h> +#include <sys/types.h> + +#include <android-base/unique_fd.h> +#include <gtest/gtest.h> + +#include "NetdClient.h" + +#define SKIP_IF_NO_NETWORK_CONNECTIVITY \ + do { \ + if (!checkNetworkConnectivity()) { \ + GTEST_LOG_(INFO) << "Skip. Required Network Connectivity. \n"; \ + return; \ + } \ + } while (0) + +namespace { + +constexpr char TEST_DOMAIN[] = "www.google.com"; + +bool checkNetworkConnectivity() { + android::base::unique_fd sock(socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP)); + if (sock == -1) return false; + static const sockaddr_in6 server6 = { + .sin6_family = AF_INET6, + .sin6_addr.s6_addr = {// 2000:: + 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}; + int ret = connect(sock, reinterpret_cast<const sockaddr*>(&server6), sizeof(server6)); + if (ret == 0) return true; + sock.reset(socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP)); + if (sock == -1) return false; + static const sockaddr_in server4 = { + .sin_family = AF_INET, + .sin_addr.s_addr = __constant_htonl(0x08080808L) // 8.8.8.8 + }; + ret = connect(sock, reinterpret_cast<const sockaddr*>(&server4), sizeof(server4)); + return !ret; +} + +void expectHasNetworking() { + // Socket + android::base::unique_fd ipv4(socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0)), + ipv6(socket(AF_INET6, SOCK_STREAM | SOCK_CLOEXEC, 0)); + EXPECT_LE(3, ipv4); + EXPECT_LE(3, ipv6); + + // DNS + addrinfo* result = nullptr; + errno = 0; + const addrinfo hints = { + .ai_family = AF_UNSPEC, + .ai_socktype = SOCK_DGRAM, + }; + EXPECT_EQ(0, getaddrinfo(TEST_DOMAIN, nullptr, &hints, &result)); + EXPECT_EQ(0, errno); + freeaddrinfo(result); +} + +void expectNoNetworking() { + // Socket + android::base::unique_fd unixSocket(socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0)); + EXPECT_LE(3, unixSocket); + android::base::unique_fd ipv4(socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0)); + EXPECT_EQ(-1, ipv4); + EXPECT_EQ(EPERM, errno); + android::base::unique_fd ipv6(socket(AF_INET6, SOCK_STREAM | SOCK_CLOEXEC, 0)); + EXPECT_EQ(-1, ipv6); + EXPECT_EQ(EPERM, errno); + + // DNS + addrinfo* result = nullptr; + errno = 0; + const addrinfo hints = { + .ai_family = AF_UNSPEC, + .ai_socktype = SOCK_DGRAM, + }; + EXPECT_EQ(EAI_NODATA, getaddrinfo(TEST_DOMAIN, nullptr, &hints, &result)); + EXPECT_EQ(EPERM, errno); + freeaddrinfo(result); +} + +} // namespace + +TEST(NetdClientIntegrationTest, setAllowNetworkingForProcess) { + SKIP_IF_NO_NETWORK_CONNECTIVITY; + // At the beginning, we should be able to use socket since the default setting is allowing. + expectHasNetworking(); + // Disable + setAllowNetworkingForProcess(false); + expectNoNetworking(); + // Reset + setAllowNetworkingForProcess(true); + expectHasNetworking(); +} |