Skip to content

Commit f237ad5

Browse files
bnoordhuisaddaleax
authored andcommitted
src: fix memory leak in DH key setters
Fix a memory leak in dh.setPublicKey() and dh.setPrivateKey() where the old keys weren't freed. Fixes: #8377 PR-URL: #14122 Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: James M Snell <[email protected]>
1 parent 0bbdb78 commit f237ad5

File tree

3 files changed

+53
-29
lines changed

3 files changed

+53
-29
lines changed

src/node_crypto.cc

+25-29
Original file line numberDiff line numberDiff line change
@@ -4881,44 +4881,40 @@ void DiffieHellman::ComputeSecret(const FunctionCallbackInfo<Value>& args) {
48814881
}
48824882

48834883

4884-
void DiffieHellman::SetPublicKey(const FunctionCallbackInfo<Value>& args) {
4885-
DiffieHellman* diffieHellman;
4886-
ASSIGN_OR_RETURN_UNWRAP(&diffieHellman, args.Holder());
4887-
Environment* env = diffieHellman->env();
4884+
void DiffieHellman::SetKey(const v8::FunctionCallbackInfo<v8::Value>& args,
4885+
BIGNUM* (DH::*field), const char* what) {
4886+
Environment* env = Environment::GetCurrent(args);
48884887

4889-
if (!diffieHellman->initialised_) {
4890-
return ThrowCryptoError(env, ERR_get_error(), "Not initialized");
4891-
}
4888+
DiffieHellman* dh;
4889+
ASSIGN_OR_RETURN_UNWRAP(&dh, args.Holder());
4890+
if (!dh->initialised_) return env->ThrowError("Not initialized");
4891+
4892+
BIGNUM** num = &((dh->dh)->*field);
4893+
char errmsg[64];
48924894

48934895
if (args.Length() == 0) {
4894-
return env->ThrowError("Public key argument is mandatory");
4895-
} else {
4896-
THROW_AND_RETURN_IF_NOT_BUFFER(args[0], "Public key");
4897-
diffieHellman->dh->pub_key = BN_bin2bn(
4898-
reinterpret_cast<unsigned char*>(Buffer::Data(args[0])),
4899-
Buffer::Length(args[0]), 0);
4896+
snprintf(errmsg, sizeof(errmsg), "%s argument is mandatory", what);
4897+
return env->ThrowError(errmsg);
4898+
}
4899+
4900+
if (!Buffer::HasInstance(args[0])) {
4901+
snprintf(errmsg, sizeof(errmsg), "%s must be a buffer", what);
4902+
return env->ThrowTypeError(errmsg);
49004903
}
4904+
4905+
*num = BN_bin2bn(reinterpret_cast<unsigned char*>(Buffer::Data(args[0])),
4906+
Buffer::Length(args[0]), *num);
4907+
CHECK_NE(*num, nullptr);
49014908
}
49024909

49034910

4904-
void DiffieHellman::SetPrivateKey(const FunctionCallbackInfo<Value>& args) {
4905-
DiffieHellman* diffieHellman;
4906-
ASSIGN_OR_RETURN_UNWRAP(&diffieHellman, args.Holder());
4907-
Environment* env = diffieHellman->env();
4911+
void DiffieHellman::SetPublicKey(const FunctionCallbackInfo<Value>& args) {
4912+
SetKey(args, &DH::pub_key, "Public key");
4913+
}
49084914

4909-
if (!diffieHellman->initialised_) {
4910-
return ThrowCryptoError(env, ERR_get_error(), "Not initialized");
4911-
}
49124915

4913-
if (args.Length() == 0) {
4914-
return env->ThrowError("Private key argument is mandatory");
4915-
} else {
4916-
THROW_AND_RETURN_IF_NOT_BUFFER(args[0], "Private key");
4917-
diffieHellman->dh->priv_key = BN_bin2bn(
4918-
reinterpret_cast<unsigned char*>(Buffer::Data(args[0])),
4919-
Buffer::Length(args[0]),
4920-
0);
4921-
}
4916+
void DiffieHellman::SetPrivateKey(const FunctionCallbackInfo<Value>& args) {
4917+
SetKey(args, &DH::priv_key, "Private key");
49224918
}
49234919

49244920

src/node_crypto.h

+2
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,8 @@ class DiffieHellman : public BaseObject {
692692
private:
693693
static void GetField(const v8::FunctionCallbackInfo<v8::Value>& args,
694694
BIGNUM* (DH::*field), const char* err_if_null);
695+
static void SetKey(const v8::FunctionCallbackInfo<v8::Value>& args,
696+
BIGNUM* (DH::*field), const char* what);
695697
bool VerifyContext();
696698

697699
bool initialised_;

test/parallel/test-crypto-dh-leak.js

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Flags: --expose-gc
2+
'use strict';
3+
4+
const common = require('../common');
5+
if (!common.hasCrypto)
6+
common.skip('missing crypto');
7+
8+
const assert = require('assert');
9+
const crypto = require('crypto');
10+
11+
const before = process.memoryUsage().rss;
12+
{
13+
const dh = crypto.createDiffieHellman(common.hasFipsCrypto ? 1024 : 256);
14+
const publicKey = dh.generateKeys();
15+
const privateKey = dh.getPrivateKey();
16+
for (let i = 0; i < 5e4; i += 1) {
17+
dh.setPublicKey(publicKey);
18+
dh.setPrivateKey(privateKey);
19+
}
20+
}
21+
global.gc();
22+
const after = process.memoryUsage().rss;
23+
24+
// RSS should stay the same, ceteris paribus, but allow for
25+
// some slop because V8 mallocs memory during execution.
26+
assert(after - before < 5 << 20);

0 commit comments

Comments
 (0)