diff options
| author | 2024-08-15 16:15:27 +0000 | |
|---|---|---|
| committer | 2024-08-16 16:00:16 +0000 | |
| commit | 4b7c2bb67d56ced2afdac8bc4a8ea84137cbb07d (patch) | |
| tree | 04f49b9c2e3bfb67e15d5fda1adebf0efba832a7 | |
| parent | acdbc9c1eecdc1b76125d99d6a10b2930610d518 (diff) | |
For aconfig flag writes, check write permission
Flag: com.android.providers.settings.check_root_and_read_only
Bug: 342636474
Test: m
Change-Id: I422b076bf8e44bbaa1185822ef99dbb4ff588084
3 files changed, 120 insertions, 14 deletions
diff --git a/packages/SettingsProvider/Android.bp b/packages/SettingsProvider/Android.bp index 75f8384321b0..3e62b7b2cf6e 100644 --- a/packages/SettingsProvider/Android.bp +++ b/packages/SettingsProvider/Android.bp @@ -32,6 +32,7 @@ android_library { "unsupportedappusage", ], static_libs: [ + "aconfig_device_paths_java", "aconfig_new_storage_flags_lib", "aconfigd_java_utils", "aconfig_demo_flags_java_lib", diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java b/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java index 8b0772bb644d..121bd3e6e771 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java @@ -20,8 +20,10 @@ import static android.provider.Settings.Config.SYNC_DISABLED_MODE_NONE; import static android.provider.Settings.Config.SYNC_DISABLED_MODE_PERSISTENT; import static android.provider.Settings.Config.SYNC_DISABLED_MODE_UNTIL_REBOOT; -import android.aconfig.Aconfig.parsed_flag; -import android.aconfig.Aconfig.parsed_flags; +import android.aconfig.DeviceProtos; +import android.aconfig.nano.Aconfig; +import android.aconfig.nano.Aconfig.parsed_flag; +import android.aconfig.nano.Aconfig.parsed_flags; import android.annotation.SuppressLint; import android.app.ActivityManager; import android.content.AttributionSource; @@ -42,7 +44,6 @@ import android.provider.Settings.Config.SyncDisabledMode; import android.provider.UpdatableDeviceConfigServiceReadiness; import android.util.Slog; -import com.android.internal.pm.pkg.component.AconfigFlags; import com.android.internal.util.FastPrintWriter; import java.io.File; @@ -136,11 +137,8 @@ public final class DeviceConfigService extends Binder { continue; } - for (parsed_flag flag : parsedFlags.getParsedFlagList()) { - String namespace = flag.getNamespace(); - String packageName = flag.getPackage(); - String name = flag.getName(); - nameSet.add(namespace + "/" + packageName + "." + name); + for (parsed_flag flag : parsedFlags.parsedFlag) { + nameSet.add(flag.namespace + "/" + flag.package_ + "." + flag.name); } } } catch (IOException e) { @@ -169,6 +167,7 @@ public final class DeviceConfigService extends Binder { static final class MyShellCommand extends ShellCommand { final SettingsProvider mProvider; + private HashMap<String, parsed_flag> mAconfigParsedFlags; enum CommandVerb { GET, @@ -186,6 +185,51 @@ public final class DeviceConfigService extends Binder { MyShellCommand(SettingsProvider provider) { mProvider = provider; + + if (Flags.checkRootAndReadOnly()) { + List<parsed_flag> parsedFlags; + try { + parsedFlags = DeviceProtos.loadAndParseFlagProtos(); + } catch (IOException e) { + throw new IllegalStateException("failed to parse aconfig protos"); + } + + mAconfigParsedFlags = new HashMap(); + for (parsed_flag flag : parsedFlags) { + mAconfigParsedFlags.put(flag.package_ + "." + flag.name, flag); + } + } + } + + /** + * Return true if a flag is aconfig. + */ + private boolean isAconfigFlag(String name) { + return mAconfigParsedFlags.get(name) != null; + } + + /** + * Return true if a flag is both aconfig and read-only. + * + * @return true if a flag is both aconfig and read-only + */ + private boolean isReadOnly(String name) { + parsed_flag flag = mAconfigParsedFlags.get(name); + if (flag != null) { + if (flag.permission == Aconfig.READ_ONLY) { + return true; + } + } + return false; + } + + /** + * Return true if the calling process is root. + * + * @return true if a flag is aconfig, and the calling process is root + */ + private boolean isRoot() { + return Binder.getCallingUid() == Process.ROOT_UID; } public static HashMap<String, String> getAllFlags(IContentProvider provider) { @@ -414,21 +458,71 @@ public final class DeviceConfigService extends Binder { pout.println(DeviceConfig.getProperty(namespace, key)); break; case PUT: + if (Flags.checkRootAndReadOnly()) { + if (isAconfigFlag(key)) { + if (!isRoot()) { + pout.println("Error: must be root to write aconfig flag"); + break; + } + + if (isReadOnly(key)) { + pout.println("Error: cannot write read-only flag"); + break; + } + } + } + DeviceConfig.setProperty(namespace, key, value, makeDefault); break; case OVERRIDE: - AconfigFlags.Permission permission = - (new AconfigFlags()).getFlagPermission(key); - if (permission == AconfigFlags.Permission.READ_ONLY) { - pout.println("cannot override read-only flag " + key); - } else { - DeviceConfig.setLocalOverride(namespace, key, value); + if (Flags.checkRootAndReadOnly()) { + if (isAconfigFlag(key)) { + if (!isRoot()) { + pout.println("Error: must be root to write aconfig flag"); + break; + } + + if (isReadOnly(key)) { + pout.println("Error: cannot write read-only flag"); + break; + } + } } + + DeviceConfig.setLocalOverride(namespace, key, value); break; case CLEAR_OVERRIDE: + if (Flags.checkRootAndReadOnly()) { + if (isAconfigFlag(key)) { + if (!isRoot()) { + pout.println("Error: must be root to write aconfig flag"); + break; + } + + if (isReadOnly(key)) { + pout.println("Error: cannot write read-only flag"); + break; + } + } + } + DeviceConfig.clearLocalOverride(namespace, key); break; case DELETE: + if (Flags.checkRootAndReadOnly()) { + if (isAconfigFlag(key)) { + if (!isRoot()) { + pout.println("Error: must be root to write aconfig flag"); + break; + } + + if (isReadOnly(key)) { + pout.println("Error: cannot write read-only flag"); + break; + } + } + } + pout.println(delete(iprovider, namespace, key) ? "Successfully deleted " + key + " from " + namespace : "Failed to delete " + key + " from " + namespace); diff --git a/packages/SettingsProvider/src/com/android/providers/settings/device_config_service.aconfig b/packages/SettingsProvider/src/com/android/providers/settings/device_config_service.aconfig index b1e6d6650226..006e644b2ac7 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/device_config_service.aconfig +++ b/packages/SettingsProvider/src/com/android/providers/settings/device_config_service.aconfig @@ -70,3 +70,14 @@ flag { purpose: PURPOSE_BUGFIX } } + +flag { + name: "check_root_and_read_only" + namespace: "core_experiments_team_internal" + description: "Check root and aconfig flag permissions in adb shell device_config commands." + bug: "342636474" + is_fixed_read_only: true + metadata { + purpose: PURPOSE_BUGFIX + } +} |