Merge "Mount appfuse in process namespace."
diff --git a/Android.mk b/Android.mk
index 5785ad9..bea18b2 100644
--- a/Android.mk
+++ b/Android.mk
@@ -29,6 +29,7 @@
 	TrimTask.cpp \
 	Keymaster.cpp \
 	KeyStorage.cpp \
+	secontext.cpp \
 
 common_c_includes := \
 	system/extras/ext4_utils \
diff --git a/CryptCommandListener.cpp b/CryptCommandListener.cpp
index c265fb0..2eac60e 100644
--- a/CryptCommandListener.cpp
+++ b/CryptCommandListener.cpp
@@ -354,6 +354,10 @@
         dumpArgs(argc, argv, -1);
         rc = cryptfs_isConvertibleToFBE();
 
+    } else if (subcommand == "init_user0") {
+        if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
+        return sendGenericOkFail(cli, e4crypt_init_user0());
+
     } else if (subcommand == "create_user_key") {
         if (!check_argc(cli, subcommand, argc, 5, "<user> <serial> <ephemeral>")) return 0;
         return sendGenericOkFail(cli,
diff --git a/Ext4Crypt.cpp b/Ext4Crypt.cpp
index fb66a6b..72c79fa 100644
--- a/Ext4Crypt.cpp
+++ b/Ext4Crypt.cpp
@@ -21,9 +21,11 @@
 
 #include <iomanip>
 #include <map>
+#include <set>
 #include <string>
 #include <sstream>
 
+#include <stdio.h>
 #include <errno.h>
 #include <dirent.h>
 #include <sys/mount.h>
@@ -75,6 +77,7 @@
     const int password_max_age_seconds = 60;
 
     const std::string user_key_dir = std::string() + DATA_MNT_POINT + "/misc/vold/user_keys";
+    const std::string user_key_temp = user_key_dir + "/temp";
 
     // How is device encrypted
     struct keys {
@@ -83,10 +86,11 @@
         time_t expiry_time;
     };
     std::map<std::string, keys> s_key_store;
-    // Maps the key paths of ephemeral keys to the keys
-    std::map<std::string, std::string> s_ephemeral_user_keys;
-    // Map user serial numbers to key references
-    std::map<int, std::string> s_key_raw_refs;
+    // Some users are ephemeral, don't try to wipe their keys from disk
+    std::set<userid_t> s_ephemeral_users;
+    // Map user ids to key references
+    std::map<userid_t, std::string> s_de_key_raw_refs;
+    std::map<userid_t, std::string> s_ce_key_raw_refs;
 
     // ext4enc:TODO get this const from somewhere good
     const int EXT4_KEY_DESCRIPTOR_SIZE = 8;
@@ -120,7 +124,7 @@
     }
 }
 
-static std::string e4crypt_install_key(const std::string &key);
+static bool install_key(const std::string &key, std::string &raw_ref);
 
 static int put_crypt_ftr_and_key(const crypt_mnt_ftr& crypt_ftr,
                                  UnencryptedProperties& props)
@@ -382,10 +386,11 @@
     clock_gettime(CLOCK_BOOTTIME, &now);
     s_key_store[path] = keys{master_key, password,
                              now.tv_sec + password_max_age_seconds};
