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