Merge "Avoid thread cache in unwinder." into sc-dev
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index ea9d333..af71fe6 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -2265,3 +2265,81 @@
     }
     return LP_METADATA_DEFAULT_PARTITION_NAME;
 }
+
+bool fs_mgr_create_canonical_mount_point(const std::string& mount_point) {
+    auto saved_errno = errno;
+    auto ok = true;
+    auto created_mount_point = !mkdir(mount_point.c_str(), 0755);
+    std::string real_mount_point;
+    if (!Realpath(mount_point, &real_mount_point)) {
+        ok = false;
+        PERROR << "failed to realpath(" << mount_point << ")";
+    } else if (mount_point != real_mount_point) {
+        ok = false;
+        LERROR << "mount point is not canonical: realpath(" << mount_point << ") -> "
+               << real_mount_point;
+    }
+    if (!ok && created_mount_point) {
+        rmdir(mount_point.c_str());
+    }
+    errno = saved_errno;
+    return ok;
+}
+
+bool fs_mgr_mount_overlayfs_fstab_entry(const FstabEntry& entry) {
+    auto overlayfs_valid_result = fs_mgr_overlayfs_valid();
+    if (overlayfs_valid_result == OverlayfsValidResult::kNotSupported) {
+        LERROR << __FUNCTION__ << "(): kernel does not support overlayfs";
+        return false;
+    }
+
+#if ALLOW_ADBD_DISABLE_VERITY == 0
+    // Allowlist the mount point if user build.
+    static const std::vector<const std::string> kAllowedPaths = {
+            "/odm", "/odm_dlkm", "/oem", "/product", "/system_ext", "/vendor", "/vendor_dlkm",
+    };
+    static const std::vector<const std::string> kAllowedPrefixes = {
+            "/mnt/product/",
+            "/mnt/vendor/",
+    };
+    if (std::none_of(kAllowedPaths.begin(), kAllowedPaths.end(),
+                     [&entry](const auto& path) -> bool {
+                         return entry.mount_point == path ||
+                                StartsWith(entry.mount_point, path + "/");
+                     }) &&
+        std::none_of(kAllowedPrefixes.begin(), kAllowedPrefixes.end(),
+                     [&entry](const auto& prefix) -> bool {
+                         return entry.mount_point != prefix &&
+                                StartsWith(entry.mount_point, prefix);
+                     })) {
+        LERROR << __FUNCTION__
+               << "(): mount point is forbidden on user build: " << entry.mount_point;
+        return false;
+    }
+#endif  // ALLOW_ADBD_DISABLE_VERITY == 0
+
+    if (!fs_mgr_create_canonical_mount_point(entry.mount_point)) {
+        return false;
+    }
+
+    auto options = "lowerdir=" + entry.lowerdir;
+    if (overlayfs_valid_result == OverlayfsValidResult::kOverrideCredsRequired) {
+        options += ",override_creds=off";
+    }
+
+    // Use "overlay-" + entry.blk_device as the mount() source, so that adb-remout-test don't
+    // confuse this with adb remount overlay, whose device name is "overlay".
+    // Overlayfs is a pseudo filesystem, so the source device is a symbolic value and isn't used to
+    // back the filesystem. However the device name would be shown in /proc/mounts.
+    auto source = "overlay-" + entry.blk_device;
+    auto report = "__mount(source=" + source + ",target=" + entry.mount_point + ",type=overlay," +
+                  options + ")=";
+    auto ret = mount(source.c_str(), entry.mount_point.c_str(), "overlay", MS_RDONLY | MS_NOATIME,
+                     options.c_str());
+    if (ret) {
+        PERROR << report << ret;
+        return false;
+    }
+    LINFO << report << ret;
+    return true;
+}
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index 853b24d..d0c89b9 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -127,15 +127,16 @@
             }
             fs_options.append(flag);
 
