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

Commit 6bab0a9c authored by Justin Yun's avatar Justin Yun
Browse files

Mount vendor overlay from the system partition

Using overlayfs, the system partition may provide files for older
version of vendor partitions by overlaying on the vendor partition.
Directories in /system/vendor_overlay will be overlaid on the
directories in /vendor to override existing files or provide new
files.

This feature works only if the kernel support overlayfs and has a
patch for override_creds. Otherwise, no-op.

Bug: 114679254
Test: Build and boot: nothing affected without overlayfs, or
                      vendor file is overrided with overlayfs

Change-Id: Iff3a308945299034123ba7bcb40dc787e102730e
parent bb3e4792
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -46,6 +46,7 @@ cc_library {
        "fs_mgr_avb_ops.cpp",
        "fs_mgr_dm_linear.cpp",
        "fs_mgr_overlayfs.cpp",
        "fs_mgr_vendor_overlay.cpp",
    ],
    shared_libs: [
        "libbase",
+19 −27
Original line number Diff line number Diff line
@@ -112,17 +112,6 @@ bool fs_mgr_dir_is_writable(const std::string& path) {
    return ret | !rmdir(test_directory.c_str());
}

std::string fs_mgr_get_context(const std::string& mount_point) {
    char* ctx = nullptr;
    auto len = getfilecon(mount_point.c_str(), &ctx);
    if ((len > 0) && ctx) {
        std::string context(ctx, len);
        free(ctx);
        return context;
    }
    return "";
}

// At less than 1% free space return value of false,
// means we will try to wrap with overlayfs.
bool fs_mgr_filesystem_has_space(const char* mount_point) {
@@ -247,19 +236,6 @@ bool fs_mgr_rw_access(const std::string& path) {
    return ret;
}

// return true if system supports overlayfs
bool fs_mgr_wants_overlayfs() {
    // Properties will return empty on init first_stage_mount, so speculative
    // determination, empty (unset) _or_ "1" is true which differs from the
    // official ro.debuggable policy.  ALLOW_ADBD_DISABLE_VERITY == 0 should
    // protect us from false in any case, so this is insurance.
    auto debuggable = android::base::GetProperty("ro.debuggable", "1");
    if (debuggable != "1") return false;

    // Overlayfs available in the kernel, and patched for override_creds?
    return fs_mgr_access("/sys/module/overlay/parameters/override_creds");
}

bool fs_mgr_overlayfs_already_mounted(const std::string& mount_point, bool overlay_only = true) {
    std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> fstab(fs_mgr_read_fstab("/proc/mounts"),
                                                               fs_mgr_free_fstab);
@@ -748,7 +724,7 @@ bool fs_mgr_overlayfs_scratch_can_be_mounted(const std::string& scratch_device)
bool fs_mgr_overlayfs_mount_all(fstab* fstab) {
    auto ret = false;

    if (!fs_mgr_wants_overlayfs()) return ret;
    if (!fs_mgr_overlayfs_supports_override_creds()) return ret;

    if (!fstab) return ret;

@@ -806,7 +782,7 @@ std::vector<std::string> fs_mgr_overlayfs_required_devices(
bool fs_mgr_overlayfs_setup(const char* backing, const char* mount_point, bool* change) {
    if (change) *change = false;
    auto ret = false;
    if (!fs_mgr_wants_overlayfs()) return ret;
    if (!fs_mgr_overlayfs_supports_override_creds()) return ret;
    if (!fs_mgr_boot_completed()) {
        errno = EBUSY;
        PERROR << "setup";
@@ -869,7 +845,7 @@ bool fs_mgr_overlayfs_teardown(const char* mount_point, bool* change) {
    for (const auto& overlay_mount_point : kOverlayMountPoints) {
        ret &= fs_mgr_overlayfs_teardown_one(overlay_mount_point, mount_point ?: "", change);
    }
    if (!fs_mgr_wants_overlayfs()) {
    if (!fs_mgr_overlayfs_supports_override_creds()) {
        // After obligatory teardown to make sure everything is clean, but if
        // we didn't want overlayfs in the the first place, we do not want to
        // waste time on a reboot (or reboot request message).
@@ -908,3 +884,19 @@ bool fs_mgr_has_shared_blocks(const std::string& mount_point, const std::string&

    return (info.feat_ro_compat & EXT4_FEATURE_RO_COMPAT_SHARED_BLOCKS) != 0;
}

std::string fs_mgr_get_context(const std::string& mount_point) {
    char* ctx = nullptr;
    if (getfilecon(mount_point.c_str(), &ctx) == -1) {
        return "";
    }

    std::string context(ctx);
    free(ctx);
    return context;
}

bool fs_mgr_overlayfs_supports_override_creds() {
    // Overlayfs available in the kernel, and patched for override_creds?
    return fs_mgr_access("/sys/module/overlay/parameters/override_creds");
}
+128 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 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.
 */

#include <dirent.h>
#include <selinux/selinux.h>
#include <sys/mount.h>
#include <unistd.h>

#include <memory>
#include <string>
#include <vector>

#include <android-base/logging.h>
#include <android-base/properties.h>
#include <fs_mgr_overlayfs.h>
#include <fs_mgr_vendor_overlay.h>
#include <fstab/fstab.h>

#include "fs_mgr_priv.h"

using namespace std::literals;

namespace {

const auto kVendorOverlaySourceDir = "/system/vendor_overlay/"s;
const auto kVndkVersionPropertyName = "ro.vndk.version"s;
const auto kVendorTopDir = "/vendor/"s;
const auto kLowerdirOption = "lowerdir="s;

std::string fs_mgr_get_vendor_overlay_top_dir() {
    // VNDK version is provided by the /vendor/default.prop
    // To read the property, it must be called at the second init stage after the default
    // properties are loaded.
    std::string vndk_version = android::base::GetProperty(kVndkVersionPropertyName, "");
    if (vndk_version.empty()) {
        return "";
    }
    return kVendorOverlaySourceDir + vndk_version;
}

std::vector<std::string> fs_mgr_get_vendor_overlay_dirs(const std::string& overlay_top) {
    std::vector<std::string> vendor_overlay_dirs;
    std::unique_ptr<DIR, decltype(&closedir)> vendor_overlay_top(opendir(overlay_top.c_str()),
                                                                 closedir);
    if (!vendor_overlay_top) return vendor_overlay_dirs;

    // Vendor overlay root for current vendor version found!
    LINFO << "vendor overlay root: " << overlay_top;
    struct dirent* dp;
    while ((dp = readdir(vendor_overlay_top.get())) != nullptr) {
        if (dp->d_type != DT_DIR || dp->d_name[0] == '.') {
            continue;
        }
        vendor_overlay_dirs.push_back(dp->d_name);
    }

    return vendor_overlay_dirs;
}

bool fs_mgr_vendor_overlay_mount(const std::string& overlay_top, const std::string& mount_point) {
    const auto vendor_mount_point = kVendorTopDir + mount_point;
    LINFO << "vendor overlay mount on " << vendor_mount_point;

    auto context = fs_mgr_get_context(vendor_mount_point);
    if (!context.empty()) {
        context = ",rootcontext="s + context;
    } else {
        PERROR << " result: cannot find the mount point";
        return false;
    }

    auto options = "override_creds=off,"s + kLowerdirOption + overlay_top + "/" + mount_point +
                   ":" + vendor_mount_point + context;
    auto report = "__mount(source=overlay,target="s + vendor_mount_point + ",type=overlay," +
                  options + ")=";
    auto ret = mount("overlay", vendor_mount_point.c_str(), "overlay", MS_RDONLY | MS_RELATIME,
                     options.c_str());
    if (ret) {
        PERROR << report << ret;
        return false;
    } else {
        LINFO << report << ret;
        return true;
    }
}

}  // namespace

// Since the vendor overlay requires to know the version of the vendor partition,
// it is not possible to mount vendor overlay at the first stage that cannot
// initialize properties.
// To read the properties, vendor overlay must be mounted at the second stage, right
// after "property_load_boot_defaults()" is called.
bool fs_mgr_vendor_overlay_mount_all() {
    const auto overlay_top = fs_mgr_get_vendor_overlay_top_dir();
    if (overlay_top.empty()) {
        LINFO << "vendor overlay: vndk version not defined";
        return false;
    }
    const auto vendor_overlay_dirs = fs_mgr_get_vendor_overlay_dirs(overlay_top);
    if (vendor_overlay_dirs.empty()) return true;
    if (!fs_mgr_overlayfs_supports_override_creds()) {
        LINFO << "vendor overlay: kernel does not support overlayfs";
        return false;
    }

    // Mount each directory in /system/vendor_overlay/<ver> on /vendor
    auto ret = true;
    for (const auto& vendor_overlay_dir : vendor_overlay_dirs) {
        if (!fs_mgr_vendor_overlay_mount(overlay_top, vendor_overlay_dir)) {
            ret = false;
        }
    }
    return ret;
}
+2 −0
Original line number Diff line number Diff line
@@ -30,3 +30,5 @@ bool fs_mgr_overlayfs_setup(const char* backing = nullptr, const char* mount_poi
                            bool* change = nullptr);
bool fs_mgr_overlayfs_teardown(const char* mount_point = nullptr, bool* change = nullptr);
bool fs_mgr_has_shared_blocks(const std::string& mount_point, const std::string& dev);
std::string fs_mgr_get_context(const std::string& mount_point);
bool fs_mgr_overlayfs_supports_override_creds();
+21 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 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.
 */

#pragma once

#include <fstab/fstab.h>

bool fs_mgr_vendor_overlay_mount_all();
Loading