Merge "Rename fscrypt_is_native() to IsFbeEnabled()"
diff --git a/debuggerd/handler/debuggerd_handler.cpp b/debuggerd/handler/debuggerd_handler.cpp
index 35be2bf..92e7675 100644
--- a/debuggerd/handler/debuggerd_handler.cpp
+++ b/debuggerd/handler/debuggerd_handler.cpp
@@ -38,6 +38,8 @@
 #include <unistd.h>
 
 #include <android-base/macros.h>
+#include <android-base/parsebool.h>
+#include <android-base/properties.h>
 #include <android-base/unique_fd.h>
 #include <async_safe/log.h>
 #include <bionic/reserved_signals.h>
@@ -49,7 +51,10 @@
 
 #include "handler/fallback.h"
 
-using android::base::Pipe;
+using ::android::base::GetBoolProperty;
+using ::android::base::ParseBool;
+using ::android::base::ParseBoolResult;
+using ::android::base::Pipe;
 
 // We muck with our fds in a 'thread' that doesn't share the same fd table.
 // Close fds in that thread with a raw close syscall instead of going through libc.
@@ -82,6 +87,13 @@
   return syscall(__NR_gettid);
 }
 
+static bool is_permissive_mte() {
+  // Environment variable for testing or local use from shell.
+  char* permissive_env = getenv("MTE_PERMISSIVE");
+  return GetBoolProperty("persist.sys.mte.permissive", false) ||
+         (permissive_env && ParseBool(permissive_env) == ParseBoolResult::kTrue);
+}
+
 static inline void futex_wait(volatile void* ftx, int value) {
   syscall(__NR_futex, ftx, FUTEX_WAIT, value, nullptr, nullptr, 0);
 }
@@ -592,7 +604,28 @@
     // If the signal is fatal, don't unlock the mutex to prevent other crashing threads from
     // starting to dump right before our death.
     pthread_mutex_unlock(&crash_mutex);
-  } else {
+  }
+#ifdef __aarch64__
+  else if (info->si_signo == SIGSEGV &&
+           (info->si_code == SEGV_MTESERR || info->si_code == SEGV_MTEAERR) &&
+           is_permissive_mte()) {
+    // If we are in permissive MTE mode, we do not crash, but instead disable MTE on this thread,
+    // and then let the failing instruction be retried. The second time should work (except
+    // if there is another non-MTE fault).
+    int tagged_addr_ctrl = prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0);
+    if (tagged_addr_ctrl < 0) {
+      fatal_errno("failed to PR_GET_TAGGED_ADDR_CTRL");
+    }
+    tagged_addr_ctrl = (tagged_addr_ctrl & ~PR_MTE_TCF_MASK) | PR_MTE_TCF_NONE;
+    if (prctl(PR_SET_TAGGED_ADDR_CTRL, tagged_addr_ctrl, 0, 0, 0) < 0) {
+      fatal_errno("failed to PR_SET_TAGGED_ADDR_CTRL");
+    }
+    async_safe_format_log(ANDROID_LOG_ERROR, "libc",
+                          "MTE ERROR DETECTED BUT RUNNING IN PERMISSIVE MODE. CONTINUING.");
+    pthread_mutex_unlock(&crash_mutex);
+  }
+#endif
+  else {
     // Resend the signal, so that either the debugger or the parent's waitpid sees it.
     resend_signal(info);
   }
