1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server; 18 19 import static android.os.Build.VERSION_CODES.R; 20 21 import static com.android.testutils.ContextUtils.mockService; 22 import static com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo; 23 import static com.android.testutils.MiscAsserts.assertThrows; 24 25 import static org.junit.Assert.assertEquals; 26 import static org.junit.Assert.assertFalse; 27 import static org.junit.Assert.assertNotNull; 28 import static org.junit.Assert.assertNull; 29 import static org.junit.Assert.assertTrue; 30 import static org.mockito.ArgumentMatchers.any; 31 import static org.mockito.ArgumentMatchers.eq; 32 import static org.mockito.Mockito.doReturn; 33 import static org.mockito.Mockito.never; 34 import static org.mockito.Mockito.times; 35 import static org.mockito.Mockito.verify; 36 37 import android.annotation.UserIdInt; 38 import android.content.BroadcastReceiver; 39 import android.content.Context; 40 import android.content.Intent; 41 import android.content.pm.PackageManager; 42 import android.net.ConnectivityManager; 43 import android.net.INetd; 44 import android.net.Uri; 45 import android.os.Handler; 46 import android.os.HandlerThread; 47 import android.os.INetworkManagementService; 48 import android.os.Looper; 49 import android.os.UserHandle; 50 import android.os.UserManager; 51 import android.security.Credentials; 52 53 import androidx.test.filters.SmallTest; 54 55 import com.android.internal.net.VpnProfile; 56 import com.android.server.connectivity.Vpn; 57 import com.android.server.connectivity.VpnProfileStore; 58 import com.android.server.net.LockdownVpnTracker; 59 import com.android.testutils.DevSdkIgnoreRule; 60 import com.android.testutils.DevSdkIgnoreRunner; 61 import com.android.testutils.HandlerUtils; 62 63 import org.junit.Before; 64 import org.junit.Rule; 65 import org.junit.Test; 66 import org.junit.runner.RunWith; 67 import org.mockito.ArgumentCaptor; 68 import org.mockito.Mock; 69 import org.mockito.MockitoAnnotations; 70 71 import java.nio.charset.StandardCharsets; 72 import java.util.List; 73 74 @RunWith(DevSdkIgnoreRunner.class) 75 @IgnoreUpTo(R) // VpnManagerService is not available before R 76 @SmallTest 77 public class VpnManagerServiceTest extends VpnTestBase { 78 private static final String CONTEXT_ATTRIBUTION_TAG = "VPN_MANAGER"; 79 80 @Rule 81 public final DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule(); 82 83 private static final int TIMEOUT_MS = 2_000; 84 85 @Mock Context mContext; 86 @Mock Context mContextWithoutAttributionTag; 87 @Mock Context mSystemContext; 88 @Mock Context mUserAllContext; 89 private HandlerThread mHandlerThread; 90 @Mock private Vpn mVpn; 91 @Mock private INetworkManagementService mNms; 92 @Mock private ConnectivityManager mCm; 93 @Mock private UserManager mUserManager; 94 @Mock private INetd mNetd; 95 @Mock private PackageManager mPackageManager; 96 @Mock private VpnProfileStore mVpnProfileStore; 97 @Mock private LockdownVpnTracker mLockdownVpnTracker; 98 99 private VpnManagerServiceDependencies mDeps; 100 private VpnManagerService mService; 101 private BroadcastReceiver mUserPresentReceiver; 102 private BroadcastReceiver mIntentReceiver; 103 private final String mNotMyVpnPkg = "com.not.my.vpn"; 104 105 class VpnManagerServiceDependencies extends VpnManagerService.Dependencies { 106 @Override makeHandlerThread()107 public HandlerThread makeHandlerThread() { 108 return mHandlerThread; 109 } 110 111 @Override getINetworkManagementService()112 public INetworkManagementService getINetworkManagementService() { 113 return mNms; 114 } 115 116 @Override getNetd()117 public INetd getNetd() { 118 return mNetd; 119 } 120 121 @Override createVpn(Looper looper, Context context, INetworkManagementService nms, INetd netd, @UserIdInt int userId)122 public Vpn createVpn(Looper looper, Context context, INetworkManagementService nms, 123 INetd netd, @UserIdInt int userId) { 124 return mVpn; 125 } 126 127 @Override getVpnProfileStore()128 public VpnProfileStore getVpnProfileStore() { 129 return mVpnProfileStore; 130 } 131 132 @Override createLockDownVpnTracker(Context context, Handler handler, Vpn vpn, VpnProfile profile)133 public LockdownVpnTracker createLockDownVpnTracker(Context context, Handler handler, 134 Vpn vpn, VpnProfile profile) { 135 return mLockdownVpnTracker; 136 } 137 138 @Override getMainUserId()139 public @UserIdInt int getMainUserId() { 140 return UserHandle.USER_SYSTEM; 141 } 142 } 143 144 @Before setUp()145 public void setUp() throws Exception { 146 MockitoAnnotations.initMocks(this); 147 148 mHandlerThread = new HandlerThread("TestVpnManagerService"); 149 mDeps = new VpnManagerServiceDependencies(); 150 151 // The attribution tag is a dependency for IKE library to collect VPN metrics correctly 152 // and thus should not be changed without updating the IKE code. 153 doReturn(mContext) 154 .when(mContextWithoutAttributionTag) 155 .createAttributionContext(CONTEXT_ATTRIBUTION_TAG); 156 157 doReturn(mUserAllContext).when(mContext).createContextAsUser(UserHandle.ALL, 0); 158 doReturn(mSystemContext).when(mContext).createContextAsUser(UserHandle.SYSTEM, 0); 159 doReturn(mPackageManager).when(mContext).getPackageManager(); 160 setMockedPackages(mPackageManager, sPackages); 161 162 mockService(mContext, ConnectivityManager.class, Context.CONNECTIVITY_SERVICE, mCm); 163 mockService(mContext, UserManager.class, Context.USER_SERVICE, mUserManager); 164 doReturn(SYSTEM_USER).when(mUserManager).getUserInfo(eq(SYSTEM_USER_ID)); 165 166 mService = new VpnManagerService(mContextWithoutAttributionTag, mDeps); 167 mService.systemReady(); 168 169 final ArgumentCaptor<BroadcastReceiver> intentReceiverCaptor = 170 ArgumentCaptor.forClass(BroadcastReceiver.class); 171 final ArgumentCaptor<BroadcastReceiver> userPresentReceiverCaptor = 172 ArgumentCaptor.forClass(BroadcastReceiver.class); 173 verify(mSystemContext).registerReceiver( 174 userPresentReceiverCaptor.capture(), any(), any(), any()); 175 verify(mUserAllContext, times(2)).registerReceiver( 176 intentReceiverCaptor.capture(), any(), any(), any()); 177 mUserPresentReceiver = userPresentReceiverCaptor.getValue(); 178 mIntentReceiver = intentReceiverCaptor.getValue(); 179 180 // Add user to create vpn in mVpn 181 onUserStarted(SYSTEM_USER_ID); 182 assertNotNull(mService.mVpns.get(SYSTEM_USER_ID)); 183 } 184 185 @Test testUpdateAppExclusionList()186 public void testUpdateAppExclusionList() { 187 // Start vpn 188 mService.startVpnProfile(TEST_VPN_PKG); 189 verify(mVpn).startVpnProfile(eq(TEST_VPN_PKG)); 190 191 // Remove package due to package replaced. 192 onPackageRemoved(PKGS[0], PKG_UIDS[0], true /* isReplacing */); 193 verify(mVpn, never()).refreshPlatformVpnAppExclusionList(); 194 195 // Add package due to package replaced. 196 onPackageAdded(PKGS[0], PKG_UIDS[0], true /* isReplacing */); 197 verify(mVpn, never()).refreshPlatformVpnAppExclusionList(); 198 199 // Remove package 200 onPackageRemoved(PKGS[0], PKG_UIDS[0], false /* isReplacing */); 201 verify(mVpn).refreshPlatformVpnAppExclusionList(); 202 203 // Add the package back 204 onPackageAdded(PKGS[0], PKG_UIDS[0], false /* isReplacing */); 205 verify(mVpn, times(2)).refreshPlatformVpnAppExclusionList(); 206 } 207 208 @Test testStartVpnProfileFromDiffPackage()209 public void testStartVpnProfileFromDiffPackage() { 210 assertThrows( 211 SecurityException.class, () -> mService.startVpnProfile(mNotMyVpnPkg)); 212 } 213 214 @Test testStopVpnProfileFromDiffPackage()215 public void testStopVpnProfileFromDiffPackage() { 216 assertThrows(SecurityException.class, () -> mService.stopVpnProfile(mNotMyVpnPkg)); 217 } 218 219 @Test testGetProvisionedVpnProfileStateFromDiffPackage()220 public void testGetProvisionedVpnProfileStateFromDiffPackage() { 221 assertThrows(SecurityException.class, () -> 222 mService.getProvisionedVpnProfileState(mNotMyVpnPkg)); 223 } 224 225 @Test testGetProvisionedVpnProfileState()226 public void testGetProvisionedVpnProfileState() { 227 mService.getProvisionedVpnProfileState(TEST_VPN_PKG); 228 verify(mVpn).getProvisionedVpnProfileState(TEST_VPN_PKG); 229 } 230 buildIntent(String action, String packageName, int userId, int uid, boolean isReplacing)231 private Intent buildIntent(String action, String packageName, int userId, int uid, 232 boolean isReplacing) { 233 final Intent intent = new Intent(action); 234 intent.putExtra(Intent.EXTRA_USER_HANDLE, userId); 235 intent.putExtra(Intent.EXTRA_UID, uid); 236 intent.putExtra(Intent.EXTRA_REPLACING, isReplacing); 237 if (packageName != null) { 238 intent.setData(Uri.fromParts("package" /* scheme */, packageName, null /* fragment */)); 239 } 240 241 return intent; 242 } 243 sendIntent(Intent intent)244 private void sendIntent(Intent intent) { 245 sendIntent(mIntentReceiver, mContext, intent); 246 } 247 sendIntent(BroadcastReceiver receiver, Context context, Intent intent)248 private void sendIntent(BroadcastReceiver receiver, Context context, Intent intent) { 249 final Handler h = mHandlerThread.getThreadHandler(); 250 251 // Send in handler thread. 252 h.post(() -> receiver.onReceive(context, intent)); 253 HandlerUtils.waitForIdle(mHandlerThread, TIMEOUT_MS); 254 } 255 onUserStarted(int userId)256 private void onUserStarted(int userId) { 257 sendIntent(buildIntent(Intent.ACTION_USER_STARTED, 258 null /* packageName */, userId, -1 /* uid */, false /* isReplacing */)); 259 } 260 onUserUnlocked(int userId)261 private void onUserUnlocked(int userId) { 262 sendIntent(buildIntent(Intent.ACTION_USER_UNLOCKED, 263 null /* packageName */, userId, -1 /* uid */, false /* isReplacing */)); 264 } 265 onUserStopped(int userId)266 private void onUserStopped(int userId) { 267 sendIntent(buildIntent(Intent.ACTION_USER_STOPPED, 268 null /* packageName */, userId, -1 /* uid */, false /* isReplacing */)); 269 } 270 onLockDownReset()271 private void onLockDownReset() { 272 sendIntent(buildIntent(LockdownVpnTracker.ACTION_LOCKDOWN_RESET, null /* packageName */, 273 UserHandle.USER_SYSTEM, -1 /* uid */, false /* isReplacing */)); 274 } 275 onPackageAdded(String packageName, int userId, int uid, boolean isReplacing)276 private void onPackageAdded(String packageName, int userId, int uid, boolean isReplacing) { 277 sendIntent(buildIntent(Intent.ACTION_PACKAGE_ADDED, packageName, userId, uid, isReplacing)); 278 } 279 onPackageAdded(String packageName, int uid, boolean isReplacing)280 private void onPackageAdded(String packageName, int uid, boolean isReplacing) { 281 onPackageAdded(packageName, UserHandle.USER_SYSTEM, uid, isReplacing); 282 } 283 onPackageRemoved(String packageName, int userId, int uid, boolean isReplacing)284 private void onPackageRemoved(String packageName, int userId, int uid, boolean isReplacing) { 285 sendIntent(buildIntent(Intent.ACTION_PACKAGE_REMOVED, packageName, userId, uid, 286 isReplacing)); 287 } 288 onPackageRemoved(String packageName, int uid, boolean isReplacing)289 private void onPackageRemoved(String packageName, int uid, boolean isReplacing) { 290 onPackageRemoved(packageName, UserHandle.USER_SYSTEM, uid, isReplacing); 291 } 292 293 @Test testReceiveIntentFromNonHandlerThread()294 public void testReceiveIntentFromNonHandlerThread() { 295 assertThrows(IllegalStateException.class, () -> 296 mIntentReceiver.onReceive(mContext, buildIntent(Intent.ACTION_PACKAGE_REMOVED, 297 PKGS[0], UserHandle.USER_SYSTEM, PKG_UIDS[0], true /* isReplacing */))); 298 299 assertThrows(IllegalStateException.class, () -> 300 mUserPresentReceiver.onReceive(mContext, new Intent(Intent.ACTION_USER_PRESENT))); 301 } 302 setupLockdownVpn(String packageName)303 private void setupLockdownVpn(String packageName) { 304 final byte[] profileTag = packageName.getBytes(StandardCharsets.UTF_8); 305 doReturn(profileTag).when(mVpnProfileStore).get(Credentials.LOCKDOWN_VPN); 306 } 307 setupVpnProfile(String profileName)308 private void setupVpnProfile(String profileName) { 309 final VpnProfile profile = new VpnProfile(profileName); 310 profile.name = profileName; 311 profile.server = "192.0.2.1"; 312 profile.dnsServers = "8.8.8.8"; 313 profile.type = VpnProfile.TYPE_IPSEC_XAUTH_PSK; 314 final byte[] encodedProfile = profile.encode(); 315 doReturn(encodedProfile).when(mVpnProfileStore).get(Credentials.VPN + profileName); 316 } 317 318 @Test testUserPresent()319 public void testUserPresent() { 320 // Verify that LockDownVpnTracker is not created. 321 verify(mLockdownVpnTracker, never()).init(); 322 323 setupLockdownVpn(TEST_VPN_PKG); 324 setupVpnProfile(TEST_VPN_PKG); 325 326 // mUserPresentReceiver only registers ACTION_USER_PRESENT intent and does no verification 327 // on action, so an empty intent is enough. 328 sendIntent(mUserPresentReceiver, mSystemContext, new Intent()); 329 330 verify(mLockdownVpnTracker).init(); 331 verify(mSystemContext).unregisterReceiver(mUserPresentReceiver); 332 verify(mUserAllContext, never()).unregisterReceiver(any()); 333 } 334 335 @Test testUpdateLockdownVpn()336 public void testUpdateLockdownVpn() { 337 setupLockdownVpn(TEST_VPN_PKG); 338 onUserUnlocked(SYSTEM_USER_ID); 339 340 // Will not create lockDownVpnTracker w/o valid profile configured in the keystore 341 verify(mLockdownVpnTracker, never()).init(); 342 343 setupVpnProfile(TEST_VPN_PKG); 344 345 // Remove the user from mVpns 346 onUserStopped(SYSTEM_USER_ID); 347 onUserUnlocked(SYSTEM_USER_ID); 348 verify(mLockdownVpnTracker, never()).init(); 349 350 // Add user back 351 onUserStarted(SYSTEM_USER_ID); 352 verify(mLockdownVpnTracker).init(); 353 354 // Trigger another update. The existing LockDownVpnTracker should be shut down and 355 // initialize another one. 356 onUserUnlocked(SYSTEM_USER_ID); 357 verify(mLockdownVpnTracker).shutdown(); 358 verify(mLockdownVpnTracker, times(2)).init(); 359 } 360 361 @Test testLockdownReset()362 public void testLockdownReset() { 363 // Init LockdownVpnTracker 364 setupLockdownVpn(TEST_VPN_PKG); 365 setupVpnProfile(TEST_VPN_PKG); 366 onUserUnlocked(SYSTEM_USER_ID); 367 verify(mLockdownVpnTracker).init(); 368 369 onLockDownReset(); 370 verify(mLockdownVpnTracker).reset(); 371 } 372 373 @Test testLockdownResetWhenLockdownVpnTrackerIsNotInit()374 public void testLockdownResetWhenLockdownVpnTrackerIsNotInit() { 375 setupLockdownVpn(TEST_VPN_PKG); 376 setupVpnProfile(TEST_VPN_PKG); 377 378 onLockDownReset(); 379 380 // LockDownVpnTracker is not created. Lockdown reset will not take effect. 381 verify(mLockdownVpnTracker, never()).reset(); 382 } 383 384 @Test testIsVpnLockdownEnabled()385 public void testIsVpnLockdownEnabled() { 386 // Vpn is created but the VPN lockdown is not enabled. 387 assertFalse(mService.isVpnLockdownEnabled(SYSTEM_USER_ID)); 388 389 // Set lockdown for the SYSTEM_USER_ID VPN. 390 doReturn(true).when(mVpn).getLockdown(); 391 assertTrue(mService.isVpnLockdownEnabled(SYSTEM_USER_ID)); 392 393 // Even lockdown is enabled but no Vpn is created for SECONDARY_USER. 394 assertFalse(mService.isVpnLockdownEnabled(SECONDARY_USER.id)); 395 } 396 397 @Test testGetVpnLockdownAllowlist()398 public void testGetVpnLockdownAllowlist() { 399 doReturn(null).when(mVpn).getLockdownAllowlist(); 400 assertNull(mService.getVpnLockdownAllowlist(SYSTEM_USER_ID)); 401 402 final List<String> expected = List.of(PKGS); 403 doReturn(expected).when(mVpn).getLockdownAllowlist(); 404 assertEquals(expected, mService.getVpnLockdownAllowlist(SYSTEM_USER_ID)); 405 406 // Even lockdown is enabled but no Vpn is created for SECONDARY_USER. 407 assertNull(mService.getVpnLockdownAllowlist(SECONDARY_USER.id)); 408 } 409 } 410