Merge tag 'android-security-10.0.0_r53' into int/10/fp2

Android security 10.0.0 release 53

* tag 'android-security-10.0.0_r53':
  minadbd sends heartbeat to rescue service for getprop command.
  Revert "libprocessgroup users use libcutils"

Change-Id: I45498e78a1ce0d8ac918cf81d241146444a060f0
diff --git a/Android.bp b/Android.bp
index f920782..f367e5e 100644
--- a/Android.bp
+++ b/Android.bp
@@ -69,6 +69,7 @@
     ],
 
     static_libs: [
+        "libc++fs",
         "libinstall",
         "librecovery_fastboot",
         "libminui",
@@ -94,6 +95,7 @@
     ],
 
     shared_libs: [
+        "libfusesideload",
         "librecovery_ui",
     ],
 }
diff --git a/install/include/install/install.h b/install/include/install/install.h
index c0a8f1f..ed0f6c7 100644
--- a/install/include/install/install.h
+++ b/install/include/install/install.h
@@ -69,3 +69,7 @@
 // Mandatory checks: ota-type, pre-device and serial number(if presents)
 // AB OTA specific checks: pre-build version, fingerprint, timestamp.
 int CheckPackageMetadata(const std::map<std::string, std::string>& metadata, OtaType ota_type);
+
+// Ensures the path to the update package is mounted. Also set the |should_use_fuse| to true if the
+// package stays on a removable media.
+bool SetupPackageMount(const std::string& package_path, bool* should_use_fuse);
diff --git a/install/install.cpp b/install/install.cpp
index e2d4700..9203ef0 100644
--- a/install/install.cpp
+++ b/install/install.cpp
@@ -30,6 +30,7 @@
 #include <atomic>
 #include <chrono>
 #include <condition_variable>
+#include <filesystem>
 #include <functional>
 #include <limits>
 #include <mutex>
@@ -736,3 +737,49 @@
   }
   return true;
 }
+
+bool SetupPackageMount(const std::string& package_path, bool* should_use_fuse) {
+  CHECK(should_use_fuse != nullptr);
+
+  if (package_path.empty()) {
+    return false;
+  }
+
+  *should_use_fuse = true;
+  if (package_path[0] == '@') {
+    auto block_map_path = package_path.substr(1);
+    if (ensure_path_mounted(block_map_path) != 0) {
+      LOG(ERROR) << "Failed to mount " << block_map_path;
+      return false;
+    }
+    // uncrypt only produces block map only if the package stays on /data.
+    *should_use_fuse = false;
+    return true;
+  }
+
+  // Package is not a block map file.
+  if (ensure_path_mounted(package_path) != 0) {
+    LOG(ERROR) << "Failed to mount " << package_path;
+    return false;
+  }
+
+  // Reject the package if the input path doesn't equal the canonicalized path.
+  // e.g. /cache/../sdcard/update_package.
+  std::error_code ec;
+  auto canonical_path = std::filesystem::canonical(package_path, ec);
+  if (ec) {
+    LOG(ERROR) << "Failed to get canonical of " << package_path << ", " << ec.message();
+    return false;
+  }
+  if (canonical_path.string() != package_path) {
+    LOG(ERROR) << "Installation aborts. The canonical path " << canonical_path.string()
+               << " doesn't equal the original path " << package_path;
+    return false;
+  }
+
+  constexpr const char* CACHE_ROOT = "/cache";
+  if (android::base::StartsWith(package_path, CACHE_ROOT)) {
+    *should_use_fuse = false;
+  }
+  return true;
+}
diff --git a/minadbd/minadbd_services.cpp b/minadbd/minadbd_services.cpp
index 6c10274..03341e4 100644
--- a/minadbd/minadbd_services.cpp
+++ b/minadbd/minadbd_services.cpp
@@ -25,10 +25,10 @@
 
 #include <functional>
 #include <memory>
+#include <set>
 #include <string>
 #include <string_view>
 #include <thread>
