1 /* 2 * Copyright (C) 2019 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.networkstack.tethering; 18 19 import static android.Manifest.permission.ACCESS_NETWORK_STATE; 20 import static android.Manifest.permission.NETWORK_SETTINGS; 21 import static android.Manifest.permission.NETWORK_STACK; 22 import static android.Manifest.permission.TETHER_PRIVILEGED; 23 import static android.content.pm.PackageManager.PERMISSION_GRANTED; 24 import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK; 25 import static android.net.TetheringManager.TETHERING_WIFI; 26 import static android.net.TetheringManager.TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION; 27 import static android.net.TetheringManager.TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION; 28 import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR; 29 import static android.net.TetheringManager.TETHER_ERROR_UNSUPPORTED; 30 import static android.net.dhcp.IDhcpServer.STATUS_UNKNOWN_ERROR; 31 32 import android.app.AppOpsManager; 33 import android.app.Service; 34 import android.bluetooth.BluetoothAdapter; 35 import android.bluetooth.BluetoothManager; 36 import android.content.Context; 37 import android.content.Intent; 38 import android.net.IIntResultListener; 39 import android.net.INetworkStackConnector; 40 import android.net.ITetheringConnector; 41 import android.net.ITetheringEventCallback; 42 import android.net.NetworkStack; 43 import android.net.TetheringManager.TetheringRequest; 44 import android.net.TetheringRequestParcel; 45 import android.net.dhcp.DhcpServerCallbacks; 46 import android.net.dhcp.DhcpServingParamsParcel; 47 import android.net.ip.IpServer; 48 import android.os.Binder; 49 import android.os.HandlerThread; 50 import android.os.IBinder; 51 import android.os.Looper; 52 import android.os.RemoteException; 53 import android.os.ResultReceiver; 54 import android.util.Log; 55 56 import androidx.annotation.NonNull; 57 import androidx.annotation.Nullable; 58 59 import com.android.internal.annotations.VisibleForTesting; 60 import com.android.networkstack.apishim.SettingsShimImpl; 61 import com.android.networkstack.apishim.common.SettingsShim; 62 import com.android.networkstack.tethering.util.TetheringPermissionsUtils; 63 64 import java.io.FileDescriptor; 65 import java.io.PrintWriter; 66 67 /** 68 * Android service used to manage tethering. 69 * 70 * <p>The service returns a binder for the system server to communicate with the tethering. 71 */ 72 public class TetheringService extends Service { 73 private static final String TAG = TetheringService.class.getSimpleName(); 74 75 private TetheringConnector mConnector; 76 private SettingsShim mSettingsShim; 77 private TetheringPermissionsUtils mTetheringPermissionsUtils; 78 79 @Override onCreate()80 public void onCreate() { 81 final TetheringDependencies deps = makeTetheringDependencies(); 82 // The Tethering object needs a fully functional context to start, so this can't be done 83 // in the constructor. 84 mConnector = new TetheringConnector(makeTethering(deps), TetheringService.this); 85 86 mSettingsShim = SettingsShimImpl.newInstance(); 87 mTetheringPermissionsUtils = new TetheringPermissionsUtils(deps.getContext()); 88 } 89 90 /** 91 * Make a reference to Tethering object. 92 */ 93 @VisibleForTesting makeTethering(TetheringDependencies deps)94 public Tethering makeTethering(TetheringDependencies deps) { 95 return new Tethering(deps); 96 } 97 98 @NonNull 99 @Override onBind(Intent intent)100 public IBinder onBind(Intent intent) { 101 return mConnector; 102 } 103 104 private static class TetheringConnector extends ITetheringConnector.Stub { 105 private final TetheringService mService; 106 private final Tethering mTethering; 107 TetheringConnector(Tethering tether, TetheringService service)108 TetheringConnector(Tethering tether, TetheringService service) { 109 mTethering = tether; 110 mService = service; 111 } 112 113 @Override tether(String iface, String callerPkg, String callingAttributionTag, IIntResultListener listener)114 public void tether(String iface, String callerPkg, String callingAttributionTag, 115 IIntResultListener listener) { 116 if (checkAndNotifyCommonError(callerPkg, callingAttributionTag, 117 false /* onlyAllowPrivileged */, false /* isDeviceOwnerAppAllowed */, 118 listener)) { 119 return; 120 } 121 122 mTethering.legacyTether(iface, listener); 123 } 124 125 @Override untether(String iface, String callerPkg, String callingAttributionTag, IIntResultListener listener)126 public void untether(String iface, String callerPkg, String callingAttributionTag, 127 IIntResultListener listener) { 128 if (checkAndNotifyCommonError(callerPkg, callingAttributionTag, 129 false /* onlyAllowPrivileged */, false /* isDeviceOwnerAppAllowed */, 130 listener)) { 131 return; 132 } 133 134 mTethering.legacyUntether(iface, listener); 135 } 136 137 @Override setUsbTethering(boolean enable, String callerPkg, String callingAttributionTag, IIntResultListener listener)138 public void setUsbTethering(boolean enable, String callerPkg, String callingAttributionTag, 139 IIntResultListener listener) { 140 if (checkAndNotifyCommonError(callerPkg, callingAttributionTag, 141 false /* onlyAllowPrivileged */, false /* isDeviceOwnerAppAllowed */, 142 listener)) { 143 return; 144 } 145 146 mTethering.setUsbTethering(enable, listener); 147 } 148 isRequestAllowedForDOOrCarrierApp(@onNull TetheringRequest request)149 private boolean isRequestAllowedForDOOrCarrierApp(@NonNull TetheringRequest request) { 150 return request.getTetheringType() == TETHERING_WIFI 151 && request.getSoftApConfiguration() != null; 152 } 153 154 @Override startTethering(TetheringRequestParcel requestParcel, String callerPkg, String callingAttributionTag, IIntResultListener listener)155 public void startTethering(TetheringRequestParcel requestParcel, String callerPkg, 156 String callingAttributionTag, IIntResultListener listener) { 157 TetheringRequest request = new TetheringRequest(requestParcel); 158 request.setUid(getBinderCallingUid()); 159 request.setPackageName(callerPkg); 160 boolean onlyAllowPrivileged = request.isExemptFromEntitlementCheck() 161 || request.getInterfaceName() != null; 162 boolean isDOOrCarrierAppAllowed = mTethering.isTetheringWithSoftApConfigEnabled() 163 && isRequestAllowedForDOOrCarrierApp(request); 164 if (checkAndNotifyCommonError(callerPkg, callingAttributionTag, onlyAllowPrivileged, 165 isDOOrCarrierAppAllowed, listener)) { 166 return; 167 } 168 mTethering.startTethering(request, callerPkg, listener); 169 } 170 171 @Override stopTethering(int type, String callerPkg, String callingAttributionTag, IIntResultListener listener)172 public void stopTethering(int type, String callerPkg, String callingAttributionTag, 173 IIntResultListener listener) { 174 if (checkAndNotifyCommonError(callerPkg, callingAttributionTag, 175 false /* onlyAllowPrivileged */, false /* isDeviceOwnerAppAllowed */, 176 listener)) { 177 return; 178 } 179 180 try { 181 mTethering.stopTethering(type); 182 listener.onResult(TETHER_ERROR_NO_ERROR); 183 } catch (RemoteException e) { } 184 } 185 186 @Override stopTetheringRequest(TetheringRequest request, String callerPkg, String callingAttributionTag, IIntResultListener listener)187 public void stopTetheringRequest(TetheringRequest request, 188 String callerPkg, String callingAttributionTag, 189 IIntResultListener listener) { 190 if (request == null) return; 191 if (listener == null) return; 192 request.setUid(getBinderCallingUid()); 193 request.setPackageName(callerPkg); 194 boolean isDOOrCarrierAppAllowed = mTethering.isTetheringWithSoftApConfigEnabled() 195 && isRequestAllowedForDOOrCarrierApp(request); 196 if (checkAndNotifyCommonError(callerPkg, callingAttributionTag, 197 false /* onlyAllowPrivileged */, isDOOrCarrierAppAllowed, listener)) { 198 return; 199 } 200 // Note: Whether tethering is actually stopped or not will depend on whether the request 201 // matches an active one with the same UID (see RequestTracker#findFuzzyMatchedRequest). 202 mTethering.stopTetheringRequest(request, listener); 203 } 204 205 @Override requestLatestTetheringEntitlementResult(int type, ResultReceiver receiver, boolean showEntitlementUi, String callerPkg, String callingAttributionTag)206 public void requestLatestTetheringEntitlementResult(int type, ResultReceiver receiver, 207 boolean showEntitlementUi, String callerPkg, String callingAttributionTag) { 208 // Wrap the app-provided ResultReceiver in an IIntResultListener in order to call 209 // checkAndNotifyCommonError with it. 210 IIntResultListener listener = new IIntResultListener() { 211 @Override 212 public void onResult(int i) { 213 receiver.send(i, null); 214 } 215 216 @Override 217 public IBinder asBinder() { 218 throw new UnsupportedOperationException("asBinder unexpectedly called on" 219 + " internal-only listener"); 220 } 221 }; 222 if (checkAndNotifyCommonError(callerPkg, callingAttributionTag, 223 false /* onlyAllowPrivileged */, false /* isDeviceOwnerAppAllowed */, 224 listener)) { 225 return; 226 } 227 228 mTethering.requestLatestTetheringEntitlementResult(type, receiver, showEntitlementUi); 229 } 230 231 @Override registerTetheringEventCallback(ITetheringEventCallback callback, String callerPkg)232 public void registerTetheringEventCallback(ITetheringEventCallback callback, 233 String callerPkg) { 234 // Silently ignore call if the callback is null. This can only happen via reflection. 235 if (callback == null) return; 236 try { 237 if (!hasTetherAccessPermission()) { 238 callback.onCallbackStopped(TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION); 239 return; 240 } 241 mTethering.registerTetheringEventCallback(callback); 242 } catch (RemoteException e) { } 243 } 244 245 @Override unregisterTetheringEventCallback(ITetheringEventCallback callback, String callerPkg)246 public void unregisterTetheringEventCallback(ITetheringEventCallback callback, 247 String callerPkg) { 248 // Silently ignore call if the callback is null. This can only happen via reflection. 249 if (callback == null) return; 250 try { 251 if (!hasTetherAccessPermission()) { 252 callback.onCallbackStopped(TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION); 253 return; 254 } 255 mTethering.unregisterTetheringEventCallback(callback); 256 } catch (RemoteException e) { } 257 } 258 259 @Override stopAllTethering(String callerPkg, String callingAttributionTag, IIntResultListener listener)260 public void stopAllTethering(String callerPkg, String callingAttributionTag, 261 IIntResultListener listener) { 262 if (checkAndNotifyCommonError(callerPkg, callingAttributionTag, 263 false /* onlyAllowPrivileged */, false /* isDeviceOwnerAppAllowed */, 264 listener)) { 265 return; 266 } 267 268 try { 269 mTethering.stopAllTethering(); 270 listener.onResult(TETHER_ERROR_NO_ERROR); 271 } catch (RemoteException e) { } 272 } 273 274 @Override isTetheringSupported(String callerPkg, String callingAttributionTag, IIntResultListener listener)275 public void isTetheringSupported(String callerPkg, String callingAttributionTag, 276 IIntResultListener listener) { 277 boolean isDOOrCarrierAppAllowed = mTethering.isTetheringWithSoftApConfigEnabled(); 278 if (checkAndNotifyCommonError(callerPkg, callingAttributionTag, 279 false /* onlyAllowPrivileged */, isDOOrCarrierAppAllowed, listener)) { 280 return; 281 } 282 try { 283 listener.onResult(TETHER_ERROR_NO_ERROR); 284 } catch (RemoteException e) { } 285 } 286 287 @Override setPreferTestNetworks(boolean prefer, IIntResultListener listener)288 public void setPreferTestNetworks(boolean prefer, IIntResultListener listener) { 289 if (!checkCallingOrSelfPermission(NETWORK_SETTINGS)) { 290 try { 291 listener.onResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION); 292 } catch (RemoteException e) { } 293 return; 294 } 295 296 mTethering.setPreferTestNetworks(prefer, listener); 297 } 298 299 @Override dump(@onNull FileDescriptor fd, @NonNull PrintWriter writer, @Nullable String[] args)300 protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter writer, 301 @Nullable String[] args) { 302 mTethering.dump(fd, writer, args); 303 } 304 checkAndNotifyCommonError(final String callerPkg, final String callingAttributionTag, final boolean onlyAllowPrivileged, final boolean isDOOrCarrierAppAllowed, final IIntResultListener listener)305 private boolean checkAndNotifyCommonError(final String callerPkg, 306 final String callingAttributionTag, final boolean onlyAllowPrivileged, 307 final boolean isDOOrCarrierAppAllowed, final IIntResultListener listener) { 308 try { 309 final int uid = getBinderCallingUid(); 310 if (!checkPackageNameMatchesUid(uid, callerPkg)) { 311 Log.e(TAG, "Package name " + callerPkg + " does not match UID " + uid); 312 listener.onResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION); 313 return true; 314 } 315 if (!hasTetherChangePermission(uid, callerPkg, callingAttributionTag, 316 onlyAllowPrivileged, isDOOrCarrierAppAllowed)) { 317 listener.onResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION); 318 return true; 319 } 320 if (!mTethering.isTetheringSupported() || !mTethering.isTetheringAllowed()) { 321 listener.onResult(TETHER_ERROR_UNSUPPORTED); 322 return true; 323 } 324 } catch (RemoteException e) { 325 return true; 326 } 327 328 return false; 329 } 330 hasNetworkSettingsPermission()331 private boolean hasNetworkSettingsPermission() { 332 return checkCallingOrSelfPermission(NETWORK_SETTINGS); 333 } 334 hasNetworkStackPermission()335 private boolean hasNetworkStackPermission() { 336 return checkCallingOrSelfPermission(NETWORK_STACK) 337 || checkCallingOrSelfPermission(PERMISSION_MAINLINE_NETWORK_STACK); 338 } 339 hasTetherPrivilegedPermission()340 private boolean hasTetherPrivilegedPermission() { 341 return checkCallingOrSelfPermission(TETHER_PRIVILEGED); 342 } 343 checkCallingOrSelfPermission(final String permission)344 private boolean checkCallingOrSelfPermission(final String permission) { 345 return mService.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED; 346 } 347 hasTetherChangePermission(final int uid, final String callerPkg, final String callingAttributionTag, final boolean onlyAllowPrivileged, final boolean isDOOrCarrierAppAllowed)348 private boolean hasTetherChangePermission(final int uid, final String callerPkg, 349 final String callingAttributionTag, final boolean onlyAllowPrivileged, 350 final boolean isDOOrCarrierAppAllowed) { 351 if (onlyAllowPrivileged && !hasNetworkStackPermission() 352 && !hasNetworkSettingsPermission()) return false; 353 354 if (hasTetherPrivilegedPermission()) return true; 355 356 // Allow DO and carrier-privileged apps to change tethering even if they don't have 357 // TETHER_PRIVILEGED. 358 // TODO: Stop tethering if the app loses DO status or carrier-privileges. 359 if (isDOOrCarrierAppAllowed 360 && (mService.isDeviceOwner(uid, callerPkg) 361 || mService.isCarrierPrivileged(callerPkg))) { 362 return true; 363 } 364 365 // After TetheringManager moves to public API, prevent third-party apps from being able 366 // to change tethering with only WRITE_SETTINGS permission. 367 if (mTethering.isTetheringWithSoftApConfigEnabled()) return false; 368 369 if (mTethering.isTetherProvisioningRequired()) return false; 370 371 // If callerPkg's uid is not same as getBinderCallingUid(), 372 // checkAndNoteWriteSettingsOperation will return false and the operation will be 373 // denied. 374 return mService.checkAndNoteWriteSettingsOperation(mService, uid, callerPkg, 375 callingAttributionTag, false /* throwException */); 376 } 377 hasTetherAccessPermission()378 private boolean hasTetherAccessPermission() { 379 if (hasTetherPrivilegedPermission()) return true; 380 381 return mService.checkCallingOrSelfPermission( 382 ACCESS_NETWORK_STATE) == PERMISSION_GRANTED; 383 } 384 getBinderCallingUid()385 private int getBinderCallingUid() { 386 return mService.getBinderCallingUid(); 387 } 388 checkPackageNameMatchesUid(final int uid, final String callerPkg)389 private boolean checkPackageNameMatchesUid(final int uid, final String callerPkg) { 390 return mService.checkPackageNameMatchesUid(mService, uid, callerPkg); 391 } 392 } 393 394 /** 395 * Check if the package is a allowed to write settings. This also accounts that such an access 396 * happened. 397 * 398 * @return {@code true} iff the package is allowed to write settings. 399 */ 400 @VisibleForTesting checkAndNoteWriteSettingsOperation(@onNull Context context, int uid, @NonNull String callingPackage, @Nullable String callingAttributionTag, boolean throwException)401 boolean checkAndNoteWriteSettingsOperation(@NonNull Context context, int uid, 402 @NonNull String callingPackage, @Nullable String callingAttributionTag, 403 boolean throwException) { 404 return mSettingsShim.checkAndNoteWriteSettingsOperation(context, uid, callingPackage, 405 callingAttributionTag, throwException); 406 } 407 408 /** 409 * Check if the package name matches the uid. 410 */ 411 @VisibleForTesting checkPackageNameMatchesUid(@onNull Context context, int uid, @NonNull String callingPackage)412 boolean checkPackageNameMatchesUid(@NonNull Context context, int uid, 413 @NonNull String callingPackage) { 414 try { 415 final AppOpsManager mAppOps = context.getSystemService(AppOpsManager.class); 416 if (mAppOps == null) { 417 return false; 418 } 419 mAppOps.checkPackage(uid, callingPackage); 420 } catch (SecurityException e) { 421 return false; 422 } 423 return true; 424 } 425 426 /** 427 * Wrapper for the Binder calling UID, used for mocks. 428 */ 429 @VisibleForTesting getBinderCallingUid()430 int getBinderCallingUid() { 431 return Binder.getCallingUid(); 432 } 433 434 /** 435 * Wrapper for {@link TetheringPermissionsUtils#isDeviceOwner(int, String)}, used for mocks. 436 */ 437 @VisibleForTesting isDeviceOwner(final int uid, final String callerPkg)438 boolean isDeviceOwner(final int uid, final String callerPkg) { 439 return mTetheringPermissionsUtils.isDeviceOwner(uid, callerPkg); 440 } 441 442 /** 443 * Wrapper for {@link TetheringPermissionsUtils#isCarrierPrivileged(String)}, used for mocks. 444 */ 445 @VisibleForTesting isCarrierPrivileged(final String callerPkg)446 boolean isCarrierPrivileged(final String callerPkg) { 447 return mTetheringPermissionsUtils.isCarrierPrivileged(callerPkg); 448 } 449 450 /** 451 * An injection method for testing. 452 */ 453 @VisibleForTesting makeTetheringDependencies()454 public TetheringDependencies makeTetheringDependencies() { 455 return new TetheringDependencies() { 456 @Override 457 public Looper makeTetheringLooper() { 458 final HandlerThread tetherThread = new HandlerThread("android.tethering"); 459 tetherThread.start(); 460 return tetherThread.getLooper(); 461 } 462 463 @Override 464 public Context getContext() { 465 return TetheringService.this; 466 } 467 468 @Override 469 public IpServer.Dependencies makeIpServerDependencies() { 470 return new IpServer.Dependencies() { 471 @Override 472 public void makeDhcpServer(String ifName, DhcpServingParamsParcel params, 473 DhcpServerCallbacks cb) { 474 try { 475 final INetworkStackConnector service = getNetworkStackConnector(); 476 if (service == null) return; 477 478 service.makeDhcpServer(ifName, params, cb); 479 } catch (RemoteException e) { 480 Log.e(TAG, "Fail to make dhcp server"); 481 try { 482 cb.onDhcpServerCreated(STATUS_UNKNOWN_ERROR, null); 483 } catch (RemoteException re) { } 484 } 485 } 486 }; 487 } 488 489 // TODO: replace this by NetworkStackClient#getRemoteConnector after refactoring 490 // networkStackClient. 491 static final int NETWORKSTACK_TIMEOUT_MS = 60_000; 492 private INetworkStackConnector getNetworkStackConnector() { 493 IBinder connector; 494 try { 495 final long before = System.currentTimeMillis(); 496 while ((connector = NetworkStack.getService()) == null) { 497 if (System.currentTimeMillis() - before > NETWORKSTACK_TIMEOUT_MS) { 498 Log.wtf(TAG, "Timeout, fail to get INetworkStackConnector"); 499 return null; 500 } 501 Thread.sleep(200); 502 } 503 } catch (InterruptedException e) { 504 Log.wtf(TAG, "Interrupted, fail to get INetworkStackConnector"); 505 return null; 506 } 507 return INetworkStackConnector.Stub.asInterface(connector); 508 } 509 510 @Override 511 public BluetoothAdapter getBluetoothAdapter() { 512 final BluetoothManager btManager = getSystemService(BluetoothManager.class); 513 if (btManager == null) { 514 return null; 515 } 516 return btManager.getAdapter(); 517 } 518 }; 519 } 520 } 521