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

Commit 6ba5dccd authored by Chad Brubaker's avatar Chad Brubaker Committed by Android (Google) Code Review
Browse files

Merge "Add ephemeral whitelist for SettingsProvider"

parents 09df4a61 97bccee6
Loading
Loading
Loading
Loading
+93 −2
Original line number Diff line number Diff line
@@ -50,6 +50,7 @@ import android.net.ConnectivityManager;
import android.net.Uri;
import android.net.wifi.WifiManager;
import android.os.BatteryManager;
import android.os.Binder;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
import android.os.DropBoxManager;
@@ -1596,6 +1597,24 @@ public final class Settings {
    // with a partial enable/disable state in multi-threaded situations.
    private static final Object mLocationSettingsLock = new Object();

    // Used in system server calling uid workaround in call()
    private static boolean sInSystemServer = false;
    private static final Object sInSystemServerLock = new Object();

    /** @hide */
    public static void setInSystemServer() {
        synchronized (sInSystemServerLock) {
            sInSystemServer = true;
        }
    }

    /** @hide */
    public static boolean isInSystemServer() {
        synchronized (sInSystemServerLock) {
            return sInSystemServer;
        }
    }

    public static class SettingNotFoundException extends AndroidException {
        public SettingNotFoundException(String msg) {
            super(msg);
@@ -1804,7 +1823,23 @@ public final class Settings {
                            }
                        }
                    }
                    Bundle b = cp.call(cr.getPackageName(), mCallGetCommand, name, args);
                    Bundle b;
                    // If we're in system server and in a binder transaction we need to clear the
                    // calling uid. This works around code in system server that did not call
                    // clearCallingIdentity, previously this wasn't needed because reading settings
                    // did not do permission checking but thats no longer the case.
                    // Long term this should be removed and callers should properly call
                    // clearCallingIdentity or use a ContentResolver from the caller as needed.
                    if (Settings.isInSystemServer() && Binder.getCallingUid() != Process.myUid()) {
                        final long token = Binder.clearCallingIdentity();
                        try {
                            b = cp.call(cr.getPackageName(), mCallGetCommand, name, args);
                        } finally {
                            Binder.restoreCallingIdentity(token);
                        }
                    } else {
                        b = cp.call(cr.getPackageName(), mCallGetCommand, name, args);
                    }
                    if (b != null) {
                        String value = b.getString(Settings.NameValueTable.VALUE);
                        // Don't update our cache for reads of other users' data
@@ -1864,7 +1899,19 @@ public final class Settings {
            try {
                Bundle queryArgs = ContentResolver.createSqlQueryBundle(
                        NAME_EQ_PLACEHOLDER, new String[]{name}, null);
                c = cp.query(cr.getPackageName(), mUri, SELECT_VALUE_PROJECTION, queryArgs, null);
                // Same workaround as above.
                if (Settings.isInSystemServer() && Binder.getCallingUid() != Process.myUid()) {
                    final long token = Binder.clearCallingIdentity();
                    try {
                        c = cp.query(cr.getPackageName(), mUri, SELECT_VALUE_PROJECTION, queryArgs,
                                null);
                    } finally {
                        Binder.restoreCallingIdentity(token);
                    }
                } else {
                    c = cp.query(cr.getPackageName(), mUri, SELECT_VALUE_PROJECTION, queryArgs,
                            null);
                }
                if (c == null) {
                    Log.w(TAG, "Can't get key " + name + " from " + mUri);
                    return null;
@@ -4020,6 +4067,22 @@ public final class Settings {
            outMap.putAll(CLONE_FROM_PARENT_ON_VALUE);
        }

        /**
         * System settings which can be accessed by ephemeral apps.
         * @hide
         */
        public static final Set<String> EPHEMERAL_SETTINGS = new ArraySet<>();
        static {
            EPHEMERAL_SETTINGS.add(TEXT_AUTO_REPLACE);
            EPHEMERAL_SETTINGS.add(TEXT_AUTO_CAPS);
            EPHEMERAL_SETTINGS.add(TEXT_AUTO_PUNCTUATE);
            EPHEMERAL_SETTINGS.add(TEXT_SHOW_PASSWORD);
            EPHEMERAL_SETTINGS.add(DATE_FORMAT);
            EPHEMERAL_SETTINGS.add(FONT_SCALE);
            EPHEMERAL_SETTINGS.add(HAPTIC_FEEDBACK_ENABLED);
            EPHEMERAL_SETTINGS.add(TIME_12_24);
        }

        /**
         * When to use Wi-Fi calling
         *
@@ -6898,6 +6961,20 @@ public final class Settings {
            outKeySet.addAll(CLONE_TO_MANAGED_PROFILE);
        }

        /**
         * Secure settings which can be accessed by ephemeral apps.
         * @hide
         */
        public static final Set<String> EPHEMERAL_SETTINGS = new ArraySet<>();
        static {
            EPHEMERAL_SETTINGS.add(ENABLED_ACCESSIBILITY_SERVICES);
            EPHEMERAL_SETTINGS.add(ACCESSIBILITY_SPEAK_PASSWORD);
            EPHEMERAL_SETTINGS.add(ACCESSIBILITY_DISPLAY_INVERSION_ENABLED);

            EPHEMERAL_SETTINGS.add(DEFAULT_INPUT_METHOD);
            EPHEMERAL_SETTINGS.add(ENABLED_INPUT_METHODS);
        }

        /**
         * Helper method for determining if a location provider is enabled.
         *
@@ -9906,6 +9983,20 @@ public final class Settings {
         * @hide
         */
        public static final String CELL_ON = "cell_on";

        /**
         * Global settings which can be accessed by ephemeral apps.
         * @hide
         */
        public static final Set<String> EPHEMERAL_SETTINGS = new ArraySet<>();
        static {
            EPHEMERAL_SETTINGS.add(WAIT_FOR_DEBUGGER);
            EPHEMERAL_SETTINGS.add(DEVICE_PROVISIONED);
            EPHEMERAL_SETTINGS.add(DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES);
            EPHEMERAL_SETTINGS.add(DEVELOPMENT_FORCE_RTL);
            EPHEMERAL_SETTINGS.add(EPHEMERAL_COOKIE_MAX_SIZE_BYTES);
        }

    }

    /**
+73 −9
Original line number Diff line number Diff line
@@ -271,6 +271,7 @@ public class SettingsProvider extends ContentProvider {

    @Override
    public boolean onCreate() {
        Settings.setInSystemServer();
        synchronized (mLock) {
            mUserManager = UserManager.get(getContext());
            mPackageManager = AppGlobals.getPackageManager();
@@ -829,7 +830,8 @@ public class SettingsProvider extends ContentProvider {
            SettingsState settingsState = mSettingsRegistry.getSettingsLocked(
                    SETTINGS_TYPE_GLOBAL, UserHandle.USER_SYSTEM);

            List<String> names = settingsState.getSettingNamesLocked();
            List<String> names = getSettingsNamesLocked(SETTINGS_TYPE_GLOBAL,
                    UserHandle.USER_SYSTEM);

            final int nameCount = names.size();

@@ -852,6 +854,9 @@ public class SettingsProvider extends ContentProvider {
            Slog.v(LOG_TAG, "getGlobalSetting(" + name + ")");
        }

        // Ensure the caller can access the setting.
        enforceSettingReadable(name, SETTINGS_TYPE_GLOBAL, UserHandle.getCallingUserId());

        // Get the value.
        synchronized (mLock) {
            return mSettingsRegistry.getSettingLocked(SETTINGS_TYPE_GLOBAL,
@@ -954,8 +959,7 @@ public class SettingsProvider extends ContentProvider {
        final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(userId);

        synchronized (mLock) {
            List<String> names = mSettingsRegistry.getSettingsNamesLocked(
                    SETTINGS_TYPE_SECURE, callingUserId);
            List<String> names = getSettingsNamesLocked(SETTINGS_TYPE_SECURE, callingUserId);

            final int nameCount = names.size();

@@ -997,6 +1001,9 @@ public class SettingsProvider extends ContentProvider {
        // Resolve the userId on whose behalf the call is made.
        final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(requestingUserId);

        // Ensure the caller can access the setting.
        enforceSettingReadable(name, SETTINGS_TYPE_SECURE, callingUserId);

        // Determine the owning user as some profile settings are cloned from the parent.
        final int owningUserId = resolveOwningUserIdForSecureSettingLocked(callingUserId, name);

@@ -1159,8 +1166,7 @@ public class SettingsProvider extends ContentProvider {
        final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(userId);

        synchronized (mLock) {
            List<String> names = mSettingsRegistry.getSettingsNamesLocked(
                    SETTINGS_TYPE_SYSTEM, callingUserId);
            List<String> names = getSettingsNamesLocked(SETTINGS_TYPE_SYSTEM, callingUserId);

            final int nameCount = names.size();

@@ -1191,6 +1197,9 @@ public class SettingsProvider extends ContentProvider {
        // Resolve the userId on whose behalf the call is made.
        final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(requestingUserId);

        // Ensure the caller can access the setting.
        enforceSettingReadable(name, SETTINGS_TYPE_SYSTEM, callingUserId);

        // Determine the owning user as some profile settings are cloned from the parent.
        final int owningUserId = resolveOwningUserIdForSystemSettingLocked(callingUserId, name);

@@ -1409,10 +1418,16 @@ public class SettingsProvider extends ContentProvider {
                && (parentId = getGroupParentLocked(userId)) != userId) {
            // The setting has a dependency and the profile has a parent
            String dependency = sSystemCloneFromParentOnDependency.get(setting);
            // Lookup the dependency setting as ourselves, some callers may not have access to it.
            final long token = Binder.clearCallingIdentity();
            try {
                Setting settingObj = getSecureSetting(dependency, userId);
                if (settingObj != null && settingObj.getValue().equals("1")) {
                    return parentId;
                }
            } finally {
                Binder.restoreCallingIdentity(token);
            }
        }
        return resolveOwningUserIdLocked(userId, sSystemCloneToManagedSettings, setting);
    }
@@ -1479,6 +1494,55 @@ public class SettingsProvider extends ContentProvider {
        }
    }

    private Set<String> getEphemeralAccessibleSettings(int settingsType) {
        switch (settingsType) {
            case SETTINGS_TYPE_GLOBAL:
                return Settings.Global.EPHEMERAL_SETTINGS;
            case SETTINGS_TYPE_SECURE:
                return Settings.Secure.EPHEMERAL_SETTINGS;
            case SETTINGS_TYPE_SYSTEM:
                return Settings.System.EPHEMERAL_SETTINGS;
            default:
                throw new IllegalArgumentException("Invalid settings type: " + settingsType);
        }
    }

    private List<String> getSettingsNamesLocked(int settingsType, int userId) {
        ApplicationInfo ai = getCallingApplicationInfoOrThrow(userId);
        if (ai.isEphemeralApp()) {
            return new ArrayList<String>(getEphemeralAccessibleSettings(settingsType));
        } else {
            return mSettingsRegistry.getSettingsNamesLocked(settingsType, userId);
        }
    }

    private void enforceSettingReadable(String settingName, int settingsType, int userId) {
        if (UserHandle.getAppId(Binder.getCallingUid()) < Process.FIRST_APPLICATION_UID) {
            return;
        }
        ApplicationInfo ai = getCallingApplicationInfoOrThrow(userId);
        if (!ai.isEphemeralApp()) {
            return;
        }
        if (!getEphemeralAccessibleSettings(settingsType).contains(settingName)) {
            throw new SecurityException("Setting " + settingName + " is not accessible from"
                    + " ephemeral package " + getCallingPackage());
        }
    }

    private ApplicationInfo getCallingApplicationInfoOrThrow(int userId) {
        ApplicationInfo ai = null;
        try {
            ai = mPackageManager.getApplicationInfo(getCallingPackage(), 0 , userId);
        } catch (RemoteException ignored) {
        }
        if (ai == null) {
            throw new IllegalStateException("Failed to lookup info for package "
                    + getCallingPackage());
        }
        return ai;
    }

    private PackageInfo getCallingPackageInfoOrThrow(int userId) {
        try {
            PackageInfo packageInfo = mPackageManager.getPackageInfo(