Loading core/java/android/net/NetworkStack.java +55 −0 Original line number Diff line number Diff line Loading @@ -15,9 +15,16 @@ */ package android.net; import static android.Manifest.permission.NETWORK_STACK; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import android.annotation.NonNull; import android.annotation.SystemApi; import android.annotation.TestApi; import android.content.Context; import java.util.ArrayList; import java.util.Arrays; /** * * Constants for client code communicating with the network stack service. Loading @@ -37,4 +44,52 @@ public class NetworkStack { "android.permission.MAINLINE_NETWORK_STACK"; private NetworkStack() {} /** * If the NetworkStack, MAINLINE_NETWORK_STACK are not allowed for a particular process, throw a * {@link SecurityException}. * * @param context {@link android.content.Context} for the process. * * @hide */ public static void checkNetworkStackPermission(final @NonNull Context context) { checkNetworkStackPermissionOr(context); } /** * If the NetworkStack, MAINLINE_NETWORK_STACK or other specified permissions are not allowed * for a particular process, throw a {@link SecurityException}. * * @param context {@link android.content.Context} for the process. * @param otherPermissions The set of permissions that could be the candidate permissions , or * empty string if none of other permissions needed. * @hide */ public static void checkNetworkStackPermissionOr(final @NonNull Context context, final @NonNull String... otherPermissions) { ArrayList<String> permissions = new ArrayList<String>(Arrays.asList(otherPermissions)); permissions.add(NETWORK_STACK); permissions.add(PERMISSION_MAINLINE_NETWORK_STACK); enforceAnyPermissionOf(context, permissions.toArray(new String[0])); } private static void enforceAnyPermissionOf(final @NonNull Context context, final @NonNull String... permissions) { if (!checkAnyPermissionOf(context, permissions)) { throw new SecurityException("Requires one of the following permissions: " + String.join(", ", permissions) + "."); } } private static boolean checkAnyPermissionOf(final @NonNull Context context, final @NonNull String... permissions) { for (String permission : permissions) { if (context.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED) { return true; } } return false; } } services/core/java/com/android/server/net/NetworkStatsService.java +2 −1 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ import static android.content.Intent.ACTION_USER_REMOVED; import static android.content.Intent.EXTRA_UID; import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED; import static android.net.ConnectivityManager.isNetworkTypeMobile; import static android.net.NetworkStack.checkNetworkStackPermission; import static android.net.NetworkStats.DEFAULT_NETWORK_ALL; import static android.net.NetworkStats.IFACE_ALL; import static android.net.NetworkStats.INTERFACES_ALL; Loading Loading @@ -899,7 +900,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { VpnInfo[] vpnArray, NetworkState[] networkStates, String activeIface) { mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); checkNetworkStackPermission(mContext); assertBandwidthControlEnabled(); final long token = Binder.clearCallingIdentity(); Loading tests/net/java/android/net/NetworkStackTest.java 0 → 100644 +75 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 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. */ package android.net; import static android.Manifest.permission.NETWORK_STACK; import static android.content.pm.PackageManager.PERMISSION_DENIED; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK; import static android.net.NetworkStack.checkNetworkStackPermission; import static android.net.NetworkStack.checkNetworkStackPermissionOr; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.any; import static org.mockito.Mockito.when; import android.content.Context; import androidx.test.runner.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @RunWith(AndroidJUnit4.class) public class NetworkStackTest { private static final String [] OTHER_PERMISSION = {"otherpermission1", "otherpermission2"}; @Mock Context mCtx; @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); } @Test public void testCheckNetworkStackPermission() throws Exception { when(mCtx.checkCallingOrSelfPermission(eq(NETWORK_STACK))).thenReturn(PERMISSION_GRANTED); when(mCtx.checkCallingOrSelfPermission(eq(PERMISSION_MAINLINE_NETWORK_STACK))) .thenReturn(PERMISSION_DENIED); checkNetworkStackPermission(mCtx); checkNetworkStackPermissionOr(mCtx, OTHER_PERMISSION); when(mCtx.checkCallingOrSelfPermission(eq(NETWORK_STACK))).thenReturn(PERMISSION_DENIED); when(mCtx.checkCallingOrSelfPermission(eq(PERMISSION_MAINLINE_NETWORK_STACK))) .thenReturn(PERMISSION_GRANTED); checkNetworkStackPermission(mCtx); checkNetworkStackPermissionOr(mCtx, OTHER_PERMISSION); when(mCtx.checkCallingOrSelfPermission(any())).thenReturn(PERMISSION_DENIED); try { checkNetworkStackPermissionOr(mCtx, OTHER_PERMISSION); } catch (SecurityException e) { // Expect to get a SecurityException return; } fail("Expect fail but permission granted."); } } Loading
core/java/android/net/NetworkStack.java +55 −0 Original line number Diff line number Diff line Loading @@ -15,9 +15,16 @@ */ package android.net; import static android.Manifest.permission.NETWORK_STACK; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import android.annotation.NonNull; import android.annotation.SystemApi; import android.annotation.TestApi; import android.content.Context; import java.util.ArrayList; import java.util.Arrays; /** * * Constants for client code communicating with the network stack service. Loading @@ -37,4 +44,52 @@ public class NetworkStack { "android.permission.MAINLINE_NETWORK_STACK"; private NetworkStack() {} /** * If the NetworkStack, MAINLINE_NETWORK_STACK are not allowed for a particular process, throw a * {@link SecurityException}. * * @param context {@link android.content.Context} for the process. * * @hide */ public static void checkNetworkStackPermission(final @NonNull Context context) { checkNetworkStackPermissionOr(context); } /** * If the NetworkStack, MAINLINE_NETWORK_STACK or other specified permissions are not allowed * for a particular process, throw a {@link SecurityException}. * * @param context {@link android.content.Context} for the process. * @param otherPermissions The set of permissions that could be the candidate permissions , or * empty string if none of other permissions needed. * @hide */ public static void checkNetworkStackPermissionOr(final @NonNull Context context, final @NonNull String... otherPermissions) { ArrayList<String> permissions = new ArrayList<String>(Arrays.asList(otherPermissions)); permissions.add(NETWORK_STACK); permissions.add(PERMISSION_MAINLINE_NETWORK_STACK); enforceAnyPermissionOf(context, permissions.toArray(new String[0])); } private static void enforceAnyPermissionOf(final @NonNull Context context, final @NonNull String... permissions) { if (!checkAnyPermissionOf(context, permissions)) { throw new SecurityException("Requires one of the following permissions: " + String.join(", ", permissions) + "."); } } private static boolean checkAnyPermissionOf(final @NonNull Context context, final @NonNull String... permissions) { for (String permission : permissions) { if (context.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED) { return true; } } return false; } }
services/core/java/com/android/server/net/NetworkStatsService.java +2 −1 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ import static android.content.Intent.ACTION_USER_REMOVED; import static android.content.Intent.EXTRA_UID; import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED; import static android.net.ConnectivityManager.isNetworkTypeMobile; import static android.net.NetworkStack.checkNetworkStackPermission; import static android.net.NetworkStats.DEFAULT_NETWORK_ALL; import static android.net.NetworkStats.IFACE_ALL; import static android.net.NetworkStats.INTERFACES_ALL; Loading Loading @@ -899,7 +900,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { VpnInfo[] vpnArray, NetworkState[] networkStates, String activeIface) { mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); checkNetworkStackPermission(mContext); assertBandwidthControlEnabled(); final long token = Binder.clearCallingIdentity(); Loading
tests/net/java/android/net/NetworkStackTest.java 0 → 100644 +75 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 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. */ package android.net; import static android.Manifest.permission.NETWORK_STACK; import static android.content.pm.PackageManager.PERMISSION_DENIED; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK; import static android.net.NetworkStack.checkNetworkStackPermission; import static android.net.NetworkStack.checkNetworkStackPermissionOr; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.any; import static org.mockito.Mockito.when; import android.content.Context; import androidx.test.runner.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @RunWith(AndroidJUnit4.class) public class NetworkStackTest { private static final String [] OTHER_PERMISSION = {"otherpermission1", "otherpermission2"}; @Mock Context mCtx; @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); } @Test public void testCheckNetworkStackPermission() throws Exception { when(mCtx.checkCallingOrSelfPermission(eq(NETWORK_STACK))).thenReturn(PERMISSION_GRANTED); when(mCtx.checkCallingOrSelfPermission(eq(PERMISSION_MAINLINE_NETWORK_STACK))) .thenReturn(PERMISSION_DENIED); checkNetworkStackPermission(mCtx); checkNetworkStackPermissionOr(mCtx, OTHER_PERMISSION); when(mCtx.checkCallingOrSelfPermission(eq(NETWORK_STACK))).thenReturn(PERMISSION_DENIED); when(mCtx.checkCallingOrSelfPermission(eq(PERMISSION_MAINLINE_NETWORK_STACK))) .thenReturn(PERMISSION_GRANTED); checkNetworkStackPermission(mCtx); checkNetworkStackPermissionOr(mCtx, OTHER_PERMISSION); when(mCtx.checkCallingOrSelfPermission(any())).thenReturn(PERMISSION_DENIED); try { checkNetworkStackPermissionOr(mCtx, OTHER_PERMISSION); } catch (SecurityException e) { // Expect to get a SecurityException return; } fail("Expect fail but permission granted."); } }