When encryption fails, reboot into recovery

Set flag on starting encryption to say it failed, and only clear
when we get into a recoverable state (partially or fully encrypted.)

Go to recovery on seeing this flag on boot

Bug: 16552363
Change-Id: I7e452b653edf3a087ecfaba8f81f41765a1c8daf
diff --git a/cryptfs.c b/cryptfs.c
index d11c133..252be0a 100644
--- a/cryptfs.c
+++ b/cryptfs.c
@@ -1524,7 +1524,8 @@
     }
   }
 
-  if (crypt_ftr.flags & CRYPT_ENCRYPTION_IN_PROGRESS) {
+  if (crypt_ftr.flags
+      & (CRYPT_ENCRYPTION_IN_PROGRESS | CRYPT_INCONSISTENT_STATE)) {
     SLOGE("Encryption process didn't finish successfully\n");
     return -2;  /* -2 is the clue to the UI that there is no usable data on the disk,
                  * and give the user an option to wipe the disk */
@@ -2412,6 +2413,15 @@
           && (crypt_ftr.flags & CRYPT_ENCRYPTION_IN_PROGRESS)) {
         previously_encrypted_upto = crypt_ftr.encrypted_upto;
         crypt_ftr.encrypted_upto = 0;
+        crypt_ftr.flags &= ~CRYPT_ENCRYPTION_IN_PROGRESS;
+
+        /* At this point, we are in an inconsistent state. Until we successfully
+           complete encryption, a reboot will leave us broken. So mark the
+           encryption failed in case that happens.
+           On successfully completing encryption, remove this flag */
+        crypt_ftr.flags |= CRYPT_INCONSISTENT_STATE;
+
+        put_crypt_ftr_and_key(&crypt_ftr);
     }
 
     property_get("ro.crypto.state", encrypted_state, "");
@@ -2561,7 +2571,11 @@
         } else {
             crypt_ftr.fs_size = nr_sec;
         }
-        crypt_ftr.flags |= CRYPT_ENCRYPTION_IN_PROGRESS;
+        /* At this point, we are in an inconsistent state. Until we successfully
+           complete encryption, a reboot will leave us broken. So mark the
+           encryption failed in case that happens.
+           On successfully completing encryption, remove this flag */
+        crypt_ftr.flags |= CRYPT_INCONSISTENT_STATE;
         crypt_ftr.crypt_type = crypt_type;
         strcpy((char *)crypt_ftr.crypto_type_name, "aes-cbc-essiv:sha256");
 
@@ -2629,18 +2643,15 @@
 
     if (! rc) {
         /* Success */
+        crypt_ftr.flags &= ~CRYPT_INCONSISTENT_STATE;
 
-        /* Clear the encryption in progress flag in the footer */
-        if (crypt_ftr.encrypted_upto == crypt_ftr.fs_size) {
-            crypt_ftr.flags &= ~CRYPT_ENCRYPTION_IN_PROGRESS;
-        } else {
+        if (crypt_ftr.encrypted_upto != crypt_ftr.fs_size) {
             SLOGD("Encrypted up to sector %lld - will continue after reboot",
                   crypt_ftr.encrypted_upto);
+            crypt_ftr.flags |= CRYPT_ENCRYPTION_IN_PROGRESS;
         }
 
-        if (crypt_ftr.encrypted_upto) {
-            put_crypt_ftr_and_key(&crypt_ftr);
-        }
+        put_crypt_ftr_and_key(&crypt_ftr);
 
         sleep(2); /* Give the UI a chance to show 100% progress */
                   /* Partially encrypted - ensure writes are flushed to ssd */
@@ -2924,9 +2935,10 @@
         }
     }
 
-    /** @TODO make sure we factory wipe in this situation
-     *  In general if we got here there is no recovery
+    /** Corrupt. Allow us to boot into framework, which will detect bad
+        crypto when it calls do_crypto_complete, then do a factory reset
      */
+    property_set("vold.decrypt", "trigger_restart_min_framework");
     return 0;
 }
 
@@ -2941,6 +2953,10 @@
         return -1;
     }
 
+    if (crypt_ftr.flags & CRYPT_INCONSISTENT_STATE) {
+        return -1;
+    }
+
     return crypt_ftr.crypt_type;
 }