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