summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteve Kondik <steve@cyngn.com>2015-12-08 03:26:56 -0800
committerSteve Kondik <steve@cyngn.com>2015-12-08 03:26:56 -0800
commit09f3036fd2eb2f4a8c29cf9a3519991b413a0904 (patch)
tree6f5cc49958abade0083f95bd067c18b169504ed5
parent28e9852ad361927c33a3b76fae95474393be0e96 (diff)
parent1f76969bd8b6179f256dafb938bb458bc997c23d (diff)
downloadandroid_system_security-09f3036fd2eb2f4a8c29cf9a3519991b413a0904.tar.gz
android_system_security-09f3036fd2eb2f4a8c29cf9a3519991b413a0904.tar.bz2
android_system_security-09f3036fd2eb2f4a8c29cf9a3519991b413a0904.zip
Merge tag 'android-6.0.1_r3' of https://android.googlesource.com/platform/system/security into HEADstable/cm-13.0-ZNH0E
Android 6.0.1 release 3
-rw-r--r--keystore/keystore.cpp98
-rw-r--r--keystore/operation.h1
2 files changed, 83 insertions, 16 deletions
diff --git a/keystore/keystore.cpp b/keystore/keystore.cpp
index 9c1e92c..8f276f5 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 @@ public:
}
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 @@ public:
}
// 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 @@ public:
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;
}
@@ -2654,23 +2699,26 @@ public:
}
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);
@@ -2874,6 +2922,24 @@ private:
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 @@ public:
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);