Add buffer wrap checks and disable throwing of std::bad_alloc.
Android is built with exceptions disabled, but "operator new" and
"operator new[]" still throw std::bad_alloc on failure rather than
returning new. In general this is a good thing, because it will cause
an immediate crash of the process rather than assigning a null pointer
which is probably not checked. But most memory allocations in Keymaster
are checked, because it's written to run in an environment where new
does *not* throw. This CL updates the code to explicitly use the
non-throwing new.
A handful of throwing news remain, but only in places where a crash on
failure is appropriate.
In addition, this CL also inserts buffer wrap checks in key locations
and changes the development-machine Makefile to build in 32-bit mode, to
make memory problems more apparent.
Bug: 21888473
Change-Id: I8ebc5ec12053e4f5274f6f57ce312abc10611cef
diff --git a/ocb_utils.cpp b/ocb_utils.cpp
index 171d07e..7038da0 100644
--- a/ocb_utils.cpp
+++ b/ocb_utils.cpp
@@ -18,6 +18,8 @@
#include <assert.h>
+#include <new>
+
#include <openssl/aes.h>
#include <openssl/sha.h>
@@ -50,7 +52,7 @@
size_t* derivation_data_length) {
*derivation_data_length =
hidden.SerializedSize() + hw_enforced.SerializedSize() + sw_enforced.SerializedSize();
- derivation_data->reset(new uint8_t[*derivation_data_length]);
+ derivation_data->reset(new (std::nothrow) uint8_t[*derivation_data_length]);
if (!derivation_data->get())
return KM_ERROR_MEMORY_ALLOCATION_FAILED;
@@ -76,9 +78,13 @@
return error;
SHA256_CTX sha256_ctx;
- UniquePtr<uint8_t[]> hash_buf(new uint8_t[SHA256_DIGEST_LENGTH]);
+ UniquePtr<uint8_t[]> hash_buf(new (std::nothrow) uint8_t[SHA256_DIGEST_LENGTH]);
+ if (!hash_buf.get())
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
Eraser hash_eraser(hash_buf.get(), SHA256_DIGEST_LENGTH);
- UniquePtr<uint8_t[]> derived_key(new uint8_t[AES_BLOCK_SIZE]);
+ UniquePtr<uint8_t[]> derived_key(new (std::nothrow) uint8_t[AES_BLOCK_SIZE]);
+ if (!derived_key.get())
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
Eraser derived_key_eraser(derived_key.get(), AES_BLOCK_SIZE);
if (!ctx->get() || !hash_buf.get() || !derived_key.get())
@@ -120,13 +126,15 @@
return KM_ERROR_INVALID_ARGUMENT;
AeCtx ctx;
+ if (!ctx.get())
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
keymaster_error_t error =
InitializeKeyWrappingContext(hw_enforced, sw_enforced, hidden, master_key, &ctx);
if (error != KM_ERROR_OK)
return error;
- ciphertext->Reset(plaintext.key_material_size);
- if (!ciphertext->key_material)
+ if (!ciphertext->Reset(plaintext.key_material_size))
return KM_ERROR_MEMORY_ALLOCATION_FAILED;
int ae_err = ae_encrypt(ctx.get(), nonce.peek_read(), plaintext.key_material,
@@ -137,7 +145,8 @@
LOG_E("Error %d while encrypting key", ae_err);
return KM_ERROR_UNKNOWN_ERROR;
}
- tag->advance_write(OCB_TAG_LENGTH);
+ if (!tag->advance_write(OCB_TAG_LENGTH))
+ return KM_ERROR_UNKNOWN_ERROR;
assert(ae_err == static_cast<int>(plaintext.key_material_size));
return KM_ERROR_OK;
}
@@ -153,13 +162,15 @@
return KM_ERROR_INVALID_ARGUMENT;
AeCtx ctx;
+ if (!ctx.get())
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
keymaster_error_t error =
InitializeKeyWrappingContext(hw_enforced, sw_enforced, hidden, master_key, &ctx);
if (error != KM_ERROR_OK)
return error;
- plaintext->Reset(ciphertext.key_material_size);
- if (!plaintext->key_material)
+ if (!plaintext->Reset(ciphertext.key_material_size))
return KM_ERROR_MEMORY_ALLOCATION_FAILED;
int ae_err = ae_decrypt(ctx.get(), nonce.peek_read(), ciphertext.key_material,