Support metadata encryption

Bug: 29189559
Test: Angler, Marlin build and boot
Change-Id: Ia7b070781f5f16ff8bfd934569a2209c80c28385
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index e3d4f87..61c9cd7 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -721,6 +721,12 @@
     return false;
 }
 
+static bool should_use_metadata_encryption(const struct fstab_rec* rec) {
+    if (!(rec->fs_mgr_flags & (MF_FILEENCRYPTION | MF_FORCEFDEORFBE))) return false;
+    if (!(rec->fs_mgr_flags & MF_KEYDIRECTORY)) return false;
+    return true;
+}
+
 // Check to see if a mountable volume has encryption requirements
 static int handle_encryptable(const struct fstab_rec* rec)
 {
@@ -733,8 +739,14 @@
                      << " - allow continue unencrypted";
             return FS_MGR_MNTALL_DEV_NOT_ENCRYPTED;
         }
+    } else if (should_use_metadata_encryption(rec)) {
+        if (umount(rec->mount_point) == 0) {
+            return FS_MGR_MNTALL_DEV_NEEDS_METADATA_ENCRYPTION;
+        } else {
+            PERROR << "Could not umount " << rec->mount_point << " - fail since can't encrypt";
+            return FS_MGR_MNTALL_FAIL;
+        }
     } else if (rec->fs_mgr_flags & (MF_FILEENCRYPTION | MF_FORCEFDEORFBE)) {
-        // Deal with file level encryption
         LINFO << rec->mount_point << " is file encrypted";
         return FS_MGR_MNTALL_DEV_FILE_ENCRYPTED;
     } else if (fs_mgr_is_encryptable(rec)) {
@@ -900,7 +912,6 @@
             continue;
         }
 
-        /* mount(2) returned an error, handle the encryptable/formattable case */
         bool wiped = partition_wiped(fstab->recs[top_idx].blk_device);
         bool crypt_footer = false;
         if (mret && mount_errno != EBUSY && mount_errno != EACCES &&
@@ -940,6 +951,8 @@
                 continue;
             }
         }
+
+        /* mount(2) returned an error, handle the encryptable/formattable case */
         if (mret && mount_errno != EBUSY && mount_errno != EACCES &&
             fs_mgr_is_encryptable(&fstab->recs[attempted_idx])) {
             if (wiped) {
@@ -965,6 +978,9 @@
                 }
             }
             encryptable = FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED;
