Add UID and package name to TetheringRequest
Add a uid and package name to TetheringRequest to keep track of which
app the request belongs to, and also convey this information to Wifi
for later use with resource conflicts.
Bug: 216524590
Test: atest TetheringManagerTest TetheringServiceTest
Change-Id: If963694cb1bbd831ba379a76043825c94ef9d67a
diff --git a/Tethering/common/TetheringLib/api/module-lib-current.txt b/Tethering/common/TetheringLib/api/module-lib-current.txt
index 460c216..a680590 100644
--- a/Tethering/common/TetheringLib/api/module-lib-current.txt
+++ b/Tethering/common/TetheringLib/api/module-lib-current.txt
@@ -46,5 +46,10 @@
method @Deprecated @NonNull public java.util.List<java.lang.String> getTetherableWifiRegexs();
}
+ public static final class TetheringManager.TetheringRequest implements android.os.Parcelable {
+ method @FlaggedApi("com.android.net.flags.tethering_request_with_soft_ap_config") @Nullable public String getPackageName();
+ method @FlaggedApi("com.android.net.flags.tethering_request_with_soft_ap_config") public int getUid();
+ }
+
}
diff --git a/Tethering/common/TetheringLib/src/android/net/TetheringManager.java b/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
index 411971d..7c7a4e0 100644
--- a/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
+++ b/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
@@ -33,6 +33,7 @@
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.Process;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.util.ArrayMap;
@@ -746,6 +747,7 @@
mBuilderParcel.exemptFromEntitlementCheck = false;
mBuilderParcel.showProvisioningUi = true;
mBuilderParcel.connectivityScope = getDefaultConnectivityScope(type);
+ mBuilderParcel.uid = Process.INVALID_UID;
mBuilderParcel.softApConfig = null;
}
@@ -920,6 +922,47 @@
}
/**
+ * Sets the UID of the app that sent this request. This should always be overridden when
+ * receiving TetheringRequest from an external source.
+ * @hide
+ */
+ public void setUid(int uid) {
+ mRequestParcel.uid = uid;
+ }
+
+ /**
+ * Sets the package name of the app that sent this request. This should always be overridden
+ * when receiving a TetheringRequest from an external source.
+ * @hide
+ */
+ public void setPackageName(String packageName) {
+ mRequestParcel.packageName = packageName;
+ }
+
+ /**
+ * Gets the UID of the app that sent this request. This defaults to
+ * {@link Process#INVALID_UID} if unset.
+ * @hide
+ */
+ @FlaggedApi(Flags.FLAG_TETHERING_REQUEST_WITH_SOFT_AP_CONFIG)
+ @SystemApi(client = MODULE_LIBRARIES)
+ public int getUid() {
+ return mRequestParcel.uid;
+ }
+
+ /**
+ * Gets the package name of the app that sent this request. This defaults to {@code null} if
+ * unset.
+ * @hide
+ */
+ @FlaggedApi(Flags.FLAG_TETHERING_REQUEST_WITH_SOFT_AP_CONFIG)
+ @SystemApi(client = MODULE_LIBRARIES)
+ @Nullable
+ public String getPackageName() {
+ return mRequestParcel.packageName;
+ }
+
+ /**
* Get a TetheringRequestParcel from the configuration
* @hide
*/
@@ -935,6 +978,8 @@
+ ", exemptFromEntitlementCheck= " + mRequestParcel.exemptFromEntitlementCheck
+ ", showProvisioningUi= " + mRequestParcel.showProvisioningUi
+ ", softApConfig= " + mRequestParcel.softApConfig
+ + ", uid= " + mRequestParcel.uid
+ + ", packageName= " + mRequestParcel.packageName
+ " ]";
}
@@ -950,7 +995,9 @@
&& parcel.exemptFromEntitlementCheck == otherParcel.exemptFromEntitlementCheck
&& parcel.showProvisioningUi == otherParcel.showProvisioningUi
&& parcel.connectivityScope == otherParcel.connectivityScope
- && Objects.equals(parcel.softApConfig, otherParcel.softApConfig);
+ && Objects.equals(parcel.softApConfig, otherParcel.softApConfig)
+ && parcel.uid == otherParcel.uid
+ && Objects.equals(parcel.packageName, otherParcel.packageName);
}
@Override
@@ -958,7 +1005,8 @@
TetheringRequestParcel parcel = getParcel();
return Objects.hash(parcel.tetheringType, parcel.localIPv4Address,
parcel.staticClientAddress, parcel.exemptFromEntitlementCheck,
- parcel.showProvisioningUi, parcel.connectivityScope, parcel.softApConfig);
+ parcel.showProvisioningUi, parcel.connectivityScope, parcel.softApConfig,
+ parcel.uid, parcel.packageName);
}
}
diff --git a/Tethering/common/TetheringLib/src/android/net/TetheringRequestParcel.aidl b/Tethering/common/TetheringLib/src/android/net/TetheringRequestParcel.aidl
index ea7a353..789d5bb 100644
--- a/Tethering/common/TetheringLib/src/android/net/TetheringRequestParcel.aidl
+++ b/Tethering/common/TetheringLib/src/android/net/TetheringRequestParcel.aidl
@@ -31,4 +31,6 @@
boolean showProvisioningUi;
int connectivityScope;
SoftApConfiguration softApConfig;
+ int uid;
+ String packageName;
}
diff --git a/Tethering/src/com/android/networkstack/tethering/TetheringService.java b/Tethering/src/com/android/networkstack/tethering/TetheringService.java
index 454cbf1..cea7e82 100644
--- a/Tethering/src/com/android/networkstack/tethering/TetheringService.java
+++ b/Tethering/src/com/android/networkstack/tethering/TetheringService.java
@@ -55,6 +55,7 @@
import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.net.module.util.PermissionUtils;
import com.android.networkstack.apishim.SettingsShimImpl;
import com.android.networkstack.apishim.common.SettingsShim;
@@ -138,8 +139,10 @@
listener)) {
return;
}
- // TODO(b/216524590): Add UID/packageName of caller to TetheringRequest here
- mTethering.startTethering(new TetheringRequest(request), callerPkg, listener);
+ TetheringRequest external = new TetheringRequest(request);
+ external.setUid(getBinderCallingUid());
+ external.setPackageName(callerPkg);
+ mTethering.startTethering(external, callerPkg, listener);
}
@Override
@@ -238,6 +241,12 @@
final String callingAttributionTag, final boolean onlyAllowPrivileged,
final IIntResultListener listener) {
try {
+ if (!checkPackageNameMatchesUid(getBinderCallingUid(), callerPkg)) {
+ Log.e(TAG, "Package name " + callerPkg + " does not match UID "
+ + getBinderCallingUid());
+ listener.onResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
+ return true;
+ }
if (!hasTetherChangePermission(callerPkg, callingAttributionTag,
onlyAllowPrivileged)) {
listener.onResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
@@ -256,6 +265,12 @@
private boolean checkAndNotifyCommonError(final String callerPkg,
final String callingAttributionTag, final ResultReceiver receiver) {
+ if (!checkPackageNameMatchesUid(getBinderCallingUid(), callerPkg)) {
+ Log.e(TAG, "Package name " + callerPkg + " does not match UID "
+ + getBinderCallingUid());
+ receiver.send(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION, null);
+ return true;
+ }
if (!hasTetherChangePermission(callerPkg, callingAttributionTag,
false /* onlyAllowPrivileged */)) {
receiver.send(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION, null);
@@ -290,9 +305,9 @@
if (mTethering.isTetherProvisioningRequired()) return false;
- int uid = Binder.getCallingUid();
+ int uid = getBinderCallingUid();
- // If callerPkg's uid is not same as Binder.getCallingUid(),
+ // If callerPkg's uid is not same as getBinderCallingUid(),
// checkAndNoteWriteSettingsOperation will return false and the operation will be
// denied.
return mService.checkAndNoteWriteSettingsOperation(mService, uid, callerPkg,
@@ -305,6 +320,14 @@
return mService.checkCallingOrSelfPermission(
ACCESS_NETWORK_STATE) == PERMISSION_GRANTED;
}
+
+ private int getBinderCallingUid() {
+ return mService.getBinderCallingUid();
+ }
+
+ private boolean checkPackageNameMatchesUid(final int uid, final String callerPkg) {
+ return mService.checkPackageNameMatchesUid(mService, uid, callerPkg);
+ }
}
/**
@@ -322,6 +345,28 @@
}
/**
+ * Check if the package name matches the uid.
+ */
+ @VisibleForTesting
+ boolean checkPackageNameMatchesUid(@NonNull Context context, int uid,
+ @NonNull String callingPackage) {
+ try {
+ PermissionUtils.enforcePackageNameMatchesUid(context, uid, callingPackage);
+ } catch (SecurityException e) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Wrapper for the Binder calling UID, used for mocks.
+ */
+ @VisibleForTesting
+ int getBinderCallingUid() {
+ return Binder.getCallingUid();
+ }
+
+ /**
* An injection method for testing.
*/
@VisibleForTesting
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/MockTetheringService.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/MockTetheringService.java
index 3c07580..7fcc5f1 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/MockTetheringService.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/MockTetheringService.java
@@ -32,6 +32,8 @@
public class MockTetheringService extends TetheringService {
private final Tethering mTethering = mock(Tethering.class);
private final ArrayMap<String, Integer> mMockedPermissions = new ArrayMap<>();
+ private final ArrayMap<String, Integer> mMockedPackageUids = new ArrayMap<>();
+ private int mMockCallingUid;
@Override
public IBinder onBind(Intent intent) {
@@ -61,6 +63,17 @@
return super.checkCallingOrSelfPermission(permission);
}
+ @Override
+ boolean checkPackageNameMatchesUid(@NonNull Context context, int uid,
+ @NonNull String callingPackage) {
+ return mMockedPackageUids.getOrDefault(callingPackage, 0) == uid;
+ }
+
+ @Override
+ int getBinderCallingUid() {
+ return mMockCallingUid;
+ }
+
public Tethering getTethering() {
return mTethering;
}
@@ -91,5 +104,19 @@
mMockedPermissions.put(permission, granted);
}
}
+
+ /**
+ * Mock a package name matching a uid.
+ */
+ public void setPackageNameUid(String packageName, int uid) {
+ mMockedPackageUids.put(packageName, uid);
+ }
+
+ /**
+ * Mock a package name matching a uid.
+ */
+ public void setCallingUid(int uid) {
+ mMockCallingUid = uid;
+ }
}
}
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java
index c0d7ad4..1988311 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java
@@ -34,6 +34,7 @@
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -79,6 +80,7 @@
public final class TetheringServiceTest {
private static final String TEST_IFACE_NAME = "test_wlan0";
private static final String TEST_CALLER_PKG = "com.android.shell";
+ private static final int TEST_CALLER_UID = 1234;
private static final String TEST_ATTRIBUTION_TAG = null;
@Mock private ITetheringEventCallback mITetheringEventCallback;
@Rule public ServiceTestRule mServiceTestRule;
@@ -128,6 +130,8 @@
mTetheringConnector = ITetheringConnector.Stub.asInterface(mMockConnector.getIBinder());
final MockTetheringService service = mMockConnector.getService();
mTethering = service.getTethering();
+ mMockConnector.setCallingUid(TEST_CALLER_UID);
+ mMockConnector.setPackageNameUid(TEST_CALLER_PKG, TEST_CALLER_UID);
}
@After
@@ -330,6 +334,16 @@
});
runAsTetherPrivileged((result) -> {
+ String wrongPackage = "wrong.package";
+ mTetheringConnector.startTethering(request, wrongPackage,
+ TEST_ATTRIBUTION_TAG, result);
+ verify(mTethering, never()).startTethering(
+ eq(new TetheringRequest(request)), eq(wrongPackage), eq(result));
+ result.assertResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
+ verifyNoMoreInteractionsForTethering();
+ });
+
+ runAsTetherPrivileged((result) -> {
runStartTethering(result, request);
verifyNoMoreInteractionsForTethering();
});
@@ -445,6 +459,13 @@
verifyNoMoreInteractionsForTethering();
});
+ runAsTetherPrivileged((none) -> {
+ mTetheringConnector.requestLatestTetheringEntitlementResult(TETHERING_WIFI, result,
+ true /* showEntitlementUi */, "wrong.package", TEST_ATTRIBUTION_TAG);
+ result.assertResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
+ verifyNoMoreInteractions(mTethering);
+ });
+
runAsWriteSettings((none) -> {
runRequestLatestTetheringEntitlementResult();
verify(mTethering).isTetherProvisioningRequired();