Mark UNSAFE_BUFFERS in cpdf_{crypto,security}_handler.cpp
Mark large sections of code without any attempt at re-writing
Bug: pdfium:2154
Change-Id: I5edad8429920cc4b3b07e0bc415e2dd52bbafe26
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/119210
Reviewed-by: Lei Zhang <thestig@chromium.org>
Reviewed-by: Thomas Sepez <tsepez@google.com>
Commit-Queue: Tom Sepez <tsepez@chromium.org>
diff --git a/core/fpdfapi/parser/cpdf_crypto_handler.cpp b/core/fpdfapi/parser/cpdf_crypto_handler.cpp
index 7851f3a..7ce9efa 100644
--- a/core/fpdfapi/parser/cpdf_crypto_handler.cpp
+++ b/core/fpdfapi/parser/cpdf_crypto_handler.cpp
@@ -4,11 +4,6 @@
// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
-#if defined(UNSAFE_BUFFERS_BUILD)
-// TODO(crbug.com/pdfium/2153): resolve buffer safety issues.
-#pragma allow_unsafe_buffers
-#endif
-
#include "core/fpdfapi/parser/cpdf_crypto_handler.h"
#include <time.h>
@@ -57,51 +52,54 @@
pdfium::span<const uint8_t> source,
uint8_t* dest_buf,
size_t& dest_size) const {
- if (m_Cipher == Cipher::kNone) {
- FXSYS_memcpy(dest_buf, source.data(), source.size());
- return;
- }
- uint8_t realkey[16];
- size_t realkeylen = sizeof(realkey);
- if (m_Cipher != Cipher::kAES || m_KeyLen != 32) {
- uint8_t key1[32];
- PopulateKey(objnum, gennum, key1);
- if (m_Cipher == Cipher::kAES) {
- FXSYS_memcpy(key1 + m_KeyLen + 5, "sAlT", 4);
- }
- size_t len = m_Cipher == Cipher::kAES ? m_KeyLen + 9 : m_KeyLen + 5;
- CRYPT_MD5Generate(pdfium::make_span(key1).first(len), realkey);
- realkeylen = std::min(m_KeyLen + 5, sizeof(realkey));
- }
- if (m_Cipher == Cipher::kAES) {
- CRYPT_AESSetKey(m_pAESContext.get(),
- m_KeyLen == 32 ? m_EncryptKey.data() : realkey, m_KeyLen);
- uint8_t iv[16];
- for (int i = 0; i < 16; i++) {
- iv[i] = (uint8_t)rand();
- }
- CRYPT_AESSetIV(m_pAESContext.get(), iv);
- FXSYS_memcpy(dest_buf, iv, 16);
- int nblocks = source.size() / 16;
- CRYPT_AESEncrypt(m_pAESContext.get(), dest_buf + 16, source.data(),
- nblocks * 16);
- uint8_t padding[16];
- FXSYS_memcpy(padding, source.data() + nblocks * 16, source.size() % 16);
- FXSYS_memset(padding + source.size() % 16, 16 - source.size() % 16,
- 16 - source.size() % 16);
- CRYPT_AESEncrypt(m_pAESContext.get(), dest_buf + nblocks * 16 + 16, padding,
- 16);
- dest_size = 32 + nblocks * 16;
- } else {
- DCHECK_EQ(dest_size, source.size());
- if (dest_buf != source.data()) {
+ // TODO(crbug.com/pdfium/2155): investigate safety.
+ UNSAFE_BUFFERS({
+ if (m_Cipher == Cipher::kNone) {
FXSYS_memcpy(dest_buf, source.data(), source.size());
+ return;
}
- // SAFETY: caller ensures that dest_buf points to at least dest_size bytes.
- CRYPT_ArcFourCryptBlock(
- UNSAFE_BUFFERS(pdfium::make_span(dest_buf, dest_size)),
- pdfium::make_span(realkey).first(realkeylen));
- }
+ uint8_t realkey[16];
+ size_t realkeylen = sizeof(realkey);
+ if (m_Cipher != Cipher::kAES || m_KeyLen != 32) {
+ uint8_t key1[32];
+ PopulateKey(objnum, gennum, key1);
+ if (m_Cipher == Cipher::kAES) {
+ FXSYS_memcpy(key1 + m_KeyLen + 5, "sAlT", 4);
+ }
+ size_t len = m_Cipher == Cipher::kAES ? m_KeyLen + 9 : m_KeyLen + 5;
+ CRYPT_MD5Generate(pdfium::make_span(key1).first(len), realkey);
+ realkeylen = std::min(m_KeyLen + 5, sizeof(realkey));
+ }
+ if (m_Cipher == Cipher::kAES) {
+ CRYPT_AESSetKey(m_pAESContext.get(),
+ m_KeyLen == 32 ? m_EncryptKey.data() : realkey, m_KeyLen);
+ uint8_t iv[16];
+ for (int i = 0; i < 16; i++) {
+ iv[i] = (uint8_t)rand();
+ }
+ CRYPT_AESSetIV(m_pAESContext.get(), iv);
+ FXSYS_memcpy(dest_buf, iv, 16);
+ int nblocks = source.size() / 16;
+ CRYPT_AESEncrypt(m_pAESContext.get(), dest_buf + 16, source.data(),
+ nblocks * 16);
+ uint8_t padding[16];
+ FXSYS_memcpy(padding, source.data() + nblocks * 16, source.size() % 16);
+ FXSYS_memset(padding + source.size() % 16, 16 - source.size() % 16,
+ 16 - source.size() % 16);
+ CRYPT_AESEncrypt(m_pAESContext.get(), dest_buf + nblocks * 16 + 16,
+ padding, 16);
+ dest_size = 32 + nblocks * 16;
+ } else {
+ DCHECK_EQ(dest_size, source.size());
+ if (dest_buf != source.data()) {
+ FXSYS_memcpy(dest_buf, source.data(), source.size());
+ }
+ // SAFETY: caller ensures that dest_buf points to at least dest_size
+ // bytes.
+ CRYPT_ArcFourCryptBlock(pdfium::make_span(dest_buf, dest_size),
+ pdfium::make_span(realkey).first(realkeylen));
+ }
+ });
}
struct AESCryptContext {
@@ -125,8 +123,10 @@
uint8_t key1[48];
PopulateKey(objnum, gennum, key1);
- if (m_Cipher == Cipher::kAES)
- FXSYS_memcpy(key1 + m_KeyLen + 5, "sAlT", 4);
+ if (m_Cipher == Cipher::kAES) {
+ // TODO(crbug.com/pdfium/2155): investigate safety.
+ UNSAFE_BUFFERS(FXSYS_memcpy(key1 + m_KeyLen + 5, "sAlT", 4));
+ }
uint8_t realkey[16];
size_t len = m_Cipher == Cipher::kAES ? m_KeyLen + 9 : m_KeyLen + 5;
@@ -171,8 +171,9 @@
if (copy_size > src_left) {
copy_size = src_left;
}
- FXSYS_memcpy(pContext->m_Block + pContext->m_BlockOffset,
- source.data() + src_off, copy_size);
+ // TODO(crbug.com/pdfium/2155): investigate safety.
+ UNSAFE_BUFFERS(FXSYS_memcpy(pContext->m_Block + pContext->m_BlockOffset,
+ source.data() + src_off, copy_size));
src_off += copy_size;
src_left -= copy_size;
pContext->m_BlockOffset += copy_size;
@@ -333,11 +334,13 @@
DCHECK(cipher != Cipher::kAES2 || keylen == 32);
DCHECK(cipher != Cipher::kRC4 || (keylen >= 5 && keylen <= 16));
- if (m_Cipher != Cipher::kNone)
- FXSYS_memcpy(m_EncryptKey.data(), key, m_KeyLen);
-
- if (m_Cipher == Cipher::kAES)
+ if (m_Cipher != Cipher::kNone) {
+ // TODO(crbug.com/pdfium/2155): investigate safety.
+ UNSAFE_BUFFERS(FXSYS_memcpy(m_EncryptKey.data(), key, m_KeyLen));
+ }
+ if (m_Cipher == Cipher::kAES) {
m_pAESContext.reset(FX_Alloc(CRYPT_aes_context, 1));
+ }
}
CPDF_CryptoHandler::~CPDF_CryptoHandler() = default;
@@ -345,10 +348,13 @@
void CPDF_CryptoHandler::PopulateKey(uint32_t objnum,
uint32_t gennum,
uint8_t* key) const {
- FXSYS_memcpy(key, m_EncryptKey.data(), m_KeyLen);
- key[m_KeyLen + 0] = (uint8_t)objnum;
- key[m_KeyLen + 1] = (uint8_t)(objnum >> 8);
- key[m_KeyLen + 2] = (uint8_t)(objnum >> 16);
- key[m_KeyLen + 3] = (uint8_t)gennum;
- key[m_KeyLen + 4] = (uint8_t)(gennum >> 8);
+ // TODO(crbug.com/pdfium/2155): investigate safety.
+ UNSAFE_BUFFERS({
+ FXSYS_memcpy(key, m_EncryptKey.data(), m_KeyLen);
+ key[m_KeyLen + 0] = (uint8_t)objnum;
+ key[m_KeyLen + 1] = (uint8_t)(objnum >> 8);
+ key[m_KeyLen + 2] = (uint8_t)(objnum >> 16);
+ key[m_KeyLen + 3] = (uint8_t)gennum;
+ key[m_KeyLen + 4] = (uint8_t)(gennum >> 8);
+ });
}
diff --git a/core/fpdfapi/parser/cpdf_security_handler.cpp b/core/fpdfapi/parser/cpdf_security_handler.cpp
index c932d63..9145b00 100644
--- a/core/fpdfapi/parser/cpdf_security_handler.cpp
+++ b/core/fpdfapi/parser/cpdf_security_handler.cpp
@@ -4,11 +4,6 @@
// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
-#if defined(UNSAFE_BUFFERS_BUILD)
-// TODO(crbug.com/pdfium/2153): resolve buffer safety issues.
-#pragma allow_unsafe_buffers
-#endif
-
#include "core/fpdfapi/parser/cpdf_security_handler.h"
#include <stdint.h>
@@ -44,10 +39,13 @@
DCHECK_EQ(sizeof(kDefaultPasscode), output.size());
size_t len = std::min(password.GetLength(), output.size());
size_t remaining = output.size() - len;
- FXSYS_memcpy(output.data(), password.unsigned_str(), len);
- if (remaining) {
- FXSYS_memcpy(&output[len], kDefaultPasscode, remaining);
- }
+ // TODO(crbug.com/pdfium/2155): investigate safety.
+ UNSAFE_BUFFERS({
+ FXSYS_memcpy(output.data(), password.unsigned_str(), len);
+ if (remaining) {
+ FXSYS_memcpy(&output[len], kDefaultPasscode, remaining);
+ }
+ });
}
void CalcEncryptKey(const CPDF_Dictionary* pEncrypt,
@@ -80,8 +78,11 @@
CRYPT_MD5Generate(pdfium::make_span(digest).first(copy_len), digest);
}
}
- FXSYS_memset(key, 0, keylen);
- FXSYS_memcpy(key, digest, copy_len);
+ // TODO(crbug.com/pdfium/2155): investigate safety.
+ UNSAFE_BUFFERS({
+ FXSYS_memset(key, 0, keylen);
+ FXSYS_memcpy(key, digest, copy_len);
+ });
}
bool IsValidKeyLengthForCipher(CPDF_CryptoHandler::Cipher cipher,
@@ -127,7 +128,8 @@
DataVector<uint8_t> inter_digest;
uint8_t* input = digest;
uint8_t* key = input;
- uint8_t* iv = input + 16;
+ // TODO(crbug.com/pdfium/2155): investigate safety.
+ uint8_t* iv = UNSAFE_BUFFERS(input + 16);
int i = 0;
size_t block_size = 32;
CRYPT_aes_context aes = {};
@@ -140,12 +142,15 @@
auto encrypted_output_span = pdfium::make_span(encrypted_output);
DataVector<uint8_t> content;
for (int j = 0; j < 64; ++j) {
- content.insert(std::end(content), password.unsigned_str(),
- password.unsigned_str() + password.GetLength());
- content.insert(std::end(content), input, input + block_size);
- if (vector) {
- content.insert(std::end(content), vector, vector + 48);
- }
+ // TODO(crbug.com/pdfium/2155): investigate safety.
+ UNSAFE_BUFFERS({
+ content.insert(std::end(content), password.unsigned_str(),
+ password.unsigned_str() + password.GetLength());
+ content.insert(std::end(content), input, input + block_size);
+ if (vector) {
+ content.insert(std::end(content), vector, vector + 48);
+ }
+ });
}
CRYPT_AESSetKey(&aes, key, 16);
CRYPT_AESSetIV(&aes, iv);
@@ -179,11 +184,13 @@
encrypted_output_span.size(), input);
}
key = input;
- iv = input + 16;
+ // TODO(crbug.com/pdfium/2155): investigate safety.
+ iv = UNSAFE_BUFFERS(input + 16);
++i;
} while (i < 64 || i - 32 < encrypted_output.back());
if (hash) {
- FXSYS_memcpy(hash, input, 32);
+ // TODO(crbug.com/pdfium/2155): investigate safety.
+ UNSAFE_BUFFERS(FXSYS_memcpy(hash, input, 32));
}
}
@@ -343,12 +350,14 @@
CRYPT_sha2_context sha;
uint8_t digest[32];
if (m_Revision >= 6) {
- Revision6_Hash(password, (const uint8_t*)pkey + 32,
+ // TODO(crbug.com/pdfium/2155): investigate safety.
+ Revision6_Hash(password, UNSAFE_BUFFERS((const uint8_t*)pkey + 32),
bOwner ? ukey.unsigned_str() : nullptr, digest);
} else {
CRYPT_SHA256Start(&sha);
CRYPT_SHA256Update(&sha, password.unsigned_str(), password.GetLength());
- CRYPT_SHA256Update(&sha, pkey + 32, 8);
+ // TODO(crbug.com/pdfium/2155): investigate safety.
+ CRYPT_SHA256Update(&sha, UNSAFE_BUFFERS(pkey + 32), 8);
if (bOwner)
CRYPT_SHA256Update(&sha, ukey.unsigned_str(), 48);
CRYPT_SHA256Finish(&sha, digest);
@@ -357,12 +366,14 @@
return false;
if (m_Revision >= 6) {
- Revision6_Hash(password, (const uint8_t*)pkey + 40,
+ // TODO(crbug.com/pdfium/2155): investigate safety.
+ Revision6_Hash(password, UNSAFE_BUFFERS((const uint8_t*)pkey + 40),
bOwner ? ukey.unsigned_str() : nullptr, digest);
} else {
CRYPT_SHA256Start(&sha);
CRYPT_SHA256Update(&sha, password.unsigned_str(), password.GetLength());
- CRYPT_SHA256Update(&sha, pkey + 40, 8);
+ // TODO(crbug.com/pdfium/2155): investigate safety.
+ CRYPT_SHA256Update(&sha, UNSAFE_BUFFERS(pkey + 40), 8);
if (bOwner)
CRYPT_SHA256Update(&sha, ukey.unsigned_str(), 48);
CRYPT_SHA256Finish(&sha, digest);
@@ -385,7 +396,8 @@
uint8_t perms_buf[16] = {};
size_t copy_len =
std::min(sizeof(perms_buf), static_cast<size_t>(perms.GetLength()));
- FXSYS_memcpy(perms_buf, perms.unsigned_str(), copy_len);
+ // TODO(crbug.com/pdfium/2155): investigate safety.
+ UNSAFE_BUFFERS(FXSYS_memcpy(perms_buf, perms.unsigned_str(), copy_len));
uint8_t buf[16];
CRYPT_AESDecrypt(&aes, buf, perms_buf, 16);
if (buf[9] != 'a' || buf[10] != 'd' || buf[11] != 'b')
@@ -455,7 +467,9 @@
uint8_t ukeybuf[32];
if (m_Revision == 2) {
- FXSYS_memcpy(ukeybuf, kDefaultPasscode, sizeof(kDefaultPasscode));
+ // TODO(crbug.com/pdfium/2155): investigate safety.
+ UNSAFE_BUFFERS(
+ FXSYS_memcpy(ukeybuf, kDefaultPasscode, sizeof(kDefaultPasscode)));
CRYPT_ArcFourCryptBlock(ukeybuf,
pdfium::make_span(m_EncryptKey).first(m_KeyLen));
return memcmp(ukey.c_str(), ukeybuf, 16) == 0;
@@ -465,10 +479,12 @@
uint8_t tmpkey[32] = {};
uint32_t copy_len = std::min(sizeof(test), ukey.GetLength());
- FXSYS_memcpy(test, ukey.c_str(), copy_len);
+ // TODO(crbug.com/pdfium/2155): investigate safety.
+ UNSAFE_BUFFERS(FXSYS_memcpy(test, ukey.c_str(), copy_len));
for (int32_t i = 19; i >= 0; i--) {
for (size_t j = 0; j < m_KeyLen; j++) {
- tmpkey[j] = m_EncryptKey[j] ^ static_cast<uint8_t>(i);
+ // TODO(crbug.com/pdfium/2155): investigate safety.
+ UNSAFE_BUFFERS(tmpkey[j] = m_EncryptKey[j] ^ static_cast<uint8_t>(i));
}
CRYPT_ArcFourCryptBlock(test, pdfium::make_span(tmpkey).first(m_KeyLen));
}
@@ -498,10 +514,13 @@
CRYPT_MD5Generate(digest, digest);
}
uint8_t enckey[32] = {};
- size_t copy_len = std::min(m_KeyLen, sizeof(digest));
- FXSYS_memcpy(enckey, digest, copy_len);
uint8_t okeybuf[32] = {};
- FXSYS_memcpy(okeybuf, okey.c_str(), okeylen);
+ size_t copy_len = std::min(m_KeyLen, sizeof(digest));
+ // TODO(crbug.com/pdfium/2155): investigate safety.
+ UNSAFE_BUFFERS({
+ FXSYS_memcpy(enckey, digest, copy_len);
+ FXSYS_memcpy(okeybuf, okey.c_str(), okeylen);
+ });
pdfium::span<uint8_t> okey_span = pdfium::make_span(okeybuf).first(okeylen);
if (m_Revision == 2) {
CRYPT_ArcFourCryptBlock(okey_span,
@@ -510,16 +529,20 @@
for (int32_t i = 19; i >= 0; i--) {
uint8_t tempkey[32] = {};
for (size_t j = 0; j < m_KeyLen; j++) {
- tempkey[j] = enckey[j] ^ static_cast<uint8_t>(i);
+ // TODO(crbug.com/pdfium/2155): investigate safety.
+ UNSAFE_BUFFERS(tempkey[j] = enckey[j] ^ static_cast<uint8_t>(i));
}
CRYPT_ArcFourCryptBlock(okey_span,
pdfium::make_span(tempkey).first(m_KeyLen));
}
}
size_t len = kRequiredOkeyLength;
- while (len && kDefaultPasscode[len - 1] == okey_span[len - 1])
- len--;
-
+ // TODO(crbug.com/pdfium/2155): investigate safety.
+ UNSAFE_BUFFERS({
+ while (len && kDefaultPasscode[len - 1] == okey_span[len - 1]) {
+ len--;
+ }
+ });
return ByteString(okeybuf, len);
}
@@ -580,7 +603,9 @@
false, file_id);
if (m_Revision < 3) {
uint8_t tempbuf[32];
- FXSYS_memcpy(tempbuf, kDefaultPasscode, sizeof(kDefaultPasscode));
+ // TODO(crbug.com/pdfium/2155): investigate safety.
+ UNSAFE_BUFFERS(
+ FXSYS_memcpy(tempbuf, kDefaultPasscode, sizeof(kDefaultPasscode)));
CRYPT_ArcFourCryptBlock(tempbuf,
pdfium::make_span(m_EncryptKey).first(key_len));
pEncryptDict->SetNewFor<CPDF_String>("U", ByteString(tempbuf, 32), false);
@@ -598,7 +623,8 @@
uint8_t tempkey[32];
for (uint8_t i = 1; i <= 19; i++) {
for (size_t j = 0; j < key_len; j++) {
- tempkey[j] = m_EncryptKey[j] ^ i;
+ // TODO(crbug.com/pdfium/2155): investigate safety.
+ UNSAFE_BUFFERS(tempkey[j] = m_EncryptKey[j] ^ i);
}
CRYPT_ArcFourCryptBlock(partial_digest_span,
pdfium::make_span(tempkey).first(key_len));
@@ -631,14 +657,17 @@
CRYPT_SHA256Update(&sha2, digest, 8);
CRYPT_SHA256Finish(&sha2, digest1);
}
- FXSYS_memcpy(digest1 + 32, digest, 16);
+ // TODO(crbug.com/pdfium/2155): investigate safety.
+ UNSAFE_BUFFERS(FXSYS_memcpy(digest1 + 32, digest, 16));
pEncryptDict->SetNewFor<CPDF_String>("U", ByteString(digest1, 48), false);
if (m_Revision >= 6) {
- Revision6_Hash(password, digest + 8, nullptr, digest1);
+ // TODO(crbug.com/pdfium/2155): investigate safety.
+ Revision6_Hash(password, UNSAFE_BUFFERS(digest + 8), nullptr, digest1);
} else {
CRYPT_SHA256Start(&sha2);
CRYPT_SHA256Update(&sha2, password.unsigned_str(), password.GetLength());
- CRYPT_SHA256Update(&sha2, digest + 8, 8);
+ // TODO(crbug.com/pdfium/2155): investigate safety.
+ CRYPT_SHA256Update(&sha2, UNSAFE_BUFFERS(digest + 8), 8);
CRYPT_SHA256Finish(&sha2, digest1);
}
CRYPT_aes_context aes = {};