diff options
| -rw-r--r-- | core/tests/coretests/src/android/provider/SettingsProviderTest.java | 48 | ||||
| -rw-r--r-- | packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java | 41 |
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 |