-#include <unordered_set>
 
 #include <android-base/file.h>
 #include <android-base/logging.h>
@@ -156,19 +156,36 @@
   }
 }
 
+// Answers the query on a given property |prop|, by writing the result to the given |sfd|. The
+// result will be newline-terminated, so nonexistent or nonallowed query will be answered with "\n".
+// If given an empty string, dumps all the supported properties (analogous to `adb shell getprop`)
+// in lines, e.g. "[prop]: [value]".
 static void RescueGetpropHostService(unique_fd sfd, const std::string& prop) {
-  static const std::unordered_set<std::string> kGetpropAllowedProps = {
-    "ro.build.fingerprint",
+  static const std::set<std::string> kGetpropAllowedProps = {
     "ro.build.date.utc",
+    "ro.build.fingerprint",
+    "ro.build.flavor",
+    "ro.build.id",
+    "ro.build.product",
+    "ro.build.tags",
+    "ro.build.version.incremental",
+    "ro.product.device",
+    "ro.product.vendor.device",
   };
-  auto allowed = kGetpropAllowedProps.find(prop) != kGetpropAllowedProps.end();
-  if (!allowed) {
-    return;
+  std::string result;
+  if (prop.empty()) {
+    for (const auto& key : kGetpropAllowedProps) {
+      auto value = android::base::GetProperty(key, "");
+      if (value.empty()) {
+        continue;
+      }
+      result += "[" + key + "]: [" + value + "]\n";
+    }
+  } else if (kGetpropAllowedProps.find(prop) != kGetpropAllowedProps.end()) {
+    result = android::base::GetProperty(prop, "") + "\n";
   }
-
-  auto result = android::base::GetProperty(prop, "");
   if (result.empty()) {
-    return;
+    result = "\n";
   }
   if (!android::base::WriteFully(sfd, result.data(), result.size())) {
     exit(kMinadbdHostSocketIOError);
diff --git a/recovery.cpp b/recovery.cpp
index 5fc673e..e51687a 100644
--- a/recovery.cpp
+++ b/recovery.cpp
@@ -50,6 +50,7 @@
 
 #include "common.h"
 #include "fsck_unshare_blocks.h"
+#include "fuse_sideload.h"
 #include "install/adb_install.h"
 #include "install/fuse_sdcard_install.h"
 #include "install/install.h"
@@ -881,7 +882,29 @@
         set_retry_bootloader_message(retry_count + 1, args);
       }
 
-      status = install_package(update_package, should_wipe_cache, true, retry_count, ui);
+      bool should_use_fuse = false;
+      if (!SetupPackageMount(update_package, &should_use_fuse)) {
+        LOG(INFO) << "Failed to set up the package access, skipping installation";
+        status = INSTALL_ERROR;
+      } else if (should_use_fuse) {
+        LOG(INFO) << "Installing package " << update_package << " with fuse";
+        auto file_data_reader = std::make_unique<FuseFileDataProvider>(update_package, 65536);
+        status = run_fuse_sideload(std::move(file_data_reader));
+      } else if (auto memory_package = Package::CreateMemoryPackage(
+                     update_package,
+                     std::bind(&RecoveryUI::SetProgress, ui, std::placeholders::_1));
+                 memory_package != nullptr) {
+        status = install_package(update_package, should_wipe_cache, true, retry_count, ui);
+      } else {
+        // We may fail to memory map the package on 32 bit builds for packages with 2GiB+ size.
+        // In such cases, we will try to install the package with fuse. This is not the default
+        // installation method because it introduces a layer of indirection from the kernel space.
+        LOG(WARNING) << "Failed to memory map package " << update_package
+                     << "; falling back to install with fuse";
+        auto file_data_reader = std::make_unique<FuseFileDataProvider>(update_package, 65536);
+        status = run_fuse_sideload(std::move(file_data_reader));
+      }
+
       if (status != INSTALL_SUCCESS) {
         ui->Print("Installation aborted.\n");
 
diff --git a/tests/Android.bp b/tests/Android.bp
index 09ef716..a0d82d5 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -99,6 +99,7 @@
     "liblp",
     "libvndksupport",
     "libtinyxml2",
+    "libc++fs",
 ]
 
 cc_test {
diff --git a/tests/component/install_test.cpp b/tests/component/install_test.cpp
index 3851329..c1f0ca8 100644
--- a/tests/component/install_test.cpp
+++ b/tests/component/install_test.cpp
@@ -34,6 +34,7 @@
 
 #include "install/install.h"
 #include "otautil/paths.h"
+#include "otautil/roots.h"
 #include "private/setup_commands.h"
 
 static void BuildZipArchive(const std::map<std::string, std::string>& file_map, int fd,
@@ -595,3 +596,30 @@
       "\n");
   test_check_package_metadata(metadata, OtaType::AB, 0);
 }
+
+TEST(InstallTest, SetupPackageMount_package_path) {
+  load_volume_table();
+  bool install_with_fuse;
+
+  // Setup should fail if the input path doesn't exist.
+  ASSERT_FALSE(SetupPackageMount("/does_not_exist", &install_with_fuse));
+
+  // Package should be installed with fuse if it's not in /cache.
+  TemporaryDir temp_dir;
+  TemporaryFile update_package(temp_dir.path);
+  ASSERT_TRUE(SetupPackageMount(update_package.path, &install_with_fuse));
+  ASSERT_TRUE(install_with_fuse);
+
+  // Setup should fail if the input path isn't canonicalized.
+  std::string uncanonical_package_path = android::base::Join(
+      std::vector<std::string>{
+          temp_dir.path,
+          "..",
+          android::base::Basename(temp_dir.path),
+          android::base::Basename(update_package.path),
+      },
+      '/');
+
+  ASSERT_EQ(0, access(uncanonical_package_path.c_str(), R_OK));
+  ASSERT_FALSE(SetupPackageMount(uncanonical_package_path, &install_with_fuse));
+}
diff --git a/tools/recovery_l10n/res/values-ar/strings.xml b/tools/recovery_l10n/res/values-ar/strings.xml
index 2af36d6..a9cd2d1 100644
--- a/tools/recovery_l10n/res/values-ar/strings.xml
+++ b/tools/recovery_l10n/res/values-ar/strings.xml
@@ -6,9 +6,9 @@
     <string name="recovery_no_command" msgid="4465476568623024327">"ليس هناك أي أمر"</string>
     <string name="recovery_error" msgid="5748178989622716736">"خطأ!"</string>
     <string name="recovery_installing_security" msgid="9184031299717114342">"جارٍ تثبيت تحديث الأمان"</string>
-    <string name="recovery_wipe_data_menu_header" msgid="550255032058254478">"‏يتعذَّر تحميل نظام Android، حيث قد تكون بياناتك تالفة. وإذا استمر ظهور هذه الرسالة، قد يتعيَّن عليك إجراء إعادة الضبط بحسب بيانات المصنع ومحو جميع بيانات المستخدم المُخزَّنة على هذا الجهاز."</string>
+    <string name="recovery_wipe_data_menu_header" msgid="550255032058254478">"‏يتعذَّر تحميل نظام Android، حيث قد تكون بياناتك تالفة. وإذا استمر ظهور هذه الرسالة، قد يتعيَّن عليك إجراء إعادة الضبط على الإعدادات الأصلية ومحو جميع بيانات المستخدم المُخزَّنة على هذا الجهاز."</string>
     <string name="recovery_try_again" msgid="7168248750158873496">"إعادة المحاولة"</string>
-    <string name="recovery_factory_data_reset" msgid="7321351565602894783">"إعادة الضبط بحسب بيانات المصنع"</string>
+    <string name="recovery_factory_data_reset" msgid="7321351565602894783">"إعادة الضبط على الإعدادات الأصلية"</string>
     <string name="recovery_wipe_data_confirmation" msgid="5439823343348043954">"هل تريد حجب كل بيانات المستخدم؟\n\n لا يمكن التراجع عن هذا الإجراء."</string>
     <string name="recovery_cancel_wipe_data" msgid="66987687653647384">"إلغاء"</string>
 </resources>
diff --git a/tools/recovery_l10n/res/values-hy/strings.xml b/tools/recovery_l10n/res/values-hy/strings.xml
index 35a0ab1..76c28a7 100644
--- a/tools/recovery_l10n/res/values-hy/strings.xml
+++ b/tools/recovery_l10n/res/values-hy/strings.xml
@@ -9,6 +9,6 @@
     <string name="recovery_wipe_data_menu_header" msgid="550255032058254478">"Չհաջողվեց բեռնել Android համակարգը։ Հնարավոր է՝ ձեր տվյալները վնասված են։ Եթե նորից տեսնեք այս հաղորդագրությունը, փորձեք վերակայել սարքի կարգավորումները և ջնջել օգտատիրոջ բոլոր տվյալները։"</string>
     <string name="recovery_try_again" msgid="7168248750158873496">"Նորից փորձել"</string>
     <string name="recovery_factory_data_reset" msgid="7321351565602894783">"Վերակայել բոլոր տվյալները"</string>
-    <string name="recovery_wipe_data_confirmation" msgid="5439823343348043954">"Մաքրե՞լ օգտատիրոջ բոլոր տվյալները։\n\n ԱՅՍ ԳՈՐԾՈՂՈՒԹՅՈՒՆԸ ՀՆԱՐԱՎՈՐ ՉԻ ԼԻՆԻ ՀԵՏԱՐԿԵԼ"</string>
+    <string name="recovery_wipe_data_confirmation" msgid="5439823343348043954">"Ջնջե՞լ օգտատիրոջ բոլոր տվյալները։\n\n ԱՅՍ ԳՈՐԾՈՂՈՒԹՅՈՒՆԸ ՀՆԱՐԱՎՈՐ ՉԻ ԼԻՆԻ ՀԵՏԱՐԿԵԼ"</string>
     <string name="recovery_cancel_wipe_data" msgid="66987687653647384">"Չեղարկել"</string>
 </resources>
diff --git a/tools/recovery_l10n/res/values-ky/strings.xml b/tools/recovery_l10n/res/values-ky/strings.xml
index 1cd69ea..837cf7d 100644
--- a/tools/recovery_l10n/res/values-ky/strings.xml
+++ b/tools/recovery_l10n/res/values-ky/strings.xml
@@ -6,7 +6,7 @@
     <string name="recovery_no_command" msgid="4465476568623024327">"Буйрук берилген жок"</string>
     <string name="recovery_error" msgid="5748178989622716736">"Ката!"</string>
     <string name="recovery_installing_security" msgid="9184031299717114342">"Коопсуздук жаңыртуусу орнотулууда"</string>
-    <string name="recovery_wipe_data_menu_header" msgid="550255032058254478">"Android тутуму жүктөлбөй жатат. Дайындарыңыз бузук болушу мүмкүн. Бул билдирүү дагы деле келе берсе, түзмөктү кайра башынан жөндөп, анда сакталган бардык колдонуучу дайындарын тазалашыңыз керек."</string>
+    <string name="recovery_wipe_data_menu_header" msgid="550255032058254478">"Android тутуму жүктөлбөй жатат. Дайын-даректериңиз бузук болушу мүмкүн. Бул билдирүү дагы деле келе берсе, түзмөктү кайра башынан жөндөп, анда сакталган бардык колдонуучу дайындарын тазалашыңыз керек."</string>
     <string name="recovery_try_again" msgid="7168248750158873496">"Кайталоо"</string>
     <string name="recovery_factory_data_reset" msgid="7321351565602894783">"Кайра башынан жөндөө"</string>
     <string name="recovery_wipe_data_confirmation" msgid="5439823343348043954">"Колдонуучу дайындарынын баары жашырылсынбы?\n\n МУНУ АРТКА КАЙТАРУУ МҮМКҮН ЭМЕС!"</string>