• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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