diff --git a/debuggerd/test_permissive_mte/Android.bp b/debuggerd/test_permissive_mte/Android.bp
new file mode 100644
index 0000000..1c09240
--- /dev/null
+++ b/debuggerd/test_permissive_mte/Android.bp
@@ -0,0 +1,38 @@
+// Copyright (C) 2022 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.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_binary {
+  name: "mte_crash",
+  srcs: ["mte_crash.cpp"],
+  sanitize: {
+    memtag_heap: true,
+    diag: {
+      memtag_heap: true,
+    },
+  },
+}
+
+java_test_host {
+    name: "permissive_mte_test",
+    libs: ["tradefed"],
+    static_libs: ["frameworks-base-hostutils", "cts-install-lib-host"],
+    srcs:  ["src/**/PermissiveMteTest.java", ":libtombstone_proto-src"],
+    data: [":mte_crash"],
+    test_config: "AndroidTest.xml",
+    test_suites: ["general-tests"],
+}
diff --git a/debuggerd/test_permissive_mte/AndroidTest.xml b/debuggerd/test_permissive_mte/AndroidTest.xml
new file mode 100644
index 0000000..bd3d018
--- /dev/null
+++ b/debuggerd/test_permissive_mte/AndroidTest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 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.
+-->
+<configuration description="Runs the permissive MTE tests">
+    <option name="test-suite-tag" value="init_test_upgrade_mte" />
+    <option name="test-suite-tag" value="apct" />
+
+    <!-- For tombstone inspection. -->
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+      <option name="cleanup" value="true" />
+      <option name="push" value="mte_crash->/data/local/tmp/mte_crash" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.HostTest" >
+        <option name="jar" value="permissive_mte_test.jar" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/debuggerd/test_permissive_mte/mte_crash.cpp b/debuggerd/test_permissive_mte/mte_crash.cpp
new file mode 100644
index 0000000..97ad73f
--- /dev/null
+++ b/debuggerd/test_permissive_mte/mte_crash.cpp
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2022 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 <stdio.h>
+#include <stdlib.h>
+
+int main(int, char**) {
+  volatile char* f = (char*)malloc(1);
+  printf("%c\n", f[17]);
+  return 0;
+}
diff --git a/debuggerd/test_permissive_mte/src/com/android/tests/debuggerd/PermissiveMteTest.java b/debuggerd/test_permissive_mte/src/com/android/tests/debuggerd/PermissiveMteTest.java
new file mode 100644
index 0000000..5ff2b5b
--- /dev/null
+++ b/debuggerd/test_permissive_mte/src/com/android/tests/debuggerd/PermissiveMteTest.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+package com.android.tests.init;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assume.assumeTrue;
+
+import com.android.server.os.TombstoneProtos.Tombstone;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+import com.android.tradefed.util.CommandResult;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.util.Arrays;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class PermissiveMteTest extends BaseHostJUnit4Test {
+  String mUUID;
+
+  @Before
+  public void setUp() throws Exception {
+    mUUID = java.util.UUID.randomUUID().toString();
+    CommandResult result =
+        getDevice().executeShellV2Command("/data/local/tmp/mte_crash setUp " + mUUID);
+    assumeTrue("mte_crash needs to segfault", result.getExitCode() == 139);
+  }
+
+  Tombstone parseTombstone(String tombstonePath) throws Exception {
+    File tombstoneFile = getDevice().pullFile(tombstonePath);
+    InputStream istr = new FileInputStream(tombstoneFile);
+    Tombstone tombstoneProto;
+    try {
+      tombstoneProto = Tombstone.parseFrom(istr);
+    } finally {
+      istr.close();
+    }
+    return tombstoneProto;
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    String[] tombstones = getDevice().getChildren("/data/tombstones");
+    for (String tombstone : tombstones) {
+      if (!tombstone.endsWith(".pb")) {
+        continue;
+      }
+      String tombstonePath = "/data/tombstones/" + tombstone;
+      Tombstone tombstoneProto = parseTombstone(tombstonePath);
+      if (!tombstoneProto.getCommandLineList().stream().anyMatch(x -> x.contains(mUUID))) {
+        continue;
+      }
+      getDevice().deleteFile(tombstonePath);
+      // remove the non .pb file as well.
+      getDevice().deleteFile(tombstonePath.substring(0, tombstonePath.length() - 3));
+    }
+  }
+
+  @Test
+  public void testCrash() throws Exception {
+    CommandResult result = getDevice().executeShellV2Command(
+        "MTE_PERMISSIVE=1 /data/local/tmp/mte_crash testCrash " + mUUID);
+    assertThat(result.getExitCode()).isEqualTo(0);
+    int numberTombstones = 0;
+    String[] tombstones = getDevice().getChildren("/data/tombstones");
+    for (String tombstone : tombstones) {
+      if (!tombstone.endsWith(".pb")) {
+        continue;
+      }
+      String tombstonePath = "/data/tombstones/" + tombstone;
+      Tombstone tombstoneProto = parseTombstone(tombstonePath);
+      if (!tombstoneProto.getCommandLineList().stream().anyMatch(x -> x.contains(mUUID))) {
+        continue;
+      }
+      if (!tombstoneProto.getCommandLineList().stream().anyMatch(x -> x.contains("testCrash"))) {
+        continue;
+      }
+      numberTombstones++;
+    }
+    assertThat(numberTombstones).isEqualTo(1);
+  }
+}
diff --git a/fastboot/vendor_boot_img_utils.cpp b/fastboot/vendor_boot_img_utils.cpp
index 9e09abb..9f05253 100644
--- a/fastboot/vendor_boot_img_utils.cpp
+++ b/fastboot/vendor_boot_img_utils.cpp
@@ -152,6 +152,9 @@
     if (memcmp(hdr->magic, VENDOR_BOOT_MAGIC, VENDOR_BOOT_MAGIC_SIZE) != 0) {
         return Errorf("Vendor boot image magic mismatch");
     }
