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