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