-    auto raw_ref = e4crypt_install_key(master_key);
-    if (raw_ref.empty()) {
+    std::string raw_ref;
+    if (!install_key(master_key, raw_ref)) {
         return -1;
     }
+    SLOGD("Installed master key");
 
     // Save reference to key so we can set policy later
     if (!props.Set(properties::ref, raw_ref)) {
@@ -427,32 +432,28 @@
     return keyctl_search(KEY_SPEC_SESSION_KEYRING, "keyring", "e4crypt", 0);
 }
 
-static int e4crypt_install_key(const ext4_encryption_key &ext4_key, const std::string &ref)
+// Install password into global keyring
+// Return raw key reference for use in policy
+static bool install_key(const std::string &key, std::string &raw_ref)
 {
+    if (key.size() != key_length/8) {
+        LOG(ERROR) << "Wrong size key " << key.size();
+        return false;
+    }
+    auto ext4_key = fill_key(key);
+    raw_ref = generate_key_ref(ext4_key.raw, ext4_key.size);
+    auto ref = keyname(raw_ref);
     key_serial_t device_keyring = e4crypt_keyring();
     key_serial_t key_id = add_key("logon", ref.c_str(),
                                   (void*)&ext4_key, sizeof(ext4_key),
                                   device_keyring);
     if (key_id == -1) {
         PLOG(ERROR) << "Failed to insert key into keyring " << device_keyring;
-        return -1;
+        return false;
     }
     LOG(INFO) << "Added key " << key_id << " (" << ref << ") to keyring "
         << device_keyring << " in process " << getpid();
-    return 0;
-}
-
-// Install password into global keyring
-// Return raw key reference for use in policy
-static std::string e4crypt_install_key(const std::string &key)
-{
-    auto ext4_key = fill_key(key);
-    auto raw_ref = generate_key_ref(ext4_key.raw, ext4_key.size);
-    auto ref = keyname(raw_ref);
-    if (e4crypt_install_key(ext4_key, ref) == -1) {
-        return "";
-    }
-    return raw_ref;
+    return true;
 }
 
 int e4crypt_restart(const char* path)
@@ -549,31 +550,35 @@
         .Set(fieldname, std::string(value)) ? 0 : -1;
 }
 
