am b707d72a: am 6efa9351: Merge "Don\'t use deprecated OpenSSL functions."

* commit 'b707d72a33c8e442cafb36f724245f1c9898fb36':
diff --git a/Loop.cpp b/Loop.cpp
index 11c114f..ca26093 100644
--- a/Loop.cpp
+++ b/Loop.cpp
@@ -35,6 +35,7 @@
 #include <sysutils/SocketClient.h>
 #include "Loop.h"
 #include "Asec.h"
+#include "sehandle.h"
 
 int Loop::dumpState(SocketClient *c) {
     int i;
@@ -132,6 +133,7 @@
     for (i = 0; i < LOOP_MAX; i++) {
         struct loop_info64 li;
         int rc;
+        char *secontext = NULL;
 
         sprintf(filename, "/dev/block/loop%d", i);
 
@@ -141,12 +143,29 @@
          */
         mode_t mode = 0660 | S_IFBLK;
         unsigned int dev = (0xff & i) | ((i << 12) & 0xfff00000) | (7 << 8);
+
+        if (sehandle) {
+            rc = selabel_lookup(sehandle, &secontext, filename, S_IFBLK);
+            if (rc == 0)
+                setfscreatecon(secontext);
+        }
+
         if (mknod(filename, mode, dev) < 0) {
             if (errno != EEXIST) {
+                int sverrno = errno;
                 SLOGE("Error creating loop device node (%s)", strerror(errno));
+                if (secontext) {
+                    freecon(secontext);
+                    setfscreatecon(NULL);
+                }
+                errno = sverrno;
                 return -1;
             }
         }
+        if (secontext) {
+            freecon(secontext);
+            setfscreatecon(NULL);
+        }
 
         if ((fd = open(filename, O_RDWR)) < 0) {
             SLOGE("Unable to open %s (%s)", filename, strerror(errno));
diff --git a/Process.cpp b/Process.cpp
index ea5fbc7..08be28e 100644
--- a/Process.cpp
+++ b/Process.cpp
@@ -170,6 +170,10 @@
     return result;
 }
 
+extern "C" void vold_killProcessesWithOpenFiles(const char *path, int action) {
+	Process::killProcessesWithOpenFiles(path, action);
+}
+
 /*
  * Hunt down processes that have files open at the given mount point.
  * action = 0 to just warn,
diff --git a/Process.h b/Process.h
index fc0c0b7..e745ca4 100644
--- a/Process.h
+++ b/Process.h
@@ -17,6 +17,8 @@
 #ifndef _PROCESS_H
 #define _PROCESS_H
 
+#ifdef __cplusplus
+
 class Process {
 public:
     static void killProcessesWithOpenFiles(const char *path, int action);
@@ -32,4 +34,11 @@
     static int pathMatchesMountPoint(const char *path, const char *mountPoint);
 };
 
+extern "C" {
+#endif /* __cplusplus */
+	void vold_killProcessesWithOpenFiles(const char *path, int action);
+#ifdef __cplusplus
+}
+#endif
+
 #endif
diff --git a/Volume.cpp b/Volume.cpp
index 0baf008..bfad29d 100644
--- a/Volume.cpp
+++ b/Volume.cpp
@@ -48,6 +48,7 @@
 #include "Fat.h"
 #include "Process.h"
 #include "cryptfs.h"
+#include "sehandle.h"
 
 extern "C" void dos_partition_dec(void const *pp, struct dos_partition *d);
 extern "C" void dos_partition_enc(void *pp, struct dos_partition *d);
@@ -219,13 +220,30 @@
 }
 
 int Volume::createDeviceNode(const char *path, int major, int minor) {
+    char *secontext = NULL;
     mode_t mode = 0660 | S_IFBLK;
     dev_t dev = (major << 8) | minor;
+    int rc;
+    if (sehandle) {
+        rc = selabel_lookup(sehandle, &secontext, path, S_IFBLK);
+        if (rc == 0)
+            setfscreatecon(secontext);
+    }
     if (mknod(path, mode, dev) < 0) {
         if (errno != EEXIST) {
+            int sverrno = errno;
+            if (secontext) {
+                freecon(secontext);
+                setfscreatecon(NULL);
+            }
+            errno = sverrno;
             return -1;
         }
     }
+    if (secontext) {
+        setfscreatecon(NULL);
+        freecon(secontext);
+    }
     return 0;
 }
 
