keystore: command to clear all keys for UID
Add ability for system UID to clear all entries for a different UID.
(cherry picked from commit a9bb549868035e05450a9b918f8d7de9deca5343)
Bug: 3020069
Change-Id: Ibd5ce287f024b89df3dd7bfc3a4e5f979a34c75c
diff --git a/keystore/keystore.cpp b/keystore/keystore.cpp
index 438a8e4..a413948 100644
--- a/keystore/keystore.cpp
+++ b/keystore/keystore.cpp
@@ -137,6 +137,7 @@
P_VERIFY = 1 << 12,
P_GRANT = 1 << 13,
P_DUPLICATE = 1 << 14,
+ P_CLEAR_UID = 1 << 15,
} perm_t;
static struct user_euid {
@@ -1656,6 +1657,70 @@
return mKeyStore->isHardwareBacked() ? 1 : 0;
}
+ int32_t clear_uid(int64_t targetUid) {
+ uid_t callingUid = IPCThreadState::self()->getCallingUid();
+ if (!has_permission(callingUid, P_CLEAR_UID)) {
+ ALOGW("permission denied for %d: clear_uid", callingUid);
+ return ::PERMISSION_DENIED;
+ }
+
+ State state = mKeyStore->getState();
+ if (!isKeystoreUnlocked(state)) {
+ ALOGD("calling clear_uid in state: %d", state);
+ return state;
+ }
+
+ const keymaster_device_t* device = mKeyStore->getDevice();
+ if (device == NULL) {
+ return ::SYSTEM_ERROR;
+ }
+
+ DIR* dir = opendir(".");
+ if (!dir) {
+ return ::SYSTEM_ERROR;
+ }
+
+ char filename[NAME_MAX];
+ int n = snprintf(filename, NAME_MAX, "%u_", static_cast<uid_t>(targetUid));
+ char *end = &filename[n];
+
+ ResponseCode rc = ::NO_ERROR;
+
+ struct dirent* file;
+ while ((file = readdir(dir)) != NULL) {
+ if (strncmp(filename, file->d_name, n)) {
+ continue;
+ }
+
+ String8 file8(&file->d_name[n]);
+ encode_key(end, file8);
+
+ Blob keyBlob;
+ if (mKeyStore->get(filename, &keyBlob, ::TYPE_ANY) != ::NO_ERROR) {
+ ALOGW("couldn't open %s", filename);
+ continue;
+ }
+
+ if (keyBlob.getType() == ::TYPE_KEY_PAIR) {
+ // A device doesn't have to implement delete_keypair.
+ if (device->delete_keypair != NULL) {
+ if (device->delete_keypair(device, keyBlob.getValue(), keyBlob.getLength())) {
+ rc = ::SYSTEM_ERROR;
+ ALOGW("device couldn't remove %s", filename);
+ }
+ }
+ }
+
+ if (unlink(filename) && errno != ENOENT) {
+ rc = ::SYSTEM_ERROR;
+ ALOGW("couldn't unlink %s", filename);
+ }
+ }
+ closedir(dir);
+
+ return rc;
+ }
+
private:
inline bool isKeystoreUnlocked(State state) {
switch (state) {