fs_mgr: set ext4 fsverity feature bit

It supports a new feature "fsverity" for ext4 file-system. When someone
adds a mount option "fsverity" to fstab file, fsmgr will use tune2fs to
enable fsverity feature if kernel support.

Bug: 117437571
Test: bootable for phone projects
Change-Id: Icf35715a2f71c430468daaafcde497f8cfe9a18d
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 70a1045..ded3678 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -81,6 +81,8 @@
 #define ZRAM_CONF_MCS   "/sys/block/zram0/max_comp_streams"
 #define ZRAM_BACK_DEV   "/sys/block/zram0/backing_dev"
 
+#define SYSFS_EXT4_VERITY "/sys/fs/ext4/features/verity"
+
 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
 
 using android::base::Realpath;
@@ -110,6 +112,7 @@
     FS_STAT_TOGGLE_QUOTAS_FAILED = 0x10000,
     FS_STAT_SET_RESERVED_BLOCKS_FAILED = 0x20000,
     FS_STAT_ENABLE_ENCRYPTION_FAILED = 0x40000,
+    FS_STAT_ENABLE_VERITY_FAILED = 0x80000,
 };
 
 // TODO: switch to inotify()
@@ -440,6 +443,43 @@
     }
 }
 
+// Enable fs-verity if needed.
+static void tune_verity(const std::string& blk_device, const FstabEntry& entry,
+                        const struct ext4_super_block* sb, int* fs_stat) {
+    bool has_verity = (sb->s_feature_ro_compat & cpu_to_le32(EXT4_FEATURE_RO_COMPAT_VERITY)) != 0;
+    bool want_verity = entry.fs_mgr_flags.fs_verity;
+
+    if (has_verity || !want_verity) {
+        return;
+    }
+
+    std::string verity_support;
+    if (!android::base::ReadFileToString(SYSFS_EXT4_VERITY, &verity_support)) {
+        LERROR << "Failed to open " << SYSFS_EXT4_VERITY;
+        return;
+    }
+
+    if (!(android::base::Trim(verity_support) == "supported")) {
+        LERROR << "Current ext4 verity not supported by kernel";
+        return;
+    }
+
+    if (!tune2fs_available()) {
+        LERROR << "Unable to enable ext4 verity on " << blk_device
+               << " because " TUNE2FS_BIN " is missing";
+        return;
+    }
+
+    LINFO << "Enabling ext4 verity on " << blk_device;
+
+    const char* argv[] = {TUNE2FS_BIN, "-O", "verity", blk_device.c_str()};
+    if (!run_tune2fs(argv, ARRAY_SIZE(argv))) {
+        LERROR << "Failed to run " TUNE2FS_BIN " to enable "
+               << "ext4 verity on " << blk_device;
+        *fs_stat |= FS_STAT_ENABLE_VERITY_FAILED;
+    }
+}
+
 // Read the primary superblock from an f2fs filesystem.  On failure return
 // false.  If it's not an f2fs filesystem, also set FS_STAT_INVALID_MAGIC.
 #define F2FS_BLKSIZE 4096
@@ -511,12 +551,14 @@
     }
 
     if (is_extfs(entry.fs_type) &&
-        (entry.fs_mgr_flags.reserved_size || entry.fs_mgr_flags.file_encryption)) {
+        (entry.fs_mgr_flags.reserved_size || entry.fs_mgr_flags.file_encryption ||
+         entry.fs_mgr_flags.fs_verity)) {
         struct ext4_super_block sb;
 
         if (read_ext4_superblock(blk_device, &sb, &fs_stat)) {
             tune_reserved_size(blk_device, entry, &sb, &fs_stat);
             tune_encrypt(blk_device, entry, &sb, &fs_stat);
+            tune_verity(blk_device, entry, &sb, &fs_stat);
         }
     }
 
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index c9f34a7..9d4f280 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -125,6 +125,7 @@
         {"zram_loopback_path=", MF_ZRAM_LOOPBACK_PATH},
         {"zram_loopback_size=", MF_ZRAM_LOOPBACK_SIZE},
         {"zram_backing_dev_path=", MF_ZRAM_BACKING_DEV_PATH},
+        {"fsverity", MF_FS_VERITY},
         {0, 0},
 };
 
@@ -1087,6 +1088,10 @@
     return fstab->fs_mgr_flags & MF_CHECKPOINT_BLK;
 }
 
+int fs_mgr_is_fs_verity(const struct fstab_rec* fstab) {
+    return fstab->fs_mgr_flags & MF_FS_VERITY;
+}
+
 FstabEntry BuildGsiSystemFstabEntry() {
     FstabEntry system = {
             .blk_device = "system_gsi",
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index 39ceff7..3b9ddee 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -128,6 +128,8 @@
                          0x400000000
 #define MF_ZRAM_BACKING_DEV_PATH \
                          0x800000000
+#define MF_FS_VERITY  \
+                         0x1000000000
 // clang-format on
 
 #define DM_BUF_SIZE 4096
diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h
index d6bd46f..4a05949 100644
--- a/fs_mgr/include_fstab/fstab/fstab.h
+++ b/fs_mgr/include_fstab/fstab/fstab.h
@@ -95,6 +95,7 @@
 int fs_mgr_is_checkpoint_fs(const struct fstab_rec* fstab);
 int fs_mgr_is_checkpoint_blk(const struct fstab_rec* fstab);
 int fs_mgr_has_sysfs_path(const struct fstab_rec* fstab);
+int fs_mgr_is_fs_verity(const struct fstab_rec* fstab);
 
 std::string fs_mgr_get_slot_suffix();
 std::set<std::string> fs_mgr_get_boot_devices();
@@ -177,6 +178,7 @@
             bool zram_loopback_path : 1;
             bool zram_loopback_size : 1;
             bool zram_backing_dev_path : 1;
+            bool fs_verity : 1;
         };
     } fs_mgr_flags;