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

Commit fbc55579 authored by Michael Groover's avatar Michael Groover Committed by Android (Google) Code Review
Browse files

Merge "Check original DeviceConfig flag in allowlist for overrides" into main

parents 9b1712df 19e5acd4
Loading
Loading
Loading
Loading
+48 −0
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import static org.hamcrest.Matchers.aMapWithSize;
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
import static org.junit.Assert.assertThat;

import android.app.UiAutomation;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
@@ -38,6 +39,7 @@ import android.test.AndroidTestCase;
import androidx.test.filters.MediumTest;
import androidx.test.filters.SmallTest;
import androidx.test.filters.Suppress;
import androidx.test.platform.app.InstrumentationRegistry;

import java.util.HashMap;
import java.util.List;
@@ -447,4 +449,50 @@ public class SettingsProviderTest extends AndroidTestCase {
            r.call(Settings.Config.CONTENT_URI, Settings.CALL_METHOD_DELETE_CONFIG, newName, null);
        }
    }

    @SmallTest
    public void testCall_putOverrideConfig() throws Exception {
        // The shell user is restricted to a set of allowlisted flags / namespaces that can be
        // written. When an flag override is requested, the flag is rewritten to be in the form:
        // device_config_overrides/namespace:flagname
        // To avoid requiring allowlisting both the base flag and the override version,
        // SettingsProvider will parse out the overridden flag and check if it has been allowlisted.
        // This test verifies that this is properly handled for both the good case as well as when
        // the overridden flag is not in the proper format by ensuring a SecurityException is not
        // thrown since these flags have been allowlisted.
        UiAutomation uiAutomation =
                InstrumentationRegistry.getInstrumentation().getUiAutomation();
        uiAutomation.adoptShellPermissionIdentity();
        ContentResolver r = getContext().getContentResolver();
        String overridesNamespace = "device_config_overrides";
        String namespace = "namespace1";
        String flagName = "key1";
        String validFlag = overridesNamespace + "/" + namespace + ":" + flagName;
        String invalidFlag1 = overridesNamespace + "/";
        String invalidFlag2 = overridesNamespace + "/" + namespace + ":";
        String invalidFlag3 = overridesNamespace + "/" + ":";
        String value = "value1";
        Bundle args = new Bundle();
        args.putString(Settings.NameValueTable.VALUE, value);

        try {
            r.call(Settings.Config.CONTENT_URI, Settings.CALL_METHOD_PUT_CONFIG, validFlag, args);
            r.call(Settings.Config.CONTENT_URI, Settings.CALL_METHOD_PUT_CONFIG, invalidFlag1,
                    args);
            r.call(Settings.Config.CONTENT_URI, Settings.CALL_METHOD_PUT_CONFIG, invalidFlag2,
                    args);
            r.call(Settings.Config.CONTENT_URI, Settings.CALL_METHOD_PUT_CONFIG, invalidFlag3,
                    args);
        } finally {
            r.call(Settings.Config.CONTENT_URI, Settings.CALL_METHOD_DELETE_CONFIG, validFlag,
                    null);
            r.call(Settings.Config.CONTENT_URI, Settings.CALL_METHOD_DELETE_CONFIG, invalidFlag1,
                    null);
            r.call(Settings.Config.CONTENT_URI, Settings.CALL_METHOD_DELETE_CONFIG, invalidFlag2,
                    null);
            r.call(Settings.Config.CONTENT_URI, Settings.CALL_METHOD_DELETE_CONFIG, invalidFlag3,
                    null);
            uiAutomation.dropShellPermissionIdentity();
        }
    }
}
+35 −6
Original line number Diff line number Diff line
@@ -385,6 +385,9 @@ public class SettingsProvider extends ContentProvider {

    private static final Set<String> sDeviceConfigAllowlistedNamespaces = new ArraySet<>();

    // TODO(b/388901162): Remove this when the same constant is exposed as an API in DeviceConfig.
    private static final String DEVICE_CONFIG_OVERRIDES_NAMESPACE = "device_config_overrides";

    // We have to call in the user manager with no lock held,
    private volatile UserManager mUserManager;

@@ -2480,12 +2483,21 @@ public class SettingsProvider extends ContentProvider {
            for (String flag : flags) {
                boolean namespaceAllowed = false;
                if (isRestrictedShell) {
                    int delimiterIndex = flag.indexOf("/");
                    String flagNamespace;
                    if (delimiterIndex != -1) {
                        flagNamespace = flag.substring(0, delimiterIndex);
                    } else {
                        flagNamespace = flag;
                    String flagNamespace = getFlagNamespace(flag);
                    // If the namespace indicates this is a flag override, then the actual
                    // namespace and flag name should be used for the allowlist verification.
                    if (DEVICE_CONFIG_OVERRIDES_NAMESPACE.equals(flagNamespace)) {
                        // Override flags are in the following form:
                        // device_config_overrides/namespace:flagName
                        int slashIndex = flag.indexOf("/");
                        int colonIndex = flag.indexOf(":", slashIndex);
                        if (slashIndex != -1 && colonIndex != -1 && (slashIndex + 1) < flag.length()
                                && (colonIndex + 1) < flag.length()) {
                            flagNamespace = flag.substring(slashIndex + 1, colonIndex);
                            StringBuilder flagBuilder = new StringBuilder(flagNamespace);
                            flagBuilder.append("/").append(flag.substring(colonIndex + 1));
                            flag = flagBuilder.toString();
                        }
                    }
                    if (allowlistedDeviceConfigNamespaces.contains(flagNamespace)) {
                        namespaceAllowed = true;
@@ -2512,6 +2524,23 @@ public class SettingsProvider extends ContentProvider {
        }
    }

    /**
     * Returns the namespace for the provided {@code flag}.
     * <p>
     * Flags are expected to be in the form namespace/flagName; if the '/' delimiter does
     * not exist, then the provided flag is returned as the namespace.
     */
    private static String getFlagNamespace(String flag) {
        int delimiterIndex = flag.indexOf("/");
        String flagNamespace;
        if (delimiterIndex != -1) {
            flagNamespace = flag.substring(0, delimiterIndex);
        } else {
            flagNamespace = flag;
        }
        return flagNamespace;
    }

    // The check is added mainly for auto devices. On auto devices, it is possible that
    // multiple users are visible simultaneously using visible background users.
    // In such cases, it is desired that Non-current user (ex. visible background users) can