-static std::string get_key_path(userid_t user_id) {
-    return StringPrintf("%s/user_%d/current", user_key_dir.c_str(), user_id);
+static std::string get_de_key_path(userid_t user_id) {
+    return StringPrintf("%s/de/%d", user_key_dir.c_str(), user_id);
 }
 
-static bool e4crypt_is_key_ephemeral(const std::string &key_path) {
-    return s_ephemeral_user_keys.find(key_path) != s_ephemeral_user_keys.end();
+static std::string get_ce_key_path(userid_t user_id) {
+    return StringPrintf("%s/ce/%d/current", user_key_dir.c_str(), user_id);
 }
 
-static bool read_user_key(userid_t user_id, std::string &key)
+static bool read_and_install_key(const std::string &key_path, std::string &raw_ref)
 {
-    const auto key_path = get_key_path(user_id);
-    const auto ephemeral_key_it = s_ephemeral_user_keys.find(key_path);
-    if (ephemeral_key_it != s_ephemeral_user_keys.end()) {
-        key = ephemeral_key_it->second;
-        return true;
-    }
+    std::string key;
     if (!android::vold::retrieveKey(key_path, key)) return false;
-    if (key.size() != key_length/8) {
-        LOG(ERROR) << "Wrong size key " << key.size() << " in " << key_path;
-        return false;
-    }
+    if (!install_key(key, raw_ref)) return false;
+    return true;
+}
+
+static bool read_and_install_user_ce_key(userid_t user_id)
+{
+    if (s_ce_key_raw_refs.count(user_id) != 0) return true;
+    const auto key_path = get_ce_key_path(user_id);
+    std::string raw_ref;
+    if (!read_and_install_key(key_path, raw_ref)) return false;
+    s_ce_key_raw_refs[user_id] = raw_ref;
+    LOG(DEBUG) << "Installed ce key for user " << user_id;
     return true;
 }
 
 static bool prepare_dir(const std::string &dir, mode_t mode, uid_t uid, gid_t gid) {
+    LOG(DEBUG) << "Preparing: " << dir;
     if (fs_prepare_dir(dir.c_str(), mode, uid, gid) != 0) {
         PLOG(ERROR) << "Failed to prepare " << dir;
         return false;
@@ -581,36 +586,147 @@
     return true;
 }
 
-static bool create_user_key(userid_t user_id, bool create_ephemeral) {
-    const auto key_path = get_key_path(user_id);
-    std::string key;
+static bool random_key(std::string &key) {
     if (android::vold::ReadRandomBytes(key_length / 8, key) != 0) {
         // TODO status_t plays badly with PLOG, fix it.
         LOG(ERROR) << "Random read failed";
         return false;
     }
-    if (create_ephemeral) {
-        // If the key should be created as ephemeral, store it in memory only.
-        s_ephemeral_user_keys[key_path] = key;
-    } else {
-        if (!prepare_dir(user_key_dir, 0700, AID_ROOT, AID_ROOT)) return false;
-        if (!prepare_dir(user_key_dir + "/user_" + std::to_string(user_id),
-            0700, AID_ROOT, AID_ROOT)) return false;
-        if (!android::vold::storeKey(key_path, key)) return false;
+    return true;
+}
+
+static bool path_exists(const std::string &path) {
+    return access(path.c_str(), F_OK) == 0;
+}
+
+// NB this assumes that there is only one thread listening for crypt commands, because
+// it creates keys in a fixed location.
+static bool store_key(const std::string &key_path, const std::string &key) {
+    if (path_exists(key_path)) {
+        LOG(ERROR) << "Already exists, cannot create key at: " << key_path;
+        return false;
+    }
+    if (path_exists(user_key_temp)) {
+        android::vold::destroyKey(user_key_temp);
+    }
+    if (!android::vold::storeKey(user_key_temp, key)) return false;
+    if (rename(user_key_temp.c_str(), key_path.c_str()) != 0) {
+        PLOG(ERROR) << "Unable to move new key to location: " << key_path;
+        return false;
     }
     LOG(DEBUG) << "Created key " << key_path;
     return true;
 }
 
-static int e4crypt_set_user_policy(userid_t user_id, int serial, std::string& path) {
-    LOG(DEBUG) << "e4crypt_set_user_policy for " << user_id << " serial " << serial;
-    if (s_key_raw_refs.count(serial) != 1) {
-        LOG(ERROR) << "Key unknown, can't e4crypt_set_user_policy for "
-            << user_id << " serial " << serial;
-        return -1;
+static bool create_and_install_user_keys(userid_t user_id, bool create_ephemeral) {
+    std::string de_key, ce_key;
+    if (!random_key(de_key)) return false;
+    if (!random_key(ce_key)) return false;
+    if (create_ephemeral) {
+        // If the key should be created as ephemeral, don't store it.
+        s_ephemeral_users.insert(user_id);
+    } else {
+        if (!store_key(get_de_key_path(user_id), de_key)) return false;
+        if (!prepare_dir(user_key_dir + "/ce/" + std::to_string(user_id),
+            0700, AID_ROOT, AID_ROOT)) return false;
+        if (!store_key(get_ce_key_path(user_id), ce_key)) return false;
     }
-    auto raw_ref = s_key_raw_refs[serial];
-    return do_policy_set(path.c_str(), raw_ref.data(), raw_ref.size());
+    std::string de_raw_ref;
+    if (!install_key(de_key, de_raw_ref)) return false;
+    s_de_key_raw_refs[user_id] = de_raw_ref;
+    std::string ce_raw_ref;
+    if (!install_key(ce_key, ce_raw_ref)) return false;
+    s_ce_key_raw_refs[user_id] = ce_raw_ref;
+    LOG(DEBUG) << "Created keys for user " << user_id;
+    return true;
+}
+
+static bool lookup_key_ref(const std::map<userid_t, std::string> &key_map,
+        userid_t user_id, std::string &raw_ref) {
+    auto refi = key_map.find(user_id);
+    if (refi == key_map.end()) {
+        LOG(ERROR) << "Cannot find key for " << user_id;
+        return false;
+    }
+    raw_ref = refi->second;
+    return true;
+}
+
+static bool set_policy(const std::string &raw_ref, const std::string& path) {
+    if (do_policy_set(path.c_str(), raw_ref.data(), raw_ref.size()) != 0) {
+        LOG(ERROR) << "Failed to set policy on: " << path;
+        return false;
+    }
+    return true;
+}
+
+static bool is_numeric(const char *name) {
+    for (const char *p = name; *p != '\0'; p++) {
+        if (!isdigit(*p))
+            return false;
+    }
+    return true;
+}
+
+static bool load_all_de_keys() {
+    auto de_dir = user_key_dir + "/de";
+    auto dirp = std::unique_ptr<DIR, int(*)(DIR*)>(opendir(de_dir.c_str()), closedir);
+    if (!dirp) {
+        PLOG(ERROR) << "Unable to read de key directory";
+        return false;
+    }
+    for (;;) {
+        errno = 0;
+        auto entry = readdir(dirp.get());
+        if (!entry) {
+            if (errno) {
+                PLOG(ERROR) << "Unable to read de key directory";
+                return false;
+            }
+            break;
+        }
+        if (entry->d_type != DT_DIR || !is_numeric(entry->d_name)) {
+            LOG(DEBUG) << "Skipping non-de-key " << entry->d_name;
+            continue;
+        }
+        userid_t user_id = atoi(entry->d_name);
+        if (s_de_key_raw_refs.count(user_id) == 0) {
+            std::string raw_ref;
+            if (!read_and_install_key(de_dir + "/" + entry->d_name, raw_ref)) return false;
+            s_de_key_raw_refs[user_id] = raw_ref;
+            LOG(DEBUG) << "Installed de key for user " << user_id;
+        }
+    }
+    // ext4enc:TODO: go through all DE directories, ensure that all user dirs have the
+    // correct policy set on them, and that no rogue ones exist.
+    return true;
+}
+
+int e4crypt_init_user0() {
+    LOG(DEBUG) << "e4crypt_init_user0";
+    if (e4crypt_is_native()) {
+        if (!prepare_dir(user_key_dir, 0700, AID_ROOT, AID_ROOT)) return -1;
+        if (!prepare_dir(user_key_dir + "/ce", 0700, AID_ROOT, AID_ROOT)) return -1;
+        if (!prepare_dir(user_key_dir + "/de", 0700, AID_ROOT, AID_ROOT)) return -1;
+        auto de_path = get_de_key_path(0);
+        auto ce_path = get_ce_key_path(0);
+        if (!path_exists(de_path) || !path_exists(ce_path)) {
+            if (path_exists(de_path)) {
+                android::vold::destroyKey(de_path); // Ignore failure
+            }
+            if (path_exists(ce_path)) {
+                android::vold::destroyKey(ce_path); // Ignore failure
+            }
+            if (!create_and_install_user_keys(0, false)) return -1;
+        }
+        if (!load_all_de_keys()) return -1;
+    }
+    // Ignore failures. FIXME this is horrid
+    // FIXME: we need an idempotent policy-setting call, which simply verifies the
+    // policy is already set on a second run, even if the directory is nonempty.
+    // Then we need to call it all the time.
+    e4crypt_prepare_user_storage(nullptr, 0, 0, false);
+    return 0;
 }
 
 int e4crypt_vold_create_user_key(userid_t user_id, int serial, bool ephemeral) {
@@ -618,29 +734,22 @@
     if (!e4crypt_is_native()) {
         return 0;
     }
-    std::string key;
-    if (read_user_key(user_id, key)) {
+    // FIXME test for existence of key that is not loaded yet
+    if (s_ce_key_raw_refs.count(user_id) != 0) {
         LOG(ERROR) << "Already exists, can't e4crypt_vold_create_user_key for "
             << user_id << " serial " << serial;
         // FIXME should we fail the command?
         return 0;
     }
-    if (!create_user_key(user_id, ephemeral)) {
-        return -1;
-    }
-    if (e4crypt_unlock_user_key(user_id, serial, nullptr) != 0) {
+    if (!create_and_install_user_keys(user_id, ephemeral)) {
         return -1;
     }
     // TODO: create second key for user_de data
     return 0;
 }
 
-static bool evict_user_key(userid_t user_id) {
-    auto key_path = get_key_path(user_id);
-    std::string key;
-    if (!read_user_key(user_id, key)) return false;
-    auto ext4_key = fill_key(key);
-    auto ref = keyname(generate_key_ref(ext4_key.raw, ext4_key.size));
+static bool evict_key(const std::string &raw_ref) {
+    auto ref = keyname(raw_ref);
     auto key_serial = keyctl_search(e4crypt_keyring(), "logon", ref.c_str(), 0);
     if (keyctl_revoke(key_serial) != 0) {
         PLOG(ERROR) << "Failed to revoke key with serial " << key_serial << " ref " << ref;
@@ -655,17 +764,18 @@
     if (!e4crypt_is_native()) {
         return 0;
     }
-    // TODO: destroy second key for user_de data
-    bool evict_success = evict_user_key(user_id);
-    auto key_path = get_key_path(user_id);
-    if (e4crypt_is_key_ephemeral(key_path)) {
-        s_ephemeral_user_keys.erase(key_path);
+    bool success = true;
+    std::string raw_ref;
+    success &= lookup_key_ref(s_ce_key_raw_refs, user_id, raw_ref) && evict_key(raw_ref);
+    success &= lookup_key_ref(s_de_key_raw_refs, user_id, raw_ref) && evict_key(raw_ref);
+    auto it = s_ephemeral_users.find(user_id);
+    if (it != s_ephemeral_users.end()) {
+        s_ephemeral_users.erase(it);
     } else {
-        if (!android::vold::destroyKey(key_path)) {
-            return -1;
-        }
+        success &= android::vold::destroyKey(get_ce_key_path(user_id));
+        success &= android::vold::destroyKey(get_de_key_path(user_id));
     }
-    return evict_success ? 0 : -1;
+    return success ? 0 : -1;
 }
 
 static int emulated_lock(const std::string& path) {
@@ -701,33 +811,10 @@
 int e4crypt_unlock_user_key(userid_t user_id, int serial, const char* token) {
     LOG(DEBUG) << "e4crypt_unlock_user_key " << user_id << " " << (token != nullptr);
     if (e4crypt_is_native()) {
-        std::string user_key;
-        if (!read_user_key(user_id, user_key)) {
-            // FIXME special case for user 0
-            if (user_id != 0) {
-                LOG(ERROR) << "Couldn't read key for " << user_id;
-                return -1;
-            }
-            // FIXME if the key exists and we just failed to read it, this destroys it.
-            if (!create_user_key(user_id, false)) {
-                return -1;
-            }
-            if (!read_user_key(user_id, user_key)) {
-                LOG(ERROR) << "Couldn't read just-created key for " << user_id;
-                return -1;
-            }
-        }
-        auto raw_ref = e4crypt_install_key(user_key);
-        if (raw_ref.empty()) {
+        if (!read_and_install_user_ce_key(user_id)) {
+            LOG(ERROR) << "Couldn't read key for " << user_id;
             return -1;
         }
-        s_key_raw_refs[serial] = raw_ref;
-        if (user_id == 0) {
-            // FIXME special case for user 0
-            // prepare their storage here
-            e4crypt_prepare_user_storage(nullptr, 0, 0, false);
-        }
-        return 0;
     } else {
         // When in emulation mode, we just use chmod. However, we also
         // unlock directories when not in emulation mode, to bring devices
@@ -739,7 +826,6 @@
             return -1;
         }
     }
-
     return 0;
 }
 
@@ -773,17 +859,21 @@
     auto user_ce_path = android::vold::BuildDataUserPath(volume_uuid, user_id);
     auto user_de_path = android::vold::BuildDataUserDePath(volume_uuid, user_id);
 
-    if (!prepare_dir(system_ce_path, 0700, AID_SYSTEM, AID_SYSTEM)) return -1;
+    // FIXME: should this be 0770 or 0700?
+    if (!prepare_dir(system_ce_path, 0770, AID_SYSTEM, AID_SYSTEM)) return -1;
     if (!prepare_dir(media_ce_path, 0770, AID_MEDIA_RW, AID_MEDIA_RW)) return -1;
     if (!prepare_dir(user_ce_path, 0771, AID_SYSTEM, AID_SYSTEM)) return -1;
     if (!prepare_dir(user_de_path, 0771, AID_SYSTEM, AID_SYSTEM)) return -1;
 
     if (e4crypt_crypto_complete(DATA_MNT_POINT) == 0) {
-        if (e4crypt_set_user_policy(user_id, serial, system_ce_path)
-                || e4crypt_set_user_policy(user_id, serial, media_ce_path)
-                || e4crypt_set_user_policy(user_id, serial, user_ce_path)) {
-            return -1;
-        }
+        std::string ce_raw_ref, de_raw_ref;
+        if (!lookup_key_ref(s_ce_key_raw_refs, user_id, ce_raw_ref)) return -1;
+        if (!lookup_key_ref(s_de_key_raw_refs, user_id, de_raw_ref)) return -1;
+        if (!set_policy(ce_raw_ref, system_ce_path)) return -1;
+        if (!set_policy(ce_raw_ref, media_ce_path)) return -1;
+        if (!set_policy(ce_raw_ref, user_ce_path)) return -1;
+        if (!set_policy(de_raw_ref, user_de_path)) return -1;
+        // FIXME I thought there were more DE directories than this
     }
 
     return 0;
diff --git a/Ext4Crypt.h b/Ext4Crypt.h
index 3fb6f16..9005f4a 100644
--- a/Ext4Crypt.h
+++ b/Ext4Crypt.h
@@ -36,6 +36,7 @@
 int e4crypt_set_field(const char* path, const char* fieldname,
                       const char* value);
 
+int e4crypt_init_user0();
 int e4crypt_vold_create_user_key(userid_t user_id, int serial, bool ephemeral);
 int e4crypt_destroy_user_key(userid_t user_id);
 
diff --git a/cryptfs.c b/cryptfs.c
index 3aa3403..c1020cd 100644
--- a/cryptfs.c
+++ b/cryptfs.c
@@ -43,7 +43,9 @@
 #include <fs_mgr.h>
 #include <time.h>
 #include <math.h>
+#include <selinux/selinux.h>
 #include "cryptfs.h"
+#include "secontext.h"
 #define LOG_TAG "Cryptfs"
 #include "cutils/log.h"
 #include "cutils/properties.h"
@@ -1712,6 +1714,15 @@
         /* If that succeeded, then mount the decrypted filesystem */
         int retries = RETRY_MOUNT_ATTEMPTS;
         int mount_rc;
+
+        /*
+         * fs_mgr_do_mount runs fsck. Use setexeccon to run trusted
+         * partitions in the fsck domain.
+         */
+        if (setexeccon(secontextFsck())){
+            SLOGE("Failed to setexeccon");
+            return -1;
+        }
         while ((mount_rc = fs_mgr_do_mount(fstab, DATA_MNT_POINT,
                                            crypto_blkdev, 0))
                != 0) {
@@ -1733,9 +1744,16 @@
                 cryptfs_set_corrupt();
                 cryptfs_trigger_restart_min_framework();
                 SLOGI("Started framework to offer wipe");
+                if (setexeccon(NULL)) {
+                    SLOGE("Failed to setexeccon");
+                }
                 return -1;
             }
         }
+        if (setexeccon(NULL)) {
+            SLOGE("Failed to setexeccon");
+            return -1;
+        }
 
         property_set("vold.decrypt", "trigger_load_persist_props");
         /* Create necessary paths on /data */
diff --git a/secontext.cpp b/secontext.cpp
new file mode 100644
index 0000000..0529a30
--- /dev/null
+++ b/secontext.cpp
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2016 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 <Utils.h>
+#include "secontext.h"
+
+security_context_t secontextFsck()
+{
+    return android::vold::sFsckContext;
+}
diff --git a/secontext.h b/secontext.h
new file mode 100644
index 0000000..08ad48e
--- /dev/null
+++ b/secontext.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2016 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 _SECONTEXT_H_
+#define _SECONTEXT_H_
+
+#include <selinux/selinux.h>
+
+__BEGIN_DECLS
+security_context_t secontextFsck();
+__END_DECLS
+
+#endif