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