Reland: Soft-enable MAC address restrictions with allowlist.
Soft-limits apps from calling bind() on NETLINK_ROUTE sockets, and
getting link info through getifaddrs(), while still allowing apps on the
allowlist to temporarily perform these actions.
This is different from existing behavior, where apps targeting an API
level < 30 were exempted from this restriction.
Actual enforcement will happen through SELinux (as is currently the
case for apps targeting API >= 30). This temporary change will then be
reverted.
If you arrived at this change due to an app showing unexpected behavior,
please file a bug at go/netlink-bug.
Bug: 170188668
Bug: 170214442
Test: Call bind() on NETLINK_ROUTE for an app on the allowlist.
Test: Call bind() on NETLINK_ROUTE for an app not on the allowlist.
Test: Call getifaddrs() for an app on the allowlist.
Test: Call getifaddrs() for an app not on the allowlist.
Test: Call bind() on a AF_UNIX socket with its protocol set to
NETLINK_ROUTE, confirm it can succeed.
Test: Verify that previously broken apps are no longer broken.
Change-Id: I8738f7912fdc816e0d30205557728ff9e84bf7e6
diff --git a/libc/Android.bp b/libc/Android.bp
index 447d17b..cce23b3 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -1009,7 +1009,9 @@
"bionic/arpa_inet.cpp",
"bionic/assert.cpp",
"bionic/atof.cpp",
+ "bionic/bind.cpp",
"bionic/bionic_allocator.cpp",
+ "bionic/bionic_appcompat.cpp",
"bionic/bionic_arc4random.cpp",
"bionic/bionic_futex.cpp",
"bionic/bionic_netlink.cpp",
diff --git a/libc/SYSCALLS.TXT b/libc/SYSCALLS.TXT
index 6142baf..7cf7a2d 100644
--- a/libc/SYSCALLS.TXT
+++ b/libc/SYSCALLS.TXT
@@ -244,7 +244,7 @@
# sockets
int __socket:socket(int, int, int) arm,lp64
int __socketpair:socketpair(int, int, int, int*) arm,lp64
-int bind(int, struct sockaddr*, socklen_t) arm,lp64
+int __bind:bind(int, struct sockaddr*, socklen_t) arm,lp64
int __connect:connect(int, struct sockaddr*, socklen_t) arm,lp64
int listen(int, int) arm,lp64
int __accept4:accept4(int, struct sockaddr*, socklen_t*, int) arm,lp64
@@ -262,7 +262,7 @@
# sockets for x86. These are done as an "indexed" call to socketcall syscall.
int __socket:socketcall:1(int, int, int) x86
-int bind:socketcall:2(int, struct sockaddr*, int) x86
+int __bind:socketcall:2(int, struct sockaddr*, int) x86
int __connect:socketcall:3(int, struct sockaddr*, socklen_t) x86
int listen:socketcall:4(int, int) x86
int getsockname:socketcall:6(int, struct sockaddr*, socklen_t*) x86
diff --git a/libc/bionic/bind.cpp b/libc/bionic/bind.cpp
new file mode 100644
index 0000000..79e8020
--- /dev/null
+++ b/libc/bionic/bind.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+// b/170214442: Intercept bind calls on NETLINK_ROUTE sockets.
+// This entire file will be reverted before release.
+
+#include <async_safe/log.h>
+#include <errno.h>
+#include <linux/rtnetlink.h>
+#include <string.h>
+#include <sys/socket.h>
+
+#include "bionic_appcompat.h"
+
+extern "C" int __bind(int fd, const struct sockaddr* addr, socklen_t addr_length);
+
+int bind(int fd, const struct sockaddr* addr, socklen_t addr_length) {
+ if (should_apply_soft_mac_bind_restrictions()) {
+ int sock_domain, sock_protocol;
+ socklen_t sock_domain_length = sizeof(sock_domain);
+ socklen_t sock_protocol_length = sizeof(sock_protocol);
+ if (getsockopt(fd, SOL_SOCKET, SO_DOMAIN, &sock_domain, &sock_domain_length) < 0 ||
+ getsockopt(fd, SOL_SOCKET, SO_PROTOCOL, &sock_protocol, &sock_protocol_length) < 0) {
+ async_safe_format_log(ANDROID_LOG_ERROR, "mac-restrictions",
+ "Could not get socket type/protocol: %s", strerror(errno));
+ } else if (AF_NETLINK == sock_domain && NETLINK_ROUTE == sock_protocol) {
+ char package_name[MAX_PACKAGE_NAME_LENGTH + 1];
+ get_package_name(package_name, sizeof(package_name));
+ async_safe_format_log(
+ ANDROID_LOG_ERROR, "mac-restrictions",
+ "%s tried to call bind() on a NETLINK_ROUTE socket, which is not allowed. Please follow "
+ "instructions at go/netlink-bug if this app behaves incorrectly.",
+ package_name);
+ errno = EACCES;
+ return -1;
+ }
+ }
+
+ return __bind(fd, addr, addr_length);
+}
diff --git a/libc/bionic/bionic_appcompat.cpp b/libc/bionic/bionic_appcompat.cpp
new file mode 100644
index 0000000..5b31c29
--- /dev/null
+++ b/libc/bionic/bionic_appcompat.cpp
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+// b/170214442: Intercept bind calls on NETLINK_ROUTE sockets and getifaddrs() calls.
+// This entire file will be reverted before release.
+
+#include <async_safe/log.h>
+#include <cutils/misc.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "bionic_appcompat.h"
+
+bool should_apply_soft_mac_restrictions(const char* const allowlist[]) {
+ if (getuid() < FIRST_APPLICATION_UID) {
+ // System app. No restrictions should be applied.
+ return false;
+ }
+ if (android_get_application_target_sdk_version() >= __ANDROID_API_R__) {
+ // Restrictions already applied by SELinux. Behave as normally.
+ return false;
+ }
+
+ char package_name[MAX_PACKAGE_NAME_LENGTH + 1];
+ if (get_package_name(package_name, sizeof(package_name)) < 0) {
+ // Error in getting own package name. Apply restrictions by default.
+ async_safe_format_log(ANDROID_LOG_ERROR, "mac-restrictions",
+ "Could not determine own package name for uid %d", getuid());
+ return true;
+ }
+ for (int i = 0; allowlist[i] != nullptr; i++) {
+ if (strcmp(package_name, allowlist[i]) == 0) {
+ async_safe_format_log(ANDROID_LOG_WARN, "mac-restrictions",
+ "Temporarily allowing %s to bypass MAC address restrictions.",
+ package_name);
+ return false;
+ }
+ }
+ return true;
+}
+
+bool should_apply_soft_mac_bind_restrictions() {
+ return should_apply_soft_mac_restrictions(soft_mac_bind_allowlist);
+}
+
+bool should_apply_soft_mac_getlink_restrictions() {
+ return should_apply_soft_mac_restrictions(soft_mac_getlink_allowlist);
+}
+
+int get_package_name(char* buffer, const int bufferlen) {
+ int file = open("/proc/self/cmdline", O_RDONLY | O_CLOEXEC);
+ if (file < 0) {
+ return file;
+ }
+
+ ssize_t len = read(file, buffer, bufferlen - 1);
+ if (len < 0) {
+ close(file);
+ return -1;
+ }
+ buffer[len] = 0;
+
+ close(file);
+ return 0;
+}
\ No newline at end of file
diff --git a/libc/bionic/bionic_appcompat.h b/libc/bionic/bionic_appcompat.h
new file mode 100644
index 0000000..1976e0b
--- /dev/null
+++ b/libc/bionic/bionic_appcompat.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#pragma once
+
+constexpr int MAX_PACKAGE_NAME_LENGTH = 230;
+
+static inline const char* const soft_mac_bind_allowlist[] = {
+ "com.skype.raider",
+ nullptr,
+};
+
+static inline const char* const soft_mac_getlink_allowlist[] = {
+ nullptr,
+};
+
+int get_package_name(char* buffer, const int bufferlen);
+bool should_apply_soft_mac_bind_restrictions();
+bool should_apply_soft_mac_getlink_restrictions();
\ No newline at end of file
diff --git a/libc/bionic/ifaddrs.cpp b/libc/bionic/ifaddrs.cpp
index 1536333..22ecdb4 100644
--- a/libc/bionic/ifaddrs.cpp
+++ b/libc/bionic/ifaddrs.cpp
@@ -42,6 +42,7 @@
#include "private/ErrnoRestorer.h"
+#include "bionic_appcompat.h"
#include "bionic_netlink.h"
// The public ifaddrs struct is full of pointers. Rather than track several
@@ -310,9 +311,12 @@
// - System apps
// - Apps with a target SDK version lower than R
bool getlink_success = false;
- if (getuid() < FIRST_APPLICATION_UID ||
- android_get_application_target_sdk_version() < __ANDROID_API_R__) {
+ if (!should_apply_soft_mac_getlink_restrictions()) {
getlink_success = nc.SendRequest(RTM_GETLINK) && nc.ReadResponses(__getifaddrs_callback, out);
+ } else if (android_get_application_target_sdk_version() < __ANDROID_API_R__) {
+ async_safe_format_log(ANDROID_LOG_WARN, "mac-restrictions",
+ "ifaddr no longer returns link info. Please follow instructions at "
+ "go/netlink-bug if this app behaves incorrectly.");
}
bool getaddr_success =
nc.SendRequest(RTM_GETADDR) && nc.ReadResponses(__getifaddrs_callback, out);