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
17package com.android.server;
18
19import static android.Manifest.permission.DUMP;
20import static android.net.IpSecManager.INVALID_RESOURCE_ID;
21import static android.system.OsConstants.AF_INET;
22import static android.system.OsConstants.EINVAL;
23import static android.system.OsConstants.IPPROTO_UDP;
24import static android.system.OsConstants.SOCK_DGRAM;
25import static com.android.internal.util.Preconditions.checkNotNull;
26
27import android.annotation.NonNull;
28import android.app.AppOpsManager;
29import android.content.Context;
30import android.net.ConnectivityManager;
31import android.net.IIpSecService;
32import android.net.INetd;
33import android.net.IpSecAlgorithm;
34import android.net.IpSecConfig;
35import android.net.IpSecManager;
36import android.net.IpSecSpiResponse;
37import android.net.IpSecTransform;
38import android.net.IpSecTransformResponse;
39import android.net.IpSecTunnelInterfaceResponse;
40import android.net.IpSecUdpEncapResponse;
41import android.net.LinkAddress;
42import android.net.Network;
43import android.net.NetworkUtils;
44import android.net.TrafficStats;
45import android.net.util.NetdService;
46import android.os.Binder;
47import android.os.DeadSystemException;
48import android.os.IBinder;
49import android.os.ParcelFileDescriptor;
50import android.os.RemoteException;
51import android.os.ServiceSpecificException;
52import android.system.ErrnoException;
53import android.system.Os;
54import android.system.OsConstants;
55import android.text.TextUtils;
56import android.util.Log;
57import android.util.Slog;
58import android.util.SparseArray;
59import android.util.SparseBooleanArray;
60
61import com.android.internal.annotations.GuardedBy;
62import com.android.internal.annotations.VisibleForTesting;
63import com.android.internal.util.Preconditions;
64
65import java.io.FileDescriptor;
66import java.io.IOException;
67import java.io.PrintWriter;
68import java.net.InetAddress;
69import java.net.InetSocketAddress;
70import java.net.UnknownHostException;
71import java.util.ArrayList;
72import java.util.List;
73
74import 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 */
87public 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 {
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         */
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         */
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
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
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
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")
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")
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
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
320        ResourceTracker(int max) {
321            mMax = max;
322            mCurrent = 0;
323        }
324
325        boolean isAvailable() {
326            return (mCurrent < mMax);
327        }
328
329        void take() {
330            if (!isAvailable()) {
331                Log.wtf(TAG, "Too many resources allocated!");
332            }
333            mCurrent++;
334        }
335
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
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
395        void removeSpiRecord(int resourceId) {
396            mSpiRecords.remove(resourceId);
397        }
398
399        void removeTransformRecord(int resourceId) {
400            mTransformRecords.remove(resourceId);
401        }
402
403        void removeTunnelInterfaceRecord(int resourceId) {
404            mTunnelInterfaceRecords.remove(resourceId);
405        }
406
407        void removeEncapSocketRecord(int resourceId) {
408            mEncapSocketRecords.remove(resourceId);
409        }
410
411        @Override
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 */
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 */
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
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
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
498        public abstract void invalidate() throws RemoteException;
499
500        /** Convenience method; retrieves the user resource record for the stored UID. */
501        protected UserRecord getUserRecord() {
502            return mUserResourceTracker.getUserRecord(uid);
503        }
504
505        @Override
506        public abstract void freeUnderlyingResources() throws RemoteException;
507
508        /** Get the resource tracker for this resource */
509        protected abstract ResourceTracker getResourceTracker();
510
511        @Override
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
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         */
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         */
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
563        void put(int key, RefcountedResource<T> obj) {
564            checkNotNull(obj, "Null resources cannot be added");
565            mArray.put(key, obj);
566        }
567
568        void remove(int key) {
569            mArray.remove(key);
570        }
571
572        @Override
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
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
598        public IpSecConfig getConfig() {
599            return mConfig;
600        }
601
602        public SpiRecord getSpiRecord() {
603            return mSpi;
604        }
605
606        public EncapSocketRecord getSocketRecord() {
607            return mSocket;
608        }
609
610        /** always guarded by IpSecService#this */
611        @Override
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
632        public void invalidate() throws RemoteException {
633            getUserRecord().removeTransformRecord(mResourceId);
634        }
635
636        @Override
637        protected ResourceTracker getResourceTracker() {
638            return getUserRecord().mTransformQuotaTracker;
639        }
640
641        @Override
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
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
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
696        public int getSpi() {
697            return mSpi;
698        }
699
700        public String getDestinationAddress() {
701            return mDestinationAddress;
702        }
703
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
713        public boolean getOwnedByTransform() {
714            return mOwnedByTransform;
715        }
716
717        @Override
718        public void invalidate() throws RemoteException {
719            getUserRecord().removeSpiRecord(mResourceId);
720        }
721
722        @Override
723        protected ResourceTracker getResourceTracker() {
724            return getUserRecord().mSpiQuotaTracker;
725        }
726
727        @Override
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
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
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
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
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
847        public String getInterfaceName() {
848            return mInterfaceName;
849        }
850
851        public Network getUnderlyingNetwork() {
852            return mUnderlyingNetwork;
853        }
854
855        /** Returns the local, outer address for the tunnelInterface */
856        public String getLocalAddress() {
857            return mLocalAddress;
858        }
859
860        /** Returns the remote, outer address for the tunnelInterface */
861        public String getRemoteAddress() {
862            return mRemoteAddress;
863        }
864
865        public int getIkey() {
866            return mIkey;
867        }
868
869        public int getOkey() {
870            return mOkey;
871        }
872
873        @Override
874        protected ResourceTracker getResourceTracker() {
875            return getUserRecord().mTunnelQuotaTracker;
876        }
877
878        @Override
879        public void invalidate() {
880            getUserRecord().removeTunnelInterfaceRecord(mResourceId);
881        }
882
883        @Override
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
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
924        public void freeUnderlyingResources() {
925            Log.d(TAG, "Closing port " + mPort);
926            IoUtils.closeQuietly(mSocket);
927            mSocket = null;
928
929            getResourceTracker().give();
930        }
931
932        public int getPort() {
933            return mPort;
934        }
935
936        public FileDescriptor getFileDescriptor() {
937            return mSocket;
938        }
939
940        @Override
941        protected ResourceTracker getResourceTracker() {
942            return getUserRecord().mSocketQuotaTracker;
943        }
944
945        @Override
946        public void invalidate() {
947            getUserRecord().removeEncapSocketRecord(mResourceId);
948        }
949
950        @Override
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     */
969    private IpSecService(Context context) {
970        this(context, IpSecServiceConfiguration.GETSRVINSTANCE);
971    }
972
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
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
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
1004    public IpSecService(
1005            Context context, IpSecServiceConfiguration config, UidFdTagger uidFdTagger) {
1006        mContext = context;
1007        mSrvConfig = config;
1008        mUidFdTagger = uidFdTagger;
1009    }
1010
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
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
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     */
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     */
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
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     */
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
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     */
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         */
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
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
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
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
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
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
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
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     */
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
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
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
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
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
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
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
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
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