+    if (hdr->page_size == 0) {
+        return Errorf("Page size cannot be zero");
+    }
     if (hdr->header_version < version) {
         return Errorf("Require vendor boot header V{} but is V{}", version, hdr->header_version);
     }
@@ -199,6 +202,7 @@
 }
 
 // round |value| up to a multiple of |page_size|.
+// aware that this can be integer overflow if value is too large
 inline uint32_t round_up(uint32_t value, uint32_t page_size) {
     return (value + page_size - 1) / page_size * page_size;
 }
@@ -311,7 +315,13 @@
     const uint32_t r = round_up(hdr->vendor_ramdisk_table_size, hdr->page_size);
     const uint32_t s = round_up(hdr->bootconfig_size, hdr->page_size);
 
-    if (hdr->vendor_ramdisk_table_entry_num == std::numeric_limits<uint32_t>::max()) {
+    uint64_t total_size = (uint64_t)o + p + q + r + s;
+    if (total_size > vendor_boot.size()) {
+        return Errorf("Vendor boot image size is too small, overflow");
+    }
+
+    if ((uint64_t)hdr->vendor_ramdisk_table_entry_num * sizeof(vendor_ramdisk_table_entry_v4) >
+        (uint64_t)o + p + q + r) {
         return Errorf("Too many vendor ramdisk entries in table, overflow");
     }
 
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index e6db491..c8684a2 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -3273,8 +3273,21 @@
                 snapuserd_client_ = nullptr;
             }
         } else {
-            status.set_userspace_snapshots(!IsDmSnapshotTestingEnabled());
-            if (IsDmSnapshotTestingEnabled()) {
+            bool userSnapshotsEnabled = true;
+            const std::string UNKNOWN = "unknown";
+            const std::string vendor_release = android::base::GetProperty(
+                    "ro.vendor.build.version.release_or_codename", UNKNOWN);
+
+            // No user-space snapshots if vendor partition is on Android 12
+            if (vendor_release.find("12") != std::string::npos) {
+                LOG(INFO) << "Userspace snapshots disabled as vendor partition is on Android: "
+                          << vendor_release;
+                userSnapshotsEnabled = false;
+            }
+
+            userSnapshotsEnabled = (userSnapshotsEnabled && !IsDmSnapshotTestingEnabled());
+            status.set_userspace_snapshots(userSnapshotsEnabled);
+            if (!userSnapshotsEnabled) {
                 is_snapshot_userspace_ = false;
                 LOG(INFO) << "User-space snapshots disabled for testing";
             } else {
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index 36abf71..6a348b4 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -91,7 +91,7 @@
 
 void MountMetadata();
 bool ShouldUseCompression();
-bool ShouldUseUserspaceSnapshots();
+bool IsDaemonRequired();
 
 class SnapshotTest : public ::testing::Test {
   public:
@@ -1208,7 +1208,7 @@
 
     // Initiate the merge and wait for it to be completed.
     ASSERT_TRUE(init->InitiateMerge());
-    ASSERT_EQ(init->IsSnapuserdRequired(), ShouldUseUserspaceSnapshots());
+    ASSERT_EQ(init->IsSnapuserdRequired(), IsDaemonRequired());
     {
         // We should have started in SECOND_PHASE since nothing shrinks.
         ASSERT_TRUE(AcquireLock());
@@ -1342,7 +1342,7 @@
 
     // Initiate the merge and wait for it to be completed.
     ASSERT_TRUE(init->InitiateMerge());
-    ASSERT_EQ(init->IsSnapuserdRequired(), ShouldUseUserspaceSnapshots());
+    ASSERT_EQ(init->IsSnapuserdRequired(), IsDaemonRequired());
     {
         // Check that the merge phase is FIRST_PHASE until at least one call
         // to ProcessUpdateState() occurs.
@@ -1450,7 +1450,7 @@
 
     // Initiate the merge and wait for it to be completed.
     ASSERT_TRUE(init->InitiateMerge());
-    ASSERT_EQ(init->IsSnapuserdRequired(), ShouldUseUserspaceSnapshots());
+    ASSERT_EQ(init->IsSnapuserdRequired(), IsDaemonRequired());
     {
         // Check that the merge phase is FIRST_PHASE until at least one call
         // to ProcessUpdateState() occurs.
@@ -2750,13 +2750,26 @@
     }
 }
 
-bool ShouldUseUserspaceSnapshots() {
+bool IsDaemonRequired() {
     if (FLAGS_force_config == "dmsnap") {
         return false;
     }
+
+    const std::string UNKNOWN = "unknown";
+    const std::string vendor_release =
+            android::base::GetProperty("ro.vendor.build.version.release_or_codename", UNKNOWN);
+
+    // No userspace snapshots if vendor partition is on Android 12
+    // However, for GRF devices, snapuserd daemon will be on
+    // vendor ramdisk in Android 12.
+    if (vendor_release.find("12") != std::string::npos) {
+        return true;
+    }
+
     if (!FLAGS_force_config.empty()) {
         return true;
     }
+
     return IsUserspaceSnapshotsEnabled();
 }
 
diff --git a/fs_mgr/tests/Android.bp b/fs_mgr/tests/Android.bp
index d82d566..fdc0d8e 100644
--- a/fs_mgr/tests/Android.bp
+++ b/fs_mgr/tests/Android.bp
@@ -52,9 +52,9 @@
     ],
 }
 
-cc_prebuilt_binary {
+sh_binary_host {
     name: "adb-remount-test.sh",
-    srcs: ["adb-remount-test.sh"],
+    src: "adb-remount-test.sh",
     target: {
         darwin: {
             enabled: false,
@@ -62,11 +62,7 @@
         windows: {
             enabled: false,
         },
-        android: {
-            enabled: false,
-        },
     },
-    host_supported: true,
 }
 
 sh_test {
diff --git a/init/TEST_MAPPING b/init/TEST_MAPPING
index fa1627c..36ca379 100644
--- a/init/TEST_MAPPING
+++ b/init/TEST_MAPPING
@@ -10,7 +10,7 @@
       "name": "MicrodroidHostTestCases"
     }
   ],
-  "hwasan-postsubmit": [
+  "hwasan-presubmit": [
     {
       "name": "CtsInitTestCases"
     },
diff --git a/init/devices.cpp b/init/devices.cpp
index d4a3cb9..28406f6 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -307,8 +307,8 @@
         PLOG(ERROR) << "setegid(" << gid << ") for " << path << " device failed";
         goto out;
     }
-    /* If the node already exists update its SELinux label to handle cases when
-     * it was created with the wrong context during coldboot procedure. */
+    /* If the node already exists update its SELinux label and the file mode to handle cases when
+     * it was created with the wrong context and file mode during coldboot procedure. */
     if (mknod(path.c_str(), mode, dev) && (errno == EEXIST) && !secontext.empty()) {
         char* fcon = nullptr;
         int rc = lgetfilecon(path.c_str(), &fcon);
@@ -330,6 +330,11 @@
             if (gid != s.st_gid) {
                 new_group = gid;
             }
+        if (mode != s.st_mode) {
+            if (chmod(path.c_str(), mode) != 0) {
+                PLOG(ERROR) << "Cannot chmod " << path << " to " << mode;
+            }
+        }
         } else {
             PLOG(ERROR) << "Cannot stat " << path;
         }
diff --git a/libcutils/TEST_MAPPING b/libcutils/TEST_MAPPING
index cca7d93..6477502 100644
--- a/libcutils/TEST_MAPPING
+++ b/libcutils/TEST_MAPPING
@@ -4,7 +4,7 @@
       "name": "libcutils_test"
     }
   ],
-  "hwasan-postsubmit": [
+  "hwasan-presubmit": [
     {
       "name": "libcutils_test"
     }
diff --git a/libpackagelistparser/TEST_MAPPING b/libpackagelistparser/TEST_MAPPING
index d69a7fb..f4a7761 100644
--- a/libpackagelistparser/TEST_MAPPING
+++ b/libpackagelistparser/TEST_MAPPING
@@ -4,7 +4,7 @@
       "name": "libpackagelistparser_test"
     }
   ],
-  "hwasan-postsubmit": [
+  "hwasan-presubmit": [
     {
       "name": "libpackagelistparser_test"
     }
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 70a3736..29b8365 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -1170,6 +1170,7 @@
     chown system system /sys/kernel/ipv4/tcp_rmem_def
     chown system system /sys/kernel/ipv4/tcp_rmem_max
     chown root radio /proc/cmdline
+    chown root system /proc/bootconfig
 
     # Define default initial receive window size in segments.
     setprop net.tcp_def_init_rwnd 60