summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Janis Danisevskis <jdanis@google.com> 2020-03-27 11:26:10 -0700
committer Janis Danisevskis <jdanis@google.com> 2020-05-19 16:04:04 +0000
commit3230a4887bc0d32a5ee0e67c7ce056a26fadee1e (patch)
tree8d98664072461dbea108e3a42ca48c48ede9bac5
parenta543dfde92e33b0d067943c6d4f0a3149d822bc2 (diff)
Preserve interrupted state across waiting for future
A normal synchronous binder call would not be influenced by an interrupted thread. With the move to asynchronous keystore IPC we wait on a future which can throw an interrupted exception. The Java crypto API does not expect the implementation to throw interrupted exceptions though. So to preserve the expected behavior we wrap the Future.get() calls in a loop that handles the interrupted exception and sets the interrupted state after the get completed successfully. Bug: 147398412 Bug: 155254932 Test: atest android.keystore.cts.CipherTest#testEncryptsAndDecryptsInterrupted Change-Id: I066180e8028cc426fa1b3739fa007faa17c8c012 (cherry picked from commit 022c8ef71354aa059f8377acfe31e64880784da0)
-rw-r--r--keystore/java/android/security/KeyStore.java70
1 files changed, 43 insertions, 27 deletions
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index 9d0fe11be46b..88b614dc7eef 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -483,14 +483,14 @@ public class KeyStore {
mBinder.asBinder().linkToDeath(promise, 0);
int errorCode = mBinder.addRngEntropy(promise, data, flags);
if (errorCode == NO_ERROR) {
- return promise.getFuture().get().getErrorCode() == NO_ERROR;
+ return interruptedPreservingGet(promise.getFuture()).getErrorCode() == NO_ERROR;
} else {
return false;
}
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
return false;
- } catch (ExecutionException | InterruptedException e) {
+ } catch (ExecutionException e) {
Log.e(TAG, "AddRngEntropy completed with exception", e);
return false;
} finally {
@@ -548,7 +548,7 @@ public class KeyStore {
private int generateKeyInternal(String alias, KeymasterArguments args, byte[] entropy, int uid,
int flags, KeyCharacteristics outCharacteristics)
- throws RemoteException, ExecutionException, InterruptedException {
+ throws RemoteException, ExecutionException {
KeyCharacteristicsPromise promise = new KeyCharacteristicsPromise();
int error = NO_ERROR;
KeyCharacteristicsCallbackResult result = null;
@@ -559,7 +559,7 @@ public class KeyStore {
Log.e(TAG, "generateKeyInternal failed on request " + error);
return error;
}
- result = promise.getFuture().get();
+ result = interruptedPreservingGet(promise.getFuture());
} finally {
mBinder.asBinder().unlinkToDeath(promise, 0);
}
@@ -592,7 +592,7 @@ public class KeyStore {
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
return SYSTEM_ERROR;
- } catch (ExecutionException | InterruptedException e) {
+ } catch (ExecutionException e) {
Log.e(TAG, "generateKey completed with exception", e);
return SYSTEM_ERROR;
}
@@ -614,7 +614,7 @@ public class KeyStore {
int error = mBinder.getKeyCharacteristics(promise, alias, clientId, appId, uid);
if (error != NO_ERROR) return error;
- KeyCharacteristicsCallbackResult result = promise.getFuture().get();
+ KeyCharacteristicsCallbackResult result = interruptedPreservingGet(promise.getFuture());
error = result.getKeystoreResponse().getErrorCode();
if (error != NO_ERROR) return error;
@@ -625,7 +625,7 @@ public class KeyStore {
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
return SYSTEM_ERROR;
- } catch (ExecutionException | InterruptedException e) {
+ } catch (ExecutionException e) {
Log.e(TAG, "GetKeyCharacteristics completed with exception", e);
return SYSTEM_ERROR;
} finally {
@@ -640,14 +640,14 @@ public class KeyStore {
private int importKeyInternal(String alias, KeymasterArguments args, int format, byte[] keyData,
int uid, int flags, KeyCharacteristics outCharacteristics)
- throws RemoteException, ExecutionException, InterruptedException {
+ throws RemoteException, ExecutionException {
KeyCharacteristicsPromise promise = new KeyCharacteristicsPromise();
mBinder.asBinder().linkToDeath(promise, 0);
try {
int error = mBinder.importKey(promise, alias, args, format, keyData, uid, flags);
if (error != NO_ERROR) return error;
- KeyCharacteristicsCallbackResult result = promise.getFuture().get();
+ KeyCharacteristicsCallbackResult result = interruptedPreservingGet(promise.getFuture());
error = result.getKeystoreResponse().getErrorCode();
if (error != NO_ERROR) return error;
@@ -675,7 +675,7 @@ public class KeyStore {
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
return SYSTEM_ERROR;
- } catch (ExecutionException | InterruptedException e) {
+ } catch (ExecutionException e) {
Log.e(TAG, "ImportKey completed with exception", e);
return SYSTEM_ERROR;
}
@@ -747,7 +747,7 @@ public class KeyStore {
String wrappingKeyAlias,
byte[] maskingKey, KeymasterArguments args, long rootSid, long fingerprintSid,
KeyCharacteristics outCharacteristics)
- throws RemoteException, ExecutionException, InterruptedException {
+ throws RemoteException, ExecutionException {
KeyCharacteristicsPromise promise = new KeyCharacteristicsPromise();
mBinder.asBinder().linkToDeath(promise, 0);
try {
@@ -755,7 +755,7 @@ public class KeyStore {
wrappingKeyAlias, maskingKey, args, rootSid, fingerprintSid);
if (error != NO_ERROR) return error;
- KeyCharacteristicsCallbackResult result = promise.getFuture().get();
+ KeyCharacteristicsCallbackResult result = interruptedPreservingGet(promise.getFuture());
error = result.getKeystoreResponse().getErrorCode();
if (error != NO_ERROR) return error;
@@ -786,7 +786,7 @@ public class KeyStore {
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
return SYSTEM_ERROR;
- } catch (ExecutionException | InterruptedException e) {
+ } catch (ExecutionException e) {
Log.e(TAG, "ImportWrappedKey completed with exception", e);
return SYSTEM_ERROR;
}
@@ -818,14 +818,14 @@ public class KeyStore {
appId = appId != null ? appId : new KeymasterBlob(new byte[0]);
int error = mBinder.exportKey(promise, alias, format, clientId, appId, uid);
if (error == NO_ERROR) {
- return promise.getFuture().get();
+ return interruptedPreservingGet(promise.getFuture());
} else {
return new ExportResult(error);
}
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
return null;
- } catch (ExecutionException | InterruptedException e) {
+ } catch (ExecutionException e) {
Log.e(TAG, "ExportKey completed with exception", e);
return null;
} finally {
@@ -864,14 +864,14 @@ public class KeyStore {
int errorCode = mBinder.begin(promise, getToken(), alias, purpose, pruneable, args,
entropy, uid);
if (errorCode == NO_ERROR) {
- return promise.getFuture().get();
+ return interruptedPreservingGet(promise.getFuture());
} else {
return new OperationResult(errorCode);
}
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
return null;
- } catch (ExecutionException | InterruptedException e) {
+ } catch (ExecutionException e) {
Log.e(TAG, "Begin completed with exception", e);
return null;
} finally {
@@ -894,14 +894,14 @@ public class KeyStore {
input = input != null ? input : new byte[0];
int errorCode = mBinder.update(promise, token, arguments, input);
if (errorCode == NO_ERROR) {
- return promise.getFuture().get();
+ return interruptedPreservingGet(promise.getFuture());
} else {
return new OperationResult(errorCode);
}
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
return null;
- } catch (ExecutionException | InterruptedException e) {
+ } catch (ExecutionException e) {
Log.e(TAG, "Update completed with exception", e);
return null;
} finally {
@@ -930,14 +930,14 @@ public class KeyStore {
signature = signature != null ? signature : new byte[0];
int errorCode = mBinder.finish(promise, token, arguments, input, signature, entropy);
if (errorCode == NO_ERROR) {
- return promise.getFuture().get();
+ return interruptedPreservingGet(promise.getFuture());
} else {
return new OperationResult(errorCode);
}
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
return null;
- } catch (ExecutionException | InterruptedException e) {
+ } catch (ExecutionException e) {
Log.e(TAG, "Finish completed with exception", e);
return null;
} finally {
@@ -972,14 +972,14 @@ public class KeyStore {
mBinder.asBinder().linkToDeath(promise, 0);
int errorCode = mBinder.abort(promise, token);
if (errorCode == NO_ERROR) {
- return promise.getFuture().get().getErrorCode();
+ return interruptedPreservingGet(promise.getFuture()).getErrorCode();
} else {
return errorCode;
}
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
return SYSTEM_ERROR;
- } catch (ExecutionException | InterruptedException e) {
+ } catch (ExecutionException e) {
Log.e(TAG, "Abort completed with exception", e);
return SYSTEM_ERROR;
} finally {
@@ -1135,7 +1135,7 @@ public class KeyStore {
}
int error = mBinder.attestKey(promise, alias, params);
if (error != NO_ERROR) return error;
- KeyAttestationCallbackResult result = promise.getFuture().get();
+ KeyAttestationCallbackResult result = interruptedPreservingGet(promise.getFuture());
error = result.getKeystoreResponse().getErrorCode();
if (error == NO_ERROR) {
outChain.shallowCopyFrom(result.getCertificateChain());
@@ -1144,7 +1144,7 @@ public class KeyStore {
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
return SYSTEM_ERROR;
- } catch (ExecutionException | InterruptedException e) {
+ } catch (ExecutionException e) {
Log.e(TAG, "AttestKey completed with exception", e);
return SYSTEM_ERROR;
} finally {
@@ -1164,7 +1164,7 @@ public class KeyStore {
}
int error = mBinder.attestDeviceIds(promise, params);
if (error != NO_ERROR) return error;
- KeyAttestationCallbackResult result = promise.getFuture().get();
+ KeyAttestationCallbackResult result = interruptedPreservingGet(promise.getFuture());
error = result.getKeystoreResponse().getErrorCode();
if (error == NO_ERROR) {
outChain.shallowCopyFrom(result.getCertificateChain());
@@ -1173,7 +1173,7 @@ public class KeyStore {
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
return SYSTEM_ERROR;
- } catch (ExecutionException | InterruptedException e) {
+ } catch (ExecutionException e) {
Log.e(TAG, "AttestDevicdeIds completed with exception", e);
return SYSTEM_ERROR;
} finally {
@@ -1387,4 +1387,20 @@ public class KeyStore {
int errorCode) {
return getInvalidKeyException(keystoreKeyAlias, uid, getKeyStoreException(errorCode));
}
+
+ private static <R> R interruptedPreservingGet(CompletableFuture<R> future)
+ throws ExecutionException {
+ boolean wasInterrupted = false;
+ while (true) {
+ try {
+ R result = future.get();
+ if (wasInterrupted) {
+ Thread.currentThread().interrupt();
+ }
+ return result;
+ } catch (InterruptedException e) {
+ wasInterrupted = true;
+ }
+ }
+ }
}