Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1991f572 authored by Alex Klyubin's avatar Alex Klyubin
Browse files

Restrict access from apps to bluetooth_address setting

BluetoothManagerService for some reason leaks the Android's Bluetooth
MAC address via Settings.Secure which is normally readable by all
apps. This lets apps bypass the restriction on access to Bluetooth MAC
address from apps.

This commit fixes the issue by restricting access to bluetooth_address
secure setting (Settings.Secure). Only packages which hold the
android.permission.LOCAL_MAC_ADDRESS permission retain access.

This commit accordingly grants LOCAL_MAC_ADDRESS permission to the
system Shell app because a number of scripts (including Android CTS)
use "adb shell settings get secure bluetooth_address" as a convenient
way to query the device's Bluetooth MAC address over ADB. This is
acceptable because the user of the device can see the Bluetooth MAC
address and thus it's fine for shell to be able to see the address as
well.

Test: See CTS test added in the cts project in this topic.
Test: "adb shell settings get secure bluetooth_address" returns the
      Bluetooth MAC address of the Android.
Test: "adb shell settings list secure | grep bluetooth_address"
      returns the Bluetooth MAC address of the Android.
Test: Bluetooth works (toggling off/on, pairing, file transfer)
Bug: 33701414

Change-Id: I17b110b96eb3794b25c1661e93d29a7a003e3c9a
parent 2c66f192
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -263,6 +263,7 @@ applications that come with the platform
        <permission name="android.permission.INSTALL_LOCATION_PROVIDER"/>
        <permission name="android.permission.INSTALL_PACKAGES"/>
        <permission name="android.permission.INTERACT_ACROSS_USERS"/>
        <permission name="android.permission.LOCAL_MAC_ADDRESS"/>
        <permission name="android.permission.MANAGE_ACTIVITY_STACKS"/>
        <permission name="android.permission.MANAGE_DEVICE_ADMINS"/>
        <permission name="android.permission.MANAGE_USB"/>
+34 −4
Original line number Diff line number Diff line
@@ -1010,8 +1010,9 @@ public class SettingsProvider extends ContentProvider {
                final int owningUserId = resolveOwningUserIdForSecureSettingLocked(callingUserId,
                        name);

                // Special case for location (sigh).
                if (isLocationProvidersAllowedRestricted(name, callingUserId, owningUserId)) {
                if (!isSecureSettingAccessible(name, callingUserId, owningUserId)) {
                    // This caller is not permitted to access this setting. Pretend the setting
                    // doesn't exist.
                    continue;
                }

@@ -1045,8 +1046,9 @@ public class SettingsProvider extends ContentProvider {
        // Determine the owning user as some profile settings are cloned from the parent.
        final int owningUserId = resolveOwningUserIdForSecureSettingLocked(callingUserId, name);

        // Special case for location (sigh).
        if (isLocationProvidersAllowedRestricted(name, callingUserId, owningUserId)) {
        if (!isSecureSettingAccessible(name, callingUserId, owningUserId)) {
            // This caller is not permitted to access this setting. Pretend the setting doesn't
            // exist.
            SettingsState settings = mSettingsRegistry.getSettingsLocked(SETTINGS_TYPE_SECURE,
                    owningUserId);
            return settings != null ? settings.getNullSetting() : null;
@@ -1358,6 +1360,34 @@ public class SettingsProvider extends ContentProvider {
        }
    }

    /**
     * Returns {@code true} if the specified secure setting should be accessible to the caller.
     */
    private boolean isSecureSettingAccessible(String name, int callingUserId,
            int owningUserId) {
        // Special case for location (sigh).
        // This check is not inside the name-based checks below because this method performs checks
        // only if the calling user ID is not the same as the owning user ID.
        if (isLocationProvidersAllowedRestricted(name, callingUserId, owningUserId)) {
            return false;
        }

        switch (name) {
            case "bluetooth_address":
                // BluetoothManagerService for some reason stores the Android's Bluetooth MAC
                // address in this secure setting. Secure settings can normally be read by any app,
                // which thus enables them to bypass the recently introduced restrictions on access
                // to device identifiers.
                // To mitigate this we make this setting available only to callers privileged to see
                // this device's MAC addresses, same as through public API
                // BluetoothAdapter.getAddress() (see BluetoothManagerService for details).
                return getContext().checkCallingOrSelfPermission(
                        Manifest.permission.LOCAL_MAC_ADDRESS) == PackageManager.PERMISSION_GRANTED;
            default:
                return true;
        }
    }

    private boolean isLocationProvidersAllowedRestricted(String name, int callingUserId,
            int owningUserId) {
        // Optimization - location providers are restricted only for managed profiles.
+1 −0
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.LOCAL_MAC_ADDRESS" />
    <uses-permission android:name="android.permission.EXPAND_STATUS_BAR" />
    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
    <uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY" />