-            if (entry->fs_type == "f2fs" && StartsWith(flag, "reserve_root=")) {
-                std::string arg;
-                if (auto equal_sign = flag.find('='); equal_sign != std::string::npos) {
-                    arg = flag.substr(equal_sign + 1);
-                }
-                if (!ParseInt(arg, &entry->reserved_size)) {
-                    LWARNING << "Warning: reserve_root= flag malformed: " << arg;
-                } else {
-                    entry->reserved_size <<= 12;
+            if (auto equal_sign = flag.find('='); equal_sign != std::string::npos) {
+                const auto arg = flag.substr(equal_sign + 1);
+                if (entry->fs_type == "f2fs" && StartsWith(flag, "reserve_root=")) {
+                    if (!ParseInt(arg, &entry->reserved_size)) {
+                        LWARNING << "Warning: reserve_root= flag malformed: " << arg;
+                    } else {
+                        entry->reserved_size <<= 12;
+                    }
+                } else if (StartsWith(flag, "lowerdir=")) {
+                    entry->lowerdir = std::move(arg);
                 }
             }
         }
@@ -298,8 +299,6 @@
             if (!ParseByteCount(arg, &entry->zram_backingdev_size)) {
                 LWARNING << "Warning: zram_backingdev_size= flag malformed: " << arg;
             }
-        } else if (StartsWith(flag, "lowerdir=")) {
-            entry->lowerdir = arg;
         } else {
             LWARNING << "Warning: unknown flag: " << flag;
         }
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index 9a94d79..4d32bda 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -92,14 +92,6 @@
     return false;
 }
 
-bool fs_mgr_overlayfs_mount_fstab_entry(const std::string&, const std::string&) {
-    return false;
-}
-
-std::vector<std::string> fs_mgr_overlayfs_required_devices(Fstab*) {
-    return {};
-}
-
 bool fs_mgr_overlayfs_setup(const char*, const char*, bool* change, bool) {
     if (change) *change = false;
     return false;
@@ -1299,18 +1291,6 @@
     }
 }
 
-bool fs_mgr_overlayfs_mount_fstab_entry(const std::string& lowers,
-                                        const std::string& mount_point) {
-    if (fs_mgr_overlayfs_invalid()) return false;
-
-    std::string aux = "lowerdir=" + lowers + ",override_creds=off";
-    auto rc = mount("overlay", mount_point.c_str(), "overlay", MS_RDONLY | MS_NOATIME, aux.c_str());
-
-    if (rc == 0) return true;
-
-    return false;
-}
-
 bool fs_mgr_overlayfs_mount_all(Fstab* fstab) {
     auto ret = false;
     if (fs_mgr_overlayfs_invalid()) return ret;
diff --git a/fs_mgr/fs_mgr_vendor_overlay.cpp b/fs_mgr/fs_mgr_vendor_overlay.cpp
index 830f0dd..1372511 100644
--- a/fs_mgr/fs_mgr_vendor_overlay.cpp
+++ b/fs_mgr/fs_mgr_vendor_overlay.cpp
@@ -92,7 +92,7 @@
     }
     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,
+    auto ret = mount("overlay", vendor_mount_point.c_str(), "overlay", MS_RDONLY | MS_NOATIME,
                      options.c_str());
     if (ret) {
         PERROR << report << ret;
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index 22c02cc..4d3ecc9 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -131,3 +131,12 @@
 // Finds the dm_bow device on which this block device is stacked, or returns
 // empty string
 std::string fs_mgr_find_bow_device(const std::string& block_device);
+
+// Creates mount point if not already existed, and checks that mount point is a
+// canonical path that doesn't contain any symbolic link or /../.
+bool fs_mgr_create_canonical_mount_point(const std::string& mount_point);
+
+// Like fs_mgr_do_mount_one() but for overlayfs fstab entries.
+// Unlike fs_mgr_overlayfs, mount overlayfs without upperdir and workdir, so the
+// filesystem cannot be remount read-write.
+bool fs_mgr_mount_overlayfs_fstab_entry(const android::fs_mgr::FstabEntry& entry);
diff --git a/fs_mgr/include/fs_mgr_overlayfs.h b/fs_mgr/include/fs_mgr_overlayfs.h
index ac95ef5..6caab1f 100644
--- a/fs_mgr/include/fs_mgr_overlayfs.h
+++ b/fs_mgr/include/fs_mgr_overlayfs.h
@@ -27,8 +27,6 @@
 android::fs_mgr::Fstab fs_mgr_overlayfs_candidate_list(const android::fs_mgr::Fstab& fstab);
 
 bool fs_mgr_overlayfs_mount_all(android::fs_mgr::Fstab* fstab);
-bool fs_mgr_overlayfs_mount_fstab_entry (const std::string& lowers, const std::string& mount_point);
-std::vector<std::string> fs_mgr_overlayfs_required_devices(android::fs_mgr::Fstab* fstab);
 bool fs_mgr_overlayfs_setup(const char* backing = nullptr, const char* mount_point = nullptr,
                             bool* change = nullptr, bool force = true);
 bool fs_mgr_overlayfs_teardown(const char* mount_point = nullptr, bool* change = nullptr);
diff --git a/fs_mgr/tests/adb-remount-test.sh b/fs_mgr/tests/adb-remount-test.sh
index 242fa93..9542bc1 100755
--- a/fs_mgr/tests/adb-remount-test.sh
+++ b/fs_mgr/tests/adb-remount-test.sh
@@ -735,23 +735,46 @@
   fi
 }
 
