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