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

Commit 0eee1edd authored by Michael Groover's avatar Michael Groover
Browse files

Add logging to detect flags set by tests

Android 16 limits the adb shell user to only modifying DeviceConfig
flags that have been allowlisted, either explicitly or through an
allowlisted namespace. However, there are a number of tests that
adopt the shell permission identity to modify flags as required
for the test; if these flags are not allowlisted, then these tests
will fail. Since only the shell user and tests have the
WRITE_ALLOWLISTED_DEVICE_CONFIG permission, this commit forces
the allowlist path to be followed when a DeviceConfig flag
modification is requested with the allowlist permission; if the
flag is not allowlisted, the flag will be logged to ensure it is
added to the allowlist to prevent test breakage once this feature
is enforced. This commit also adds a new WritableNamespaces class
that will contain the set of namespaces that have been approved
for modification.

Bug: 364083026
Flag: android.security.protect_device_config_flags
Test: Manually verified test with flag not in allowlist logged the
  flag but did not fail the test.
Change-Id: Ifefe9d47ab73c3e202a027ce37df58592f0a7de4
parent 255746a3
Loading
Loading
Loading
Loading
+24 −12
Original line number Diff line number Diff line
@@ -2434,28 +2434,40 @@ public class SettingsProvider extends ContentProvider {
                context.checkCallingOrSelfPermission(
                Manifest.permission.WRITE_DEVICE_CONFIG)
                == PackageManager.PERMISSION_GRANTED;
        boolean isRoot = Binder.getCallingUid() == Process.ROOT_UID;
        // Only the shell user and tests request the allowlist permission; this is used to force
        // the WRITE_ALLOWLISTED_DEVICE_CONFIG path to log any flags that need to be allowlisted.
        boolean isRestrictedShell = android.security.Flags.protectDeviceConfigFlags()
                && hasAllowlistPermission;

        if (isRoot) {
            return;
        }

        if (hasWritePermission) {
        if (!isRestrictedShell && hasWritePermission) {
            assertCallingUserDenyList(flags);
        } else if (hasAllowlistPermission) {
            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;
                    }
                    if (WritableNamespaces.ALLOWLIST.contains(flagNamespace)) {
                        namespaceAllowed = true;
                    }
                } else {
                    for (String allowlistedPrefix : WritableNamespacePrefixes.ALLOWLIST) {
                        if (flag.startsWith(allowlistedPrefix)) {
                            namespaceAllowed = true;
                            break;
                        }
                    }
                }

                if (!namespaceAllowed && !DeviceConfig.getAdbWritableFlags().contains(flag)) {
                    throw new SecurityException("Permission denial for flag '"
                        + flag
                        + "'; allowlist permission granted, but must add flag to the allowlist.");
                    Slog.wtf(LOG_TAG, "Permission denial for flag '" + flag
                            + "'; allowlist permission granted, but must add flag to the "
                            + "allowlist");
                }
            }
            assertCallingUserDenyList(flags);
+38 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.providers.settings;

import android.util.ArraySet;

import java.util.Arrays;
import java.util.Set;

/**
 * Contains the list of namespaces in which any flag can be written by adb without root
 * permissions.
 * <p>
 * A security review is required for any namespace that's added to this list. To add to
 * the list, create a change and tag the OWNER. In the commit message, include a
 * description of the flag's functionality, and a justification for why it needs to be
 * allowlisted.
 */
final class WritableNamespaces {
    public static final Set<String> ALLOWLIST =
            new ArraySet<String>(Arrays.asList(
                    "exo"
            ));
}