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