Fix failure to save master key on new profile

New profiles use the master key of the parent user for keystore.
Unfortunately copyMasterKey only copies the key from the parent to the
user in memory but doesn't save it to disk, causing the child user to be
uninitialized after a reboot.

Bug: 23889443

(cherry picked from commit 79e0f6440aee69659bc01a0669a329dbaeaf471c)

Change-Id: I1f148fde3862d22292dfce217aacdc3f70f9c2ef
diff --git a/keystore/keystore.cpp b/keystore/keystore.cpp
index 0906abf..bb5a411 100644
--- a/keystore/keystore.cpp
+++ b/keystore/keystore.cpp
@@ -920,6 +920,38 @@
         }
         memcpy(mMasterKey, src->mMasterKey, MASTER_KEY_SIZE_BYTES);
         setupMasterKeys();
+        return copyMasterKeyFile(src);
+    }
+
+    ResponseCode copyMasterKeyFile(UserState* src) {
+        /* Copy the master key file to the new user.
+         * Unfortunately we don't have the src user's password so we cannot
+         * generate a new file with a new salt.
+         */
+        int in = TEMP_FAILURE_RETRY(open(src->getMasterKeyFileName(), O_RDONLY));
+        if (in < 0) {
+            return ::SYSTEM_ERROR;
+        }
+        blob rawBlob;
+        size_t length = readFully(in, (uint8_t*) &rawBlob, sizeof(rawBlob));
+        if (close(in) != 0) {
+            return ::SYSTEM_ERROR;
+        }
+        int out = TEMP_FAILURE_RETRY(open(mMasterKeyFile,
+                O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR));
+        if (out < 0) {
+            return ::SYSTEM_ERROR;
+        }
+        size_t outLength = writeFully(out, (uint8_t*) &rawBlob, length);
+        if (close(out) != 0) {
+            return ::SYSTEM_ERROR;
+        }
+        if (outLength != length) {
+            ALOGW("blob not fully written %zu != %zu", outLength, length);
+            unlink(mMasterKeyFile);
+            return ::SYSTEM_ERROR;
+        }
+
         return ::NO_ERROR;
     }
 
@@ -1980,10 +2012,12 @@
         }
         // Unconditionally clear the keystore, just to be safe.
         mKeyStore->resetUser(userId, false);
-
-        // If the user has a parent user then use the parent's
-        // masterkey/password, otherwise there's nothing to do.
         if (parentId != -1) {
+            // This profile must share the same master key password as the parent
+            // profile. Because the password of the parent profile is not known
+            // here, the best we can do is copy the parent's master key and master
+            // key file. This makes this profile use the same master key as the
+            // parent profile, forever.
             return mKeyStore->copyMasterKey(parentId, userId);
         } else {
             return ::NO_ERROR;
@@ -2021,7 +2055,17 @@
 
         State state = mKeyStore->getState(userId);
         if (state != ::STATE_LOCKED) {
-            ALOGI("calling unlock when not locked, ignoring.");
+            switch (state) {
+                case ::STATE_NO_ERROR:
+                    ALOGI("calling unlock when already unlocked, ignoring.");
+                    break;
+                case ::STATE_UNINITIALIZED:
+                    ALOGE("unlock called on uninitialized keystore.");
+                    break;
+                default:
+                    ALOGE("unlock called on keystore in unknown state: %d", state);
+                    break;
+            }
             return state;
         }