Merge "keystore: Add SOTER support in keystore"
diff --git a/keystore/keystore.cpp b/keystore/keystore.cpp
index 4a4e3ab..e9fa408 100644
--- a/keystore/keystore.cpp
+++ b/keystore/keystore.cpp
@@ -79,6 +79,7 @@
 #define KEY_SIZE        ((NAME_MAX - 15) / 2)
 #define VALUE_SIZE      32768
 #define PASSWORD_SIZE   VALUE_SIZE
+const size_t MAX_OPERATIONS = 15;
 
 using keymaster::SoftKeymasterDevice;
 
@@ -920,6 +921,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;
     }
 
@@ -1989,10 +2022,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;
@@ -2030,7 +2065,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;
         }
 
@@ -2679,23 +2724,26 @@
         }
 
         keymaster_key_param_set_t outParams = {NULL, 0};
+
+        // If there are more than MAX_OPERATIONS, abort the oldest operation that was started as
+        // pruneable.
+        while (mOperationMap.getOperationCount() >= MAX_OPERATIONS) {
+            ALOGD("Reached or exceeded concurrent operations limit");
+            if (!pruneOperation()) {
+                break;
+            }
+        }
+
         err = dev->begin(dev, purpose, &key, &inParams, &outParams, &handle);
+        if (err != KM_ERROR_OK) {
+            ALOGE("Got error %d from begin()", err);
+        }
 
         // If there are too many operations abort the oldest operation that was
         // started as pruneable and try again.
         while (err == KM_ERROR_TOO_MANY_OPERATIONS && mOperationMap.hasPruneableOperation()) {
-            sp<IBinder> oldest = mOperationMap.getOldestPruneableOperation();
-            ALOGD("Ran out of operation handles, trying to prune %p", oldest.get());
-
-            // We mostly ignore errors from abort() below because all we care about is whether at
-            // least one pruneable operation has been removed.
-            size_t op_count_before = mOperationMap.getPruneableOperationCount();
-            int abort_error = abort(oldest);
-            size_t op_count_after = mOperationMap.getPruneableOperationCount();
-            if (op_count_after >= op_count_before) {
-                // Failed to create space for a new operation. Bail to avoid an infinite loop.
-                ALOGE("Failed to remove pruneable operation %p, error: %d",
-                      oldest.get(), abort_error);
+            ALOGE("Ran out of operation handles");
+            if (!pruneOperation()) {
                 break;
             }
             err = dev->begin(dev, purpose, &key, &inParams, &outParams, &handle);
@@ -2899,6 +2947,24 @@
     static const int32_t UID_SELF = -1;
 
     /**
+     * Prune the oldest pruneable operation.
+     */
+    inline bool pruneOperation() {
+        sp<IBinder> oldest = mOperationMap.getOldestPruneableOperation();
+        ALOGD("Trying to prune operation %p", oldest.get());
+        size_t op_count_before_abort = mOperationMap.getOperationCount();
+        // We mostly ignore errors from abort() because all we care about is whether at least
+        // one operation has been removed.
+        int abort_error = abort(oldest);
+        if (mOperationMap.getOperationCount() >= op_count_before_abort) {
+            ALOGE("Failed to abort pruneable operation %p, error: %d", oldest.get(),
+                  abort_error);
+            return false;
+        }
+        return true;
+    }
+
+    /**
      * Get the effective target uid for a binder operation that takes an
      * optional uid as the target.
      */
diff --git a/keystore/operation.h b/keystore/operation.h
index 01c4dbe..d8d1b18 100644
--- a/keystore/operation.h
+++ b/keystore/operation.h
@@ -57,6 +57,7 @@
                       const keymaster_key_characteristics_t** outCharacteristics);
     bool removeOperation(sp<IBinder> token);
     bool hasPruneableOperation() const;
+    size_t getOperationCount() const { return mMap.size(); }
     size_t getPruneableOperationCount() const;
     bool getOperationAuthToken(sp<IBinder> token, const hw_auth_token_t** outToken);
     bool setOperationAuthToken(sp<IBinder> token, const hw_auth_token_t* authToken);