From 82654c3dd013b1bacb711074392f55f88d69d52b Mon Sep 17 00:00:00 2001 From: Danny Lin Date: Tue, 5 Oct 2021 18:42:40 -0700 Subject: [PATCH 01/13] gmscompat: Add ConnectivityManager hook for baseline compatibility This is part of GmsCompat's baseline compatibility for unprivileged Google Play Services. Change-Id: I3e87706f1f3b87c0af9d00f6ce92144469596f8c --- framework/src/android/net/ConnectivityManager.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/framework/src/android/net/ConnectivityManager.java b/framework/src/android/net/ConnectivityManager.java index 4eaf973297..5f2416b5fe 100644 --- a/framework/src/android/net/ConnectivityManager.java +++ b/framework/src/android/net/ConnectivityManager.java @@ -40,6 +40,7 @@ import android.annotation.SystemService; import android.app.PendingIntent; import android.app.admin.DevicePolicyManager; +import android.app.compat.gms.GmsCompat; import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; @@ -3131,6 +3132,10 @@ public int untether(String iface) { @RequiresPermission(anyOf = {android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public boolean isTetheringSupported() { + if (GmsCompat.isEnabled()) { + return false; + } + return getTetheringManager().isTetheringSupported(); } From 1bdb152a4cdd6980a675f4f3c2afb730a77a4903 Mon Sep 17 00:00:00 2001 From: Dave Daynard Date: Fri, 15 Oct 2021 18:02:03 +0100 Subject: [PATCH 02/13] Remove DUN requirement for tethering Ported from 11. Tethering was moved from frameworks/base/packages/Tethering to packages/modules/Connectivity/Tethering --- .../networkstack/tethering/TetheringConfiguration.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java b/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java index 298940e4fc..9016cddbe7 100644 --- a/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java +++ b/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java @@ -16,7 +16,6 @@ package com.android.networkstack.tethering; -import static android.content.Context.TELEPHONY_SERVICE; import static android.net.ConnectivityManager.TYPE_ETHERNET; import static android.net.ConnectivityManager.TYPE_MOBILE; import static android.net.ConnectivityManager.TYPE_MOBILE_DUN; @@ -34,7 +33,6 @@ import android.provider.Settings; import android.telephony.CarrierConfigManager; import android.telephony.SubscriptionManager; -import android.telephony.TelephonyManager; import android.text.TextUtils; import androidx.annotation.NonNull; @@ -505,10 +503,7 @@ private static String makeString(String[] strings) { /** Check whether dun is required. */ public static boolean checkDunRequired(Context ctx) { - final TelephonyManager tm = (TelephonyManager) ctx.getSystemService(TELEPHONY_SERVICE); - // TelephonyManager would uses the active data subscription, which should be the one used - // by tethering. - return (tm != null) ? tm.isTetheringApnRequired() : false; + return false; } public int getOffloadPollInterval() { From f581b6c646e31c78b4a8036f5b7bf58a8663f395 Mon Sep 17 00:00:00 2001 From: flawedworld Date: Sun, 17 Oct 2021 23:27:09 +0100 Subject: [PATCH 03/13] Use Cloudflare DNS servers instead of Google DNS servers for diagnostics, connectivity checking and tethering --- .../networkstack/tethering/TetheringConfiguration.java | 2 +- framework/src/android/net/util/DnsUtils.java | 4 ++-- .../com/android/server/connectivity/NetworkDiagnostics.java | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java b/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java index 9016cddbe7..a8904e0051 100644 --- a/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java +++ b/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java @@ -77,7 +77,7 @@ public class TetheringConfiguration { "192.168.48.2", "192.168.48.254", "192.168.49.2", "192.168.49.254", }; - private static final String[] DEFAULT_IPV4_DNS = {"8.8.4.4", "8.8.8.8"}; + private static final String[] DEFAULT_IPV4_DNS = {"1.0.0.1", "1.1.1.1"}; @VisibleForTesting public static final int TETHER_USB_RNDIS_FUNCTION = 0; diff --git a/framework/src/android/net/util/DnsUtils.java b/framework/src/android/net/util/DnsUtils.java index 3fe245edb9..d3e2f66105 100644 --- a/framework/src/android/net/util/DnsUtils.java +++ b/framework/src/android/net/util/DnsUtils.java @@ -342,7 +342,7 @@ private static int compareIpv6PrefixMatchLen(@NonNull InetAddress srcAddr, */ public static boolean haveIpv4(@Nullable Network network) { final SocketAddress addrIpv4 = - new InetSocketAddress(InetAddresses.parseNumericAddress("8.8.8.8"), 0); + new InetSocketAddress(InetAddresses.parseNumericAddress("1.1.1.1"), 0); return checkConnectivity(network, AF_INET, addrIpv4); } @@ -352,7 +352,7 @@ public static boolean haveIpv4(@Nullable Network network) { */ public static boolean haveIpv6(@Nullable Network network) { final SocketAddress addrIpv6 = - new InetSocketAddress(InetAddresses.parseNumericAddress("2000::"), 0); + new InetSocketAddress(InetAddresses.parseNumericAddress("2606:4700:4700::1001"), 0); return checkConnectivity(network, AF_INET6, addrIpv6); } diff --git a/service/src/com/android/server/connectivity/NetworkDiagnostics.java b/service/src/com/android/server/connectivity/NetworkDiagnostics.java index 3db37e59e0..8f36ba0d94 100644 --- a/service/src/com/android/server/connectivity/NetworkDiagnostics.java +++ b/service/src/com/android/server/connectivity/NetworkDiagnostics.java @@ -109,9 +109,9 @@ public class NetworkDiagnostics { private static final String TAG = "NetworkDiagnostics"; - private static final InetAddress TEST_DNS4 = InetAddresses.parseNumericAddress("8.8.8.8"); + private static final InetAddress TEST_DNS4 = InetAddresses.parseNumericAddress("1.1.1.1"); private static final InetAddress TEST_DNS6 = InetAddresses.parseNumericAddress( - "2001:4860:4860::8888"); + "2606:4700:4700::1001"); // For brevity elsewhere. private static final long now() { From fb37ff25dc77314260651905545743cff4992d40 Mon Sep 17 00:00:00 2001 From: flawedworld Date: Sun, 17 Oct 2021 23:31:28 +0100 Subject: [PATCH 04/13] default to GrapheneOS connectivity check server --- service/src/com/android/server/ConnectivityService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java index 51862033e4..ad2684841d 100755 --- a/service/src/com/android/server/ConnectivityService.java +++ b/service/src/com/android/server/ConnectivityService.java @@ -432,7 +432,7 @@ public class ConnectivityService extends IConnectivityManager.Stub * (preferably via runtime resource overlays). */ private static final String DEFAULT_CAPTIVE_PORTAL_HTTP_URL = - "http://connectivitycheck.gstatic.com/generate_204"; + "http://connectivitycheck.grapheneos.network/generate_204"; // TODO: create better separation between radio types and network types From 420c872d2665fbaeea03d1a062e9cd97439eb3a7 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Wed, 6 Oct 2021 03:05:49 +0300 Subject: [PATCH 05/13] enforce INTERNET permission per-uid instead of per-appId 13: 0a4c2f9719 --- bpf_progs/netd.c | 10 +-- .../connectivity/PermissionMonitor.java | 63 ++++++++++++++----- 2 files changed, 48 insertions(+), 25 deletions(-) diff --git a/bpf_progs/netd.c b/bpf_progs/netd.c index 5ce22279ad..a7c4b98986 100644 --- a/bpf_progs/netd.c +++ b/bpf_progs/netd.c @@ -662,14 +662,8 @@ DEFINE_XTBPF_PROG("skfilter/denylist/xtbpf", AID_ROOT, AID_NET_ADMIN, xt_bpf_den static __always_inline inline uint8_t get_app_permissions() { uint64_t gid_uid = bpf_get_current_uid_gid(); - /* - * A given app is guaranteed to have the same app ID in all the profiles in - * which it is installed, and install permission is granted to app for all - * user at install time so we only check the appId part of a request uid at - * run time. See UserHandle#isSameApp for detail. - */ - uint32_t appId = (gid_uid & 0xffffffff) % AID_USER_OFFSET; // == PER_USER_RANGE == 100000 - uint8_t* permissions = bpf_uid_permission_map_lookup_elem(&appId); + uint32_t uid = (gid_uid & 0xffffffff); + uint8_t* permissions = bpf_uid_permission_map_lookup_elem(&uid); // if UID not in map, then default to just INTERNET permission. return permissions ? *permissions : BPF_PERMISSION_INTERNET; } diff --git a/service/src/com/android/server/connectivity/PermissionMonitor.java b/service/src/com/android/server/connectivity/PermissionMonitor.java index beaa174f5b..3608008560 100755 --- a/service/src/com/android/server/connectivity/PermissionMonitor.java +++ b/service/src/com/android/server/connectivity/PermissionMonitor.java @@ -426,6 +426,11 @@ public synchronized void startMonitoring() { userAllContext.registerReceiver( mIntentReceiver, intentFilter, null /* broadcastPermission */, handler); + mPackageManager.addOnPermissionsChangeListener(uid -> { + // traffic permissions are INTERNET and UPDATE_DEVICE_STATS + handler.post(() -> sendPackagePermissionsForUid(uid, getTrafficPermissionForUid(uid))); + }); + // Listen to EXTERNAL_APPLICATIONS_AVAILABLE is that an app becoming available means it may // need to gain a permission. But an app that becomes unavailable can neither gain nor lose // permissions on that account, it just can no longer run. Thus, doesn't need to listen to @@ -600,7 +605,7 @@ synchronized void onUserAdded(@NonNull UserHandle user) { mUsersTrafficPermissions.put(user, addedUserAppIds); // Generate appIds from all users and send result to netd. final SparseIntArray appIds = makeAppIdsTrafficPermForAllUsers(); - sendAppIdsTrafficPermission(appIds); + sendUidsTrafficPermission(user.getIdentifier(), appIds); // Log user added mPermissionUpdateLogs.log("New user(" + user.getIdentifier() + ") added: nPerm uids=" @@ -649,7 +654,7 @@ synchronized void onUserRemoved(@NonNull UserHandle user) { appIds.put(appId, PERMISSION_UNINSTALLED); } } - sendAppIdsTrafficPermission(appIds); + sendUidsTrafficPermission(user.getIdentifier(), appIds); // Log user removed mPermissionUpdateLogs.log("User(" + user.getIdentifier() + ") removed: nPerm uids=" @@ -773,16 +778,25 @@ private synchronized void updateAppIdTrafficPermission(int uid) { } } - private synchronized int getAppIdTrafficPermission(int appId) { + private synchronized int getUidTrafficPermission(final int uid) { + final int userId = UserHandle.getUserId(uid); + int permission = PERMISSION_NONE; boolean installed = false; + for (UserHandle user : mUsersTrafficPermissions.keySet()) { + if (user.getIdentifier() != userId) { + continue; + } + final SparseIntArray userApps = mUsersTrafficPermissions.get(user); + final int appId = UserHandle.getAppId(uid); final int appIdx = userApps.indexOfKey(appId); if (appIdx >= 0) { permission |= userApps.valueAt(appIdx); installed = true; } + break; } return installed ? permission : PERMISSION_UNINSTALLED; } @@ -801,8 +815,8 @@ synchronized void onPackageAdded(@NonNull final String packageName, final int ui updateAppIdTrafficPermission(uid); // Get the appId permission from all users then send the latest permission to netd. final int appId = UserHandle.getAppId(uid); - final int appIdTrafficPerm = getAppIdTrafficPermission(appId); - sendPackagePermissionsForAppId(appId, appIdTrafficPerm); + final int uidTrafficPerm = getUidTrafficPermission(uid); + sendPackagePermissionsForUid(uid, uidTrafficPerm); final int currentPermission = mUidToNetworkPerm.get(uid, PERMISSION_NONE); final int permission = highestPermissionForUid(uid, currentPermission, packageName); @@ -832,7 +846,7 @@ synchronized void onPackageAdded(@NonNull final String packageName, final int ui mPermissionUpdateLogs.log("Package add: uid=" + uid + ", nPerm=(" + permissionToString(permission) + "/" + permissionToString(currentPermission) + ")" - + ", tPerm=" + permissionToString(appIdTrafficPerm)); + + ", tPerm=" + permissionToString(uidTrafficPerm)); } private int highestUidNetworkPermission(int uid) { @@ -865,8 +879,8 @@ synchronized void onPackageRemoved(@NonNull final String packageName, final int updateAppIdTrafficPermission(uid); // Get the appId permission from all users then send the latest permission to netd. final int appId = UserHandle.getAppId(uid); - final int appIdTrafficPerm = getAppIdTrafficPermission(appId); - sendPackagePermissionsForAppId(appId, appIdTrafficPerm); + final int uidTrafficPerm = getUidTrafficPermission(uid); + sendPackagePermissionsForUid(uid, uidTrafficPerm); // If the newly-removed package falls within some VPN's uid range, update Netd with it. // This needs to happen before the mUidToNetworkPerm update below, since @@ -886,7 +900,7 @@ synchronized void onPackageRemoved(@NonNull final String packageName, final int mPermissionUpdateLogs.log("Package remove: uid=" + uid + ", nPerm=(" + permissionToString(permission) + "/" + permissionToString(currentPermission) + ")" - + ", tPerm=" + permissionToString(appIdTrafficPerm)); + + ", tPerm=" + permissionToString(uidTrafficPerm)); if (permission != currentPermission) { final SparseIntArray apps = new SparseIntArray(); @@ -1135,14 +1149,17 @@ private void updateLockdownUidRule(int uid, boolean add) { * @hide */ @VisibleForTesting - void sendPackagePermissionsForAppId(int appId, int permissions) { + void sendPackagePermissionsForUid(int uid, int permissions) { + int userId = UserHandle.getUserId(uid); + int appId = UserHandle.getAppId(uid); + SparseIntArray netdPermissionsAppIds = new SparseIntArray(); netdPermissionsAppIds.put(appId, permissions); if (hasSdkSandbox(appId)) { int sdkSandboxAppId = sProcessShim.toSdkSandboxUid(appId); netdPermissionsAppIds.put(sdkSandboxAppId, permissions); } - sendAppIdsTrafficPermission(netdPermissionsAppIds); + sendUidsTrafficPermission(userId, netdPermissionsAppIds); } /** @@ -1154,7 +1171,7 @@ void sendPackagePermissionsForAppId(int appId, int permissions) { * @hide */ @VisibleForTesting - void sendAppIdsTrafficPermission(SparseIntArray netdPermissionsAppIds) { + void sendUidsTrafficPermission(final int userId, SparseIntArray netdPermissionsAppIds) { ensureRunningOnHandlerThread(); final ArrayList allPermissionAppIds = new ArrayList<>(); final ArrayList internetPermissionAppIds = new ArrayList<>(); @@ -1189,29 +1206,41 @@ void sendAppIdsTrafficPermission(SparseIntArray netdPermissionsAppIds) { if (allPermissionAppIds.size() != 0) { mBpfNetMaps.setNetPermForUids( PERMISSION_INTERNET | PERMISSION_UPDATE_DEVICE_STATS, - toIntArray(allPermissionAppIds)); + appIdListToUidArray(userId, allPermissionAppIds)); } if (internetPermissionAppIds.size() != 0) { mBpfNetMaps.setNetPermForUids(PERMISSION_INTERNET, - toIntArray(internetPermissionAppIds)); + appIdListToUidArray(userId, internetPermissionAppIds)); } if (updateStatsPermissionAppIds.size() != 0) { mBpfNetMaps.setNetPermForUids(PERMISSION_UPDATE_DEVICE_STATS, - toIntArray(updateStatsPermissionAppIds)); + appIdListToUidArray(userId, updateStatsPermissionAppIds)); } if (noPermissionAppIds.size() != 0) { mBpfNetMaps.setNetPermForUids(PERMISSION_NONE, - toIntArray(noPermissionAppIds)); + appIdListToUidArray(userId, noPermissionAppIds)); } if (uninstalledAppIds.size() != 0) { mBpfNetMaps.setNetPermForUids(PERMISSION_UNINSTALLED, - toIntArray(uninstalledAppIds)); + appIdListToUidArray(userId, uninstalledAppIds)); } } catch (RemoteException | ServiceSpecificException e) { Log.e(TAG, "Pass appId list of special permission failed." + e); } } + private static int[] appIdListToUidArray(int userId, ArrayList appIds) { + final int cnt = appIds.size(); + int[] array = new int[cnt]; + + for (int i = 0; i < cnt; ++i) { + int appId = appIds.get(i).intValue(); + array[i] = UserHandle.getUid(userId, appId); + } + + return array; + } + private synchronized void onSettingChanged() { // Step1. Update uids allowed to use restricted networks and compute the set of uids to // update. From fb1857bc41e475d45998a645d0f9c359b54bdb69 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Tue, 30 Aug 2022 12:27:52 +0300 Subject: [PATCH 06/13] don't crash INTERNET-unaware apps that try to access NsdManager --- .../src/android/net/nsd/NsdManager.java | 41 ++++++++++++++++--- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/framework-t/src/android/net/nsd/NsdManager.java b/framework-t/src/android/net/nsd/NsdManager.java index b21e22ad7b..f1c605c7ff 100644 --- a/framework-t/src/android/net/nsd/NsdManager.java +++ b/framework-t/src/android/net/nsd/NsdManager.java @@ -38,6 +38,7 @@ import android.net.ConnectivityThread; import android.net.Network; import android.net.NetworkRequest; +import android.net.nsd.IOffloadEngine; import android.os.Handler; import android.os.Looper; import android.os.Message; @@ -724,11 +725,41 @@ public NsdManager(Context context, INsdManager service) { // Instead of launching separate threads to handle tasks from the various instances. mHandler = new ServiceHandler(ConnectivityThread.getInstanceLooper()); - try { - mService = service.connect(new NsdCallbackImpl(mHandler), CompatChanges.isChangeEnabled( - ENABLE_PLATFORM_MDNS_BACKEND)); - } catch (RemoteException e) { - throw new RuntimeException("Failed to connect to NsdService"); + if (android.content.pm.SpecialRuntimePermAppUtils.isInternetCompatEnabled()) { + // INsdManager#connect() enforces INTERNET permission + mService = new INsdServiceConnector() { + final NsdCallbackImpl callback = new NsdCallbackImpl(mHandler); + + @Override public void registerService(int listenerKey, AdvertisingRequest advertisingRequest) { + callback.onRegisterServiceFailed(listenerKey, FAILURE_INTERNAL_ERROR); + } + @Override public void unregisterService(int listenerKey) { + callback.onUnregisterServiceFailed(listenerKey, FAILURE_INTERNAL_ERROR); + } + @Override public void discoverServices(int listenerKey, DiscoveryRequest discoveryRequest) { + callback.onDiscoverServicesFailed(listenerKey, FAILURE_INTERNAL_ERROR); + } + @Override public void stopDiscovery(int listenerKey) { + callback.onStopDiscoveryFailed(listenerKey, FAILURE_INTERNAL_ERROR); + } + @Override public void resolveService(int listenerKey, NsdServiceInfo serviceInfo) { + callback.onResolveServiceFailed(listenerKey, FAILURE_INTERNAL_ERROR); + } + @Override public void startDaemon() {} + @Override public void stopResolution(int listenerKey) {} + @Override public void registerServiceInfoCallback(int listenerKey, NsdServiceInfo serviceInfo) {} + @Override public void unregisterServiceInfoCallback(int listenerKey) {} + @Override public void registerOffloadEngine(String ifaceName, IOffloadEngine cb, long offloadCapabilities, long offloadType) {} + @Override public void unregisterOffloadEngine(IOffloadEngine cb) {} + @Override public android.os.IBinder asBinder() { return null; } + }; + } else { + try { + mService = service.connect(new NsdCallbackImpl(mHandler), CompatChanges.isChangeEnabled( + ENABLE_PLATFORM_MDNS_BACKEND)); + } catch (RemoteException e) { + throw new RuntimeException("Failed to connect to NsdService"); + } } // Only proactively start the daemon if the target SDK < S AND platform < V, For target From 72c9c97bedb5dc1cd02d9ad423466a9886c2aa4c Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Tue, 30 Aug 2022 13:18:56 +0300 Subject: [PATCH 07/13] use Cloudflare DNS for MTU detection in CLAT initialization --- .../src/com/android/server/connectivity/ClatCoordinator.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/service/src/com/android/server/connectivity/ClatCoordinator.java b/service/src/com/android/server/connectivity/ClatCoordinator.java index b1c770beed..bfaf1a6343 100644 --- a/service/src/com/android/server/connectivity/ClatCoordinator.java +++ b/service/src/com/android/server/connectivity/ClatCoordinator.java @@ -91,7 +91,7 @@ public class ClatCoordinator { static final String INIT_V4ADDR_STRING = "192.0.0.4"; @VisibleForTesting static final int INIT_V4ADDR_PREFIX_LEN = 29; - private static final InetAddress GOOGLE_DNS_4 = InetAddress.parseNumericAddress("8.8.8.8"); + private static final InetAddress CLOUDFLARE_DNS_4 = InetAddress.parseNumericAddress("1.1.1.1"); private static final int INVALID_IFINDEX = 0; @@ -645,7 +645,7 @@ public String clatStart(final String iface, final int netId, mNetd.interfaceSetEnableIPv6(tunIface, false /* enabled */); // Detect ipv4 mtu. final int detectedMtu = mDeps.detectMtu(pfx96Str, - ByteBuffer.wrap(GOOGLE_DNS_4.getAddress()).getInt(), fwmark); + ByteBuffer.wrap(CLOUDFLARE_DNS_4.getAddress()).getInt(), fwmark); final int mtu = adjustMtu(detectedMtu); Log.i(TAG, "detected ipv4 mtu of " + detectedMtu + " adjusted to " + mtu); // Config tun interface mtu, address and bring up. From 0d985538f46c8cfb2082e96ad7c5987438b2ca97 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Wed, 24 May 2023 13:09:08 +0300 Subject: [PATCH 08/13] extend connectivity checks setting to Dns{Tls,Udp}Check --- .../connectivity/NetworkDiagnostics.java | 77 +++++++++++++++++-- 1 file changed, 70 insertions(+), 7 deletions(-) diff --git a/service/src/com/android/server/connectivity/NetworkDiagnostics.java b/service/src/com/android/server/connectivity/NetworkDiagnostics.java index 8f36ba0d94..0711c0e1d4 100644 --- a/service/src/com/android/server/connectivity/NetworkDiagnostics.java +++ b/service/src/com/android/server/connectivity/NetworkDiagnostics.java @@ -30,6 +30,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.TargetApi; +import android.ext.settings.ConnChecksSetting; import android.net.InetAddresses; import android.net.LinkAddress; import android.net.LinkProperties; @@ -700,10 +701,9 @@ public void run() { // This needs to be fixed length so it can be dropped into the pre-canned packet. final String sixRandomDigits = String.valueOf(mRandom.nextInt(900000) + 100000); - appendDnsToMeasurementDescription(sixRandomDigits, mSocketAddress); - // Build a trivial DNS packet. final byte[] dnsPacket = getDnsQueryPacket(sixRandomDigits); + appendDnsToMeasurementDescription(sixRandomDigits, mSocketAddress); int count = 0; mMeasurement.startTime = now(); @@ -737,9 +737,12 @@ public void run() { close(); } + private String qnameEnding; + protected byte[] getDnsQueryPacket(String sixRandomDigits) { byte[] rnd = sixRandomDigits.getBytes(StandardCharsets.US_ASCII); - return new byte[] { + + byte[] start = { (byte) mRandom.nextInt(), (byte) mRandom.nextInt(), // [0-1] query ID 1, 0, // [2-3] flags; byte[2] = 1 for recursion desired (RD). 0, 1, // [4-5] QDCOUNT (number of queries) @@ -748,20 +751,80 @@ protected byte[] getDnsQueryPacket(String sixRandomDigits) { 0, 0, // [10-11] ARCOUNT (number of additional records) 17, rnd[0], rnd[1], rnd[2], rnd[3], rnd[4], rnd[5], '-', 'a', 'n', 'd', 'r', 'o', 'i', 'd', '-', 'd', 's', - 6, 'm', 'e', 't', 'r', 'i', 'c', - 7, 'g', 's', 't', 'a', 't', 'i', 'c', - 3, 'c', 'o', 'm', + }; + + final String qnameEnding; + if (ConnChecksSetting.get() == ConnChecksSetting.VAL_STANDARD) { + qnameEnding = "metric.gstatic.com"; + } else { + qnameEnding = "dnscheck.grapheneos.org"; + } + this.qnameEnding = qnameEnding; + byte[] middle = getQnameFragment(qnameEnding); + + byte[] end = { 0, // null terminator of FQDN (root TLD) 0, (byte) mQueryType, // QTYPE 0, 1 // QCLASS, set to 1 = IN (Internet) }; + + return concatByteArrays(start, middle, end); + } + + private byte[] concatByteArrays(byte[]... arrs) { + int len = 0; + for (byte[] arr : arrs) { + if (Integer.MAX_VALUE - len < arr.length) { + // overflow + throw new IllegalArgumentException(); + } + len += arr.length; + } + byte[] res = new byte[len]; + int off = 0; + for (byte[] arr : arrs) { + int l = arr.length; + System.arraycopy(arr, 0, res, off, l); + off += l; + } + return res; + } + + protected byte[] getQnameFragment(String hostnameFragment) { + String[] strArr = hostnameFragment.split("\\."); + int len = strArr.length; + byte[][] arr = new byte[len][]; + for (int i = 0; i < len; ++i) { + arr[i] = getQnameLabel(strArr[i]); + } + return concatByteArrays(arr); + } + + private byte[] getQnameLabel(String s) { + final int l = s.length(); + if (l > 0b11_1111 /* 63 */) { + // should be a 6 bit number + throw new IllegalArgumentException(s); + } + + byte[] res = new byte[1 + l]; + res[0] = (byte) l; + + for (int i = 0; i < l; ++i) { + int ch = s.charAt(i); + if (ch > 0x7f) { + throw new IllegalArgumentException(s); + } + res[1 + i] = (byte) ch; + } + return res; } protected void appendDnsToMeasurementDescription( String sixRandomDigits, SocketAddress sockAddr) { mMeasurement.description += " src{" + socketAddressToString(sockAddr) + "}" + " qtype{" + mQueryType + "}" - + " qname{" + sixRandomDigits + "-android-ds.metric.gstatic.com}"; + + " qname{" + sixRandomDigits + "-android-ds." + qnameEnding + "}"; } } From 0c0215f6a9f58d10b3cdb5df38109e1d8ff7b1d5 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Thu, 5 Oct 2023 09:39:18 +0300 Subject: [PATCH 09/13] ConnectivityManager: pretend that network is down to INTERNET-unaware callers --- .../src/android/net/ConnectivityManager.java | 129 ++++++++++++++++++ 1 file changed, 129 insertions(+) diff --git a/framework/src/android/net/ConnectivityManager.java b/framework/src/android/net/ConnectivityManager.java index 5f2416b5fe..5708f72136 100644 --- a/framework/src/android/net/ConnectivityManager.java +++ b/framework/src/android/net/ConnectivityManager.java @@ -45,6 +45,7 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.pm.SpecialRuntimePermAppUtils; import android.net.ConnectivityDiagnosticsManager.DataStallReport.DetectionMethod; import android.net.IpSecManager.UdpEncapsulationSocket; import android.net.SocketKeepalive.Callback; @@ -1493,6 +1494,10 @@ public int getNetworkPreference() { @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) @Nullable public NetworkInfo getActiveNetworkInfo() { + if (SpecialRuntimePermAppUtils.isInternetCompatEnabled()) { + return null; + } + try { return mService.getActiveNetworkInfo(); } catch (RemoteException e) { @@ -1514,6 +1519,10 @@ public NetworkInfo getActiveNetworkInfo() { @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) @Nullable public Network getActiveNetwork() { + if (SpecialRuntimePermAppUtils.isInternetCompatEnabled()) { + return null; + } + try { return mService.getActiveNetwork(); } catch (RemoteException e) { @@ -1747,6 +1756,10 @@ public NetworkInfo getActiveNetworkInfoForUid(int uid, boolean ignoreBlocked) { @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) @Nullable public NetworkInfo getNetworkInfo(int networkType) { + if (SpecialRuntimePermAppUtils.isInternetCompatEnabled()) { + return null; + } + try { return mService.getNetworkInfo(networkType); } catch (RemoteException e) { @@ -1768,6 +1781,10 @@ public NetworkInfo getNetworkInfo(int networkType) { @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) @Nullable public NetworkInfo getNetworkInfo(@Nullable Network network) { + if (SpecialRuntimePermAppUtils.isInternetCompatEnabled()) { + return null; + } + return getNetworkInfoForUid(network, Process.myUid(), false); } @@ -1794,6 +1811,10 @@ public NetworkInfo getNetworkInfoForUid(Network network, int uid, boolean ignore @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) @NonNull public NetworkInfo[] getAllNetworkInfo() { + if (SpecialRuntimePermAppUtils.isInternetCompatEnabled()) { + return new NetworkInfo[0]; + } + try { return mService.getAllNetworkInfo(); } catch (RemoteException e) { @@ -1833,6 +1854,10 @@ public List getAllNetworkStateSnapshots() { @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) @UnsupportedAppUsage public Network getNetworkForType(int networkType) { + if (SpecialRuntimePermAppUtils.isInternetCompatEnabled()) { + return null; + } + try { return mService.getNetworkForType(networkType); } catch (RemoteException e) { @@ -1856,6 +1881,10 @@ public Network getNetworkForType(int networkType) { @NonNull @Deprecated public Network[] getAllNetworks() { + if (SpecialRuntimePermAppUtils.isInternetCompatEnabled()) { + return new Network[0]; + } + try { return mService.getAllNetworks(); } catch (RemoteException e) { @@ -1894,6 +1923,10 @@ public NetworkCapabilities[] getDefaultNetworkCapabilitiesForUser(int userId) { @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 109783091) public LinkProperties getActiveLinkProperties() { + if (SpecialRuntimePermAppUtils.isInternetCompatEnabled()) { + return null; + } + try { return mService.getActiveLinkProperties(); } catch (RemoteException e) { @@ -1919,6 +1952,10 @@ public LinkProperties getActiveLinkProperties() { @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562) public LinkProperties getLinkProperties(int networkType) { + if (SpecialRuntimePermAppUtils.isInternetCompatEnabled()) { + return null; + } + try { return mService.getLinkPropertiesForType(networkType); } catch (RemoteException e) { @@ -1936,6 +1973,10 @@ public LinkProperties getLinkProperties(int networkType) { @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) @Nullable public LinkProperties getLinkProperties(@Nullable Network network) { + if (SpecialRuntimePermAppUtils.isInternetCompatEnabled()) { + return null; + } + try { return mService.getLinkProperties(network); } catch (RemoteException e) { @@ -1990,6 +2031,10 @@ public LinkProperties getRedactedLinkPropertiesForPackage(@NonNull LinkPropertie @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) @Nullable public NetworkCapabilities getNetworkCapabilities(@Nullable Network network) { + if (SpecialRuntimePermAppUtils.isInternetCompatEnabled()) { + return null; + } + try { return mService.getNetworkCapabilities( network, mContext.getOpPackageName(), getAttributionTag()); @@ -3002,6 +3047,10 @@ private static ConnectivityManager getInstance() { @UnsupportedAppUsage @Deprecated public String[] getTetherableIfaces() { + if (SpecialRuntimePermAppUtils.isInternetCompatEnabled()) { + return new String[0]; + } + return getTetheringManager().getTetherableIfaces(); } @@ -3017,6 +3066,10 @@ public String[] getTetherableIfaces() { @UnsupportedAppUsage @Deprecated public String[] getTetheredIfaces() { + if (SpecialRuntimePermAppUtils.isInternetCompatEnabled()) { + return new String[0]; + } + return getTetheringManager().getTetheredIfaces(); } @@ -3038,6 +3091,10 @@ public String[] getTetheredIfaces() { @UnsupportedAppUsage @Deprecated public String[] getTetheringErroredIfaces() { + if (SpecialRuntimePermAppUtils.isInternetCompatEnabled()) { + return new String[0]; + } + return getTetheringManager().getTetheringErroredIfaces(); } @@ -3348,6 +3405,10 @@ public void unregisterTetheringEventCallback( @UnsupportedAppUsage @Deprecated public String[] getTetherableUsbRegexs() { + if (SpecialRuntimePermAppUtils.isInternetCompatEnabled()) { + return new String[0]; + } + return getTetheringManager().getTetherableUsbRegexs(); } @@ -3366,6 +3427,10 @@ public String[] getTetherableUsbRegexs() { @UnsupportedAppUsage @Deprecated public String[] getTetherableWifiRegexs() { + if (SpecialRuntimePermAppUtils.isInternetCompatEnabled()) { + return new String[0]; + } + return getTetheringManager().getTetherableWifiRegexs(); } @@ -3385,6 +3450,10 @@ public String[] getTetherableWifiRegexs() { @UnsupportedAppUsage @Deprecated public String[] getTetherableBluetoothRegexs() { + if (SpecialRuntimePermAppUtils.isInternetCompatEnabled()) { + return new String[0]; + } + return getTetheringManager().getTetherableBluetoothRegexs(); } @@ -3525,6 +3594,10 @@ public int setUsbTethering(boolean enable) { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) @Deprecated public int getLastTetherError(String iface) { + if (SpecialRuntimePermAppUtils.isInternetCompatEnabled()) { + return TetheringManager.TETHER_ERROR_UNKNOWN_IFACE; + } + int error = getTetheringManager().getLastTetherError(iface); if (error == TetheringManager.TETHER_ERROR_UNKNOWN_TYPE) { // TETHER_ERROR_UNKNOWN_TYPE was introduced with TetheringManager and has never been @@ -3667,6 +3740,10 @@ public void reportBadNetwork(@Nullable Network network) { * Internet using {@code network} or {@code false} if not. */ public void reportNetworkConnectivity(@Nullable Network network, boolean hasConnectivity) { + if (SpecialRuntimePermAppUtils.isInternetCompatEnabled()) { + return; + } + printStackTrace(); try { mService.reportNetworkConnectivity(network, hasConnectivity); @@ -3773,6 +3850,10 @@ public ProxyInfo getDefaultProxy() { @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562) public boolean isNetworkSupported(int networkType) { + if (SpecialRuntimePermAppUtils.isInternetCompatEnabled()) { + return false; + } + try { return mService.isNetworkSupported(networkType); } catch (RemoteException e) { @@ -3793,6 +3874,10 @@ public boolean isNetworkSupported(int networkType) { */ @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public boolean isActiveNetworkMetered() { + if (SpecialRuntimePermAppUtils.isInternetCompatEnabled()) { + return false; + } + try { return mService.isActiveNetworkMetered(); } catch (RemoteException e) { @@ -4874,6 +4959,10 @@ public void requestNetwork(@NonNull NetworkRequest request, * corresponding NetworkRequest you'd like to remove. Cannot be null. */ public void releaseNetworkRequest(@NonNull PendingIntent operation) { + if (SpecialRuntimePermAppUtils.isInternetCompatEnabled()) { + return; + } + printStackTrace(); checkPendingIntentNotNull(operation); try { @@ -4921,6 +5010,10 @@ private static void checkTimeout(int timeoutMs) { @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerNetworkCallback(@NonNull NetworkRequest request, @NonNull NetworkCallback networkCallback) { + if (SpecialRuntimePermAppUtils.isInternetCompatEnabled()) { + return; + } + registerNetworkCallback(request, networkCallback, getDefaultHandler()); } @@ -4949,6 +5042,10 @@ public void registerNetworkCallback(@NonNull NetworkRequest request, @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerNetworkCallback(@NonNull NetworkRequest request, @NonNull NetworkCallback networkCallback, @NonNull Handler handler) { + if (SpecialRuntimePermAppUtils.isInternetCompatEnabled()) { + return; + } + CallbackHandler cbHandler = new CallbackHandler(handler); NetworkCapabilities nc = request.networkCapabilities; sendRequestForNetwork(nc, networkCallback, 0, LISTEN, TYPE_NONE, cbHandler); @@ -4997,6 +5094,10 @@ public void registerNetworkCallback(@NonNull NetworkRequest request, @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerNetworkCallback(@NonNull NetworkRequest request, @NonNull PendingIntent operation) { + if (SpecialRuntimePermAppUtils.isInternetCompatEnabled()) { + return; + } + printStackTrace(); checkPendingIntentNotNull(operation); try { @@ -5032,6 +5133,10 @@ public void registerNetworkCallback(@NonNull NetworkRequest request, */ @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerDefaultNetworkCallback(@NonNull NetworkCallback networkCallback) { + if (SpecialRuntimePermAppUtils.isInternetCompatEnabled()) { + return; + } + registerDefaultNetworkCallback(networkCallback, getDefaultHandler()); } @@ -5058,6 +5163,10 @@ public void registerDefaultNetworkCallback(@NonNull NetworkCallback networkCallb @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerDefaultNetworkCallback(@NonNull NetworkCallback networkCallback, @NonNull Handler handler) { + if (SpecialRuntimePermAppUtils.isInternetCompatEnabled()) { + return; + } + registerDefaultNetworkCallbackForUid(Process.INVALID_UID, networkCallback, handler); } @@ -5163,6 +5272,10 @@ public void registerSystemDefaultNetworkCallback(@NonNull NetworkCallback networ @SuppressLint("ExecutorRegistration") public void registerBestMatchingNetworkCallback(@NonNull NetworkRequest request, @NonNull NetworkCallback networkCallback, @NonNull Handler handler) { + if (SpecialRuntimePermAppUtils.isInternetCompatEnabled()) { + return; + } + final NetworkCapabilities nc = request.networkCapabilities; final CallbackHandler cbHandler = new CallbackHandler(handler); sendRequestForNetwork(nc, networkCallback, 0, LISTEN_FOR_BEST, TYPE_NONE, cbHandler); @@ -5181,6 +5294,10 @@ public void registerBestMatchingNetworkCallback(@NonNull NetworkRequest request, * @return {@code true} on success, {@code false} if the {@link Network} is no longer valid. */ public boolean requestBandwidthUpdate(@NonNull Network network) { + if (SpecialRuntimePermAppUtils.isInternetCompatEnabled()) { + return false; + } + try { return mService.requestBandwidthUpdate(network); } catch (RemoteException e) { @@ -5201,6 +5318,10 @@ public boolean requestBandwidthUpdate(@NonNull Network network) { * @param networkCallback The {@link NetworkCallback} used when making the request. */ public void unregisterNetworkCallback(@NonNull NetworkCallback networkCallback) { + if (SpecialRuntimePermAppUtils.isInternetCompatEnabled()) { + return; + } + printStackTrace(); checkCallbackNotNull(networkCallback); final List reqs = new ArrayList<>(); @@ -5243,6 +5364,10 @@ public void unregisterNetworkCallback(@NonNull NetworkCallback networkCallback) * Cannot be null. */ public void unregisterNetworkCallback(@NonNull PendingIntent operation) { + if (SpecialRuntimePermAppUtils.isInternetCompatEnabled()) { + return; + } + releaseNetworkRequest(operation); } @@ -5462,6 +5587,10 @@ public boolean shouldAvoidBadWifi() { */ @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public @MultipathPreference int getMultipathPreference(@Nullable Network network) { + if (SpecialRuntimePermAppUtils.isInternetCompatEnabled()) { + return 0; + } + try { return mService.getMultipathPreference(network); } catch (RemoteException e) { From da5bac051b878e2a76f550e2f2e1be46c2a8976c Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Thu, 19 Sep 2024 14:31:42 -0400 Subject: [PATCH 10/13] drop multicast when lockdown VPN enabled --- bpf_progs/netd.c | 96 ++++++++++++++++++++++++++++++++++++++++----- bpf_progs/netd.h | 1 + netd/BpfHandler.cpp | 8 +++- 3 files changed, 93 insertions(+), 12 deletions(-) diff --git a/bpf_progs/netd.c b/bpf_progs/netd.c index a7c4b98986..c0deb470d4 100644 --- a/bpf_progs/netd.c +++ b/bpf_progs/netd.c @@ -46,6 +46,10 @@ static const int BPF_MATCH = 1; static const bool TRACE_ON = true; static const bool TRACE_OFF = false; +// Used for setsockopt/lockdown_vpn_multicast. +static const int SETSOCKOPT_EPERM = 0; +static const int SETSOCKOPT_ALLOWED = 1; + // offsetof(struct iphdr, ihl) -- but that's a bitfield #define IPPROTO_IHL_OFF 0 @@ -406,13 +410,26 @@ static __always_inline inline bool ingress_should_discard(struct __sk_buff* skb, return true; // disallowed interface } +static __always_inline inline bool is_multicast(struct __sk_buff* skb, + const struct kver_uint kver) { + uint8_t addr_first_octet; + if (skb->protocol == htons(ETH_P_IP)) { + __u32 daddr4; + (void) bpf_skb_load_bytes_net(skb, IP4_OFFSET(daddr), &daddr4, sizeof(daddr4), kver); + addr_first_octet = (ntohl(daddr4) >> 24) & 0xFF; + if (addr_first_octet >= 224 && addr_first_octet <= 239) return true; + } else if (skb->protocol == htons(ETH_P_IPV6)) { + __u32 daddr6[4]; + (void) bpf_skb_load_bytes_net(skb, IP6_OFFSET(daddr), &daddr6, sizeof(daddr6), kver); + addr_first_octet = (ntohl(daddr6[0]) >> 24) & 0xFF; + if (addr_first_octet == 0xFF) return true; + } + return false; +} + static __always_inline inline int bpf_owner_match(struct __sk_buff* skb, uint32_t uid, const struct egress_bool egress, const struct kver_uint kver) { - if (is_system_uid(uid)) return PASS; - - if (skip_owner_match(skb, egress, kver)) return PASS; - BpfConfig enabledRules = getConfig(UID_RULES_CONFIGURATION_KEY); // BACKGROUND match does not apply to loopback traffic @@ -422,6 +439,14 @@ static __always_inline inline int bpf_owner_match(struct __sk_buff* skb, uint32_ uint32_t uidRules = uidEntry ? uidEntry->rule : 0; uint32_t allowed_iif = uidEntry ? uidEntry->iif : 0; + if ((uidRules & LOCKDOWN_VPN_MATCH) && is_multicast(skb, kver)) { + return DROP; + } + + if (is_system_uid(uid)) return PASS; + + if (skip_owner_match(skb, egress, kver)) return PASS; + if (isBlockedByUidRules(enabledRules, uidRules)) return DROP; if (!egress.egress && skb->ifindex != 1) { @@ -466,6 +491,8 @@ static __always_inline inline int bpf_traffic_account(struct __sk_buff* skb, // packets to an unconnected udp socket. // But it can also happen for egress from a timewait socket. // Let's treat such cases as 'root' which is_system_uid() + // TODO: Verify that this can never occur for multicast traffic. Have done manual testing, but + // need to read the kernel networking code to see if it is possible. if (sock_uid == 65534) sock_uid = 0; uint64_t cookie = bpf_get_socket_cookie(skb); // 0 iff !skb->sk @@ -732,7 +759,7 @@ DEFINE_NETD_V_BPF_PROG_KVER("sendmsg6/udp6_sendmsg", AID_ROOT, AID_ROOT, udp6_se return check_localhost(ctx); } -DEFINE_NETD_V_BPF_PROG_KVER("getsockopt/prog", AID_ROOT, AID_ROOT, getsockopt_prog, KVER_5_4) +DEFINE_NETD_V_BPF_PROG_KVER("getsockopt/prog", AID_ROOT, AID_ROOT, getsockopt_prog, KVER_5_8) (struct bpf_sockopt *ctx) { // Tell kernel to return 'original' kernel reply (instead of the bpf modified buffer) // This is important if the answer is larger than PAGE_SIZE (max size this bpf hook can provide) @@ -740,12 +767,61 @@ DEFINE_NETD_V_BPF_PROG_KVER("getsockopt/prog", AID_ROOT, AID_ROOT, getsockopt_pr return 1; // ALLOW } -DEFINE_NETD_V_BPF_PROG_KVER("setsockopt/prog", AID_ROOT, AID_ROOT, setsockopt_prog, KVER_5_4) -(struct bpf_sockopt *ctx) { - // Tell kernel to use/process original buffer provided by userspace. - // This is important if it is larger than PAGE_SIZE (max size this bpf hook can handle). +// Upstream uses 0 for attach_flags, so can only attach one program per attach type per cgroup. +// See include/uapi/linux/bpf.h. If this program becomes too difficult to understand once upstream +// are actually doing something with it, we can look into using BPF_F_ALLOW_MULTI or just using +// a separate function for each program. +// +// This program prevents kernel-generated multicast traffic (IGMP, MLD) from being triggered by a +// UID that is under a lockdown VPN. A known leak that still exists is when a UID joins a multicast +// group prior to being under a lockdown VPN and then becomes under a lockdown VPN. In this case the +// IGMP/MLD will be generated when the kernel destroys the thread. This is considered very low +// severity. +DEFINE_NETD_BPF_PROG_KVER("setsockopt/prog", AID_ROOT, AID_ROOT, setsockopt_prog, KVER_5_8) +(struct bpf_sockopt* ctx) { + // Force use of original userspace value in setsockopt call, otherwise will have problems with + // values > PAGE_SIZE. + // https://github.com/torvalds/linux/commit/d8fe449a9c51a37d844ab607e14e2f5c657d3cf2 ctx->optlen = 0; - return 1; // ALLOW + + uint64_t gid_uid = bpf_get_current_uid_gid(); + uint32_t uid = (gid_uid & 0xFFFFFFFF); + + UidOwnerValue* uidEntry = bpf_uid_owner_map_lookup_elem(&uid); + uint32_t uidRule = uidEntry ? uidEntry->rule : 0; + + if (!(uidRule & LOCKDOWN_VPN_MATCH)) { + return SETSOCKOPT_ALLOWED; + } + + if (ctx->level == IPPROTO_IP + && (ctx->optname == IP_ADD_MEMBERSHIP + || ctx->optname == IP_ADD_SOURCE_MEMBERSHIP + || ctx->optname == IP_DROP_MEMBERSHIP + || ctx->optname == IP_DROP_SOURCE_MEMBERSHIP + || ctx->optname == IP_BLOCK_SOURCE + || ctx->optname == IP_UNBLOCK_SOURCE + || ctx->optname == IP_MSFILTER)) { + return SETSOCKOPT_EPERM; + } + + if (ctx->level == IPPROTO_IPV6 + && (ctx->optname == IPV6_ADD_MEMBERSHIP /** IPV6_JOIN_GROUP **/ + || ctx->optname == IPV6_DROP_MEMBERSHIP /** IPV6_LEAVE_GROUP **/)) { + return SETSOCKOPT_EPERM; + } + + if ((ctx->level == IPPROTO_IP || ctx->level == IPPROTO_IPV6) + && (ctx->optname == MCAST_JOIN_GROUP + || ctx->optname == MCAST_LEAVE_GROUP + || ctx->optname == MCAST_BLOCK_SOURCE + || ctx->optname == MCAST_UNBLOCK_SOURCE + || ctx->optname == MCAST_JOIN_SOURCE_GROUP + || ctx->optname == MCAST_LEAVE_SOURCE_GROUP)) { + return SETSOCKOPT_EPERM; + } + + return SETSOCKOPT_ALLOWED; } LICENSE("Apache 2.0"); diff --git a/bpf_progs/netd.h b/bpf_progs/netd.h index 4877a4bfdd..7dc20aba12 100644 --- a/bpf_progs/netd.h +++ b/bpf_progs/netd.h @@ -165,6 +165,7 @@ ASSERT_STRING_EQUAL(XT_BPF_DENYLIST_PROG_PATH, BPF_NETD_PATH "prog_netd_skfilte #define CGROUP_UDP6_SENDMSG_PROG_PATH BPF_NETD_PATH "prog_netd_sendmsg6_udp6_sendmsg" #define CGROUP_GETSOCKOPT_PROG_PATH BPF_NETD_PATH "prog_netd_getsockopt_prog" #define CGROUP_SETSOCKOPT_PROG_PATH BPF_NETD_PATH "prog_netd_setsockopt_prog" +#define CGROUP_SOCKET_PROG_PATH BPF_NETD_PATH "prog_netd_cgroupsock_inet_create" #define TC_BPF_INGRESS_ACCOUNT_PROG_NAME "prog_netd_schedact_ingress_account" #define TC_BPF_INGRESS_ACCOUNT_PROG_PATH BPF_NETD_PATH TC_BPF_INGRESS_ACCOUNT_PROG_NAME diff --git a/netd/BpfHandler.cpp b/netd/BpfHandler.cpp index 0f84656dd1..9ceabf3ce2 100644 --- a/netd/BpfHandler.cpp +++ b/netd/BpfHandler.cpp @@ -128,7 +128,10 @@ static Status initPrograms(const char* cg2_path) { RETURN_IF_NOT_OK(attachProgramToCgroup(CGROUP_UDP6_SENDMSG_PROG_PATH, cg_fd, BPF_CGROUP_UDP6_SENDMSG)); - if (bpf::isAtLeastKernelVersion(5, 4, 0)) { + // BPF_PROG_TYPE_CGROUP_SOCKOPT was introduced in 5.3, but + // https://github.com/torvalds/linux/commit/d8fe449a9c51a37d844ab607e14e2f5c657d3cf2 was + // added in 5.8, which is required. + if (bpf::isAtLeastKernelVersion(5, 8, 0)) { RETURN_IF_NOT_OK(attachProgramToCgroup(CGROUP_GETSOCKOPT_PROG_PATH, cg_fd, BPF_CGROUP_GETSOCKOPT)); RETURN_IF_NOT_OK(attachProgramToCgroup(CGROUP_SETSOCKOPT_PROG_PATH, @@ -139,6 +142,7 @@ static Status initPrograms(const char* cg2_path) { RETURN_IF_NOT_OK(attachProgramToCgroup(CGROUP_INET_RELEASE_PROG_PATH, cg_fd, BPF_CGROUP_INET_SOCK_RELEASE)); } + } if (bpf::isAtLeastKernelVersion(4, 19, 0)) { @@ -166,7 +170,7 @@ static Status initPrograms(const char* cg2_path) { if (bpf::queryProgram(cg_fd, BPF_CGROUP_UDP4_SENDMSG) <= 0) abort(); if (bpf::queryProgram(cg_fd, BPF_CGROUP_UDP6_SENDMSG) <= 0) abort(); - if (bpf::isAtLeastKernelVersion(5, 4, 0)) { + if (bpf::isAtLeastKernelVersion(5, 8, 0)) { if (bpf::queryProgram(cg_fd, BPF_CGROUP_GETSOCKOPT) <= 0) abort(); if (bpf::queryProgram(cg_fd, BPF_CGROUP_SETSOCKOPT) <= 0) abort(); } From 040497d577f161e4dff97ebde4254a3e53de7703 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Sat, 19 Oct 2024 17:16:08 +0300 Subject: [PATCH 11/13] gmscompat: add stubs for NearbyManager API It's used by the Find My Device feature to locate offline devices. --- .../java/android/nearby/NearbyManager.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/nearby/framework/java/android/nearby/NearbyManager.java b/nearby/framework/java/android/nearby/NearbyManager.java index cae653d889..00db635e9c 100644 --- a/nearby/framework/java/android/nearby/NearbyManager.java +++ b/nearby/framework/java/android/nearby/NearbyManager.java @@ -26,6 +26,7 @@ import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.SystemService; +import android.app.compat.gms.GmsCompat; import android.bluetooth.BluetoothManager; import android.content.Context; import android.location.LocationManager; @@ -226,6 +227,9 @@ public int startScan(@NonNull ScanRequest scanRequest, } } catch (RemoteException e) { throw e.rethrowFromSystemServer(); + } catch (SecurityException e) { + GmsCompat.catchOrRethrow(e); + return ScanStatus.ERROR; } } @@ -261,6 +265,8 @@ public void stopScan(@NonNull ScanCallback scanCallback) { } } catch (RemoteException e) { throw e.rethrowFromSystemServer(); + } catch (SecurityException e) { + GmsCompat.catchOrRethrow(e); } } @@ -545,6 +551,8 @@ public void setPoweredOffFindingEphemeralIds(@NonNull List eids) { mService.setPoweredOffFindingEphemeralIds(ephemeralIdList); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); + } catch (SecurityException e) { + GmsCompat.catchOrRethrow(e); } } @@ -590,6 +598,8 @@ public void setPoweredOffFindingMode(@PoweredOffFindingMode int poweredOffFindin poweredOffFindingMode == POWERED_OFF_FINDING_MODE_ENABLED); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); + } catch (SecurityException e) { + GmsCompat.catchOrRethrow(e); } } @@ -613,6 +623,9 @@ public void setPoweredOffFindingMode(@PoweredOffFindingMode int poweredOffFindin ? POWERED_OFF_FINDING_MODE_ENABLED : POWERED_OFF_FINDING_MODE_DISABLED; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); + } catch (SecurityException e) { + GmsCompat.catchOrRethrow(e); + throw e; } } From 118033c3bc45d3944cd6bb77b6a22f2b6015a21b Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Sun, 20 Oct 2024 17:15:56 +0300 Subject: [PATCH 12/13] fixup! gmscompat: add stubs for NearbyManager API --- nearby/framework/java/android/nearby/NearbyManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nearby/framework/java/android/nearby/NearbyManager.java b/nearby/framework/java/android/nearby/NearbyManager.java index 00db635e9c..68ef9afcd1 100644 --- a/nearby/framework/java/android/nearby/NearbyManager.java +++ b/nearby/framework/java/android/nearby/NearbyManager.java @@ -625,7 +625,7 @@ public void setPoweredOffFindingMode(@PoweredOffFindingMode int poweredOffFindin throw e.rethrowFromSystemServer(); } catch (SecurityException e) { GmsCompat.catchOrRethrow(e); - throw e; + return POWERED_OFF_FINDING_MODE_DISABLED; } } From a0a8fbf08bb2f3817aac57eaa54772e23278be59 Mon Sep 17 00:00:00 2001 From: quh4gko8 <88831734+quh4gko8@users.noreply.github.com> Date: Sun, 27 Oct 2024 09:56:04 +0000 Subject: [PATCH 13/13] Set allocated size for permission mapping to maximum number of uid possible on production builds --- bpf_progs/netd.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bpf_progs/netd.h b/bpf_progs/netd.h index 7dc20aba12..45efc99dfc 100644 --- a/bpf_progs/netd.h +++ b/bpf_progs/netd.h @@ -117,13 +117,13 @@ STRUCT_SIZE(PacketTrace, 8+4+4 + 4+4 + 2+2 + 1+1+1+1); // 'static' - otherwise these constants end up in .rodata in the resulting .o post compilation static const int COOKIE_UID_MAP_SIZE = 10000; -static const int UID_COUNTERSET_MAP_SIZE = 4000; +static const int UID_COUNTERSET_MAP_SIZE = 3300000; static const int APP_STATS_MAP_SIZE = 10000; static const int STATS_MAP_SIZE = 5000; static const int IFACE_INDEX_NAME_MAP_SIZE = 1000; static const int IFACE_STATS_MAP_SIZE = 1000; static const int CONFIGURATION_MAP_SIZE = 2; -static const int UID_OWNER_MAP_SIZE = 4000; +static const int UID_OWNER_MAP_SIZE = 3300000; static const int INGRESS_DISCARD_MAP_SIZE = 100; static const int PACKET_TRACE_BUF_SIZE = 32 * 1024; static const int DATA_SAVER_ENABLED_MAP_SIZE = 1;