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

Commit 13e51e7f authored by Oli Lan's avatar Oli Lan
Browse files

Create DE_sys APEX data directories.

This creates the directory /data/misc/apexdata, at the same time as other
directories under /data/misc. Then, when apexd has finished activating
APEXes, a directory is created under /data/misc/apexdata for every
APEX, with the same name as the APEX module name.

See go/apex-data-directories.

APEXes are discovered by scanning the /apex directory. It may be better
to delegate this process to a library, but it is proposed to defer that
change to a future CL.

Bug: 141148175
Test: Built and flashed, checked directories were created.
Change-Id: I639d6f490ae0b97f116ce38ff3ac348bd73aa20e
parent 1fd9c556
Loading
Loading
Loading
Loading
+68 −25
Original line number Diff line number Diff line
@@ -360,57 +360,61 @@ static Result<void> do_interface_stop(const BuiltinArguments& args) {
    return {};
}

// mkdir <path> [mode] [owner] [group] [<option> ...]
static Result<void> do_mkdir(const BuiltinArguments& args) {
    auto options = ParseMkdir(args.args);
    if (!options) return options.error();
static Result<void> make_dir_with_options(const MkdirOptions& options) {
    std::string ref_basename;
    if (options->ref_option == "ref") {
    if (options.ref_option == "ref") {
        ref_basename = fscrypt_key_ref;
    } else if (options->ref_option == "per_boot_ref") {
    } else if (options.ref_option == "per_boot_ref") {
        ref_basename = fscrypt_key_per_boot_ref;
    } else {
        return Error() << "Unknown key option: '" << options->ref_option << "'";
        return Error() << "Unknown key option: '" << options.ref_option << "'";
    }

    struct stat mstat;
    if (lstat(options->target.c_str(), &mstat) != 0) {
    if (lstat(options.target.c_str(), &mstat) != 0) {
        if (errno != ENOENT) {
            return ErrnoError() << "lstat() failed on " << options->target;
            return ErrnoError() << "lstat() failed on " << options.target;
        }
        if (!make_dir(options->target, options->mode)) {
            return ErrnoErrorIgnoreEnoent() << "mkdir() failed on " << options->target;
        if (!make_dir(options.target, options.mode)) {
            return ErrnoErrorIgnoreEnoent() << "mkdir() failed on " << options.target;
        }
        if (lstat(options->target.c_str(), &mstat) != 0) {
            return ErrnoError() << "lstat() failed on new " << options->target;
        if (lstat(options.target.c_str(), &mstat) != 0) {
            return ErrnoError() << "lstat() failed on new " << options.target;
        }
    }
    if (!S_ISDIR(mstat.st_mode)) {
        return Error() << "Not a directory on " << options->target;
        return Error() << "Not a directory on " << options.target;
    }
    bool needs_chmod = (mstat.st_mode & ~S_IFMT) != options->mode;
    if ((options->uid != static_cast<uid_t>(-1) && options->uid != mstat.st_uid) ||
        (options->gid != static_cast<gid_t>(-1) && options->gid != mstat.st_gid)) {
        if (lchown(options->target.c_str(), options->uid, options->gid) == -1) {
            return ErrnoError() << "lchown failed on " << options->target;
    bool needs_chmod = (mstat.st_mode & ~S_IFMT) != options.mode;
    if ((options.uid != static_cast<uid_t>(-1) && options.uid != mstat.st_uid) ||
        (options.gid != static_cast<gid_t>(-1) && options.gid != mstat.st_gid)) {
        if (lchown(options.target.c_str(), options.uid, options.gid) == -1) {
            return ErrnoError() << "lchown failed on " << options.target;
        }
        // chown may have cleared S_ISUID and S_ISGID, chmod again
        needs_chmod = true;
    }
    if (needs_chmod) {
        if (fchmodat(AT_FDCWD, options->target.c_str(), options->mode, AT_SYMLINK_NOFOLLOW) == -1) {
            return ErrnoError() << "fchmodat() failed on " << options->target;
        if (fchmodat(AT_FDCWD, options.target.c_str(), options.mode, AT_SYMLINK_NOFOLLOW) == -1) {
            return ErrnoError() << "fchmodat() failed on " << options.target;
        }
    }
    if (fscrypt_is_native()) {
        if (!FscryptSetDirectoryPolicy(ref_basename, options->fscrypt_action, options->target)) {
        if (!FscryptSetDirectoryPolicy(ref_basename, options.fscrypt_action, options.target)) {
            return reboot_into_recovery(
                    {"--prompt_and_wipe_data", "--reason=set_policy_failed:"s + options->target});
                    {"--prompt_and_wipe_data", "--reason=set_policy_failed:"s + options.target});
        }
    }
    return {};
}

// mkdir <path> [mode] [owner] [group] [<option> ...]
static Result<void> do_mkdir(const BuiltinArguments& args) {
    auto options = ParseMkdir(args.args);
    if (!options) return options.error();
    return make_dir_with_options(*options);
}

/* umount <path> */
static Result<void> do_umount(const BuiltinArguments& args) {
    if (umount(args[1].c_str()) < 0) {
@@ -1172,7 +1176,7 @@ static Result<void> do_mark_post_data(const BuiltinArguments& args) {
    return {};
}

static Result<void> do_parse_apex_configs(const BuiltinArguments& args) {
static Result<void> parse_apex_configs() {
    glob_t glob_result;
    static constexpr char glob_pattern[] = "/apex/*/etc/*.rc";
    const int ret = glob(glob_pattern, GLOB_MARK, nullptr, &glob_result);
@@ -1211,6 +1215,45 @@ static Result<void> do_parse_apex_configs(const BuiltinArguments& args) {
    }
}

/*
 * Creates a directory under /data/misc/apexdata/ for each APEX.
 */
static Result<void> create_apex_data_dirs() {
    auto dirp = std::unique_ptr<DIR, int (*)(DIR*)>(opendir("/apex"), closedir);
    if (!dirp) {
        return ErrnoError() << "Unable to open apex directory";
    }
    struct dirent* entry;
    while ((entry = readdir(dirp.get())) != nullptr) {
        if (entry->d_type != DT_DIR) continue;

        const char* name = entry->d_name;
        // skip any starting with "."
        if (name[0] == '.') continue;

        if (strchr(name, '@') != nullptr) continue;

        auto path = "/data/misc/apexdata/" + std::string(name);
        auto system_uid = DecodeUid("system");
        auto options =
                MkdirOptions{path, 0700, *system_uid, *system_uid, FscryptAction::kNone, "ref"};
        make_dir_with_options(options);
    }
    return {};
}

static Result<void> do_perform_apex_config(const BuiltinArguments& args) {
    auto create_dirs = create_apex_data_dirs();
    if (!create_dirs) {
        return create_dirs.error();
    }
    auto parse_configs = parse_apex_configs();
    if (!parse_configs) {
        return parse_configs.error();
    }
    return {};
}

static Result<void> do_enter_default_mount_ns(const BuiltinArguments& args) {
    if (SwitchToDefaultMountNamespace()) {
        return {};
@@ -1271,7 +1314,7 @@ const BuiltinFunctionMap& GetBuiltinFunctionMap() {
        // mount and umount are run in the same context as mount_all for symmetry.
        {"mount_all",               {1,     kMax, {false,  do_mount_all}}},
        {"mount",                   {3,     kMax, {false,  do_mount}}},
        {"parse_apex_configs",      {0,     0,    {false,  do_parse_apex_configs}}},
        {"perform_apex_config",     {0,     0,    {false,  do_perform_apex_config}}},
        {"umount",                  {1,     1,    {false,  do_umount}}},
        {"umount_all",              {1,     1,    {false,  do_umount_all}}},
        {"readahead",               {1,     2,    {true,   do_readahead}}},
+3 −1
Original line number Diff line number Diff line
@@ -579,6 +579,7 @@ on post-fs-data
    mkdir /data/misc/profman 0770 system shell
    mkdir /data/misc/gcov 0770 root root
    mkdir /data/misc/installd 0700 root root
    mkdir /data/misc/apexdata 0700 root root

    mkdir /data/preloads 0775 system system encryption=None

@@ -668,7 +669,8 @@ on post-fs-data

    # Wait for apexd to finish activating APEXes before starting more processes.
    wait_for_prop apexd.status ready
    parse_apex_configs
    perform_apex_config

    exec_start derive_sdk

    init_user0