Skip to content

Commit e66aa77

Browse files
committed
fix: allocate memory of Buffer with V8's allocator
Blink overrides ArrayBuffer's allocator with its own one, while Node simply uses malloc and free. This commit prevents the crash that would be resultant of mixing them together.
1 parent 10df34b commit e66aa77

File tree

7 files changed

+134
-61
lines changed

7 files changed

+134
-61
lines changed

src/node_buffer.cc

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,10 @@ bool zero_fill_all_buffers = false;
6161

6262
namespace {
6363

64-
inline void* BufferMalloc(size_t length) {
65-
return zero_fill_all_buffers ? node::UncheckedCalloc(length) :
66-
node::UncheckedMalloc(length);
64+
inline void* BufferMalloc(v8::Isolate* isolate, size_t length) {
65+
auto* allocator = isolate->GetArrayBufferAllocator();
66+
return zero_fill_all_buffers ? allocator->Allocate(length) :
67+
allocator->AllocateUninitialized(length);
6768
}
6869

6970
} // namespace
@@ -245,7 +246,7 @@ MaybeLocal<Object> New(Isolate* isolate,
245246
char* data = nullptr;
246247

247248
if (length > 0) {
248-
data = static_cast<char*>(BufferMalloc(length));
249+
data = static_cast<char*>(BufferMalloc(isolate, length));
249250

250251
if (data == nullptr)
251252
return Local<Object>();
@@ -254,10 +255,14 @@ MaybeLocal<Object> New(Isolate* isolate,
254255
CHECK(actual <= length);
255256

256257
if (actual == 0) {
257-
free(data);
258+
isolate->GetArrayBufferAllocator()->Free(data, length);
258259
data = nullptr;
259260
} else if (actual < length) {
260-
data = node::Realloc(data, actual);
261+
auto* allocator = isolate->GetArrayBufferAllocator();
262+
auto* excessive_data = data;
263+
data = static_cast<char*>(allocator->AllocateUninitialized(actual));
264+
memcpy(data, excessive_data, actual);
265+
allocator->Free(excessive_data, length);
261266
}
262267
}
263268

@@ -266,7 +271,7 @@ MaybeLocal<Object> New(Isolate* isolate,
266271
return scope.Escape(buf);
267272

268273
// Object failed to be created. Clean up resources.
269-
free(data);
274+
isolate->GetArrayBufferAllocator()->Free(data, length);
270275
return Local<Object>();
271276
}
272277

@@ -292,7 +297,7 @@ MaybeLocal<Object> New(Environment* env, size_t length) {
292297

293298
void* data;
294299
if (length > 0) {
295-
data = BufferMalloc(length);
300+
data = BufferMalloc(env->isolate(), length);
296301
if (data == nullptr)
297302
return Local<Object>();
298303
} else {
@@ -308,7 +313,7 @@ MaybeLocal<Object> New(Environment* env, size_t length) {
308313

309314
if (ui.IsEmpty()) {
310315
// Object failed to be created. Clean up resources.
311-
free(data);
316+
env->isolate()->GetArrayBufferAllocator()->Free(data, length);
312317
}
313318

314319
return scope.Escape(ui.FromMaybe(Local<Uint8Array>()));
@@ -334,10 +339,11 @@ MaybeLocal<Object> Copy(Environment* env, const char* data, size_t length) {
334339
return Local<Object>();
335340
}
336341

342+
auto* allocator = env->isolate()->GetArrayBufferAllocator();
337343
void* new_data;
338344
if (length > 0) {
339345
CHECK_NOT_NULL(data);
340-
new_data = node::UncheckedMalloc(length);
346+
new_data = allocator->AllocateUninitialized(length);
341347
if (new_data == nullptr)
342348
return Local<Object>();
343349
memcpy(new_data, data, length);
@@ -354,7 +360,7 @@ MaybeLocal<Object> Copy(Environment* env, const char* data, size_t length) {
354360

355361
if (ui.IsEmpty()) {
356362
// Object failed to be created. Clean up resources.
357-
free(new_data);
363+
allocator->Free(new_data, length);
358364
}
359365

360366
return scope.Escape(ui.FromMaybe(Local<Uint8Array>()));

src/node_crypto.cc

Lines changed: 50 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1865,7 +1865,8 @@ void SSLWrap<Base>::GetFinished(const FunctionCallbackInfo<Value>& args) {
18651865
if (len == 0)
18661866
return;
18671867

1868-
char* buf = Malloc(len);
1868+
auto* allocator = env->isolate()->GetArrayBufferAllocator();
1869+
char* buf = static_cast<char*>(allocator->AllocateUninitialized(len));
18691870
CHECK_EQ(len, SSL_get_finished(w->ssl_.get(), buf, len));
18701871
args.GetReturnValue().Set(Buffer::New(env, buf, len).ToLocalChecked());
18711872
}
@@ -1888,7 +1889,8 @@ void SSLWrap<Base>::GetPeerFinished(const FunctionCallbackInfo<Value>& args) {
18881889
if (len == 0)
18891890
return;
18901891

1891-
char* buf = Malloc(len);
1892+
auto* allocator = env->isolate()->GetArrayBufferAllocator();
1893+
char* buf = static_cast<char*>(allocator->AllocateUninitialized(len));
18921894
CHECK_EQ(len, SSL_get_peer_finished(w->ssl_.get(), buf, len));
18931895
args.GetReturnValue().Set(Buffer::New(env, buf, len).ToLocalChecked());
18941896
}
@@ -1908,7 +1910,8 @@ void SSLWrap<Base>::GetSession(const FunctionCallbackInfo<Value>& args) {
19081910
int slen = i2d_SSL_SESSION(sess, nullptr);
19091911
CHECK_GT(slen, 0);
19101912

1911-
char* sbuf = Malloc(slen);
1913+
auto* allocator = env->isolate()->GetArrayBufferAllocator();
1914+
char* sbuf = static_cast<char*>(allocator->AllocateUninitialized(slen));
19121915
unsigned char* p = reinterpret_cast<unsigned char*>(sbuf);
19131916
i2d_SSL_SESSION(sess, &p);
19141917
args.GetReturnValue().Set(Buffer::New(env, sbuf, slen).ToLocalChecked());
@@ -2329,11 +2332,12 @@ int SSLWrap<Base>::TLSExtStatusCallback(SSL* s, void* arg) {
23292332
size_t len = Buffer::Length(obj);
23302333

23312334
// OpenSSL takes control of the pointer after accepting it
2332-
char* data = node::Malloc(len);
2335+
auto* allocator = env->isolate()->GetArrayBufferAllocator();
2336+
uint8_t* data = static_cast<uint8_t*>(allocator->AllocateUninitialized(len));
23332337
memcpy(data, resp, len);
23342338

23352339
if (!SSL_set_tlsext_status_ocsp_resp(s, data, len))
2336-
free(data);
2340+
allocator->Free(data, len);
23372341
w->ocsp_response_.Reset();
23382342

23392343
return SSL_TLSEXT_ERR_OK;
@@ -3037,7 +3041,8 @@ CipherBase::UpdateResult CipherBase::Update(const char* data,
30373041
return kErrorState;
30383042
}
30393043

3040-
*out = Malloc<unsigned char>(buff_len);
3044+
auto* allocator = env()->isolate()->GetArrayBufferAllocator();
3045+
*out = static_cast<unsigned char*>(allocator->AllocateUninitialized(buff_len));
30413046
int r = EVP_CipherUpdate(ctx_.get(),
30423047
*out,
30433048
out_len,
@@ -3080,7 +3085,8 @@ void CipherBase::Update(const FunctionCallbackInfo<Value>& args) {
30803085
}
30813086

30823087
if (r != kSuccess) {
3083-
free(out);
3088+
auto* allocator = env->isolate()->GetArrayBufferAllocator();
3089+
allocator->Free(out, out_len);
30843090
if (r == kErrorState) {
30853091
ThrowCryptoError(env, ERR_get_error(),
30863092
"Trying to add data in unsupported state");
@@ -3119,8 +3125,9 @@ bool CipherBase::Final(unsigned char** out, int* out_len) {
31193125

31203126
const int mode = EVP_CIPHER_CTX_mode(ctx_.get());
31213127

3122-
*out = Malloc<unsigned char>(
3123-
static_cast<size_t>(EVP_CIPHER_CTX_block_size(ctx_.get())));
3128+
auto* allocator = env()->isolate()->GetArrayBufferAllocator();
3129+
*out = static_cast<unsigned char*>(allocator->AllocateUninitialized(
3130+
EVP_CIPHER_CTX_block_size(ctx_.get())));
31243131

31253132
if (kind_ == kDecipher && IsSupportedAuthenticatedMode(mode)) {
31263133
MaybePassAuthTagToOpenSSL();
@@ -3169,7 +3176,8 @@ void CipherBase::Final(const FunctionCallbackInfo<Value>& args) {
31693176
bool r = cipher->Final(&out_value, &out_len);
31703177

31713178
if (out_len <= 0 || !r) {
3172-
free(out_value);
3179+
auto* allocator = env->isolate()->GetArrayBufferAllocator();
3180+
allocator->Free(out_value, out_len);
31733181
out_value = nullptr;
31743182
out_len = 0;
31753183
if (!r) {
@@ -3818,7 +3826,8 @@ void Verify::VerifyFinal(const FunctionCallbackInfo<Value>& args) {
38183826
template <PublicKeyCipher::Operation operation,
38193827
PublicKeyCipher::EVP_PKEY_cipher_init_t EVP_PKEY_cipher_init,
38203828
PublicKeyCipher::EVP_PKEY_cipher_t EVP_PKEY_cipher>
3821-
bool PublicKeyCipher::Cipher(const char* key_pem,
3829+
bool PublicKeyCipher::Cipher(Environment* env,
3830+
const char* key_pem,
38223831
int key_pem_len,
38233832
const char* passphrase,
38243833
int padding,
@@ -3827,6 +3836,7 @@ bool PublicKeyCipher::Cipher(const char* key_pem,
38273836
unsigned char** out,
38283837
size_t* out_len) {
38293838
EVPKeyPointer pkey;
3839+
auto* allocator = env->isolate()->GetArrayBufferAllocator();
38303840

38313841
// Check if this is a PKCS#8 or RSA public key before trying as X.509 and
38323842
// private key.
@@ -3859,7 +3869,7 @@ bool PublicKeyCipher::Cipher(const char* key_pem,
38593869
if (EVP_PKEY_cipher(ctx.get(), nullptr, out_len, data, len) <= 0)
38603870
return false;
38613871

3862-
*out = Malloc<unsigned char>(*out_len);
3872+
*out = static_cast<unsigned char*>(allocator->AllocateUninitialized(*out_len));
38633873

38643874
if (EVP_PKEY_cipher(ctx.get(), *out, out_len, data, len) <= 0)
38653875
return false;
@@ -3893,6 +3903,7 @@ void PublicKeyCipher::Cipher(const FunctionCallbackInfo<Value>& args) {
38933903
ClearErrorOnReturn clear_error_on_return;
38943904

38953905
bool r = Cipher<operation, EVP_PKEY_cipher_init, EVP_PKEY_cipher>(
3906+
env,
38963907
kbuf,
38973908
klen,
38983909
args.Length() >= 4 && !args[3]->IsNull() ? *passphrase : nullptr,
@@ -3903,7 +3914,8 @@ void PublicKeyCipher::Cipher(const FunctionCallbackInfo<Value>& args) {
39033914
&out_len);
39043915

39053916
if (out_len == 0 || !r) {
3906-
free(out_value);
3917+
auto* allocator = env->isolate()->GetArrayBufferAllocator();
3918+
allocator->Free(out_value, out_len);
39073919
out_value = nullptr;
39083920
out_len = 0;
39093921
if (!r) {
@@ -4116,7 +4128,8 @@ void DiffieHellman::GenerateKeys(const FunctionCallbackInfo<Value>& args) {
41164128
const BIGNUM* pub_key;
41174129
DH_get0_key(diffieHellman->dh_.get(), &pub_key, nullptr);
41184130
size_t size = BN_num_bytes(pub_key);
4119-
char* data = Malloc(size);
4131+
auto* allocator = env->isolate()->GetArrayBufferAllocator();
4132+
char* data = static_cast<char*>(allocator->AllocateUninitialized(size));
41204133
BN_bn2bin(pub_key, reinterpret_cast<unsigned char*>(data));
41214134
args.GetReturnValue().Set(Buffer::New(env, data, size).ToLocalChecked());
41224135
}
@@ -4135,7 +4148,8 @@ void DiffieHellman::GetField(const FunctionCallbackInfo<Value>& args,
41354148
if (num == nullptr) return env->ThrowError(err_if_null);
41364149

41374150
size_t size = BN_num_bytes(num);
4138-
char* data = Malloc(size);
4151+
auto* allocator = env->isolate()->GetArrayBufferAllocator();
4152+
char* data = static_cast<char*>(allocator->AllocateUninitialized(size));
41394153
BN_bn2bin(num, reinterpret_cast<unsigned char*>(data));
41404154
args.GetReturnValue().Set(Buffer::New(env, data, size).ToLocalChecked());
41414155
}
@@ -4199,7 +4213,8 @@ void DiffieHellman::ComputeSecret(const FunctionCallbackInfo<Value>& args) {
41994213
Buffer::Length(args[0]),
42004214
0));
42014215

4202-
MallocedBuffer<char> data(DH_size(diffieHellman->dh_.get()));
4216+
auto* allocator = env->isolate()->GetArrayBufferAllocator();
4217+
MallocedBuffer<char> data(DH_size(diffieHellman->dh_.get()), allocator);
42034218

42044219
int size = DH_compute_key(reinterpret_cast<unsigned char*>(data.data),
42054220
key.get(),
@@ -4419,13 +4434,14 @@ void ECDH::ComputeSecret(const FunctionCallbackInfo<Value>& args) {
44194434
}
44204435

44214436
// NOTE: field_size is in bits
4437+
auto* allocator = env->isolate()->GetArrayBufferAllocator();
44224438
int field_size = EC_GROUP_get_degree(ecdh->group_);
44234439
size_t out_len = (field_size + 7) / 8;
4424-
char* out = node::Malloc(out_len);
4440+
char* out = static_cast<char*>(allocator->AllocateUninitialized(out_len));
44254441

44264442
int r = ECDH_compute_key(out, out_len, pub.get(), ecdh->key_.get(), nullptr);
44274443
if (!r) {
4428-
free(out);
4444+
allocator->Free(out, out_len);
44294445
return env->ThrowError("Failed to compute ECDH key");
44304446
}
44314447

@@ -4456,11 +4472,13 @@ void ECDH::GetPublicKey(const FunctionCallbackInfo<Value>& args) {
44564472
if (size == 0)
44574473
return env->ThrowError("Failed to get public key length");
44584474

4459-
unsigned char* out = node::Malloc<unsigned char>(size);
4475+
auto* allocator = env->isolate()->GetArrayBufferAllocator();
4476+
unsigned char* out =
4477+
static_cast<unsigned char*>(allocator->AllocateUninitialized(size));
44604478

44614479
int r = EC_POINT_point2oct(ecdh->group_, pub, form, out, size, nullptr);
44624480
if (r != size) {
4463-
free(out);
4481+
allocator->Free(out, size);
44644482
return env->ThrowError("Failed to get public key");
44654483
}
44664484

@@ -4480,11 +4498,13 @@ void ECDH::GetPrivateKey(const FunctionCallbackInfo<Value>& args) {
44804498
if (b == nullptr)
44814499
return env->ThrowError("Failed to get ECDH private key");
44824500

4501+
auto* allocator = env->isolate()->GetArrayBufferAllocator();
44834502
int size = BN_num_bytes(b);
4484-
unsigned char* out = node::Malloc<unsigned char>(size);
4503+
unsigned char* out =
4504+
static_cast<unsigned char*>(allocator->AllocateUninitialized(size));
44854505

44864506
if (size != BN_bn2bin(b, out)) {
4487-
free(out);
4507+
allocator->Free(out, size);
44884508
return env->ThrowError("Failed to convert ECDH private key to Buffer");
44894509
}
44904510

@@ -4953,8 +4973,9 @@ void VerifySpkac(const FunctionCallbackInfo<Value>& args) {
49534973
}
49544974

49554975

4956-
char* ExportPublicKey(const char* data, int len, size_t* size) {
4976+
char* ExportPublicKey(Environment* env, const char* data, int len, size_t* size) {
49574977
char* buf = nullptr;
4978+
auto* allocator = env->isolate()->GetArrayBufferAllocator();
49584979

49594980
BIOPointer bio(BIO_new(BIO_s_mem()));
49604981
if (!bio)
@@ -4975,7 +4996,7 @@ char* ExportPublicKey(const char* data, int len, size_t* size) {
49754996
BIO_get_mem_ptr(bio.get(), &ptr);
49764997

49774998
*size = ptr->length;
4978-
buf = Malloc(*size);
4999+
buf = static_cast<char*>(allocator->AllocateUninitialized(*size));
49795000
memcpy(buf, ptr->data, *size);
49805001

49815002
return buf;
@@ -4993,7 +5014,7 @@ void ExportPublicKey(const FunctionCallbackInfo<Value>& args) {
49935014
CHECK_NOT_NULL(data);
49945015

49955016
size_t pkey_size;
4996-
char* pkey = ExportPublicKey(data, length, &pkey_size);
5017+
char* pkey = ExportPublicKey(env, data, length, &pkey_size);
49975018
if (pkey == nullptr)
49985019
return args.GetReturnValue().SetEmptyString();
49995020

@@ -5075,11 +5096,13 @@ void ConvertKey(const FunctionCallbackInfo<Value>& args) {
50755096
if (size == 0)
50765097
return env->ThrowError("Failed to get public key length");
50775098

5078-
unsigned char* out = node::Malloc<unsigned char>(size);
5099+
auto* allocator = env->isolate()->GetArrayBufferAllocator();
5100+
unsigned char* out =
5101+
static_cast<unsigned char*>(allocator->AllocateUninitialized(size));
50795102

50805103
int r = EC_POINT_point2oct(group.get(), pub.get(), form, out, size, nullptr);
50815104
if (r != size) {
5082-
free(out);
5105+
allocator->Free(out, size);
50835106
return env->ThrowError("Failed to get public key");
50845107
}
50855108

src/node_crypto.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -576,7 +576,8 @@ class PublicKeyCipher {
576576
template <Operation operation,
577577
EVP_PKEY_cipher_init_t EVP_PKEY_cipher_init,
578578
EVP_PKEY_cipher_t EVP_PKEY_cipher>
579-
static bool Cipher(const char* key_pem,
579+
static bool Cipher(Environment* env,
580+
const char* key_pem,
580581
int key_pem_len,
581582
const char* passphrase,
582583
int padding,

0 commit comments

Comments
 (0)