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

Commit 1dacd42a authored by Bowgo Tsai's avatar Bowgo Tsai
Browse files

Allow overriding ro.debuggable to 1 on USER builds

When init found "/force_debuggable" in the first-stage ramdisk, it will
do the following if the device is unlocked:
  1. load /system/etc/adb_debug.prop (with ro.debuggable=1)
  2 .load userdebug_plat_sepolicy.cil instead of original plat_sepolicy.cil from
    /system/etc/selinux/.

This make it possible to run VTS on a USER build GSI, by using a special
ramdisk containing "/force_debuggable".

Bug: 126493225
Test: unlock a USER build device, check 'adb root' can work
Change-Id: I9b4317bac1ce92f2c0baa67c83d4b12deba62c92
parent 9b30c0a7
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -199,6 +199,12 @@ int FirstStageMain(int argc, char** argv) {
        SwitchRoot("/first_stage_ramdisk");
    }

    // If this file is present, the second-stage init will use a userdebug sepolicy
    // and load adb_debug.prop to allow adb root, if the device is unlocked.
    if (access("/force_debuggable", F_OK) == 0) {
        setenv("INIT_FORCE_DEBUGGABLE", "true", 1);
    }

    if (!DoFirstStageMount()) {
        LOG(FATAL) << "Failed to mount required partitions early ...";
    }
+11 −1
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <cutils/android_reboot.h>
#include <fs_avb/fs_avb.h>
#include <fs_mgr_vendor_overlay.h>
#include <keyutils.h>
#include <libavb/libavb.h>
@@ -74,6 +75,7 @@ using android::base::ReadFileToString;
using android::base::StringPrintf;
using android::base::Timer;
using android::base::Trim;
using android::fs_mgr::AvbHandle;

namespace android {
namespace init {
@@ -92,6 +94,7 @@ static std::string wait_prop_value;
static bool shutting_down;
static std::string shutdown_command;
static bool do_shutdown = false;
static bool load_debug_prop = false;

std::vector<std::string> late_import_paths;

@@ -655,10 +658,17 @@ int SecondStageMain(int argc, char** argv) {
    const char* avb_version = getenv("INIT_AVB_VERSION");
    if (avb_version) property_set("ro.boot.avb_version", avb_version);

    // See if need to load debug props to allow adb root, when the device is unlocked.
    const char* force_debuggable_env = getenv("INIT_FORCE_DEBUGGABLE");
    if (force_debuggable_env && AvbHandle::IsDeviceUnlocked()) {
        load_debug_prop = "true"s == force_debuggable_env;
    }

    // Clean up our environment.
    unsetenv("INIT_STARTED_AT");
    unsetenv("INIT_SELINUX_TOOK");
    unsetenv("INIT_AVB_VERSION");
    unsetenv("INIT_FORCE_DEBUGGABLE");

    // Now set up SELinux for second stage.
    SelinuxSetupKernelLogging();
@@ -672,7 +682,7 @@ int SecondStageMain(int argc, char** argv) {

    InstallSignalFdHandler(&epoll);

    property_load_boot_defaults();
    property_load_boot_defaults(load_debug_prop);
    fs_mgr_vendor_overlay_mount_all();
    export_oem_lock_status();
    StartPropertyService(&epoll);
+7 −1
Original line number Diff line number Diff line
@@ -866,7 +866,7 @@ static void property_derive_build_fingerprint() {
    }
}

void property_load_boot_defaults() {
void property_load_boot_defaults(bool load_debug_prop) {
    // TODO(b/117892318): merge prop.default and build.prop files into one
    // We read the properties and their values into a map, in order to always allow properties
    // loaded in the later property files to override the properties in loaded in the earlier
@@ -888,6 +888,12 @@ void property_load_boot_defaults() {
    load_properties_from_file("/product_services/build.prop", nullptr, &properties);
    load_properties_from_file("/factory/factory.prop", "ro.*", &properties);

    if (load_debug_prop) {
        constexpr static const char kAdbDebugProp[] = "/system/etc/adb_debug.prop";
        LOG(INFO) << "Loading " << kAdbDebugProp;
        load_properties_from_file(kAdbDebugProp, nullptr, &properties);
    }

    for (const auto& [name, value] : properties) {
        std::string error;
        if (PropertySet(name, value, &error) != PROP_SUCCESS) {
+1 −1
Original line number Diff line number Diff line
@@ -36,7 +36,7 @@ uint32_t HandlePropertySet(const std::string& name, const std::string& value,
extern bool PropertyChildReap(pid_t pid);

void property_init(void);
void property_load_boot_defaults(void);
void property_load_boot_defaults(bool);
void load_persist_props(void);
void load_system_props(void);
void StartPropertyService(Epoll* epoll);
+19 −2
Original line number Diff line number Diff line
@@ -61,14 +61,18 @@
#include <android-base/parseint.h>
#include <android-base/unique_fd.h>
#include <cutils/android_reboot.h>
#include <fs_avb/fs_avb.h>
#include <selinux/android.h>

#include "reboot_utils.h"
#include "util.h"

using namespace std::string_literals;

using android::base::ParseInt;
using android::base::Timer;
using android::base::unique_fd;
using android::fs_mgr::AvbHandle;

namespace android {
namespace init {
@@ -267,6 +271,8 @@ bool GetVendorMappingVersion(std::string* plat_vers) {
}

constexpr const char plat_policy_cil_file[] = "/system/etc/selinux/plat_sepolicy.cil";
constexpr const char userdebug_plat_policy_cil_file[] =
        "/system/etc/selinux/userdebug_plat_sepolicy.cil";

bool IsSplitPolicyDevice() {
    return access(plat_policy_cil_file, R_OK) != -1;
@@ -282,10 +288,21 @@ bool LoadSplitPolicy() {
    // secilc is invoked to compile the above three policy files into a single monolithic policy
    // file. This file is then loaded into the kernel.

    // See if we need to load userdebug_plat_sepolicy.cil instead of plat_sepolicy.cil.
    const char* force_debuggable_env = getenv("INIT_FORCE_DEBUGGABLE");
    bool use_userdebug_policy =
            ((force_debuggable_env && "true"s == force_debuggable_env) &&
             AvbHandle::IsDeviceUnlocked() && access(userdebug_plat_policy_cil_file, F_OK) == 0);
    if (use_userdebug_policy) {
        LOG(WARNING) << "Using userdebug system sepolicy";
    }

    // Load precompiled policy from vendor image, if a matching policy is found there. The policy
    // must match the platform policy on the system image.
    std::string precompiled_sepolicy_file;
    if (FindPrecompiledSplitPolicy(&precompiled_sepolicy_file)) {
    // use_userdebug_policy requires compiling sepolicy with userdebug_plat_sepolicy.cil.
    // Thus it cannot use the precompiled policy from vendor image.
    if (!use_userdebug_policy && FindPrecompiledSplitPolicy(&precompiled_sepolicy_file)) {
        unique_fd fd(open(precompiled_sepolicy_file.c_str(), O_RDONLY | O_CLOEXEC | O_BINARY));
        if (fd != -1) {
            if (selinux_android_load_policy_from_fd(fd, precompiled_sepolicy_file.c_str()) < 0) {
@@ -358,7 +375,7 @@ bool LoadSplitPolicy() {
    // clang-format off
    std::vector<const char*> compile_args {
        "/system/bin/secilc",
        plat_policy_cil_file,
        use_userdebug_policy ? userdebug_plat_policy_cil_file : plat_policy_cil_file,
        "-m", "-M", "true", "-G", "-N",
        // Target the highest policy language version supported by the kernel
        "-c", version_as_string.c_str(),