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