• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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 org.junit.Assert.assertEquals;
20 import static org.junit.Assert.assertNotNull;
21 import static org.junit.Assert.fail;
22 import static org.mockito.Matchers.anyInt;
23 import static org.mockito.Matchers.anyString;
24 import static org.mockito.Matchers.eq;
25 import static org.mockito.Mockito.mock;
26 import static org.mockito.Mockito.times;
27 import static org.mockito.Mockito.verify;
28 import static org.mockito.Mockito.when;
29 
30 import android.app.AppOpsManager;
31 import android.content.Context;
32 import android.net.INetd;
33 import android.net.IpSecAlgorithm;
34 import android.net.IpSecConfig;
35 import android.net.IpSecManager;
36 import android.net.IpSecSpiResponse;
37 import android.net.IpSecTransformResponse;
38 import android.net.IpSecTunnelInterfaceResponse;
39 import android.net.LinkAddress;
40 import android.net.Network;
41 import android.net.NetworkUtils;
42 import android.os.Binder;
43 import android.os.ParcelFileDescriptor;
44 import android.test.mock.MockContext;
45 import android.support.test.filters.SmallTest;
46 import android.system.Os;
47 
48 import java.net.Socket;
49 import java.util.Arrays;
50 import java.util.Collection;
51 
52 import org.junit.Before;
53 import org.junit.Test;
54 import org.junit.runner.RunWith;
55 import org.junit.runners.Parameterized;
56 
57 /** Unit tests for {@link IpSecService}. */
58 @SmallTest
59 @RunWith(Parameterized.class)
60 public class IpSecServiceParameterizedTest {
61 
62     private static final int TEST_SPI = 0xD1201D;
63 
64     private final String mDestinationAddr;
65     private final String mSourceAddr;
66     private final LinkAddress mLocalInnerAddress;
67 
68     @Parameterized.Parameters
ipSecConfigs()69     public static Collection ipSecConfigs() {
70         return Arrays.asList(
71                 new Object[][] {
72                 {"1.2.3.4", "8.8.4.4", "10.0.1.1/24"},
73                 {"2601::2", "2601::10", "2001:db8::1/64"}
74         });
75     }
76 
77     private static final byte[] AEAD_KEY = {
78         0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
79         0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
80         0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
81         0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
82         0x73, 0x61, 0x6C, 0x74
83     };
84     private static final byte[] CRYPT_KEY = {
85         0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
86         0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
87         0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
88         0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F
89     };
90     private static final byte[] AUTH_KEY = {
91         0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
92         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F,
93         0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
94         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F
95     };
96 
97     AppOpsManager mMockAppOps = mock(AppOpsManager.class);
98 
99     MockContext mMockContext = new MockContext() {
100         @Override
101         public Object getSystemService(String name) {
102             switch(name) {
103                 case Context.APP_OPS_SERVICE:
104                     return mMockAppOps;
105                 default:
106                     return null;
107             }
108         }
109 
110         @Override
111         public void enforceCallingOrSelfPermission(String permission, String message) {
112             if (permission == android.Manifest.permission.MANAGE_IPSEC_TUNNELS) {
113                 return;
114             }
115             throw new SecurityException("Unavailable permission requested");
116         }
117     };
118 
119     INetd mMockNetd;
120     IpSecService.IpSecServiceConfiguration mMockIpSecSrvConfig;
121     IpSecService mIpSecService;
122     Network fakeNetwork = new Network(0xAB);
123 
124     private static final IpSecAlgorithm AUTH_ALGO =
125             new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, AUTH_KEY, AUTH_KEY.length * 4);
126     private static final IpSecAlgorithm CRYPT_ALGO =
127             new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
128     private static final IpSecAlgorithm AEAD_ALGO =
129             new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128);
130 
IpSecServiceParameterizedTest( String sourceAddr, String destAddr, String localInnerAddr)131     public IpSecServiceParameterizedTest(
132             String sourceAddr, String destAddr, String localInnerAddr) {
133         mSourceAddr = sourceAddr;
134         mDestinationAddr = destAddr;
135         mLocalInnerAddress = new LinkAddress(localInnerAddr);
136     }
137 
138     @Before
setUp()139     public void setUp() throws Exception {
140         mMockNetd = mock(INetd.class);
141         mMockIpSecSrvConfig = mock(IpSecService.IpSecServiceConfiguration.class);
142         mIpSecService = new IpSecService(mMockContext, mMockIpSecSrvConfig);
143 
144         // Injecting mock netd
145         when(mMockIpSecSrvConfig.getNetdInstance()).thenReturn(mMockNetd);
146         // A package granted the AppOp for MANAGE_IPSEC_TUNNELS will be MODE_ALLOWED.
147         when(mMockAppOps.noteOp(anyInt(), anyInt(), eq("blessedPackage")))
148             .thenReturn(AppOpsManager.MODE_ALLOWED);
149         // A system package will not be granted the app op, so this should fall back to
150         // a permissions check, which should pass.
151         when(mMockAppOps.noteOp(anyInt(), anyInt(), eq("systemPackage")))
152             .thenReturn(AppOpsManager.MODE_DEFAULT);
153         // A mismatch between the package name and the UID will return MODE_IGNORED.
154         when(mMockAppOps.noteOp(anyInt(), anyInt(), eq("badPackage")))
155             .thenReturn(AppOpsManager.MODE_IGNORED);
156     }
157 
158     @Test
testIpSecServiceReserveSpi()159     public void testIpSecServiceReserveSpi() throws Exception {
160         when(mMockNetd.ipSecAllocateSpi(anyInt(), anyString(), eq(mDestinationAddr), eq(TEST_SPI)))
161                 .thenReturn(TEST_SPI);
162 
163         IpSecSpiResponse spiResp =
164                 mIpSecService.allocateSecurityParameterIndex(
165                         mDestinationAddr, TEST_SPI, new Binder());
166         assertEquals(IpSecManager.Status.OK, spiResp.status);
167         assertEquals(TEST_SPI, spiResp.spi);
168     }
169 
170     @Test
testReleaseSecurityParameterIndex()171     public void testReleaseSecurityParameterIndex() throws Exception {
172         when(mMockNetd.ipSecAllocateSpi(anyInt(), anyString(), eq(mDestinationAddr), eq(TEST_SPI)))
173                 .thenReturn(TEST_SPI);
174 
175         IpSecSpiResponse spiResp =
176                 mIpSecService.allocateSecurityParameterIndex(
177                         mDestinationAddr, TEST_SPI, new Binder());
178 
179         mIpSecService.releaseSecurityParameterIndex(spiResp.resourceId);
180 
181         verify(mMockNetd)
182                 .ipSecDeleteSecurityAssociation(
183                         eq(spiResp.resourceId),
184                         anyString(),
185                         anyString(),
186                         eq(TEST_SPI),
187                         anyInt(),
188                         anyInt());
189 
190         // Verify quota and RefcountedResource objects cleaned up
191         IpSecService.UserRecord userRecord =
192                 mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
193         assertEquals(0, userRecord.mSpiQuotaTracker.mCurrent);
194         try {
195             userRecord.mSpiRecords.getRefcountedResourceOrThrow(spiResp.resourceId);
196             fail("Expected IllegalArgumentException on attempt to access deleted resource");
197         } catch (IllegalArgumentException expected) {
198 
199         }
200     }
201 
202     @Test
testSecurityParameterIndexBinderDeath()203     public void testSecurityParameterIndexBinderDeath() throws Exception {
204         when(mMockNetd.ipSecAllocateSpi(anyInt(), anyString(), eq(mDestinationAddr), eq(TEST_SPI)))
205                 .thenReturn(TEST_SPI);
206 
207         IpSecSpiResponse spiResp =
208                 mIpSecService.allocateSecurityParameterIndex(
209                         mDestinationAddr, TEST_SPI, new Binder());
210 
211         IpSecService.UserRecord userRecord =
212                 mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
213         IpSecService.RefcountedResource refcountedRecord =
214                 userRecord.mSpiRecords.getRefcountedResourceOrThrow(spiResp.resourceId);
215 
216         refcountedRecord.binderDied();
217 
218         verify(mMockNetd)
219                 .ipSecDeleteSecurityAssociation(
220                         eq(spiResp.resourceId),
221                         anyString(),
222                         anyString(),
223                         eq(TEST_SPI),
224                         anyInt(),
225                         anyInt());
226 
227         // Verify quota and RefcountedResource objects cleaned up
228         assertEquals(0, userRecord.mSpiQuotaTracker.mCurrent);
229         try {
230             userRecord.mSpiRecords.getRefcountedResourceOrThrow(spiResp.resourceId);
231             fail("Expected IllegalArgumentException on attempt to access deleted resource");
232         } catch (IllegalArgumentException expected) {
233 
234         }
235     }
236 
getNewSpiResourceId(String remoteAddress, int returnSpi)237     private int getNewSpiResourceId(String remoteAddress, int returnSpi) throws Exception {
238         when(mMockNetd.ipSecAllocateSpi(anyInt(), anyString(), anyString(), anyInt()))
239                 .thenReturn(returnSpi);
240 
241         IpSecSpiResponse spi =
242                 mIpSecService.allocateSecurityParameterIndex(
243                         NetworkUtils.numericToInetAddress(remoteAddress).getHostAddress(),
244                         IpSecManager.INVALID_SECURITY_PARAMETER_INDEX,
245                         new Binder());
246         return spi.resourceId;
247     }
248 
addDefaultSpisAndRemoteAddrToIpSecConfig(IpSecConfig config)249     private void addDefaultSpisAndRemoteAddrToIpSecConfig(IpSecConfig config) throws Exception {
250         config.setSpiResourceId(getNewSpiResourceId(mDestinationAddr, TEST_SPI));
251         config.setSourceAddress(mSourceAddr);
252         config.setDestinationAddress(mDestinationAddr);
253     }
254 
addAuthAndCryptToIpSecConfig(IpSecConfig config)255     private void addAuthAndCryptToIpSecConfig(IpSecConfig config) throws Exception {
256         config.setEncryption(CRYPT_ALGO);
257         config.setAuthentication(AUTH_ALGO);
258     }
259 
260     @Test
testCreateTransform()261     public void testCreateTransform() throws Exception {
262         IpSecConfig ipSecConfig = new IpSecConfig();
263         addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
264         addAuthAndCryptToIpSecConfig(ipSecConfig);
265 
266         IpSecTransformResponse createTransformResp =
267                 mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
268         assertEquals(IpSecManager.Status.OK, createTransformResp.status);
269 
270         verify(mMockNetd)
271                 .ipSecAddSecurityAssociation(
272                         eq(createTransformResp.resourceId),
273                         anyInt(),
274                         anyString(),
275                         anyString(),
276                         anyInt(),
277                         eq(TEST_SPI),
278                         anyInt(),
279                         anyInt(),
280                         eq(IpSecAlgorithm.AUTH_HMAC_SHA256),
281                         eq(AUTH_KEY),
282                         anyInt(),
283                         eq(IpSecAlgorithm.CRYPT_AES_CBC),
284                         eq(CRYPT_KEY),
285                         anyInt(),
286                         eq(""),
287                         eq(new byte[] {}),
288                         eq(0),
289                         anyInt(),
290                         anyInt(),
291                         anyInt());
292     }
293 
294     @Test
testCreateTransformAead()295     public void testCreateTransformAead() throws Exception {
296         IpSecConfig ipSecConfig = new IpSecConfig();
297         addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
298 
299         ipSecConfig.setAuthenticatedEncryption(AEAD_ALGO);
300 
301         IpSecTransformResponse createTransformResp =
302                 mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
303         assertEquals(IpSecManager.Status.OK, createTransformResp.status);
304 
305         verify(mMockNetd)
306                 .ipSecAddSecurityAssociation(
307                         eq(createTransformResp.resourceId),
308                         anyInt(),
309                         anyString(),
310                         anyString(),
311                         anyInt(),
312                         eq(TEST_SPI),
313                         anyInt(),
314                         anyInt(),
315                         eq(""),
316                         eq(new byte[] {}),
317                         eq(0),
318                         eq(""),
319                         eq(new byte[] {}),
320                         eq(0),
321                         eq(IpSecAlgorithm.AUTH_CRYPT_AES_GCM),
322                         eq(AEAD_KEY),
323                         anyInt(),
324                         anyInt(),
325                         anyInt(),
326                         anyInt());
327     }
328 
329     @Test
testCreateTwoTransformsWithSameSpis()330     public void testCreateTwoTransformsWithSameSpis() throws Exception {
331         IpSecConfig ipSecConfig = new IpSecConfig();
332         addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
333         addAuthAndCryptToIpSecConfig(ipSecConfig);
334 
335         IpSecTransformResponse createTransformResp =
336                 mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
337         assertEquals(IpSecManager.Status.OK, createTransformResp.status);
338 
339         // Attempting to create transform a second time with the same SPIs should throw an error...
340         try {
341                 mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
342                 fail("IpSecService should have thrown an error for reuse of SPI");
343         } catch (IllegalStateException expected) {
344         }
345 
346         // ... even if the transform is deleted
347         mIpSecService.deleteTransform(createTransformResp.resourceId);
348         try {
349                 mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
350                 fail("IpSecService should have thrown an error for reuse of SPI");
351         } catch (IllegalStateException expected) {
352         }
353     }
354 
355     @Test
testReleaseOwnedSpi()356     public void testReleaseOwnedSpi() throws Exception {
357         IpSecConfig ipSecConfig = new IpSecConfig();
358         addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
359         addAuthAndCryptToIpSecConfig(ipSecConfig);
360 
361         IpSecTransformResponse createTransformResp =
362                 mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
363         IpSecService.UserRecord userRecord =
364                 mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
365         assertEquals(1, userRecord.mSpiQuotaTracker.mCurrent);
366         mIpSecService.releaseSecurityParameterIndex(ipSecConfig.getSpiResourceId());
367         verify(mMockNetd, times(0))
368                 .ipSecDeleteSecurityAssociation(
369                         eq(createTransformResp.resourceId),
370                         anyString(),
371                         anyString(),
372                         eq(TEST_SPI),
373                         anyInt(),
374                         anyInt());
375         // quota is not released until the SPI is released by the Transform
376         assertEquals(1, userRecord.mSpiQuotaTracker.mCurrent);
377     }
378 
379     @Test
testDeleteTransform()380     public void testDeleteTransform() throws Exception {
381         IpSecConfig ipSecConfig = new IpSecConfig();
382         addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
383         addAuthAndCryptToIpSecConfig(ipSecConfig);
384 
385         IpSecTransformResponse createTransformResp =
386                 mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
387         mIpSecService.deleteTransform(createTransformResp.resourceId);
388 
389         verify(mMockNetd, times(1))
390                 .ipSecDeleteSecurityAssociation(
391                         eq(createTransformResp.resourceId),
392                         anyString(),
393                         anyString(),
394                         eq(TEST_SPI),
395                         anyInt(),
396                         anyInt());
397 
398         // Verify quota and RefcountedResource objects cleaned up
399         IpSecService.UserRecord userRecord =
400                 mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
401         assertEquals(0, userRecord.mTransformQuotaTracker.mCurrent);
402         assertEquals(1, userRecord.mSpiQuotaTracker.mCurrent);
403 
404         mIpSecService.releaseSecurityParameterIndex(ipSecConfig.getSpiResourceId());
405         // Verify that ipSecDeleteSa was not called when the SPI was released because the
406         // ownedByTransform property should prevent it; (note, the called count is cumulative).
407         verify(mMockNetd, times(1))
408                 .ipSecDeleteSecurityAssociation(
409                         anyInt(),
410                         anyString(),
411                         anyString(),
412                         anyInt(),
413                         anyInt(),
414                         anyInt());
415         assertEquals(0, userRecord.mSpiQuotaTracker.mCurrent);
416 
417         try {
418             userRecord.mTransformRecords.getRefcountedResourceOrThrow(
419                     createTransformResp.resourceId);
420             fail("Expected IllegalArgumentException on attempt to access deleted resource");
421         } catch (IllegalArgumentException expected) {
422 
423         }
424     }
425 
426     @Test
testTransportModeTransformBinderDeath()427     public void testTransportModeTransformBinderDeath() throws Exception {
428         IpSecConfig ipSecConfig = new IpSecConfig();
429         addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
430         addAuthAndCryptToIpSecConfig(ipSecConfig);
431 
432         IpSecTransformResponse createTransformResp =
433                 mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
434 
435         IpSecService.UserRecord userRecord =
436                 mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
437         IpSecService.RefcountedResource refcountedRecord =
438                 userRecord.mTransformRecords.getRefcountedResourceOrThrow(
439                         createTransformResp.resourceId);
440 
441         refcountedRecord.binderDied();
442 
443         verify(mMockNetd)
444                 .ipSecDeleteSecurityAssociation(
445                         eq(createTransformResp.resourceId),
446                         anyString(),
447                         anyString(),
448                         eq(TEST_SPI),
449                         anyInt(),
450                         anyInt());
451 
452         // Verify quota and RefcountedResource objects cleaned up
453         assertEquals(0, userRecord.mTransformQuotaTracker.mCurrent);
454         try {
455             userRecord.mTransformRecords.getRefcountedResourceOrThrow(
456                     createTransformResp.resourceId);
457             fail("Expected IllegalArgumentException on attempt to access deleted resource");
458         } catch (IllegalArgumentException expected) {
459 
460         }
461     }
462 
463     @Test
testApplyTransportModeTransform()464     public void testApplyTransportModeTransform() throws Exception {
465         IpSecConfig ipSecConfig = new IpSecConfig();
466         addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
467         addAuthAndCryptToIpSecConfig(ipSecConfig);
468 
469         IpSecTransformResponse createTransformResp =
470                 mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
471         ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(new Socket());
472 
473         int resourceId = createTransformResp.resourceId;
474         mIpSecService.applyTransportModeTransform(pfd, IpSecManager.DIRECTION_OUT, resourceId);
475 
476         verify(mMockNetd)
477                 .ipSecApplyTransportModeTransform(
478                         eq(pfd.getFileDescriptor()),
479                         eq(resourceId),
480                         eq(IpSecManager.DIRECTION_OUT),
481                         anyString(),
482                         anyString(),
483                         eq(TEST_SPI));
484     }
485 
486     @Test
testRemoveTransportModeTransform()487     public void testRemoveTransportModeTransform() throws Exception {
488         ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(new Socket());
489         mIpSecService.removeTransportModeTransforms(pfd);
490 
491         verify(mMockNetd).ipSecRemoveTransportModeTransform(pfd.getFileDescriptor());
492     }
493 
createAndValidateTunnel( String localAddr, String remoteAddr, String pkgName)494     private IpSecTunnelInterfaceResponse createAndValidateTunnel(
495             String localAddr, String remoteAddr, String pkgName) {
496         IpSecTunnelInterfaceResponse createTunnelResp =
497                 mIpSecService.createTunnelInterface(
498                         mSourceAddr, mDestinationAddr, fakeNetwork, new Binder(), pkgName);
499 
500         assertNotNull(createTunnelResp);
501         assertEquals(IpSecManager.Status.OK, createTunnelResp.status);
502         return createTunnelResp;
503     }
504 
505     @Test
testCreateTunnelInterface()506     public void testCreateTunnelInterface() throws Exception {
507         IpSecTunnelInterfaceResponse createTunnelResp =
508                 createAndValidateTunnel(mSourceAddr, mDestinationAddr, "blessedPackage");
509 
510         // Check that we have stored the tracking object, and retrieve it
511         IpSecService.UserRecord userRecord =
512                 mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
513         IpSecService.RefcountedResource refcountedRecord =
514                 userRecord.mTunnelInterfaceRecords.getRefcountedResourceOrThrow(
515                         createTunnelResp.resourceId);
516 
517         assertEquals(1, userRecord.mTunnelQuotaTracker.mCurrent);
518         verify(mMockNetd)
519                 .addVirtualTunnelInterface(
520                         eq(createTunnelResp.interfaceName),
521                         eq(mSourceAddr),
522                         eq(mDestinationAddr),
523                         anyInt(),
524                         anyInt());
525     }
526 
527     @Test
testDeleteTunnelInterface()528     public void testDeleteTunnelInterface() throws Exception {
529         IpSecTunnelInterfaceResponse createTunnelResp =
530                 createAndValidateTunnel(mSourceAddr, mDestinationAddr, "blessedPackage");
531 
532         IpSecService.UserRecord userRecord =
533                 mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
534 
535         mIpSecService.deleteTunnelInterface(createTunnelResp.resourceId, "blessedPackage");
536 
537         // Verify quota and RefcountedResource objects cleaned up
538         assertEquals(0, userRecord.mTunnelQuotaTracker.mCurrent);
539         verify(mMockNetd).removeVirtualTunnelInterface(eq(createTunnelResp.interfaceName));
540         try {
541             userRecord.mTunnelInterfaceRecords.getRefcountedResourceOrThrow(
542                     createTunnelResp.resourceId);
543             fail("Expected IllegalArgumentException on attempt to access deleted resource");
544         } catch (IllegalArgumentException expected) {
545         }
546     }
547 
548     @Test
testTunnelInterfaceBinderDeath()549     public void testTunnelInterfaceBinderDeath() throws Exception {
550         IpSecTunnelInterfaceResponse createTunnelResp =
551                 createAndValidateTunnel(mSourceAddr, mDestinationAddr, "blessedPackage");
552 
553         IpSecService.UserRecord userRecord =
554                 mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
555         IpSecService.RefcountedResource refcountedRecord =
556                 userRecord.mTunnelInterfaceRecords.getRefcountedResourceOrThrow(
557                         createTunnelResp.resourceId);
558 
559         refcountedRecord.binderDied();
560 
561         // Verify quota and RefcountedResource objects cleaned up
562         assertEquals(0, userRecord.mTunnelQuotaTracker.mCurrent);
563         verify(mMockNetd).removeVirtualTunnelInterface(eq(createTunnelResp.interfaceName));
564         try {
565             userRecord.mTunnelInterfaceRecords.getRefcountedResourceOrThrow(
566                     createTunnelResp.resourceId);
567             fail("Expected IllegalArgumentException on attempt to access deleted resource");
568         } catch (IllegalArgumentException expected) {
569         }
570     }
571 
572     @Test
testAddRemoveAddressFromTunnelInterface()573     public void testAddRemoveAddressFromTunnelInterface() throws Exception {
574         for (String pkgName : new String[]{"blessedPackage", "systemPackage"}) {
575             IpSecTunnelInterfaceResponse createTunnelResp =
576                     createAndValidateTunnel(mSourceAddr, mDestinationAddr, pkgName);
577             mIpSecService.addAddressToTunnelInterface(
578                     createTunnelResp.resourceId, mLocalInnerAddress, pkgName);
579             verify(mMockNetd, times(1))
580                     .interfaceAddAddress(
581                             eq(createTunnelResp.interfaceName),
582                             eq(mLocalInnerAddress.getAddress().getHostAddress()),
583                             eq(mLocalInnerAddress.getPrefixLength()));
584             mIpSecService.removeAddressFromTunnelInterface(
585                     createTunnelResp.resourceId, mLocalInnerAddress, pkgName);
586             verify(mMockNetd, times(1))
587                     .interfaceDelAddress(
588                             eq(createTunnelResp.interfaceName),
589                             eq(mLocalInnerAddress.getAddress().getHostAddress()),
590                             eq(mLocalInnerAddress.getPrefixLength()));
591             mIpSecService.deleteTunnelInterface(createTunnelResp.resourceId, pkgName);
592         }
593     }
594 
595     @Test
testAddTunnelFailsForBadPackageName()596     public void testAddTunnelFailsForBadPackageName() throws Exception {
597         try {
598             IpSecTunnelInterfaceResponse createTunnelResp =
599                     createAndValidateTunnel(mSourceAddr, mDestinationAddr, "badPackage");
600             fail("Expected a SecurityException for badPackage.");
601         } catch (SecurityException expected) {
602         }
603     }
604 }
605