diff --git a/cryptfs.c b/cryptfs.c
index 566eef9..9fba014 100644
--- a/cryptfs.c
+++ b/cryptfs.c
@@ -40,6 +40,7 @@
 #include <ext4.h>
 #include <linux/kdev_t.h>
 #include <fs_mgr.h>
+#include <time.h>
 #include "cryptfs.h"
 #define LOG_TAG "Cryptfs"
 #include "cutils/log.h"
@@ -53,6 +54,7 @@
 #include "ext4_utils.h"
 #include "f2fs_sparseblock.h"
 #include "CheckBattery.h"
+#include "Process.h"
 
 #include <hardware/keymaster.h>
 
@@ -1427,32 +1429,46 @@
     return encrypt_master_key(passwd, salt, key_buf, master_key, crypt_ftr);
 }
 
-static int wait_and_unmount(char *mountpoint)
+static int wait_and_unmount(char *mountpoint, bool kill)
 {
-    int i, rc;
+    int i, err, rc;
 #define WAIT_UNMOUNT_COUNT 20
 
     /*  Now umount the tmpfs filesystem */
     for (i=0; i<WAIT_UNMOUNT_COUNT; i++) {
-        if (umount(mountpoint)) {
-            if (errno == EINVAL) {
-                /* EINVAL is returned if the directory is not a mountpoint,
-                 * i.e. there is no filesystem mounted there.  So just get out.
-                 */
-                break;
-            }
-            sleep(1);
-            i++;
-        } else {
-          break;
+        if (umount(mountpoint) == 0) {
+            break;
         }
+
+        if (errno == EINVAL) {
+            /* EINVAL is returned if the directory is not a mountpoint,
+             * i.e. there is no filesystem mounted there.  So just get out.
+             */
+            break;
+        }
+
+        err = errno;
+
+        /* If allowed, be increasingly aggressive before the last two retries */
+        if (kill) {
+            if (i == (WAIT_UNMOUNT_COUNT - 3)) {
+                SLOGW("sending SIGHUP to processes with open files\n");
+                vold_killProcessesWithOpenFiles(mountpoint, 1);
+            } else if (i == (WAIT_UNMOUNT_COUNT - 2)) {
+                SLOGW("sending SIGKILL to processes with open files\n");
+                vold_killProcessesWithOpenFiles(mountpoint, 2);
+            }
+        }
+
+        sleep(1);
     }
 
     if (i < WAIT_UNMOUNT_COUNT) {
       SLOGD("unmounting %s succeeded\n", mountpoint);
       rc = 0;
     } else {
-      SLOGE("unmounting %s failed\n", mountpoint);
+      vold_killProcessesWithOpenFiles(mountpoint, 0);
+      SLOGE("unmounting %s failed: %s\n", mountpoint, strerror(err));
       rc = -1;
     }
 
@@ -1586,7 +1602,7 @@
         return -1;
     }
 
-    if (! (rc = wait_and_unmount(DATA_MNT_POINT)) ) {
+    if (! (rc = wait_and_unmount(DATA_MNT_POINT, true)) ) {
         /* If ro.crypto.readonly is set to 1, mount the decrypted
          * filesystem readonly.  This is used when /data is mounted by
          * recovery mode.
@@ -1783,6 +1799,9 @@
 
   if (rc == 0) {
     crypt_ftr->failed_decrypt_count = 0;
+    if (orig_failed_decrypt_count != 0) {
+      put_crypt_ftr_and_key(crypt_ftr);
+    }
 
     /* Save the name of the crypto block device
      * so we can mount it when restarting the framework. */
@@ -1877,7 +1896,10 @@
     create_crypto_blk_dev(&sd_crypt_ftr, saved_master_key, real_blkdev, 
                           crypto_blkdev, label);
 
-    stat(crypto_blkdev, &statbuf);
+    if (stat(crypto_blkdev, &statbuf) < 0) {
+        SLOGE("Error get stat for crypto_blkdev %s. err=%d(%s)\n",
+              crypto_blkdev, errno, strerror(errno));
+    }
     *new_major = MAJOR(statbuf.st_rdev);
     *new_minor = MINOR(statbuf.st_rdev);
 
@@ -1910,6 +1932,68 @@
     return 0;
 }
 
+/*
+ * TODO - transition patterns to new format in calling code
+ *        and remove this vile hack, and the use of hex in
+ *        the password passing code.
+ *
+ * Patterns are passed in zero based (i.e. the top left dot
+ * is represented by zero, the top middle one etc), but we want
+ * to store them '1' based.
+ * This is to allow us to migrate the calling code to use this
+ * convention. It also solves a nasty problem whereby scrypt ignores
+ * trailing zeros, so patterns ending at the top left could be
+ * truncated, and similarly, you could add the top left to any
+ * pattern and still match.
+ * adjust_passwd is a hack function that returns the alternate representation
+ * if the password appears to be a pattern (hex numbers all less than 09)
+ * If it succeeds we need to try both, and in particular try the alternate
+ * first. If the original matches, then we need to update the footer
+ * with the alternate.
+ * All code that accepts passwords must adjust them first. Since
+ * cryptfs_check_passwd is always the first function called after a migration
+ * (and indeed on any boot) we only need to do the double try in this
+ * function.
+ */
+char* adjust_passwd(const char* passwd)
+{
+    size_t index, length;
+
+    if (!passwd) {
+        return 0;
+    }
+
+    // Check even length. Hex encoded passwords are always
+    // an even length, since each character encodes to two characters.
+    length = strlen(passwd);
+    if (length % 2) {
+        SLOGW("Password not correctly hex encoded.");
+        return 0;
+    }
+
+    // Check password is old-style pattern - a collection of hex
+    // encoded bytes less than 9 (00 through 08)
+    for (index = 0; index < length; index +=2) {
+        if (passwd[index] != '0'
+            || passwd[index + 1] < '0' || passwd[index + 1] > '8') {
+            return 0;
+        }
+    }
+
+    // Allocate room for adjusted passwd and null terminate
+    char* adjusted = malloc(length + 1);
+    adjusted[length] = 0;
+
+    // Add 0x31 ('1') to each character
+    for (index = 0; index < length; index += 2) {
+        // output is 31 through 39 so set first byte to three, second to src + 1
+        adjusted[index] = '3';
+        adjusted[index + 1] = passwd[index + 1] + 1;
+    }
+
+    return adjusted;
+}
+
 int cryptfs_check_passwd(char *passwd)
 {
     struct crypt_mnt_ftr crypt_ftr;
@@ -1919,8 +2003,31 @@
     if (rc)
         return rc;
 
-    rc = test_mount_encrypted_fs(&crypt_ftr, passwd,
-                                 DATA_MNT_POINT, "userdata");
+    char* adjusted_passwd = adjust_passwd(passwd);
+    if (adjusted_passwd) {
+        int failed_decrypt_count = crypt_ftr.failed_decrypt_count;
+        rc = test_mount_encrypted_fs(&crypt_ftr, adjusted_passwd,
+                                     DATA_MNT_POINT, "userdata");
+
+        // Maybe the original one still works?
+        if (rc) {
+            // Don't double count this failure
+            crypt_ftr.failed_decrypt_count = failed_decrypt_count;
+            rc = test_mount_encrypted_fs(&crypt_ftr, passwd,
+                                         DATA_MNT_POINT, "userdata");
+            if (!rc) {
+                // cryptfs_changepw also adjusts so pass original
+                // Note that adjust_passwd only recognises patterns
+                // so we can safely use CRYPT_TYPE_PATTERN
+                SLOGI("Updating pattern to new format");
+                cryptfs_changepw(CRYPT_TYPE_PATTERN, passwd);
+            }
+        }
+        free(adjusted_passwd);
+    } else {
+        rc = test_mount_encrypted_fs(&crypt_ftr, passwd,
+                                     DATA_MNT_POINT, "userdata");
+    }
 
     if (rc == 0 && crypt_ftr.crypt_type != CRYPT_TYPE_DEFAULT) {
         cryptfs_clear_password();
@@ -1966,6 +2073,11 @@
         /* If the device has no password, then just say the password is valid */
         rc = 0;
     } else {
+        char* adjusted_passwd = adjust_passwd(passwd);
+        if (adjusted_passwd) {
+            passwd = adjusted_passwd;
+        }
+
         decrypt_master_key(passwd, decrypted_master_key, &crypt_ftr, 0, 0);
         if (!memcmp(decrypted_master_key, saved_master_key, crypt_ftr.keysize)) {
             /* They match, the password is correct */
@@ -1975,6 +2087,8 @@
             sleep(1);
             rc = 1;
         }
+
+        free(adjusted_passwd);
     }
 
     return rc;
@@ -2123,32 +2237,59 @@
         data->cur_pct = data->new_pct;
         snprintf(buf, sizeof(buf), "%" PRId64, data->cur_pct);
         property_set("vold.encrypt_progress", buf);
-        SLOGI("Encrypted %" PRId64 " percent of drive", data->cur_pct);
     }
 
     if (data->cur_pct >= 5) {
-        double elapsed_time = difftime(time(NULL), data->time_started);
-        off64_t remaining_blocks = data->tot_used_blocks
-                                   - data->used_blocks_already_done;
-        int remaining_time = (int)(elapsed_time * remaining_blocks
-                                   / data->used_blocks_already_done);
+        struct timespec time_now;
+        if (clock_gettime(CLOCK_MONOTONIC, &time_now)) {
+            SLOGW("Error getting time");
+        } else {
+            double elapsed_time = difftime(time_now.tv_sec, data->time_started);
+            off64_t remaining_blocks = data->tot_used_blocks
+                                       - data->used_blocks_already_done;
+            int remaining_time = (int)(elapsed_time * remaining_blocks
+                                       / data->used_blocks_already_done);
 
-        // Change time only if not yet set, lower, or a lot higher for
-        // best user experience
-        if (data->remaining_time == -1
-            || remaining_time < data->remaining_time
-            || remaining_time > data->remaining_time + 60) {
-            char buf[8];
-            snprintf(buf, sizeof(buf), "%d", remaining_time);
-            property_set("vold.encrypt_time_remaining", buf);
-
-            SLOGI("Encrypted %" PRId64 " percent of drive, %d seconds to go",
-                  data->cur_pct, remaining_time);
-            data->remaining_time = remaining_time;
+            // Change time only if not yet set, lower, or a lot higher for
+            // best user experience
+            if (data->remaining_time == -1
+                || remaining_time < data->remaining_time
+                || remaining_time > data->remaining_time + 60) {
+                char buf[8];
+                snprintf(buf, sizeof(buf), "%d", remaining_time);
+                property_set("vold.encrypt_time_remaining", buf);
+                data->remaining_time = remaining_time;
+            }
         }
     }
 }
 
+static void log_progress(struct encryptGroupsData const* data, bool completed)
+{
+    // Precondition - if completed data = 0 else data != 0
+
+    // Track progress so we can skip logging blocks
+    static off64_t offset = -1;
+
+    // Need to close existing 'Encrypting from' log?
+    if (completed || (offset != -1 && data->offset != offset)) {
+        SLOGI("Encrypted to sector %" PRId64,
+              offset / info.block_size * CRYPT_SECTOR_SIZE);
+        offset = -1;
+    }
+
+    // Need to start new 'Encrypting from' log?
+    if (!completed && offset != data->offset) {
+        SLOGI("Encrypting from sector %" PRId64,
+              data->offset / info.block_size * CRYPT_SECTOR_SIZE);
+    }
+
+    // Update offset
+    if (!completed) {
+        offset = data->offset + (off64_t)data->count * info.block_size;
+    }
+}
+
 static int flush_outstanding_data(struct encryptGroupsData* data)
 {
     if (data->count == 0) {
@@ -2172,8 +2313,7 @@
               data->crypto_blkdev);
         return -1;
     } else {
-        SLOGI("Encrypted %d blocks at sector %" PRId64,
-              data->count, data->offset / info.block_size * CRYPT_SECTOR_SIZE);
+      log_progress(data, false);
     }
 
     data->count = 0;
@@ -2262,6 +2402,7 @@
     rc = 0;
 
 errout:
+    log_progress(0, true);
     free(data->buffer);
     free(block_bitmap);
     return rc;
@@ -2288,27 +2429,27 @@
     data.crypto_blkdev = crypto_blkdev;
 
     if ( (data.realfd = open(real_blkdev, O_RDWR)) < 0) {
-        SLOGE("Error opening real_blkdev %s for inplace encrypt\n",
-              real_blkdev);
+        SLOGE("Error opening real_blkdev %s for inplace encrypt. err=%d(%s)\n",
+              real_blkdev, errno, strerror(errno));
         rc = -1;
         goto errout;
     }
 
     if ( (data.cryptofd = open(crypto_blkdev, O_WRONLY)) < 0) {
-        SLOGE("Error opening crypto_blkdev %s for inplace encrypt\n",
-              crypto_blkdev);
-        rc = -1;
+        SLOGE("Error opening crypto_blkdev %s for ext4 inplace encrypt. err=%d(%s)\n",
+              crypto_blkdev, errno, strerror(errno));
+        rc = ENABLE_INPLACE_ERR_DEV;
         goto errout;
     }
 
     if (setjmp(setjmp_env)) {
-        SLOGE("Reading extent caused an exception");
+        SLOGE("Reading ext4 extent caused an exception\n");
         rc = -1;
         goto errout;
     }
 
     if (read_ext(data.realfd, 0) != 0) {
-        SLOGE("Failed to read extent");
+        SLOGE("Failed to read ext4 extent\n");
         rc = -1;
         goto errout;
     }
@@ -2317,7 +2458,7 @@
     data.tot_numblocks = tot_size / CRYPT_SECTORS_PER_BUFSIZE;
     data.blocks_already_done = *size_already_done / CRYPT_SECTORS_PER_BUFSIZE;
 
-    SLOGI("Encrypting filesystem in place...");
+    SLOGI("Encrypting ext4 filesystem in place...");
 
     data.tot_used_blocks = data.numblocks;
     for (i = 0; i < aux_info.groups; ++i) {
@@ -2326,7 +2467,13 @@
 
     data.one_pct = data.tot_used_blocks / 100;
     data.cur_pct = 0;
-    data.time_started = time(NULL);
+
+    struct timespec time_started = {0};
+    if (clock_gettime(CLOCK_MONOTONIC, &time_started)) {
+        SLOGW("Error getting time at start");
+        // Note - continue anyway - we'll run with 0
+    }
+    data.time_started = time_started.tv_sec;
     data.remaining_time = -1;
 
     rc = encrypt_groups(&data);
@@ -2345,6 +2492,30 @@
     return rc;
 }
 
+static void log_progress_f2fs(u64 block, bool completed)
+{
+    // Precondition - if completed data = 0 else data != 0
+
+    // Track progress so we can skip logging blocks
+    static u64 last_block = (u64)-1;
+
+    // Need to close existing 'Encrypting from' log?
+    if (completed || (last_block != (u64)-1 && block != last_block + 1)) {
+        SLOGI("Encrypted to block %" PRId64, last_block);
+        last_block = -1;
+    }
+
+    // Need to start new 'Encrypting from' log?
+    if (!completed && (last_block == (u64)-1 || block != last_block + 1)) {
+        SLOGI("Encrypting from block %" PRId64, block);
+    }
+
+    // Update offset
+    if (!completed) {
+        last_block = block;
+    }
+}
+
 static int encrypt_one_block_f2fs(u64 pos, void *data)
 {
     struct encryptGroupsData *priv_dat = (struct encryptGroupsData *)data;
@@ -2355,15 +2526,15 @@
     off64_t offset = pos * CRYPT_INPLACE_BUFSIZE;
 
     if (pread64(priv_dat->realfd, priv_dat->buffer, CRYPT_INPLACE_BUFSIZE, offset) <= 0) {
-        SLOGE("Error reading real_blkdev %s for inplace encrypt", priv_dat->crypto_blkdev);
+        SLOGE("Error reading real_blkdev %s for f2fs inplace encrypt", priv_dat->crypto_blkdev);
         return -1;
     }
 
     if (pwrite64(priv_dat->cryptofd, priv_dat->buffer, CRYPT_INPLACE_BUFSIZE, offset) <= 0) {
-        SLOGE("Error writing crypto_blkdev %s for inplace encrypt", priv_dat->crypto_blkdev);
+        SLOGE("Error writing crypto_blkdev %s for f2fs inplace encrypt", priv_dat->crypto_blkdev);
         return -1;
     } else {
-        SLOGD("Encrypted block %"PRIu64, pos);
+        log_progress_f2fs(pos, false);
     }
 
     return 0;
@@ -2379,10 +2550,10 @@
     u32 i;
     struct encryptGroupsData data;
     struct f2fs_info *f2fs_info = NULL;
-    int rc = -1;
+    int rc = ENABLE_INPLACE_ERR_OTHER;
     if (previously_encrypted_upto > *size_already_done) {
         SLOGD("Not fast encrypting since resuming part way through");
-        return -1;
+        return ENABLE_INPLACE_ERR_OTHER;
     }
     memset(&data, 0, sizeof(data));
     data.real_blkdev = real_blkdev;
@@ -2390,13 +2561,14 @@
     data.realfd = -1;
     data.cryptofd = -1;
     if ( (data.realfd = open64(real_blkdev, O_RDWR)) < 0) {
-        SLOGE("Error opening real_blkdev %s for inplace encrypt\n",
+        SLOGE("Error opening real_blkdev %s for f2fs inplace encrypt\n",
               real_blkdev);
         goto errout;
     }
     if ( (data.cryptofd = open64(crypto_blkdev, O_WRONLY)) < 0) {
-        SLOGE("Error opening crypto_blkdev %s for inplace encrypt\n",
-              crypto_blkdev);
+        SLOGE("Error opening crypto_blkdev %s for f2fs inplace encrypt. err=%d(%s)\n",
+              crypto_blkdev, errno, strerror(errno));
+        rc = ENABLE_INPLACE_ERR_DEV;
         goto errout;
     }
 
@@ -2427,7 +2599,8 @@
     rc = run_on_used_blocks(data.blocks_already_done, f2fs_info, &encrypt_one_block_f2fs, &data);
 
     if (rc) {
-        SLOGE("Error in running over blocks");
+        SLOGE("Error in running over f2fs blocks");
+        rc = ENABLE_INPLACE_ERR_OTHER;
         goto errout;
     }
 
@@ -2438,6 +2611,7 @@
     if (rc)
         SLOGE("Failed to encrypt f2fs filesystem on %s", real_blkdev);
 
+    log_progress_f2fs(0, true);
     free(f2fs_info);
     free(data.buffer);
     close(data.realfd);
@@ -2453,20 +2627,21 @@
 {
     int realfd, cryptofd;
     char *buf[CRYPT_INPLACE_BUFSIZE];
-    int rc = -1;
+    int rc = ENABLE_INPLACE_ERR_OTHER;
     off64_t numblocks, i, remainder;
     off64_t one_pct, cur_pct, new_pct;
     off64_t blocks_already_done, tot_numblocks;
 
     if ( (realfd = open(real_blkdev, O_RDONLY)) < 0) { 
         SLOGE("Error opening real_blkdev %s for inplace encrypt\n", real_blkdev);
-        return -1;
+        return ENABLE_INPLACE_ERR_OTHER;
     }
 
     if ( (cryptofd = open(crypto_blkdev, O_WRONLY)) < 0) { 
-        SLOGE("Error opening crypto_blkdev %s for inplace encrypt\n", crypto_blkdev);
+        SLOGE("Error opening crypto_blkdev %s for inplace encrypt. err=%d(%s)\n",
+              crypto_blkdev, errno, strerror(errno));
         close(realfd);
-        return -1;
+        return ENABLE_INPLACE_ERR_DEV;
     }
 
     /* This is pretty much a simple loop of reading 4K, and writing 4K.
@@ -2565,11 +2740,13 @@
     return rc;
 }
 
+/* returns on of the ENABLE_INPLACE_* return codes */
 static int cryptfs_enable_inplace(char *crypto_blkdev, char *real_blkdev,
                                   off64_t size, off64_t *size_already_done,
                                   off64_t tot_size,
                                   off64_t previously_encrypted_upto)
 {
+    int rc_ext4, rc_f2fs, rc_full;
     if (previously_encrypted_upto) {
         SLOGD("Continuing encryption from %" PRId64, previously_encrypted_upto);
     }
@@ -2583,21 +2760,32 @@
      * As is, cryptfs_enable_inplace_ext4 will fail on an f2fs partition, and
      * then we will drop down to cryptfs_enable_inplace_f2fs.
      * */
-    if (cryptfs_enable_inplace_ext4(crypto_blkdev, real_blkdev,
+    if ((rc_ext4 = cryptfs_enable_inplace_ext4(crypto_blkdev, real_blkdev,
                                 size, size_already_done,
-                                tot_size, previously_encrypted_upto) == 0) {
+                                tot_size, previously_encrypted_upto)) == 0) {
       return 0;
     }
+    SLOGD("cryptfs_enable_inplace_ext4()=%d\n", rc_ext4);
 
-    if (cryptfs_enable_inplace_f2fs(crypto_blkdev, real_blkdev,
+    if ((rc_f2fs = cryptfs_enable_inplace_f2fs(crypto_blkdev, real_blkdev,
                                 size, size_already_done,
-                                tot_size, previously_encrypted_upto) == 0) {
+                                tot_size, previously_encrypted_upto)) == 0) {
       return 0;
     }
+    SLOGD("cryptfs_enable_inplace_f2fs()=%d\n", rc_f2fs);
 
-    return cryptfs_enable_inplace_full(crypto_blkdev, real_blkdev,
+    rc_full = cryptfs_enable_inplace_full(crypto_blkdev, real_blkdev,
                                        size, size_already_done, tot_size,
                                        previously_encrypted_upto);
+    SLOGD("cryptfs_enable_inplace_full()=%d\n", rc_full);
+
+    /* Hack for b/17898962, the following is the symptom... */
+    if (rc_ext4 == ENABLE_INPLACE_ERR_DEV
+        && rc_f2fs == ENABLE_INPLACE_ERR_DEV
+        && rc_full == ENABLE_INPLACE_ERR_DEV) {
+            return ENABLE_INPLACE_ERR_DEV;
+    }
+    return rc_full;
 }
 
 #define CRYPTO_ENABLE_WIPE 1
@@ -2677,6 +2865,12 @@
                                     tot_encryption_size,
                                     previously_encrypted_upto);
 
+        if (rc == ENABLE_INPLACE_ERR_DEV) {
+            /* Hack for b/17898962 */
+            SLOGE("cryptfs_enable: crypto block dev failure. Must reboot...\n");
+            cryptfs_reboot(reboot);
+        }
+
         if (!rc) {
             crypt_ftr->encrypted_upto = cur_encryption_done;
         }
@@ -2826,13 +3020,13 @@
          * above, so just unmount it now.  We must do this _AFTER_ killing the framework,
          * unlike the case for vold managed devices above.
          */
-        if (wait_and_unmount(sd_mnt_point)) {
+        if (wait_and_unmount(sd_mnt_point, false)) {
             goto error_shutting_down;
         }
     }
 
     /* Now unmount the /data partition. */
-    if (wait_and_unmount(DATA_MNT_POINT)) {
+    if (wait_and_unmount(DATA_MNT_POINT, false)) {
         if (allow_reboot) {
             goto error_shutting_down;
         } else {
@@ -2999,7 +3193,8 @@
             mkdir("/cache/recovery", 0700);
             int fd = open("/cache/recovery/command", O_RDWR|O_CREAT|O_TRUNC, 0600);
             if (fd >= 0) {
-                write(fd, "--wipe_data", strlen("--wipe_data") + 1);
+                write(fd, "--wipe_data\n", strlen("--wipe_data\n") + 1);
+                write(fd, "--reason=cryptfs_enable_internal\n", strlen("--reason=cryptfs_enable_internal\n") + 1);
                 close(fd);
             } else {
                 SLOGE("could not open /cache/recovery/command\n");
@@ -3048,7 +3243,15 @@
 
 int cryptfs_enable(char *howarg, int type, char *passwd, int allow_reboot)
 {
-    return cryptfs_enable_internal(howarg, type, passwd, allow_reboot);
+    char* adjusted_passwd = adjust_passwd(passwd);
+    if (adjusted_passwd) {
+        passwd = adjusted_passwd;
+    }
+
+    int rc = cryptfs_enable_internal(howarg, type, passwd, allow_reboot);
+
+    free(adjusted_passwd);
+    return rc;
 }
 
 int cryptfs_enable_default(char *howarg, int allow_reboot)
@@ -3081,6 +3284,11 @@
 
     crypt_ftr.crypt_type = crypt_type;
 
+    char* adjusted_passwd = adjust_passwd(newpw);
+    if (adjusted_passwd) {
+        newpw = adjusted_passwd;
+    }
+
     encrypt_master_key(crypt_type == CRYPT_TYPE_DEFAULT ? DEFAULT_PASSWORD
                                                         : newpw,
                        crypt_ftr.salt,
@@ -3091,6 +3299,7 @@
     /* save the key */
     put_crypt_ftr_and_key(&crypt_ftr);
 
+    free(adjusted_passwd);
     return 0;
 }
 
diff --git a/cryptfs.h b/cryptfs.h
index 490bc11..66e0b4c 100644
--- a/cryptfs.h
+++ b/cryptfs.h
@@ -196,6 +196,11 @@
 #define CRYPTO_COMPLETE_INCONSISTENT  -3
 #define CRYPTO_COMPLETE_CORRUPT       -4
 
+/* Return values for cryptfs_enable_inplace*() */
+#define ENABLE_INPLACE_OK 0
+#define ENABLE_INPLACE_ERR_OTHER -1
+#define ENABLE_INPLACE_ERR_DEV -2  /* crypto_blkdev issue */
+
 #ifdef __cplusplus
 extern "C" {
 #endif
diff --git a/main.cpp b/main.cpp
index d4b7d28..c07f48d 100644
--- a/main.cpp
+++ b/main.cpp
@@ -36,6 +36,7 @@
 #include "NetlinkManager.h"
 #include "DirectVolume.h"
 #include "cryptfs.h"
+#include "sehandle.h"
 
 static int process_config(VolumeManager *vm);
 static void coldboot(const char *path);
@@ -43,6 +44,8 @@
 #define FSTAB_PREFIX "/fstab."
 struct fstab *fstab;
 
+struct selabel_handle *sehandle;
+
 int main() {
 
     VolumeManager *vm;
@@ -51,6 +54,10 @@
 
     SLOGI("Vold 2.1 (the revenge) firing up");
 
+    sehandle = selinux_android_file_context_handle();
+    if (sehandle)
+        selinux_android_set_sehandle(sehandle);
+
     mkdir("/dev/block/vold", 0755);
 
     /* For when cryptfs checks and mounts an encrypted filesystem */
diff --git a/sehandle.h b/sehandle.h
new file mode 100644
index 0000000..f59d7eb
--- /dev/null
+++ b/sehandle.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+#ifndef _SEHANDLE_H
+#define _SEHANDLE_H
+
+#include <selinux/android.h>
+
+extern struct selabel_handle *sehandle;
+
+#endif