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 android.Manifest.permission.DUMP;
20 import static android.net.IpSecManager.INVALID_RESOURCE_ID;
21 import static android.system.OsConstants.AF_INET;
22 import static android.system.OsConstants.AF_INET6;
23 import static android.system.OsConstants.AF_UNSPEC;
24 import static android.system.OsConstants.EINVAL;
25 import static android.system.OsConstants.IPPROTO_UDP;
26 import static android.system.OsConstants.SOCK_DGRAM;
27 
28 import android.annotation.NonNull;
29 import android.app.AppOpsManager;
30 import android.content.Context;
31 import android.content.pm.PackageManager;
32 import android.net.IIpSecService;
33 import android.net.INetd;
34 import android.net.IpSecAlgorithm;
35 import android.net.IpSecConfig;
36 import android.net.IpSecManager;
37 import android.net.IpSecSpiResponse;
38 import android.net.IpSecTransform;
39 import android.net.IpSecTransformResponse;
40 import android.net.IpSecTunnelInterfaceResponse;
41 import android.net.IpSecUdpEncapResponse;
42 import android.net.LinkAddress;
43 import android.net.Network;
44 import android.net.NetworkUtils;
45 import android.net.TrafficStats;
46 import android.net.util.NetdService;
47 import android.os.Binder;
48 import android.os.IBinder;
49 import android.os.INetworkManagementService;
50 import android.os.ParcelFileDescriptor;
51 import android.os.RemoteException;
52 import android.os.ServiceSpecificException;
53 import android.system.ErrnoException;
54 import android.system.Os;
55 import android.system.OsConstants;
56 import android.text.TextUtils;
57 import android.util.Log;
58 import android.util.Slog;
59 import android.util.SparseArray;
60 import android.util.SparseBooleanArray;
61 
62 import com.android.internal.annotations.GuardedBy;
63 import com.android.internal.annotations.VisibleForTesting;
64 import com.android.internal.util.Preconditions;
65 
66 import libcore.io.IoUtils;
67 
68 import java.io.FileDescriptor;
69 import java.io.IOException;
70 import java.io.PrintWriter;
71 import java.net.Inet4Address;
72 import java.net.Inet6Address;
73 import java.net.InetAddress;
74 import java.net.InetSocketAddress;
75 import java.net.UnknownHostException;
76 import java.util.ArrayList;
77 import java.util.List;
78 import java.util.Objects;
79 
80 /**
81  * A service to manage multiple clients that want to access the IpSec API. The service is
82  * responsible for maintaining a list of clients and managing the resources (and related quotas)
83  * that each of them own.
84  *
85  * <p>Synchronization in IpSecService is done on all entrypoints due to potential race conditions at
86  * the kernel/xfrm level. Further, this allows the simplifying assumption to be made that only one
87  * thread is ever running at a time.
88  *
89  * @hide
90  */
91 public class IpSecService extends IIpSecService.Stub {
92     private static final String TAG = "IpSecService";
93     private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
94 
95     private static final String NETD_SERVICE_NAME = "netd";
96     private static final int[] ADDRESS_FAMILIES =
97             new int[] {OsConstants.AF_INET, OsConstants.AF_INET6};
98 
99     private static final int NETD_FETCH_TIMEOUT_MS = 5000; // ms
100     private static final InetAddress INADDR_ANY;
101 
102     @VisibleForTesting static final int MAX_PORT_BIND_ATTEMPTS = 10;
103 
104     static {
105         try {
106             INADDR_ANY = InetAddress.getByAddress(new byte[] {0, 0, 0, 0});
107         } catch (UnknownHostException e) {
108             throw new RuntimeException(e);
109         }
110     }
111 
112     static final int FREE_PORT_MIN = 1024; // ports 1-1023 are reserved
113     static final int PORT_MAX = 0xFFFF; // ports are an unsigned 16-bit integer
114 
115     /* Binder context for this service */
116     private final Context mContext;
117 
118     /* NetworkManager instance */
119     private final INetworkManagementService mNetworkManager;
120 
121     /**
122      * The next non-repeating global ID for tracking resources between users, this service, and
123      * kernel data structures. Accessing this variable is not thread safe, so it is only read or
124      * modified within blocks synchronized on IpSecService.this. We want to avoid -1
125      * (INVALID_RESOURCE_ID) and 0 (we probably forgot to initialize it).
126      */
127     @GuardedBy("IpSecService.this")
128     private int mNextResourceId = 1;
129 
130     interface IpSecServiceConfiguration {
getNetdInstance()131         INetd getNetdInstance() throws RemoteException;
132 
133         static IpSecServiceConfiguration GETSRVINSTANCE =
134                 new IpSecServiceConfiguration() {
135                     @Override
136                     public INetd getNetdInstance() throws RemoteException {
137                         final INetd netd = NetdService.getInstance();
138                         if (netd == null) {
139                             throw new RemoteException("Failed to Get Netd Instance");
140                         }
141                         return netd;
142                     }
143                 };
144     }
145 
146     private final IpSecServiceConfiguration mSrvConfig;
147     final UidFdTagger mUidFdTagger;
148 
149     /**
150      * Interface for user-reference and kernel-resource cleanup.
151      *
152      * <p>This interface must be implemented for a resource to be reference counted.
153      */
154     @VisibleForTesting
155     public interface IResource {
156         /**
157          * Invalidates a IResource object, ensuring it is invalid for the purposes of allocating new
158          * objects dependent on it.
159          *
160          * <p>Implementations of this method are expected to remove references to the IResource
161          * object from the IpSecService's tracking arrays. The removal from the arrays ensures that
162          * the resource is considered invalid for user access or allocation or use in other
163          * resources.
164          *
165          * <p>References to the IResource object may be held by other RefcountedResource objects,
166          * and as such, the underlying resources and quota may not be cleaned up.
167          */
invalidate()168         void invalidate() throws RemoteException;
169 
170         /**
171          * Releases underlying resources and related quotas.
172          *
173          * <p>Implementations of this method are expected to remove all system resources that are
174          * tracked by the IResource object. Due to other RefcountedResource objects potentially
175          * having references to the IResource object, freeUnderlyingResources may not always be
176          * called from releaseIfUnreferencedRecursively().
177          */
freeUnderlyingResources()178         void freeUnderlyingResources() throws RemoteException;
179     }
180 
181     /**
182      * RefcountedResource manages references and dependencies in an exclusively acyclic graph.
183      *
184      * <p>RefcountedResource implements both explicit and implicit resource management. Creating a
185      * RefcountedResource object creates an explicit reference that must be freed by calling
186      * userRelease(). Additionally, adding this object as a child of another RefcountedResource
187      * object will add an implicit reference.
188      *
189      * <p>Resources are cleaned up when all references, both implicit and explicit, are released
190      * (ie, when userRelease() is called and when all parents have called releaseReference() on this
191      * object.)
192      */
193     @VisibleForTesting
194     public class RefcountedResource<T extends IResource> implements IBinder.DeathRecipient {
195         private final T mResource;
196         private final List<RefcountedResource> mChildren;
197         int mRefCount = 1; // starts at 1 for user's reference.
198         IBinder mBinder;
199 
RefcountedResource(T resource, IBinder binder, RefcountedResource... children)200         RefcountedResource(T resource, IBinder binder, RefcountedResource... children) {
201             synchronized (IpSecService.this) {
202                 this.mResource = resource;
203                 this.mChildren = new ArrayList<>(children.length);
204                 this.mBinder = binder;
205 
206                 for (RefcountedResource child : children) {
207                     mChildren.add(child);
208                     child.mRefCount++;
209                 }
210 
211                 try {
212                     mBinder.linkToDeath(this, 0);
213                 } catch (RemoteException e) {
214                     binderDied();
215                     e.rethrowFromSystemServer();
216                 }
217             }
218         }
219 
220         /**
221          * If the Binder object dies, this function is called to free the system resources that are
222          * being tracked by this record and to subsequently release this record for garbage
223          * collection
224          */
225         @Override
binderDied()226         public void binderDied() {
227             synchronized (IpSecService.this) {
228                 try {
229                     userRelease();
230                 } catch (Exception e) {
231                     Log.e(TAG, "Failed to release resource: " + e);
232                 }
233             }
234         }
235 
getResource()236         public T getResource() {
237             return mResource;
238         }
239 
240         /**
241          * Unlinks from binder and performs IpSecService resource cleanup (removes from resource
242          * arrays)
243          *
244          * <p>If this method has been previously called, the RefcountedResource's binder field will
245          * be null, and the method will return without performing the cleanup a second time.
246          *
247          * <p>Note that calling this function does not imply that kernel resources will be freed at
248          * this time, or that the related quota will be returned. Such actions will only be
249          * performed upon the reference count reaching zero.
250          */
251         @GuardedBy("IpSecService.this")
userRelease()252         public void userRelease() throws RemoteException {
253             // Prevent users from putting reference counts into a bad state by calling
254             // userRelease() multiple times.
255             if (mBinder == null) {
256                 return;
257             }
258 
259             mBinder.unlinkToDeath(this, 0);
260             mBinder = null;
261 
262             mResource.invalidate();
263 
264             releaseReference();
265         }
266 
267         /**
268          * Removes a reference to this resource. If the resultant reference count is zero, the
269          * underlying resources are freed, and references to all child resources are also dropped
270          * recursively (resulting in them freeing their resources and children, etcetera)
271          *
272          * <p>This method also sets the reference count to an invalid value (-1) to signify that it
273          * has been fully released. Any subsequent calls to this method will result in an
274          * IllegalStateException being thrown due to resource already having been previously
275          * released
276          */
277         @VisibleForTesting
278         @GuardedBy("IpSecService.this")
releaseReference()279         public void releaseReference() throws RemoteException {
280             mRefCount--;
281 
282             if (mRefCount > 0) {
283                 return;
284             } else if (mRefCount < 0) {
285                 throw new IllegalStateException(
286                         "Invalid operation - resource has already been released.");
287             }
288 
289             // Cleanup own resources
290             mResource.freeUnderlyingResources();
291 
292             // Cleanup child resources as needed
293             for (RefcountedResource<? extends IResource> child : mChildren) {
294                 child.releaseReference();
295             }
296 
297             // Enforce that resource cleanup can only be called once
298             // By decrementing the refcount (from 0 to -1), the next call will throw an
299             // IllegalStateException - it has already been released fully.
300             mRefCount--;
301         }
302 
303         @Override
toString()304         public String toString() {
305             return new StringBuilder()
306                     .append("{mResource=")
307                     .append(mResource)
308                     .append(", mRefCount=")
309                     .append(mRefCount)
310                     .append(", mChildren=")
311                     .append(mChildren)
312                     .append("}")
313                     .toString();
314         }
315     }
316 
317     /**
318      * Very simple counting class that looks much like a counting semaphore
319      *
320      * <p>This class is not thread-safe, and expects that that users of this class will ensure
321      * synchronization and thread safety by holding the IpSecService.this instance lock.
322      */
323     @VisibleForTesting
324     static class ResourceTracker {
325         private final int mMax;
326         int mCurrent;
327 
ResourceTracker(int max)328         ResourceTracker(int max) {
329             mMax = max;
330             mCurrent = 0;
331         }
332 
isAvailable()333         boolean isAvailable() {
334             return (mCurrent < mMax);
335         }
336 
take()337         void take() {
338             if (!isAvailable()) {
339                 Log.wtf(TAG, "Too many resources allocated!");
340             }
341             mCurrent++;
342         }
343 
give()344         void give() {
345             if (mCurrent <= 0) {
346                 Log.wtf(TAG, "We've released this resource too many times");
347             }
348             mCurrent--;
349         }
350 
351         @Override
toString()352         public String toString() {
353             return new StringBuilder()
354                     .append("{mCurrent=")
355                     .append(mCurrent)
356                     .append(", mMax=")
357                     .append(mMax)
358                     .append("}")
359                     .toString();
360         }
361     }
362 
363     @VisibleForTesting
364     static final class UserRecord {
365         /* Maximum number of each type of resource that a single UID may possess */
366 
367         // Up to 4 active VPNs/IWLAN with potential soft handover.
368         public static final int MAX_NUM_TUNNEL_INTERFACES = 8;
369         public static final int MAX_NUM_ENCAP_SOCKETS = 16;
370 
371         // SPIs and Transforms are both cheap, and are 1:1 correlated.
372         public static final int MAX_NUM_TRANSFORMS = 64;
373         public static final int MAX_NUM_SPIS = 64;
374 
375         /**
376          * Store each of the OwnedResource types in an (thinly wrapped) sparse array for indexing
377          * and explicit (user) reference management.
378          *
379          * <p>These are stored in separate arrays to improve debuggability and dump output clarity.
380          *
381          * <p>Resources are removed from this array when the user releases their explicit reference
382          * by calling one of the releaseResource() methods.
383          */
384         final RefcountedResourceArray<SpiRecord> mSpiRecords =
385                 new RefcountedResourceArray<>(SpiRecord.class.getSimpleName());
386         final RefcountedResourceArray<TransformRecord> mTransformRecords =
387                 new RefcountedResourceArray<>(TransformRecord.class.getSimpleName());
388         final RefcountedResourceArray<EncapSocketRecord> mEncapSocketRecords =
389                 new RefcountedResourceArray<>(EncapSocketRecord.class.getSimpleName());
390         final RefcountedResourceArray<TunnelInterfaceRecord> mTunnelInterfaceRecords =
391                 new RefcountedResourceArray<>(TunnelInterfaceRecord.class.getSimpleName());
392 
393         /**
394          * Trackers for quotas for each of the OwnedResource types.
395          *
396          * <p>These trackers are separate from the resource arrays, since they are incremented and
397          * decremented at different points in time. Specifically, quota is only returned upon final
398          * resource deallocation (after all explicit and implicit references are released). Note
399          * that it is possible that calls to releaseResource() will not return the used quota if
400          * there are other resources that depend on (are parents of) the resource being released.
401          */
402         final ResourceTracker mSpiQuotaTracker = new ResourceTracker(MAX_NUM_SPIS);
403         final ResourceTracker mTransformQuotaTracker = new ResourceTracker(MAX_NUM_TRANSFORMS);
404         final ResourceTracker mSocketQuotaTracker = new ResourceTracker(MAX_NUM_ENCAP_SOCKETS);
405         final ResourceTracker mTunnelQuotaTracker = new ResourceTracker(MAX_NUM_TUNNEL_INTERFACES);
406 
removeSpiRecord(int resourceId)407         void removeSpiRecord(int resourceId) {
408             mSpiRecords.remove(resourceId);
409         }
410 
removeTransformRecord(int resourceId)411         void removeTransformRecord(int resourceId) {
412             mTransformRecords.remove(resourceId);
413         }
414 
removeTunnelInterfaceRecord(int resourceId)415         void removeTunnelInterfaceRecord(int resourceId) {
416             mTunnelInterfaceRecords.remove(resourceId);
417         }
418 
removeEncapSocketRecord(int resourceId)419         void removeEncapSocketRecord(int resourceId) {
420             mEncapSocketRecords.remove(resourceId);
421         }
422 
423         @Override
toString()424         public String toString() {
425             return new StringBuilder()
426                     .append("{mSpiQuotaTracker=")
427                     .append(mSpiQuotaTracker)
428                     .append(", mTransformQuotaTracker=")
429                     .append(mTransformQuotaTracker)
430                     .append(", mSocketQuotaTracker=")
431                     .append(mSocketQuotaTracker)
432                     .append(", mTunnelQuotaTracker=")
433                     .append(mTunnelQuotaTracker)
434                     .append(", mSpiRecords=")
435                     .append(mSpiRecords)
436                     .append(", mTransformRecords=")
437                     .append(mTransformRecords)
438                     .append(", mEncapSocketRecords=")
439                     .append(mEncapSocketRecords)
440                     .append(", mTunnelInterfaceRecords=")
441                     .append(mTunnelInterfaceRecords)
442                     .append("}")
443                     .toString();
444         }
445     }
446 
447     /**
448      * This class is not thread-safe, and expects that that users of this class will ensure
449      * synchronization and thread safety by holding the IpSecService.this instance lock.
450      */
451     @VisibleForTesting
452     static final class UserResourceTracker {
453         private final SparseArray<UserRecord> mUserRecords = new SparseArray<>();
454 
455         /** Lazy-initialization/getter that populates or retrieves the UserRecord as needed */
getUserRecord(int uid)456         public UserRecord getUserRecord(int uid) {
457             checkCallerUid(uid);
458 
459             UserRecord r = mUserRecords.get(uid);
460             if (r == null) {
461                 r = new UserRecord();
462                 mUserRecords.put(uid, r);
463             }
464             return r;
465         }
466 
467         /** Safety method; guards against access of other user's UserRecords */
checkCallerUid(int uid)468         private void checkCallerUid(int uid) {
469             if (uid != Binder.getCallingUid()
470                     && android.os.Process.SYSTEM_UID != Binder.getCallingUid()) {
471                 throw new SecurityException("Attempted access of unowned resources");
472             }
473         }
474 
475         @Override
toString()476         public String toString() {
477             return mUserRecords.toString();
478         }
479     }
480 
481     @VisibleForTesting final UserResourceTracker mUserResourceTracker = new UserResourceTracker();
482 
483     /**
484      * The OwnedResourceRecord class provides a facility to cleanly and reliably track system
485      * resources. It relies on a provided resourceId that should uniquely identify the kernel
486      * resource. To use this class, the user should implement the invalidate() and
487      * freeUnderlyingResources() methods that are responsible for cleaning up IpSecService resource
488      * tracking arrays and kernel resources, respectively.
489      *
490      * <p>This class associates kernel resources with the UID that owns and controls them.
491      */
492     private abstract class OwnedResourceRecord implements IResource {
493         final int pid;
494         final int uid;
495         protected final int mResourceId;
496 
OwnedResourceRecord(int resourceId)497         OwnedResourceRecord(int resourceId) {
498             super();
499             if (resourceId == INVALID_RESOURCE_ID) {
500                 throw new IllegalArgumentException("Resource ID must not be INVALID_RESOURCE_ID");
501             }
502             mResourceId = resourceId;
503             pid = Binder.getCallingPid();
504             uid = Binder.getCallingUid();
505 
506             getResourceTracker().take();
507         }
508 
509         @Override
invalidate()510         public abstract void invalidate() throws RemoteException;
511 
512         /** Convenience method; retrieves the user resource record for the stored UID. */
getUserRecord()513         protected UserRecord getUserRecord() {
514             return mUserResourceTracker.getUserRecord(uid);
515         }
516 
517         @Override
freeUnderlyingResources()518         public abstract void freeUnderlyingResources() throws RemoteException;
519 
520         /** Get the resource tracker for this resource */
getResourceTracker()521         protected abstract ResourceTracker getResourceTracker();
522 
523         @Override
toString()524         public String toString() {
525             return new StringBuilder()
526                     .append("{mResourceId=")
527                     .append(mResourceId)
528                     .append(", pid=")
529                     .append(pid)
530                     .append(", uid=")
531                     .append(uid)
532                     .append("}")
533                     .toString();
534         }
535     };
536 
537     /**
538      * Thin wrapper over SparseArray to ensure resources exist, and simplify generic typing.
539      *
540      * <p>RefcountedResourceArray prevents null insertions, and throws an IllegalArgumentException
541      * if a key is not found during a retrieval process.
542      */
543     static class RefcountedResourceArray<T extends IResource> {
544         SparseArray<RefcountedResource<T>> mArray = new SparseArray<>();
545         private final String mTypeName;
546 
RefcountedResourceArray(String typeName)547         public RefcountedResourceArray(String typeName) {
548             this.mTypeName = typeName;
549         }
550 
551         /**
552          * Accessor method to get inner resource object.
553          *
554          * @throws IllegalArgumentException if no resource with provided key is found.
555          */
getResourceOrThrow(int key)556         T getResourceOrThrow(int key) {
557             return getRefcountedResourceOrThrow(key).getResource();
558         }
559 
560         /**
561          * Accessor method to get reference counting wrapper.
562          *
563          * @throws IllegalArgumentException if no resource with provided key is found.
564          */
getRefcountedResourceOrThrow(int key)565         RefcountedResource<T> getRefcountedResourceOrThrow(int key) {
566             RefcountedResource<T> resource = mArray.get(key);
567             if (resource == null) {
568                 throw new IllegalArgumentException(
569                         String.format("No such %s found for given id: %d", mTypeName, key));
570             }
571 
572             return resource;
573         }
574 
put(int key, RefcountedResource<T> obj)575         void put(int key, RefcountedResource<T> obj) {
576             Objects.requireNonNull(obj, "Null resources cannot be added");
577             mArray.put(key, obj);
578         }
579 
remove(int key)580         void remove(int key) {
581             mArray.remove(key);
582         }
583 
584         @Override
toString()585         public String toString() {
586             return mArray.toString();
587         }
588     }
589 
590     /**
591      * Tracks an SA in the kernel, and manages cleanup paths. Once a TransformRecord is
592      * created, the SpiRecord that originally tracked the SAs will reliquish the
593      * responsibility of freeing the underlying SA to this class via the mOwnedByTransform flag.
594      */
595     private final class TransformRecord extends OwnedResourceRecord {
596         private final IpSecConfig mConfig;
597         private final SpiRecord mSpi;
598         private final EncapSocketRecord mSocket;
599 
TransformRecord( int resourceId, IpSecConfig config, SpiRecord spi, EncapSocketRecord socket)600         TransformRecord(
601                 int resourceId, IpSecConfig config, SpiRecord spi, EncapSocketRecord socket) {
602             super(resourceId);
603             mConfig = config;
604             mSpi = spi;
605             mSocket = socket;
606 
607             spi.setOwnedByTransform();
608         }
609 
getConfig()610         public IpSecConfig getConfig() {
611             return mConfig;
612         }
613 
getSpiRecord()614         public SpiRecord getSpiRecord() {
615             return mSpi;
616         }
617 
getSocketRecord()618         public EncapSocketRecord getSocketRecord() {
619             return mSocket;
620         }
621 
622         /** always guarded by IpSecService#this */
623         @Override
freeUnderlyingResources()624         public void freeUnderlyingResources() {
625             int spi = mSpi.getSpi();
626             try {
627                 mSrvConfig
628                         .getNetdInstance()
629                         .ipSecDeleteSecurityAssociation(
630                                 uid,
631                                 mConfig.getSourceAddress(),
632                                 mConfig.getDestinationAddress(),
633                                 spi,
634                                 mConfig.getMarkValue(),
635                                 mConfig.getMarkMask(),
636                                 mConfig.getXfrmInterfaceId());
637             } catch (RemoteException | ServiceSpecificException e) {
638                 Log.e(TAG, "Failed to delete SA with ID: " + mResourceId, e);
639             }
640 
641             getResourceTracker().give();
642         }
643 
644         @Override
invalidate()645         public void invalidate() throws RemoteException {
646             getUserRecord().removeTransformRecord(mResourceId);
647         }
648 
649         @Override
getResourceTracker()650         protected ResourceTracker getResourceTracker() {
651             return getUserRecord().mTransformQuotaTracker;
652         }
653 
654         @Override
toString()655         public String toString() {
656             StringBuilder strBuilder = new StringBuilder();
657             strBuilder
658                     .append("{super=")
659                     .append(super.toString())
660                     .append(", mSocket=")
661                     .append(mSocket)
662                     .append(", mSpi.mResourceId=")
663                     .append(mSpi.mResourceId)
664                     .append(", mConfig=")
665                     .append(mConfig)
666                     .append("}");
667             return strBuilder.toString();
668         }
669     }
670 
671     /**
672      * Tracks a single SA in the kernel, and manages cleanup paths. Once used in a Transform, the
673      * responsibility for cleaning up underlying resources will be passed to the TransformRecord
674      * object
675      */
676     private final class SpiRecord extends OwnedResourceRecord {
677         private final String mSourceAddress;
678         private final String mDestinationAddress;
679         private int mSpi;
680 
681         private boolean mOwnedByTransform = false;
682 
SpiRecord(int resourceId, String sourceAddress, String destinationAddress, int spi)683         SpiRecord(int resourceId, String sourceAddress, String destinationAddress, int spi) {
684             super(resourceId);
685             mSourceAddress = sourceAddress;
686             mDestinationAddress = destinationAddress;
687             mSpi = spi;
688         }
689 
690         /** always guarded by IpSecService#this */
691         @Override
freeUnderlyingResources()692         public void freeUnderlyingResources() {
693             try {
694                 if (!mOwnedByTransform) {
695                     mSrvConfig
696                             .getNetdInstance()
697                             .ipSecDeleteSecurityAssociation(
698                                     uid, mSourceAddress, mDestinationAddress, mSpi, 0 /* mark */,
699                                     0 /* mask */, 0 /* if_id */);
700                 }
701             } catch (ServiceSpecificException | RemoteException e) {
702                 Log.e(TAG, "Failed to delete SPI reservation with ID: " + mResourceId, e);
703             }
704 
705             mSpi = IpSecManager.INVALID_SECURITY_PARAMETER_INDEX;
706 
707             getResourceTracker().give();
708         }
709 
getSpi()710         public int getSpi() {
711             return mSpi;
712         }
713 
getDestinationAddress()714         public String getDestinationAddress() {
715             return mDestinationAddress;
716         }
717 
setOwnedByTransform()718         public void setOwnedByTransform() {
719             if (mOwnedByTransform) {
720                 // Programming error
721                 throw new IllegalStateException("Cannot own an SPI twice!");
722             }
723 
724             mOwnedByTransform = true;
725         }
726 
getOwnedByTransform()727         public boolean getOwnedByTransform() {
728             return mOwnedByTransform;
729         }
730 
731         @Override
invalidate()732         public void invalidate() throws RemoteException {
733             getUserRecord().removeSpiRecord(mResourceId);
734         }
735 
736         @Override
getResourceTracker()737         protected ResourceTracker getResourceTracker() {
738             return getUserRecord().mSpiQuotaTracker;
739         }
740 
741         @Override
toString()742         public String toString() {
743             StringBuilder strBuilder = new StringBuilder();
744             strBuilder
745                     .append("{super=")
746                     .append(super.toString())
747                     .append(", mSpi=")
748                     .append(mSpi)
749                     .append(", mSourceAddress=")
750                     .append(mSourceAddress)
751                     .append(", mDestinationAddress=")
752                     .append(mDestinationAddress)
753                     .append(", mOwnedByTransform=")
754                     .append(mOwnedByTransform)
755                     .append("}");
756             return strBuilder.toString();
757         }
758     }
759 
760     // These values have been reserved in NetIdManager
761     @VisibleForTesting static final int TUN_INTF_NETID_START = 0xFC00;
762 
763     public static final int TUN_INTF_NETID_RANGE = 0x0400;
764 
765     private final SparseBooleanArray mTunnelNetIds = new SparseBooleanArray();
766     private int mNextTunnelNetIdIndex = 0;
767 
768     /**
769      * Reserves a netId within the range of netIds allocated for IPsec tunnel interfaces
770      *
771      * <p>This method should only be called from Binder threads. Do not call this from within the
772      * system server as it will crash the system on failure.
773      *
774      * @return an integer key within the netId range, if successful
775      * @throws IllegalStateException if unsuccessful (all netId are currently reserved)
776      */
777     @VisibleForTesting
reserveNetId()778     int reserveNetId() {
779         synchronized (mTunnelNetIds) {
780             for (int i = 0; i < TUN_INTF_NETID_RANGE; i++) {
781                 int index = mNextTunnelNetIdIndex;
782                 int netId = index + TUN_INTF_NETID_START;
783                 if (++mNextTunnelNetIdIndex >= TUN_INTF_NETID_RANGE) mNextTunnelNetIdIndex = 0;
784                 if (!mTunnelNetIds.get(netId)) {
785                     mTunnelNetIds.put(netId, true);
786                     return netId;
787                 }
788             }
789         }
790         throw new IllegalStateException("No free netIds to allocate");
791     }
792 
793     @VisibleForTesting
releaseNetId(int netId)794     void releaseNetId(int netId) {
795         synchronized (mTunnelNetIds) {
796             mTunnelNetIds.delete(netId);
797         }
798     }
799 
800     private final class TunnelInterfaceRecord extends OwnedResourceRecord {
801         private final String mInterfaceName;
802         private final Network mUnderlyingNetwork;
803 
804         // outer addresses
805         private final String mLocalAddress;
806         private final String mRemoteAddress;
807 
808         private final int mIkey;
809         private final int mOkey;
810 
811         private final int mIfId;
812 
TunnelInterfaceRecord( int resourceId, String interfaceName, Network underlyingNetwork, String localAddr, String remoteAddr, int ikey, int okey, int intfId)813         TunnelInterfaceRecord(
814                 int resourceId,
815                 String interfaceName,
816                 Network underlyingNetwork,
817                 String localAddr,
818                 String remoteAddr,
819                 int ikey,
820                 int okey,
821                 int intfId) {
822             super(resourceId);
823 
824             mInterfaceName = interfaceName;
825             mUnderlyingNetwork = underlyingNetwork;
826             mLocalAddress = localAddr;
827             mRemoteAddress = remoteAddr;
828             mIkey = ikey;
829             mOkey = okey;
830             mIfId = intfId;
831         }
832 
833         /** always guarded by IpSecService#this */
834         @Override
freeUnderlyingResources()835         public void freeUnderlyingResources() {
836             // Calls to netd
837             //       Teardown VTI
838             //       Delete global policies
839             try {
840                 final INetd netd = mSrvConfig.getNetdInstance();
841                 netd.ipSecRemoveTunnelInterface(mInterfaceName);
842 
843                 for (int selAddrFamily : ADDRESS_FAMILIES) {
844                     netd.ipSecDeleteSecurityPolicy(
845                             uid,
846                             selAddrFamily,
847                             IpSecManager.DIRECTION_OUT,
848                             mOkey,
849                             0xffffffff,
850                             mIfId);
851                     netd.ipSecDeleteSecurityPolicy(
852                             uid,
853                             selAddrFamily,
854                             IpSecManager.DIRECTION_IN,
855                             mIkey,
856                             0xffffffff,
857                             mIfId);
858                 }
859             } catch (ServiceSpecificException | RemoteException e) {
860                 Log.e(
861                         TAG,
862                         "Failed to delete VTI with interface name: "
863                                 + mInterfaceName
864                                 + " and id: "
865                                 + mResourceId, e);
866             }
867 
868             getResourceTracker().give();
869             releaseNetId(mIkey);
870             releaseNetId(mOkey);
871         }
872 
getInterfaceName()873         public String getInterfaceName() {
874             return mInterfaceName;
875         }
876 
getUnderlyingNetwork()877         public Network getUnderlyingNetwork() {
878             return mUnderlyingNetwork;
879         }
880 
881         /** Returns the local, outer address for the tunnelInterface */
getLocalAddress()882         public String getLocalAddress() {
883             return mLocalAddress;
884         }
885 
886         /** Returns the remote, outer address for the tunnelInterface */
getRemoteAddress()887         public String getRemoteAddress() {
888             return mRemoteAddress;
889         }
890 
getIkey()891         public int getIkey() {
892             return mIkey;
893         }
894 
getOkey()895         public int getOkey() {
896             return mOkey;
897         }
898 
getIfId()899         public int getIfId() {
900             return mIfId;
901         }
902 
903         @Override
getResourceTracker()904         protected ResourceTracker getResourceTracker() {
905             return getUserRecord().mTunnelQuotaTracker;
906         }
907 
908         @Override
invalidate()909         public void invalidate() {
910             getUserRecord().removeTunnelInterfaceRecord(mResourceId);
911         }
912 
913         @Override
toString()914         public String toString() {
915             return new StringBuilder()
916                     .append("{super=")
917                     .append(super.toString())
918                     .append(", mInterfaceName=")
919                     .append(mInterfaceName)
920                     .append(", mUnderlyingNetwork=")
921                     .append(mUnderlyingNetwork)
922                     .append(", mLocalAddress=")
923                     .append(mLocalAddress)
924                     .append(", mRemoteAddress=")
925                     .append(mRemoteAddress)
926                     .append(", mIkey=")
927                     .append(mIkey)
928                     .append(", mOkey=")
929                     .append(mOkey)
930                     .append("}")
931                     .toString();
932         }
933     }
934 
935     /**
936      * Tracks a UDP encap socket, and manages cleanup paths
937      *
938      * <p>While this class does not manage non-kernel resources, race conditions around socket
939      * binding require that the service creates the encap socket, binds it and applies the socket
940      * policy before handing it to a user.
941      */
942     private final class EncapSocketRecord extends OwnedResourceRecord {
943         private FileDescriptor mSocket;
944         private final int mPort;
945 
EncapSocketRecord(int resourceId, FileDescriptor socket, int port)946         EncapSocketRecord(int resourceId, FileDescriptor socket, int port) {
947             super(resourceId);
948             mSocket = socket;
949             mPort = port;
950         }
951 
952         /** always guarded by IpSecService#this */
953         @Override
freeUnderlyingResources()954         public void freeUnderlyingResources() {
955             Log.d(TAG, "Closing port " + mPort);
956             IoUtils.closeQuietly(mSocket);
957             mSocket = null;
958 
959             getResourceTracker().give();
960         }
961 
getPort()962         public int getPort() {
963             return mPort;
964         }
965 
getFileDescriptor()966         public FileDescriptor getFileDescriptor() {
967             return mSocket;
968         }
969 
970         @Override
getResourceTracker()971         protected ResourceTracker getResourceTracker() {
972             return getUserRecord().mSocketQuotaTracker;
973         }
974 
975         @Override
invalidate()976         public void invalidate() {
977             getUserRecord().removeEncapSocketRecord(mResourceId);
978         }
979 
980         @Override
toString()981         public String toString() {
982             return new StringBuilder()
983                     .append("{super=")
984                     .append(super.toString())
985                     .append(", mSocket=")
986                     .append(mSocket)
987                     .append(", mPort=")
988                     .append(mPort)
989                     .append("}")
990                     .toString();
991         }
992     }
993 
994     /**
995      * Constructs a new IpSecService instance
996      *
997      * @param context Binder context for this service
998      */
IpSecService(Context context, INetworkManagementService networkManager)999     private IpSecService(Context context, INetworkManagementService networkManager) {
1000         this(context, networkManager, IpSecServiceConfiguration.GETSRVINSTANCE);
1001     }
1002 
create(Context context, INetworkManagementService networkManager)1003     static IpSecService create(Context context, INetworkManagementService networkManager)
1004             throws InterruptedException {
1005         final IpSecService service = new IpSecService(context, networkManager);
1006         service.connectNativeNetdService();
1007         return service;
1008     }
1009 
1010     @NonNull
getAppOpsManager()1011     private AppOpsManager getAppOpsManager() {
1012         AppOpsManager appOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
1013         if(appOps == null) throw new RuntimeException("System Server couldn't get AppOps");
1014         return appOps;
1015     }
1016 
1017     /** @hide */
1018     @VisibleForTesting
IpSecService(Context context, INetworkManagementService networkManager, IpSecServiceConfiguration config)1019     public IpSecService(Context context, INetworkManagementService networkManager,
1020             IpSecServiceConfiguration config) {
1021         this(
1022                 context,
1023                 networkManager,
1024                 config,
1025                 (fd, uid) -> {
1026                     try {
1027                         TrafficStats.setThreadStatsUid(uid);
1028                         TrafficStats.tagFileDescriptor(fd);
1029                     } finally {
1030                         TrafficStats.clearThreadStatsUid();
1031                     }
1032                 });
1033     }
1034 
1035     /** @hide */
1036     @VisibleForTesting
IpSecService(Context context, INetworkManagementService networkManager, IpSecServiceConfiguration config, UidFdTagger uidFdTagger)1037     public IpSecService(Context context, INetworkManagementService networkManager,
1038             IpSecServiceConfiguration config, UidFdTagger uidFdTagger) {
1039         mContext = context;
1040         mNetworkManager = Objects.requireNonNull(networkManager);
1041         mSrvConfig = config;
1042         mUidFdTagger = uidFdTagger;
1043     }
1044 
systemReady()1045     public void systemReady() {
1046         if (isNetdAlive()) {
1047             Slog.d(TAG, "IpSecService is ready");
1048         } else {
1049             Slog.wtf(TAG, "IpSecService not ready: failed to connect to NetD Native Service!");
1050         }
1051     }
1052 
connectNativeNetdService()1053     private void connectNativeNetdService() {
1054         // Avoid blocking the system server to do this
1055         new Thread() {
1056             @Override
1057             public void run() {
1058                 synchronized (IpSecService.this) {
1059                     NetdService.get(NETD_FETCH_TIMEOUT_MS);
1060                 }
1061             }
1062         }.start();
1063     }
1064 
isNetdAlive()1065     synchronized boolean isNetdAlive() {
1066         try {
1067             final INetd netd = mSrvConfig.getNetdInstance();
1068             if (netd == null) {
1069                 return false;
1070             }
1071             return netd.isAlive();
1072         } catch (RemoteException re) {
1073             return false;
1074         }
1075     }
1076 
1077     /**
1078      * Checks that the provided InetAddress is valid for use in an IPsec SA. The address must not be
1079      * a wildcard address and must be in a numeric form such as 1.2.3.4 or 2001::1.
1080      */
checkInetAddress(String inetAddress)1081     private static void checkInetAddress(String inetAddress) {
1082         if (TextUtils.isEmpty(inetAddress)) {
1083             throw new IllegalArgumentException("Unspecified address");
1084         }
1085 
1086         InetAddress checkAddr = NetworkUtils.numericToInetAddress(inetAddress);
1087 
1088         if (checkAddr.isAnyLocalAddress()) {
1089             throw new IllegalArgumentException("Inappropriate wildcard address: " + inetAddress);
1090         }
1091     }
1092 
1093     /**
1094      * Checks the user-provided direction field and throws an IllegalArgumentException if it is not
1095      * DIRECTION_IN or DIRECTION_OUT
1096      */
checkDirection(int direction)1097     private static void checkDirection(int direction) {
1098         switch (direction) {
1099             case IpSecManager.DIRECTION_OUT:
1100             case IpSecManager.DIRECTION_IN:
1101                 return;
1102         }
1103         throw new IllegalArgumentException("Invalid Direction: " + direction);
1104     }
1105 
1106     /** Get a new SPI and maintain the reservation in the system server */
1107     @Override
allocateSecurityParameterIndex( String destinationAddress, int requestedSpi, IBinder binder)1108     public synchronized IpSecSpiResponse allocateSecurityParameterIndex(
1109             String destinationAddress, int requestedSpi, IBinder binder) throws RemoteException {
1110         checkInetAddress(destinationAddress);
1111         // RFC 4303 Section 2.1 - 0=local, 1-255=reserved.
1112         if (requestedSpi > 0 && requestedSpi < 256) {
1113             throw new IllegalArgumentException("ESP SPI must not be in the range of 0-255.");
1114         }
1115         Objects.requireNonNull(binder, "Null Binder passed to allocateSecurityParameterIndex");
1116 
1117         int callingUid = Binder.getCallingUid();
1118         UserRecord userRecord = mUserResourceTracker.getUserRecord(callingUid);
1119         final int resourceId = mNextResourceId++;
1120 
1121         int spi = IpSecManager.INVALID_SECURITY_PARAMETER_INDEX;
1122         try {
1123             if (!userRecord.mSpiQuotaTracker.isAvailable()) {
1124                 return new IpSecSpiResponse(
1125                         IpSecManager.Status.RESOURCE_UNAVAILABLE, INVALID_RESOURCE_ID, spi);
1126             }
1127 
1128             spi =
1129                     mSrvConfig
1130                             .getNetdInstance()
1131                             .ipSecAllocateSpi(callingUid, "", destinationAddress, requestedSpi);
1132             Log.d(TAG, "Allocated SPI " + spi);
1133             userRecord.mSpiRecords.put(
1134                     resourceId,
1135                     new RefcountedResource<SpiRecord>(
1136                             new SpiRecord(resourceId, "", destinationAddress, spi), binder));
1137         } catch (ServiceSpecificException e) {
1138             if (e.errorCode == OsConstants.ENOENT) {
1139                 return new IpSecSpiResponse(
1140                         IpSecManager.Status.SPI_UNAVAILABLE, INVALID_RESOURCE_ID, spi);
1141             }
1142             throw e;
1143         } catch (RemoteException e) {
1144             throw e.rethrowFromSystemServer();
1145         }
1146         return new IpSecSpiResponse(IpSecManager.Status.OK, resourceId, spi);
1147     }
1148 
1149     /* This method should only be called from Binder threads. Do not call this from
1150      * within the system server as it will crash the system on failure.
1151      */
releaseResource(RefcountedResourceArray resArray, int resourceId)1152     private void releaseResource(RefcountedResourceArray resArray, int resourceId)
1153             throws RemoteException {
1154         resArray.getRefcountedResourceOrThrow(resourceId).userRelease();
1155     }
1156 
1157     /** Release a previously allocated SPI that has been registered with the system server */
1158     @Override
releaseSecurityParameterIndex(int resourceId)1159     public synchronized void releaseSecurityParameterIndex(int resourceId) throws RemoteException {
1160         UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
1161         releaseResource(userRecord.mSpiRecords, resourceId);
1162     }
1163 
1164     /**
1165      * This function finds and forcibly binds to a random system port, ensuring that the port cannot
1166      * be unbound.
1167      *
1168      * <p>A socket cannot be un-bound from a port if it was bound to that port by number. To select
1169      * a random open port and then bind by number, this function creates a temp socket, binds to a
1170      * random port (specifying 0), gets that port number, and then uses is to bind the user's UDP
1171      * Encapsulation Socket forcibly, so that it cannot be un-bound by the user with the returned
1172      * FileHandle.
1173      *
1174      * <p>The loop in this function handles the inherent race window between un-binding to a port
1175      * and re-binding, during which the system could *technically* hand that port out to someone
1176      * else.
1177      */
bindToRandomPort(FileDescriptor sockFd)1178     private int bindToRandomPort(FileDescriptor sockFd) throws IOException {
1179         for (int i = MAX_PORT_BIND_ATTEMPTS; i > 0; i--) {
1180             try {
1181                 FileDescriptor probeSocket = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
1182                 Os.bind(probeSocket, INADDR_ANY, 0);
1183                 int port = ((InetSocketAddress) Os.getsockname(probeSocket)).getPort();
1184                 Os.close(probeSocket);
1185                 Log.v(TAG, "Binding to port " + port);
1186                 Os.bind(sockFd, INADDR_ANY, port);
1187                 return port;
1188             } catch (ErrnoException e) {
1189                 // Someone miraculously claimed the port just after we closed probeSocket.
1190                 if (e.errno == OsConstants.EADDRINUSE) {
1191                     continue;
1192                 }
1193                 throw e.rethrowAsIOException();
1194             }
1195         }
1196         throw new IOException("Failed " + MAX_PORT_BIND_ATTEMPTS + " attempts to bind to a port");
1197     }
1198 
1199     /**
1200      * Functional interface to do traffic tagging of given sockets to UIDs.
1201      *
1202      * <p>Specifically used by openUdpEncapsulationSocket to ensure data usage on the UDP encap
1203      * sockets are billed to the UID that the UDP encap socket was created on behalf of.
1204      *
1205      * <p>Separate class so that the socket tagging logic can be mocked; TrafficStats uses static
1206      * methods that cannot be easily mocked/tested.
1207      */
1208     @VisibleForTesting
1209     public interface UidFdTagger {
1210         /**
1211          * Sets socket tag to assign all traffic to the provided UID.
1212          *
1213          * <p>Since the socket is created on behalf of an unprivileged application, all traffic
1214          * should be accounted to the UID of the unprivileged application.
1215          */
tag(FileDescriptor fd, int uid)1216         public void tag(FileDescriptor fd, int uid) throws IOException;
1217     }
1218 
1219     /**
1220      * Open a socket via the system server and bind it to the specified port (random if port=0).
1221      * This will return a PFD to the user that represent a bound UDP socket. The system server will
1222      * cache the socket and a record of its owner so that it can and must be freed when no longer
1223      * needed.
1224      */
1225     @Override
openUdpEncapsulationSocket(int port, IBinder binder)1226     public synchronized IpSecUdpEncapResponse openUdpEncapsulationSocket(int port, IBinder binder)
1227             throws RemoteException {
1228         if (port != 0 && (port < FREE_PORT_MIN || port > PORT_MAX)) {
1229             throw new IllegalArgumentException(
1230                     "Specified port number must be a valid non-reserved UDP port");
1231         }
1232         Objects.requireNonNull(binder, "Null Binder passed to openUdpEncapsulationSocket");
1233 
1234         int callingUid = Binder.getCallingUid();
1235         UserRecord userRecord = mUserResourceTracker.getUserRecord(callingUid);
1236         final int resourceId = mNextResourceId++;
1237         FileDescriptor sockFd = null;
1238         try {
1239             if (!userRecord.mSocketQuotaTracker.isAvailable()) {
1240                 return new IpSecUdpEncapResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE);
1241             }
1242 
1243             sockFd = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
1244             mUidFdTagger.tag(sockFd, callingUid);
1245 
1246             // This code is common to both the unspecified and specified port cases
1247             Os.setsockoptInt(
1248                     sockFd,
1249                     OsConstants.IPPROTO_UDP,
1250                     OsConstants.UDP_ENCAP,
1251                     OsConstants.UDP_ENCAP_ESPINUDP);
1252 
1253             mSrvConfig.getNetdInstance().ipSecSetEncapSocketOwner(
1254                         new ParcelFileDescriptor(sockFd), callingUid);
1255             if (port != 0) {
1256                 Log.v(TAG, "Binding to port " + port);
1257                 Os.bind(sockFd, INADDR_ANY, port);
1258             } else {
1259                 port = bindToRandomPort(sockFd);
1260             }
1261 
1262             userRecord.mEncapSocketRecords.put(
1263                     resourceId,
1264                     new RefcountedResource<EncapSocketRecord>(
1265                             new EncapSocketRecord(resourceId, sockFd, port), binder));
1266             return new IpSecUdpEncapResponse(IpSecManager.Status.OK, resourceId, port, sockFd);
1267         } catch (IOException | ErrnoException e) {
1268             IoUtils.closeQuietly(sockFd);
1269         }
1270         // If we make it to here, then something has gone wrong and we couldn't open a socket.
1271         // The only reasonable condition that would cause that is resource unavailable.
1272         return new IpSecUdpEncapResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE);
1273     }
1274 
1275     /** close a socket that has been been allocated by and registered with the system server */
1276     @Override
closeUdpEncapsulationSocket(int resourceId)1277     public synchronized void closeUdpEncapsulationSocket(int resourceId) throws RemoteException {
1278         UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
1279         releaseResource(userRecord.mEncapSocketRecords, resourceId);
1280     }
1281 
1282     /**
1283      * Create a tunnel interface for use in IPSec tunnel mode. The system server will cache the
1284      * tunnel interface and a record of its owner so that it can and must be freed when no longer
1285      * needed.
1286      */
1287     @Override
createTunnelInterface( String localAddr, String remoteAddr, Network underlyingNetwork, IBinder binder, String callingPackage)1288     public synchronized IpSecTunnelInterfaceResponse createTunnelInterface(
1289             String localAddr, String remoteAddr, Network underlyingNetwork, IBinder binder,
1290             String callingPackage) {
1291         enforceTunnelFeatureAndPermissions(callingPackage);
1292         Objects.requireNonNull(binder, "Null Binder passed to createTunnelInterface");
1293         Objects.requireNonNull(underlyingNetwork, "No underlying network was specified");
1294         checkInetAddress(localAddr);
1295         checkInetAddress(remoteAddr);
1296 
1297         // TODO: Check that underlying network exists, and IP addresses not assigned to a different
1298         //       network (b/72316676).
1299 
1300         int callerUid = Binder.getCallingUid();
1301         UserRecord userRecord = mUserResourceTracker.getUserRecord(callerUid);
1302         if (!userRecord.mTunnelQuotaTracker.isAvailable()) {
1303             return new IpSecTunnelInterfaceResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE);
1304         }
1305 
1306         final int resourceId = mNextResourceId++;
1307         final int ikey = reserveNetId();
1308         final int okey = reserveNetId();
1309         String intfName = String.format("%s%d", INetd.IPSEC_INTERFACE_PREFIX, resourceId);
1310 
1311         try {
1312             // Calls to netd:
1313             //       Create VTI
1314             //       Add inbound/outbound global policies
1315             //              (use reqid = 0)
1316             final INetd netd = mSrvConfig.getNetdInstance();
1317             netd.ipSecAddTunnelInterface(intfName, localAddr, remoteAddr, ikey, okey, resourceId);
1318 
1319             Binder.withCleanCallingIdentity(() -> {
1320                 mNetworkManager.setInterfaceUp(intfName);
1321             });
1322 
1323             for (int selAddrFamily : ADDRESS_FAMILIES) {
1324                 // Always send down correct local/remote addresses for template.
1325                 netd.ipSecAddSecurityPolicy(
1326                         callerUid,
1327                         selAddrFamily,
1328                         IpSecManager.DIRECTION_OUT,
1329                         localAddr,
1330                         remoteAddr,
1331                         0,
1332                         okey,
1333                         0xffffffff,
1334                         resourceId);
1335                 netd.ipSecAddSecurityPolicy(
1336                         callerUid,
1337                         selAddrFamily,
1338                         IpSecManager.DIRECTION_IN,
1339                         remoteAddr,
1340                         localAddr,
1341                         0,
1342                         ikey,
1343                         0xffffffff,
1344                         resourceId);
1345             }
1346 
1347             userRecord.mTunnelInterfaceRecords.put(
1348                     resourceId,
1349                     new RefcountedResource<TunnelInterfaceRecord>(
1350                             new TunnelInterfaceRecord(
1351                                     resourceId,
1352                                     intfName,
1353                                     underlyingNetwork,
1354                                     localAddr,
1355                                     remoteAddr,
1356                                     ikey,
1357                                     okey,
1358                                     resourceId),
1359                             binder));
1360             return new IpSecTunnelInterfaceResponse(IpSecManager.Status.OK, resourceId, intfName);
1361         } catch (RemoteException e) {
1362             // Release keys if we got an error.
1363             releaseNetId(ikey);
1364             releaseNetId(okey);
1365             throw e.rethrowFromSystemServer();
1366         } catch (Throwable t) {
1367             // Release keys if we got an error.
1368             releaseNetId(ikey);
1369             releaseNetId(okey);
1370             throw t;
1371         }
1372     }
1373 
1374     /**
1375      * Adds a new local address to the tunnel interface. This allows packets to be sent and received
1376      * from multiple local IP addresses over the same tunnel.
1377      */
1378     @Override
addAddressToTunnelInterface( int tunnelResourceId, LinkAddress localAddr, String callingPackage)1379     public synchronized void addAddressToTunnelInterface(
1380             int tunnelResourceId, LinkAddress localAddr, String callingPackage) {
1381         enforceTunnelFeatureAndPermissions(callingPackage);
1382         UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
1383 
1384         // Get tunnelInterface record; if no such interface is found, will throw
1385         // IllegalArgumentException
1386         TunnelInterfaceRecord tunnelInterfaceInfo =
1387                 userRecord.mTunnelInterfaceRecords.getResourceOrThrow(tunnelResourceId);
1388 
1389         try {
1390             // We can assume general validity of the IP address, since we get them as a
1391             // LinkAddress, which does some validation.
1392             mSrvConfig
1393                     .getNetdInstance()
1394                     .interfaceAddAddress(
1395                             tunnelInterfaceInfo.mInterfaceName,
1396                             localAddr.getAddress().getHostAddress(),
1397                             localAddr.getPrefixLength());
1398         } catch (RemoteException e) {
1399             throw e.rethrowFromSystemServer();
1400         }
1401     }
1402 
1403     /**
1404      * Remove a new local address from the tunnel interface. After removal, the address will no
1405      * longer be available to send from, or receive on.
1406      */
1407     @Override
removeAddressFromTunnelInterface( int tunnelResourceId, LinkAddress localAddr, String callingPackage)1408     public synchronized void removeAddressFromTunnelInterface(
1409             int tunnelResourceId, LinkAddress localAddr, String callingPackage) {
1410         enforceTunnelFeatureAndPermissions(callingPackage);
1411 
1412         UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
1413         // Get tunnelInterface record; if no such interface is found, will throw
1414         // IllegalArgumentException
1415         TunnelInterfaceRecord tunnelInterfaceInfo =
1416                 userRecord.mTunnelInterfaceRecords.getResourceOrThrow(tunnelResourceId);
1417 
1418         try {
1419             // We can assume general validity of the IP address, since we get them as a
1420             // LinkAddress, which does some validation.
1421             mSrvConfig
1422                     .getNetdInstance()
1423                     .interfaceDelAddress(
1424                             tunnelInterfaceInfo.mInterfaceName,
1425                             localAddr.getAddress().getHostAddress(),
1426                             localAddr.getPrefixLength());
1427         } catch (RemoteException e) {
1428             throw e.rethrowFromSystemServer();
1429         }
1430     }
1431 
1432     /**
1433      * Delete a TunnelInterface that has been been allocated by and registered with the system
1434      * server
1435      */
1436     @Override
deleteTunnelInterface( int resourceId, String callingPackage)1437     public synchronized void deleteTunnelInterface(
1438             int resourceId, String callingPackage) throws RemoteException {
1439         enforceTunnelFeatureAndPermissions(callingPackage);
1440         UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
1441         releaseResource(userRecord.mTunnelInterfaceRecords, resourceId);
1442     }
1443 
1444     @VisibleForTesting
validateAlgorithms(IpSecConfig config)1445     void validateAlgorithms(IpSecConfig config) throws IllegalArgumentException {
1446         IpSecAlgorithm auth = config.getAuthentication();
1447         IpSecAlgorithm crypt = config.getEncryption();
1448         IpSecAlgorithm aead = config.getAuthenticatedEncryption();
1449 
1450         // Validate the algorithm set
1451         Preconditions.checkArgument(
1452                 aead != null || crypt != null || auth != null,
1453                 "No Encryption or Authentication algorithms specified");
1454         Preconditions.checkArgument(
1455                 auth == null || auth.isAuthentication(),
1456                 "Unsupported algorithm for Authentication");
1457         Preconditions.checkArgument(
1458                 crypt == null || crypt.isEncryption(), "Unsupported algorithm for Encryption");
1459         Preconditions.checkArgument(
1460                 aead == null || aead.isAead(),
1461                 "Unsupported algorithm for Authenticated Encryption");
1462         Preconditions.checkArgument(
1463                 aead == null || (auth == null && crypt == null),
1464                 "Authenticated Encryption is mutually exclusive with other Authentication "
1465                         + "or Encryption algorithms");
1466     }
1467 
getFamily(String inetAddress)1468     private int getFamily(String inetAddress) {
1469         int family = AF_UNSPEC;
1470         InetAddress checkAddress = NetworkUtils.numericToInetAddress(inetAddress);
1471         if (checkAddress instanceof Inet4Address) {
1472             family = AF_INET;
1473         } else if (checkAddress instanceof Inet6Address) {
1474             family = AF_INET6;
1475         }
1476         return family;
1477     }
1478 
1479     /**
1480      * Checks an IpSecConfig parcel to ensure that the contents are sane and throws an
1481      * IllegalArgumentException if they are not.
1482      */
checkIpSecConfig(IpSecConfig config)1483     private void checkIpSecConfig(IpSecConfig config) {
1484         UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
1485 
1486         switch (config.getEncapType()) {
1487             case IpSecTransform.ENCAP_NONE:
1488                 break;
1489             case IpSecTransform.ENCAP_ESPINUDP:
1490             case IpSecTransform.ENCAP_ESPINUDP_NON_IKE:
1491                 // Retrieve encap socket record; will throw IllegalArgumentException if not found
1492                 userRecord.mEncapSocketRecords.getResourceOrThrow(
1493                         config.getEncapSocketResourceId());
1494 
1495                 int port = config.getEncapRemotePort();
1496                 if (port <= 0 || port > 0xFFFF) {
1497                     throw new IllegalArgumentException("Invalid remote UDP port: " + port);
1498                 }
1499                 break;
1500             default:
1501                 throw new IllegalArgumentException("Invalid Encap Type: " + config.getEncapType());
1502         }
1503 
1504         validateAlgorithms(config);
1505 
1506         // Retrieve SPI record; will throw IllegalArgumentException if not found
1507         SpiRecord s = userRecord.mSpiRecords.getResourceOrThrow(config.getSpiResourceId());
1508 
1509         // Check to ensure that SPI has not already been used.
1510         if (s.getOwnedByTransform()) {
1511             throw new IllegalStateException("SPI already in use; cannot be used in new Transforms");
1512         }
1513 
1514         // If no remote address is supplied, then use one from the SPI.
1515         if (TextUtils.isEmpty(config.getDestinationAddress())) {
1516             config.setDestinationAddress(s.getDestinationAddress());
1517         }
1518 
1519         // All remote addresses must match
1520         if (!config.getDestinationAddress().equals(s.getDestinationAddress())) {
1521             throw new IllegalArgumentException("Mismatched remote addresseses.");
1522         }
1523 
1524         // This check is technically redundant due to the chain of custody between the SPI and
1525         // the IpSecConfig, but in the future if the dest is allowed to be set explicitly in
1526         // the transform, this will prevent us from messing up.
1527         checkInetAddress(config.getDestinationAddress());
1528 
1529         // Require a valid source address for all transforms.
1530         checkInetAddress(config.getSourceAddress());
1531 
1532         // Check to ensure source and destination have the same address family.
1533         String sourceAddress = config.getSourceAddress();
1534         String destinationAddress = config.getDestinationAddress();
1535         int sourceFamily = getFamily(sourceAddress);
1536         int destinationFamily = getFamily(destinationAddress);
1537         if (sourceFamily != destinationFamily) {
1538             throw new IllegalArgumentException(
1539                     "Source address ("
1540                             + sourceAddress
1541                             + ") and destination address ("
1542                             + destinationAddress
1543                             + ") have different address families.");
1544         }
1545 
1546         // Throw an error if UDP Encapsulation is not used in IPv4.
1547         if (config.getEncapType() != IpSecTransform.ENCAP_NONE && sourceFamily != AF_INET) {
1548             throw new IllegalArgumentException(
1549                     "UDP Encapsulation is not supported for this address family");
1550         }
1551 
1552         switch (config.getMode()) {
1553             case IpSecTransform.MODE_TRANSPORT:
1554                 break;
1555             case IpSecTransform.MODE_TUNNEL:
1556                 break;
1557             default:
1558                 throw new IllegalArgumentException(
1559                         "Invalid IpSecTransform.mode: " + config.getMode());
1560         }
1561 
1562         config.setMarkValue(0);
1563         config.setMarkMask(0);
1564     }
1565 
1566     private static final String TUNNEL_OP = AppOpsManager.OPSTR_MANAGE_IPSEC_TUNNELS;
1567 
enforceTunnelFeatureAndPermissions(String callingPackage)1568     private void enforceTunnelFeatureAndPermissions(String callingPackage) {
1569         if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_IPSEC_TUNNELS)) {
1570             throw new UnsupportedOperationException(
1571                     "IPsec Tunnel Mode requires PackageManager.FEATURE_IPSEC_TUNNELS");
1572         }
1573 
1574         Objects.requireNonNull(callingPackage, "Null calling package cannot create IpSec tunnels");
1575 
1576         // OP_MANAGE_IPSEC_TUNNELS will return MODE_ERRORED by default, including for the system
1577         // server. If the appop is not granted, require that the caller has the MANAGE_IPSEC_TUNNELS
1578         // permission or is the System Server.
1579         if (AppOpsManager.MODE_ALLOWED == getAppOpsManager().noteOpNoThrow(
1580                 TUNNEL_OP, Binder.getCallingUid(), callingPackage)) {
1581             return;
1582         }
1583         mContext.enforceCallingOrSelfPermission(
1584                 android.Manifest.permission.MANAGE_IPSEC_TUNNELS, "IpSecService");
1585     }
1586 
createOrUpdateTransform( IpSecConfig c, int resourceId, SpiRecord spiRecord, EncapSocketRecord socketRecord)1587     private void createOrUpdateTransform(
1588             IpSecConfig c, int resourceId, SpiRecord spiRecord, EncapSocketRecord socketRecord)
1589             throws RemoteException {
1590 
1591         int encapType = c.getEncapType(), encapLocalPort = 0, encapRemotePort = 0;
1592         if (encapType != IpSecTransform.ENCAP_NONE) {
1593             encapLocalPort = socketRecord.getPort();
1594             encapRemotePort = c.getEncapRemotePort();
1595         }
1596 
1597         IpSecAlgorithm auth = c.getAuthentication();
1598         IpSecAlgorithm crypt = c.getEncryption();
1599         IpSecAlgorithm authCrypt = c.getAuthenticatedEncryption();
1600 
1601         String cryptName;
1602         if (crypt == null) {
1603             cryptName = (authCrypt == null) ? IpSecAlgorithm.CRYPT_NULL : "";
1604         } else {
1605             cryptName = crypt.getName();
1606         }
1607 
1608         mSrvConfig
1609                 .getNetdInstance()
1610                 .ipSecAddSecurityAssociation(
1611                         Binder.getCallingUid(),
1612                         c.getMode(),
1613                         c.getSourceAddress(),
1614                         c.getDestinationAddress(),
1615                         (c.getNetwork() != null) ? c.getNetwork().netId : 0,
1616                         spiRecord.getSpi(),
1617                         c.getMarkValue(),
1618                         c.getMarkMask(),
1619                         (auth != null) ? auth.getName() : "",
1620                         (auth != null) ? auth.getKey() : new byte[] {},
1621                         (auth != null) ? auth.getTruncationLengthBits() : 0,
1622                         cryptName,
1623                         (crypt != null) ? crypt.getKey() : new byte[] {},
1624                         (crypt != null) ? crypt.getTruncationLengthBits() : 0,
1625                         (authCrypt != null) ? authCrypt.getName() : "",
1626                         (authCrypt != null) ? authCrypt.getKey() : new byte[] {},
1627                         (authCrypt != null) ? authCrypt.getTruncationLengthBits() : 0,
1628                         encapType,
1629                         encapLocalPort,
1630                         encapRemotePort,
1631                         c.getXfrmInterfaceId());
1632     }
1633 
1634     /**
1635      * Create a IPsec transform, which represents a single security association in the kernel. The
1636      * transform will be cached by the system server and must be freed when no longer needed. It is
1637      * possible to free one, deleting the SA from underneath sockets that are using it, which will
1638      * result in all of those sockets becoming unable to send or receive data.
1639      */
1640     @Override
createTransform( IpSecConfig c, IBinder binder, String callingPackage)1641     public synchronized IpSecTransformResponse createTransform(
1642             IpSecConfig c, IBinder binder, String callingPackage) throws RemoteException {
1643         Objects.requireNonNull(c);
1644         if (c.getMode() == IpSecTransform.MODE_TUNNEL) {
1645             enforceTunnelFeatureAndPermissions(callingPackage);
1646         }
1647         checkIpSecConfig(c);
1648         Objects.requireNonNull(binder, "Null Binder passed to createTransform");
1649         final int resourceId = mNextResourceId++;
1650 
1651         UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
1652         List<RefcountedResource> dependencies = new ArrayList<>();
1653 
1654         if (!userRecord.mTransformQuotaTracker.isAvailable()) {
1655             return new IpSecTransformResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE);
1656         }
1657 
1658         EncapSocketRecord socketRecord = null;
1659         if (c.getEncapType() != IpSecTransform.ENCAP_NONE) {
1660             RefcountedResource<EncapSocketRecord> refcountedSocketRecord =
1661                     userRecord.mEncapSocketRecords.getRefcountedResourceOrThrow(
1662                             c.getEncapSocketResourceId());
1663             dependencies.add(refcountedSocketRecord);
1664             socketRecord = refcountedSocketRecord.getResource();
1665         }
1666 
1667         RefcountedResource<SpiRecord> refcountedSpiRecord =
1668                 userRecord.mSpiRecords.getRefcountedResourceOrThrow(c.getSpiResourceId());
1669         dependencies.add(refcountedSpiRecord);
1670         SpiRecord spiRecord = refcountedSpiRecord.getResource();
1671 
1672         createOrUpdateTransform(c, resourceId, spiRecord, socketRecord);
1673 
1674         // SA was created successfully, time to construct a record and lock it away
1675         userRecord.mTransformRecords.put(
1676                 resourceId,
1677                 new RefcountedResource<TransformRecord>(
1678                         new TransformRecord(resourceId, c, spiRecord, socketRecord),
1679                         binder,
1680                         dependencies.toArray(new RefcountedResource[dependencies.size()])));
1681         return new IpSecTransformResponse(IpSecManager.Status.OK, resourceId);
1682     }
1683 
1684     /**
1685      * Delete a transport mode transform that was previously allocated by + registered with the
1686      * system server. If this is called on an inactive (or non-existent) transform, it will not
1687      * return an error. It's safe to de-allocate transforms that may have already been deleted for
1688      * other reasons.
1689      */
1690     @Override
deleteTransform(int resourceId)1691     public synchronized void deleteTransform(int resourceId) throws RemoteException {
1692         UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
1693         releaseResource(userRecord.mTransformRecords, resourceId);
1694     }
1695 
1696     /**
1697      * Apply an active transport mode transform to a socket, which will apply the IPsec security
1698      * association as a correspondent policy to the provided socket
1699      */
1700     @Override
applyTransportModeTransform( ParcelFileDescriptor socket, int direction, int resourceId)1701     public synchronized void applyTransportModeTransform(
1702             ParcelFileDescriptor socket, int direction, int resourceId) throws RemoteException {
1703         int callingUid = Binder.getCallingUid();
1704         UserRecord userRecord = mUserResourceTracker.getUserRecord(callingUid);
1705         checkDirection(direction);
1706         // Get transform record; if no transform is found, will throw IllegalArgumentException
1707         TransformRecord info = userRecord.mTransformRecords.getResourceOrThrow(resourceId);
1708 
1709         // TODO: make this a function.
1710         if (info.pid != getCallingPid() || info.uid != callingUid) {
1711             throw new SecurityException("Only the owner of an IpSec Transform may apply it!");
1712         }
1713 
1714         // Get config and check that to-be-applied transform has the correct mode
1715         IpSecConfig c = info.getConfig();
1716         Preconditions.checkArgument(
1717                 c.getMode() == IpSecTransform.MODE_TRANSPORT,
1718                 "Transform mode was not Transport mode; cannot be applied to a socket");
1719 
1720         mSrvConfig
1721                 .getNetdInstance()
1722                 .ipSecApplyTransportModeTransform(
1723                         socket,
1724                         callingUid,
1725                         direction,
1726                         c.getSourceAddress(),
1727                         c.getDestinationAddress(),
1728                         info.getSpiRecord().getSpi());
1729     }
1730 
1731     /**
1732      * Remove transport mode transforms from a socket, applying the default (empty) policy. This
1733      * ensures that NO IPsec policy is applied to the socket (would be the equivalent of applying a
1734      * policy that performs no IPsec). Today the resourceId parameter is passed but not used:
1735      * reserved for future improved input validation.
1736      */
1737     @Override
removeTransportModeTransforms(ParcelFileDescriptor socket)1738     public synchronized void removeTransportModeTransforms(ParcelFileDescriptor socket)
1739             throws RemoteException {
1740         mSrvConfig
1741                 .getNetdInstance()
1742                 .ipSecRemoveTransportModeTransform(socket);
1743     }
1744 
1745     /**
1746      * Apply an active tunnel mode transform to a TunnelInterface, which will apply the IPsec
1747      * security association as a correspondent policy to the provided interface
1748      */
1749     @Override
applyTunnelModeTransform( int tunnelResourceId, int direction, int transformResourceId, String callingPackage)1750     public synchronized void applyTunnelModeTransform(
1751             int tunnelResourceId, int direction,
1752             int transformResourceId, String callingPackage) throws RemoteException {
1753         enforceTunnelFeatureAndPermissions(callingPackage);
1754         checkDirection(direction);
1755 
1756         int callingUid = Binder.getCallingUid();
1757         UserRecord userRecord = mUserResourceTracker.getUserRecord(callingUid);
1758 
1759         // Get transform record; if no transform is found, will throw IllegalArgumentException
1760         TransformRecord transformInfo =
1761                 userRecord.mTransformRecords.getResourceOrThrow(transformResourceId);
1762 
1763         // Get tunnelInterface record; if no such interface is found, will throw
1764         // IllegalArgumentException
1765         TunnelInterfaceRecord tunnelInterfaceInfo =
1766                 userRecord.mTunnelInterfaceRecords.getResourceOrThrow(tunnelResourceId);
1767 
1768         // Get config and check that to-be-applied transform has the correct mode
1769         IpSecConfig c = transformInfo.getConfig();
1770         Preconditions.checkArgument(
1771                 c.getMode() == IpSecTransform.MODE_TUNNEL,
1772                 "Transform mode was not Tunnel mode; cannot be applied to a tunnel interface");
1773 
1774         EncapSocketRecord socketRecord = null;
1775         if (c.getEncapType() != IpSecTransform.ENCAP_NONE) {
1776             socketRecord =
1777                     userRecord.mEncapSocketRecords.getResourceOrThrow(c.getEncapSocketResourceId());
1778         }
1779         SpiRecord spiRecord = transformInfo.getSpiRecord();
1780 
1781         int mark =
1782                 (direction == IpSecManager.DIRECTION_OUT)
1783                         ? tunnelInterfaceInfo.getOkey()
1784                         : tunnelInterfaceInfo.getIkey();
1785 
1786         try {
1787             // Default to using the invalid SPI of 0 for inbound SAs. This allows policies to skip
1788             // SPI matching as part of the template resolution.
1789             int spi = IpSecManager.INVALID_SECURITY_PARAMETER_INDEX;
1790             c.setXfrmInterfaceId(tunnelInterfaceInfo.getIfId());
1791 
1792             // TODO: enable this when UPDSA supports updating marks. Adding kernel support upstream
1793             //     (and backporting) would allow us to narrow the mark space, and ensure that the SA
1794             //     and SPs have matching marks (as VTI are meant to be built).
1795             // Currently update does nothing with marks. Leave empty (defaulting to 0) to ensure the
1796             //     config matches the actual allocated resources in the kernel.
1797             // All SAs will have zero marks (from creation time), and any policy that matches the
1798             //     same src/dst could match these SAs. Non-IpSecService governed processes that
1799             //     establish floating policies with the same src/dst may result in undefined
1800             //     behavior. This is generally limited to vendor code due to the permissions
1801             //     (CAP_NET_ADMIN) required.
1802             //
1803             // c.setMarkValue(mark);
1804             // c.setMarkMask(0xffffffff);
1805 
1806             if (direction == IpSecManager.DIRECTION_OUT) {
1807                 // Set output mark via underlying network (output only)
1808                 c.setNetwork(tunnelInterfaceInfo.getUnderlyingNetwork());
1809 
1810                 // Set outbound SPI only. We want inbound to use any valid SA (old, new) on rekeys,
1811                 // but want to guarantee outbound packets are sent over the new SA.
1812                 spi = spiRecord.getSpi();
1813             }
1814 
1815             // Always update the policy with the relevant XFRM_IF_ID
1816             for (int selAddrFamily : ADDRESS_FAMILIES) {
1817                 mSrvConfig
1818                         .getNetdInstance()
1819                         .ipSecUpdateSecurityPolicy(
1820                                 callingUid,
1821                                 selAddrFamily,
1822                                 direction,
1823                                 transformInfo.getConfig().getSourceAddress(),
1824                                 transformInfo.getConfig().getDestinationAddress(),
1825                                 spi, // If outbound, also add SPI to the policy.
1826                                 mark, // Must always set policy mark; ikey/okey for VTIs
1827                                 0xffffffff,
1828                                 c.getXfrmInterfaceId());
1829             }
1830 
1831             // Update SA with tunnel mark (ikey or okey based on direction)
1832             createOrUpdateTransform(c, transformResourceId, spiRecord, socketRecord);
1833         } catch (ServiceSpecificException e) {
1834             if (e.errorCode == EINVAL) {
1835                 throw new IllegalArgumentException(e.toString());
1836             } else {
1837                 throw e;
1838             }
1839         }
1840     }
1841 
1842     @Override
dump(FileDescriptor fd, PrintWriter pw, String[] args)1843     protected synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1844         mContext.enforceCallingOrSelfPermission(DUMP, TAG);
1845 
1846         pw.println("IpSecService dump:");
1847         pw.println("NetdNativeService Connection: " + (isNetdAlive() ? "alive" : "dead"));
1848         pw.println();
1849 
1850         pw.println("mUserResourceTracker:");
1851         pw.println(mUserResourceTracker);
1852     }
1853 }
1854