summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/tests/coretests/src/android/provider/SettingsProviderTest.java48
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java41
2 files changed, 83 insertions, 6 deletions
diff --git a/core/tests/coretests/src/android/provider/SettingsProviderTest.java b/core/tests/coretests/src/android/provider/SettingsProviderTest.java
index 133177935984..c58d53ba967c 100644
--- a/core/tests/coretests/src/android/provider/SettingsProviderTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsProviderTest.java
@@ -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();
+ }
+ }
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index cb656bdd5d54..b31503e26246 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -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