+[ "USAGE: join_with <delimiter> <strings>
+
+Joins strings with delimiter" ]
+join_with() {
+  if [ "${#}" -lt 2 ]; then
+    echo
+    return
+  fi
+  local delimiter="${1}"
+  local result="${2}"
+  shift 2
+  for element in "${@}"; do
+    result+="${delimiter}${element}"
+  done
+  echo "${result}"
+}
+
 [ "USAGE: skip_administrative_mounts [data] < /proc/mounts
 
 Filters out all administrative (eg: sysfs) mounts uninteresting to the test" ]
 skip_administrative_mounts() {
+  local exclude_filesystems=(
+    "overlay" "tmpfs" "none" "sysfs" "proc" "selinuxfs" "debugfs" "bpf"
+    "binfmt_misc" "cg2_bpf" "pstore" "tracefs" "adb" "mtp" "ptp" "devpts"
+    "ramdumpfs" "binder" "securityfs" "functionfs" "rootfs"
+  )
+  local exclude_devices=(
+    "\/sys\/kernel\/debug" "\/data\/media" "\/dev\/block\/loop[0-9]*"
+    "${exclude_filesystems[@]}"
+  )
+  local exclude_mount_points=(
+    "\/cache" "\/mnt\/scratch" "\/mnt\/vendor\/persist" "\/persist"
+    "\/metadata"
+  )
   if [ "data" = "${1}" ]; then
-    grep -v " /data "
-  else
-    cat -
-  fi |
-  grep -v \
-    -e "^\(overlay\|tmpfs\|none\|sysfs\|proc\|selinuxfs\|debugfs\|bpf\) " \
-    -e "^\(binfmt_misc\|cg2_bpf\|pstore\|tracefs\|adb\|mtp\|ptp\|devpts\) " \
-    -e "^\(ramdumpfs\|binder\|/sys/kernel/debug\|securityfs\) " \
-    -e " functionfs " \
-    -e "^\(/data/media\|/dev/block/loop[0-9]*\) " \
-    -e "^rootfs / rootfs rw," \
-    -e " /\(cache\|mnt/scratch\|mnt/vendor/persist\|persist\|metadata\) "
+    exclude_mount_points+=("\/data")
+  fi
+  awk '$1 !~ /^('"$(join_with "|" "${exclude_devices[@]}")"')$/ &&
+      $2 !~ /^('"$(join_with "|" "${exclude_mount_points[@]}")"')$/ &&
+      $3 !~ /^('"$(join_with "|" "${exclude_filesystems[@]}")"')$/'
 }
 
 [ "USAGE: skip_unrelated_mounts < /proc/mounts
@@ -907,9 +930,11 @@
 
 # Acquire list of system partitions
 
+# KISS (assume system partition mount point is "/<partition name>")
 PARTITIONS=`adb_su cat /vendor/etc/fstab* </dev/null |
+              grep -v "^[#${SPACE}${TAB}]" |
               skip_administrative_mounts |
-              sed -n "s@^\([^ ${TAB}/][^ ${TAB}/]*\)[ ${TAB}].*[, ${TAB}]ro[, ${TAB}].*@\1@p" |
+              awk '$1 ~ /^[^\/]+$/ && "/"$1 == $2 && $4 ~ /(^|,)ro(,|$)/ { print $1 }' |
               sort -u |
               tr '\n' ' '`
 PARTITIONS="${PARTITIONS:-system vendor}"
diff --git a/init/Android.bp b/init/Android.bp
index 98e62fe..7eeafa2 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -387,6 +387,7 @@
 
     srcs: [
         "devices_test.cpp",
+        "epoll_test.cpp",
         "firmware_handler_test.cpp",
         "init_test.cpp",
         "keychords_test.cpp",
diff --git a/init/epoll.cpp b/init/epoll.cpp
index 17d63fa..74d8aac 100644
--- a/init/epoll.cpp
+++ b/init/epoll.cpp
@@ -38,11 +38,12 @@
     return {};
 }
 
-Result<void> Epoll::RegisterHandler(int fd, std::function<void()> handler, uint32_t events) {
+Result<void> Epoll::RegisterHandler(int fd, Handler handler, uint32_t events) {
     if (!events) {
         return Error() << "Must specify events";
     }
-    auto [it, inserted] = epoll_handlers_.emplace(fd, std::move(handler));
+    auto sp = std::make_shared<decltype(handler)>(std::move(handler));
+    auto [it, inserted] = epoll_handlers_.emplace(fd, std::move(sp));
     if (!inserted) {
         return Error() << "Cannot specify two epoll handlers for a given FD";
     }
@@ -69,7 +70,7 @@
     return {};
 }
 
-Result<std::vector<std::function<void()>*>> Epoll::Wait(
+Result<std::vector<std::shared_ptr<Epoll::Handler>>> Epoll::Wait(
         std::optional<std::chrono::milliseconds> timeout) {
     int timeout_ms = -1;
     if (timeout && timeout->count() < INT_MAX) {
@@ -81,9 +82,10 @@
     if (num_events == -1) {
         return ErrnoError() << "epoll_wait failed";
     }
-    std::vector<std::function<void()>*> pending_functions;
+    std::vector<std::shared_ptr<Handler>> pending_functions;
     for (int i = 0; i < num_events; ++i) {
-        pending_functions.emplace_back(reinterpret_cast<std::function<void()>*>(ev[i].data.ptr));
+        auto sp = *reinterpret_cast<std::shared_ptr<Handler>*>(ev[i].data.ptr);
+        pending_functions.emplace_back(std::move(sp));
     }
 
     return pending_functions;
diff --git a/init/epoll.h b/init/epoll.h
index c32a661..0df5289 100644
--- a/init/epoll.h
+++ b/init/epoll.h
@@ -22,6 +22,7 @@
 #include <chrono>
 #include <functional>
 #include <map>
+#include <memory>
 #include <optional>
 #include <vector>
 
@@ -36,15 +37,17 @@
   public:
     Epoll();
 
+    typedef std::function<void()> Handler;
+
     Result<void> Open();
-    Result<void> RegisterHandler(int fd, std::function<void()> handler, uint32_t events = EPOLLIN);
+    Result<void> RegisterHandler(int fd, Handler handler, uint32_t events = EPOLLIN);
     Result<void> UnregisterHandler(int fd);
-    Result<std::vector<std::function<void()>*>> Wait(
+    Result<std::vector<std::shared_ptr<Handler>>> Wait(
             std::optional<std::chrono::milliseconds> timeout);
 
   private:
     android::base::unique_fd epoll_fd_;
-    std::map<int, std::function<void()>> epoll_handlers_;
+    std::map<int, std::shared_ptr<Handler>> epoll_handlers_;
 };
 
 }  // namespace init
diff --git a/init/epoll_test.cpp b/init/epoll_test.cpp
new file mode 100644
index 0000000..9236cd5
--- /dev/null
+++ b/init/epoll_test.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2021 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 "epoll.h"
+
+#include <sys/unistd.h>
+
+#include <unordered_set>
+
+#include <android-base/file.h>
+#include <gtest/gtest.h>
+
+namespace android {
+namespace init {
+
+std::unordered_set<void*> sValidObjects;
+
+class CatchDtor final {
+  public:
+    CatchDtor() { sValidObjects.emplace(this); }
+    CatchDtor(const CatchDtor&) { sValidObjects.emplace(this); }
+    ~CatchDtor() {
+        auto iter = sValidObjects.find(this);
+        if (iter != sValidObjects.end()) {
+            sValidObjects.erase(iter);
+        }
+    }
+};
+
+TEST(epoll, UnregisterHandler) {
+    Epoll epoll;
+    ASSERT_RESULT_OK(epoll.Open());
+
+    int fds[2];
+    ASSERT_EQ(pipe(fds), 0);
+
+    CatchDtor catch_dtor;
+    bool handler_invoked;
+    auto handler = [&, catch_dtor]() -> void {
+        auto result = epoll.UnregisterHandler(fds[0]);
+        ASSERT_EQ(result.ok(), !handler_invoked);
+        handler_invoked = true;
+        ASSERT_NE(sValidObjects.find((void*)&catch_dtor), sValidObjects.end());
+    };
+
+    epoll.RegisterHandler(fds[0], std::move(handler));
+
+    uint8_t byte = 0xee;
+    ASSERT_TRUE(android::base::WriteFully(fds[1], &byte, sizeof(byte)));
+
+    auto results = epoll.Wait({});
+    ASSERT_RESULT_OK(results);
+    ASSERT_EQ(results->size(), size_t(1));
+
+    for (const auto& function : *results) {
+        (*function)();
+        (*function)();
+    }
+    ASSERT_TRUE(handler_invoked);
+}
+
+}  // namespace init
+}  // namespace android
diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp
index a733839..f5c10bb 100644
--- a/init/first_stage_mount.cpp
+++ b/init/first_stage_mount.cpp
@@ -331,12 +331,6 @@
     if (devices.empty()) {
         return true;
     }
-    // excluding overlays
-    for (auto iter = devices.begin(); iter != devices.end(); ) {
-        if (*iter=="overlay")  iter = devices.erase(iter);
-        else iter++;
-    }
-
     return block_dev_init_.InitDevices(std::move(devices));
 }
 
@@ -426,6 +420,10 @@
         *end = begin + 1;
     }
 
+    if (!fs_mgr_create_canonical_mount_point(begin->mount_point)) {
+        return false;
+    }
+
     if (begin->fs_mgr_flags.logical) {
         if (!fs_mgr_update_logical_partition(&(*begin))) {
             return false;
@@ -548,6 +546,7 @@
             continue;
         }
 
+        // Handle overlayfs entries later.
         if (current->fs_type == "overlay") {
             ++current;
             continue;
@@ -577,6 +576,12 @@
         current = end;
     }
 
+    for (const auto& entry : fstab_) {
+        if (entry.fs_type == "overlay") {
+            fs_mgr_mount_overlayfs_fstab_entry(entry);
+        }
+    }
+
     // If we don't see /system or / in the fstab, then we need to create an root entry for
     // overlayfs.
     if (!GetEntryForMountPoint(&fstab_, "/system") && !GetEntryForMountPoint(&fstab_, "/")) {
@@ -602,13 +607,6 @@
     };
     MapScratchPartitionIfNeeded(&fstab_, init_devices);
 
-    for (auto current = fstab_.begin(); current != fstab_.end(); ) {
-        if (current->fs_type == "overlay") {
-            fs_mgr_overlayfs_mount_fstab_entry(current->lowerdir, current->mount_point);
-        }
-        ++current;
-    }
-
     fs_mgr_overlayfs_mount_all(&fstab_);
 
     return true;
@@ -695,6 +693,10 @@
     // Includes the partition names of fstab records.
     // Notes that fstab_rec->blk_device has A/B suffix updated by fs_mgr when A/B is used.
     for (const auto& fstab_entry : fstab_) {
+        // Skip pseudo filesystems.
+        if (fstab_entry.fs_type == "overlay") {
+            continue;
+        }
         if (!fstab_entry.fs_mgr_flags.logical) {
             devices->emplace(basename(fstab_entry.blk_device.c_str()));
         }
@@ -757,6 +759,10 @@
         if (fstab_entry.fs_mgr_flags.avb) {
             need_dm_verity_ = true;
         }
+        // Skip pseudo filesystems.
+        if (fstab_entry.fs_type == "overlay") {
+            continue;
+        }
         if (fstab_entry.fs_mgr_flags.logical) {
             // Don't try to find logical partitions via uevent regeneration.
             logical_partitions.emplace(basename(fstab_entry.blk_device.c_str()));
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 1013d41..6e85da5 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -762,7 +762,7 @@
     # profile file layout
     mkdir /data/misc/profiles 0771 system system
     mkdir /data/misc/profiles/cur 0771 system system
-    mkdir /data/misc/profiles/ref 0770 system system
+    mkdir /data/misc/profiles/ref 0771 system system
     mkdir /data/misc/profman 0770 system shell
     mkdir /data/misc/gcov 0770 root root
     mkdir /data/misc/installd 0700 root root