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