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