diff --git a/fs_mgr/Android.bp b/fs_mgr/Android.bp index 3cce0e8f9..6c8a9434c 100644 --- a/fs_mgr/Android.bp +++ b/fs_mgr/Android.bp @@ -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", diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp index 2ac638a2a..34e24f801 100644 --- a/fs_mgr/fs_mgr_overlayfs.cpp +++ b/fs_mgr/fs_mgr_overlayfs.cpp @@ -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(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 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"); +} diff --git a/fs_mgr/fs_mgr_vendor_overlay.cpp b/fs_mgr/fs_mgr_vendor_overlay.cpp new file mode 100644 index 000000000..360a11730 --- /dev/null +++ b/fs_mgr/fs_mgr_vendor_overlay.cpp @@ -0,0 +1,128 @@ +/* + * 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 +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#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 fs_mgr_get_vendor_overlay_dirs(const std::string& overlay_top) { + std::vector vendor_overlay_dirs; + std::unique_ptr 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/ 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; +} diff --git a/fs_mgr/include/fs_mgr_overlayfs.h b/fs_mgr/include/fs_mgr_overlayfs.h index 91825322e..72202ab30 100644 --- a/fs_mgr/include/fs_mgr_overlayfs.h +++ b/fs_mgr/include/fs_mgr_overlayfs.h @@ -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(); diff --git a/fs_mgr/include/fs_mgr_vendor_overlay.h b/fs_mgr/include/fs_mgr_vendor_overlay.h new file mode 100644 index 000000000..9771a0cb6 --- /dev/null +++ b/fs_mgr/include/fs_mgr_vendor_overlay.h @@ -0,0 +1,21 @@ +/* + * 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 + +bool fs_mgr_vendor_overlay_mount_all(); diff --git a/init/init.cpp b/init/init.cpp index b12ba8c89..90803f794 100644 --- a/init/init.cpp +++ b/init/init.cpp @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -717,6 +718,7 @@ int main(int argc, char** argv) { InstallSignalFdHandler(&epoll); property_load_boot_defaults(); + fs_mgr_vendor_overlay_mount_all(); export_oem_lock_status(); StartPropertyService(&epoll); set_usb_controller();