summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShawn Willden <swillden@google.com>2015-10-30 10:05:43 -0600
committerShawn Willden <swillden@google.com>2015-10-30 15:29:18 -0600
commitddab0bb51320af9f277d98a4e36e77ea527503e5 (patch)
treeba7399a7e3fc256b9757867e1dc08bb7909fda67
parent410ba59a76a8feb48ffb5bde3045ac6f76db0c36 (diff)
downloadandroid_system_security-ddab0bb51320af9f277d98a4e36e77ea527503e5.tar.gz
android_system_security-ddab0bb51320af9f277d98a4e36e77ea527503e5.tar.bz2
android_system_security-ddab0bb51320af9f277d98a4e36e77ea527503e5.zip
Limit maximum number of concurrent keystore operations.
If keystore is allowed to consume all 16 of the keymaster operation table slots, cryptfs may not be able to use keymaster to protect the disk encryption key during a password change. This CL prevents keystore from allowing more than 15 concurrent keystore operations, leaving one available for cyptfs. Bug: 25312003 Change-Id: I3bcae59c6a79d5f7d2e2f432251bb7b818f57581
-rw-r--r--keystore/keystore.cpp46
-rw-r--r--keystore/operation.h1
2 files changed, 35 insertions, 12 deletions
diff --git a/keystore/keystore.cpp b/keystore/keystore.cpp
index bb5a411..e466466 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;
@@ -2689,23 +2690,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);
@@ -2909,6 +2913,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);