+        } else if (mret && mount_errno != EBUSY && mount_errno != EACCES &&
+                   should_use_metadata_encryption(&fstab->recs[attempted_idx])) {
+            encryptable = FS_MGR_MNTALL_DEV_IS_METADATA_ENCRYPTED;
         } else {
             if (fs_mgr_is_nofail(&fstab->recs[attempted_idx])) {
                 PERROR << "Ignoring failure to mount an un-encryptable or wiped partition on"
@@ -1256,48 +1272,46 @@
     return ret;
 }
 
-/*
- * key_loc must be at least PROPERTY_VALUE_MAX bytes long
- *
- * real_blk_device must be at least PROPERTY_VALUE_MAX bytes long
- */
-int fs_mgr_get_crypt_info(struct fstab *fstab, char *key_loc, char *real_blk_device, int size)
-{
-    int i = 0;
+struct fstab_rec const* fs_mgr_get_crypt_entry(struct fstab const* fstab) {
+    int i;
 
     if (!fstab) {
-        return -1;
-    }
-    /* Initialize return values to null strings */
-    if (key_loc) {
-        *key_loc = '\0';
-    }
-    if (real_blk_device) {
-        *real_blk_device = '\0';
+        return NULL;
     }
 
     /* Look for the encryptable partition to find the data */
     for (i = 0; i < fstab->num_entries; i++) {
         /* Don't deal with vold managed enryptable partitions here */
-        if (fstab->recs[i].fs_mgr_flags & MF_VOLDMANAGED) {
-            continue;
+        if (!(fstab->recs[i].fs_mgr_flags & MF_VOLDMANAGED) &&
+            (fstab->recs[i].fs_mgr_flags &
+             (MF_CRYPT | MF_FORCECRYPT | MF_FORCEFDEORFBE | MF_FILEENCRYPTION))) {
+            return &fstab->recs[i];
         }
-        if (!(fstab->recs[i].fs_mgr_flags
-              & (MF_CRYPT | MF_FORCECRYPT | MF_FORCEFDEORFBE))) {
-            continue;
-        }
-
-        /* We found a match */
-        if (key_loc) {
-            strlcpy(key_loc, fstab->recs[i].key_loc, size);
-        }
-        if (real_blk_device) {
-            strlcpy(real_blk_device, fstab->recs[i].blk_device, size);
-        }
-        break;
     }
+    return NULL;
+}
 
-    return 0;
+/*
+ * key_loc must be at least PROPERTY_VALUE_MAX bytes long
+ *
+ * real_blk_device must be at least PROPERTY_VALUE_MAX bytes long
+ */
+void fs_mgr_get_crypt_info(struct fstab* fstab, char* key_loc, char* real_blk_device, size_t size) {
+    struct fstab_rec const* rec = fs_mgr_get_crypt_entry(fstab);
+    if (key_loc) {
+        if (rec) {
+            strlcpy(key_loc, rec->key_loc, size);
+        } else {
+            *key_loc = '\0';
+        }
+    }
+    if (real_blk_device) {
+        if (rec) {
+            strlcpy(real_blk_device, rec->blk_device, size);
+        } else {
+            *real_blk_device = '\0';
+        }
+    }
 }
 
 bool fs_mgr_load_verity_state(int* mode) {
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index 0a694c1..e43eb7a 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -31,6 +31,7 @@
 
 struct fs_mgr_flag_values {
     char *key_loc;
+    char* key_dir;
     char *verity_loc;
     long long part_length;
     char *label;
@@ -70,34 +71,35 @@
 };
 
 static struct flag_list fs_mgr_flags[] = {
-    { "wait",               MF_WAIT },
-    { "check",              MF_CHECK },
-    { "encryptable=",       MF_CRYPT },
-    { "forceencrypt=",      MF_FORCECRYPT },
-    { "fileencryption=",    MF_FILEENCRYPTION },
-    { "forcefdeorfbe=",     MF_FORCEFDEORFBE },
-    { "nonremovable",       MF_NONREMOVABLE },
-    { "voldmanaged=",       MF_VOLDMANAGED},
-    { "length=",            MF_LENGTH },
-    { "recoveryonly",       MF_RECOVERYONLY },
-    { "swapprio=",          MF_SWAPPRIO },
-    { "zramsize=",          MF_ZRAMSIZE },
-    { "max_comp_streams=",  MF_MAX_COMP_STREAMS },
-    { "verifyatboot",       MF_VERIFYATBOOT },
-    { "verify",             MF_VERIFY },
-    { "avb",                MF_AVB },
-    { "noemulatedsd",       MF_NOEMULATEDSD },
-    { "notrim",             MF_NOTRIM },
-    { "formattable",        MF_FORMATTABLE },
-    { "slotselect",         MF_SLOTSELECT },
-    { "nofail",             MF_NOFAIL },
-    { "latemount",          MF_LATEMOUNT },
-    { "reservedsize=",      MF_RESERVEDSIZE },
-    { "quota",              MF_QUOTA },
-    { "eraseblk=",          MF_ERASEBLKSIZE },
-    { "logicalblk=",        MF_LOGICALBLKSIZE },
-    { "defaults",           0 },
-    { 0,                    0 },
+    {"wait", MF_WAIT},
+    {"check", MF_CHECK},
+    {"encryptable=", MF_CRYPT},
+    {"forceencrypt=", MF_FORCECRYPT},
+    {"fileencryption=", MF_FILEENCRYPTION},
+    {"forcefdeorfbe=", MF_FORCEFDEORFBE},
+    {"keydirectory=", MF_KEYDIRECTORY},
+    {"nonremovable", MF_NONREMOVABLE},
+    {"voldmanaged=", MF_VOLDMANAGED},
+    {"length=", MF_LENGTH},
+    {"recoveryonly", MF_RECOVERYONLY},
+    {"swapprio=", MF_SWAPPRIO},
+    {"zramsize=", MF_ZRAMSIZE},
+    {"max_comp_streams=", MF_MAX_COMP_STREAMS},
+    {"verifyatboot", MF_VERIFYATBOOT},
+    {"verify", MF_VERIFY},
+    {"avb", MF_AVB},
+    {"noemulatedsd", MF_NOEMULATEDSD},
+    {"notrim", MF_NOTRIM},
+    {"formattable", MF_FORMATTABLE},
+    {"slotselect", MF_SLOTSELECT},
+    {"nofail", MF_NOFAIL},
+    {"latemount", MF_LATEMOUNT},
+    {"reservedsize=", MF_RESERVEDSIZE},
+    {"quota", MF_QUOTA},
+    {"eraseblk=", MF_ERASEBLKSIZE},
+    {"logicalblk=", MF_LOGICALBLKSIZE},
+    {"defaults", 0},
+    {0, 0},
 };
 
 #define EM_AES_256_XTS  1
@@ -266,6 +268,11 @@
                     } else {
                         flag_vals->file_names_mode = EM_AES_256_CTS;
                     }
+                } else if ((fl[i].flag == MF_KEYDIRECTORY) && flag_vals) {
+                    /* The metadata flag is followed by an = and the
+                     * directory for the keys.  Get it and return it.
+                     */
+                    flag_vals->key_dir = strdup(strchr(p, '=') + 1);
                 } else if ((fl[i].flag == MF_LENGTH) && flag_vals) {
                     /* The length flag is followed by an = and the
                      * size of the partition.  Get it and return it.
@@ -557,6 +564,7 @@
         fstab->recs[cnt].fs_mgr_flags = parse_flags(p, fs_mgr_flags,
                                                     &flag_vals, NULL, 0);
         fstab->recs[cnt].key_loc = flag_vals.key_loc;
+        fstab->recs[cnt].key_dir = flag_vals.key_dir;
         fstab->recs[cnt].verity_loc = flag_vals.verity_loc;
         fstab->recs[cnt].length = flag_vals.part_length;
         fstab->recs[cnt].label = flag_vals.label;
@@ -716,6 +724,7 @@
         free(fstab->recs[i].fs_type);
         free(fstab->recs[i].fs_options);
         free(fstab->recs[i].key_loc);
+        free(fstab->recs[i].key_dir);
         free(fstab->recs[i].label);
     }
 
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index c985462..3ca507b 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -107,6 +107,7 @@
 #define MF_ERASEBLKSIZE     0x800000
 #define MF_LOGICALBLKSIZE  0X1000000
 #define MF_AVB             0X2000000
+#define MF_KEYDIRECTORY 0X4000000
 
 #define DM_BUF_SIZE 4096
 
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index fd63dfd..26ae48a 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -72,6 +72,7 @@
     char *fs_options;
     int fs_mgr_flags;
     char *key_loc;
+    char* key_dir;
     char *verity_loc;
     long long length;
     char *label;
@@ -95,6 +96,8 @@
 struct fstab *fs_mgr_read_fstab(const char *fstab_path);
 void fs_mgr_free_fstab(struct fstab *fstab);
 
+#define FS_MGR_MNTALL_DEV_IS_METADATA_ENCRYPTED 7
+#define FS_MGR_MNTALL_DEV_NEEDS_METADATA_ENCRYPTION 6
 #define FS_MGR_MNTALL_DEV_FILE_ENCRYPTED 5
 #define FS_MGR_MNTALL_DEV_NEEDS_RECOVERY 4
 #define FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION 3
@@ -112,8 +115,8 @@
 int fs_mgr_do_mount_one(struct fstab_rec *rec);
 int fs_mgr_do_tmpfs_mount(const char *n_name);
 int fs_mgr_unmount_all(struct fstab *fstab);
-int fs_mgr_get_crypt_info(struct fstab *fstab, char *key_loc,
-                          char *real_blk_device, int size);
+struct fstab_rec const* fs_mgr_get_crypt_entry(struct fstab const* fstab);
+void fs_mgr_get_crypt_info(struct fstab* fstab, char* key_loc, char* real_blk_device, size_t size);
 bool fs_mgr_load_verity_state(int* mode);
 bool fs_mgr_update_verity_state(fs_mgr_verity_state_callback callback);
 int fs_mgr_add_entry(struct fstab *fstab,
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 43eb420..f687b6c 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -481,6 +481,23 @@
         // Although encrypted, we have device key, so we do not need to
         // do anything different from the nonencrypted case.
         ActionManager::GetInstance().QueueEventTrigger("nonencrypted");
+    } else if (code == FS_MGR_MNTALL_DEV_IS_METADATA_ENCRYPTED) {
+        if (e4crypt_install_keyring()) {
+            return -1;
+        }
+        property_set("ro.crypto.state", "encrypted");
+        property_set("ro.crypto.type", "file");
+
+        // defaultcrypto detects file/block encryption. init flow is same for each.
+        ActionManager::GetInstance().QueueEventTrigger("defaultcrypto");
+    } else if (code == FS_MGR_MNTALL_DEV_NEEDS_METADATA_ENCRYPTION) {
+        if (e4crypt_install_keyring()) {
+            return -1;
+        }
+        property_set("ro.crypto.type", "file");
+
+        // encrypt detects file/block encryption. init flow is same for each.
+        ActionManager::GetInstance().QueueEventTrigger("encrypt");
     } else if (code > 0) {
         PLOG(ERROR) << "fs_mgr_mount_all returned unexpected error " << code;
     }