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/IKeystoreService.cpp b/keystore/IKeystoreService.cpp
index 520d266..e899c12 100644
--- a/keystore/IKeystoreService.cpp
+++ b/keystore/IKeystoreService.cpp
@@ -528,6 +528,25 @@
}
return ret;
}
+
+ virtual int32_t clear_uid(int64_t uid)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
+ data.writeInt64(uid);
+ status_t status = remote()->transact(BnKeystoreService::CLEAR_UID, data, &reply);
+ if (status != NO_ERROR) {
+ ALOGD("clear_uid() could not contact remote: %d\n", status);
+ return -1;
+ }
+ int32_t err = reply.readExceptionCode();
+ int32_t ret = reply.readInt32();
+ if (err < 0) {
+ ALOGD("clear_uid() caught exception %d\n", err);
+ return -1;
+ }
+ return ret;
+ }
};
IMPLEMENT_META_INTERFACE(KeystoreService, "android.security.keystore");
@@ -797,6 +816,14 @@
reply->writeInt32(ret);
return NO_ERROR;
}
+ case CLEAR_UID: {
+ CHECK_INTERFACE(IKeystoreService, data, reply);
+ int64_t uid = data.readInt64();
+ int32_t ret = clear_uid(uid);
+ reply->writeNoException();
+ reply->writeInt32(ret);
+ return NO_ERROR;
+ }
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/keystore/include/keystore/IKeystoreService.h b/keystore/include/keystore/IKeystoreService.h
index 6b2f406..050dd5b 100644
--- a/keystore/include/keystore/IKeystoreService.h
+++ b/keystore/include/keystore/IKeystoreService.h
@@ -51,6 +51,7 @@
GETMTIME = IBinder::FIRST_CALL_TRANSACTION + 19,
DUPLICATE = IBinder::FIRST_CALL_TRANSACTION + 20,
IS_HARDWARE_BACKED = IBinder::FIRST_CALL_TRANSACTION + 21,
+ CLEAR_UID = IBinder::FIRST_CALL_TRANSACTION + 22,
};
DECLARE_META_INTERFACE(KeystoreService);
@@ -101,6 +102,8 @@
int32_t destUid) = 0;
virtual int32_t is_hardware_backed() = 0;
+
+ virtual int32_t clear_uid(int64_t uid) = 0;
};
// ----------------------------------------------------------------------------
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) {