diff options
author | 2023-06-10 02:26:48 -0700 | |
---|---|---|
committer | 2023-06-10 02:26:48 -0700 | |
commit | a2ec2ea397e96dd7bb64177964e11bf4c9a4b91b (patch) | |
tree | 33338c794afc142a7b137b6cfea7da6dea37fccb | |
parent | f51878a8ec64f313c63e790543477c934184954c (diff) | |
download | bun-a2ec2ea397e96dd7bb64177964e11bf4c9a4b91b.tar.gz bun-a2ec2ea397e96dd7bb64177964e11bf4c9a4b91b.tar.zst bun-a2ec2ea397e96dd7bb64177964e11bf4c9a4b91b.zip |
Fixes #3250 (#3269)
* Fixes #3250
We must call `EVP_MD_CTX_cleanup` because `EVP_MD_CTX` containers pointers inside to allocated memory
* Fix leak
* Update sha.zig
---------
Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
-rw-r--r-- | src/bun.js/api/bun.zig | 36 | ||||
-rw-r--r-- | src/bun.js/base.zig | 23 | ||||
-rw-r--r-- | src/sha.zig | 5 |
3 files changed, 51 insertions, 13 deletions
diff --git a/src/bun.js/api/bun.zig b/src/bun.js/api/bun.zig index 7e9e3ca30..72815d9a2 100644 --- a/src/bun.js/api/bun.zig +++ b/src/bun.js/api/bun.zig @@ -1533,7 +1533,6 @@ pub const Crypto = struct { var ctx: BoringSSL.EVP_MD_CTX = undefined; BoringSSL.EVP_MD_CTX_init(&ctx); _ = BoringSSL.EVP_DigestInit_ex(&ctx, md, engine); - return .{ .ctx = ctx, .md = md, @@ -1615,6 +1614,11 @@ pub const Crypto = struct { defer name_str.deinit(); return byNameAndEngine(global.bunVM().rareData().boringEngine(), name_str.slice()); } + + pub fn deinit(this: *EVP) void { + // https://github.com/oven-sh/bun/issues/3250 + _ = BoringSSL.EVP_MD_CTX_cleanup(&this.ctx); + } }; fn createCryptoError(globalThis: *JSC.JSGlobalObject, err_code: u32) JSValue { @@ -1867,6 +1871,7 @@ pub const Crypto = struct { // we use SHA512 to hash the password if it's longer than 72 bytes if (password.len > 72) { var sha_256 = bun.sha.SHA512.init(); + defer sha_256.deinit(); sha_256.update(password); sha_256.final(outbuf[0..bun.sha.SHA512.digest]); password_to_use = outbuf[0..bun.sha.SHA512.digest]; @@ -2469,10 +2474,11 @@ pub const Crypto = struct { fn hashToEncoding( globalThis: *JSGlobalObject, evp: *EVP, - input: JSC.Node.StringOrBuffer, + input: JSC.Node.SliceOrBuffer, encoding: JSC.Node.Encoding, ) JSC.JSValue { var output_digest_buf: Digest = undefined; + defer input.deinit(); const len = evp.hash(globalThis.bunVM().rareData().boringEngine(), input.slice(), &output_digest_buf) orelse { const err = BoringSSL.ERR_get_error(); @@ -2487,11 +2493,12 @@ pub const Crypto = struct { fn hashToBytes( globalThis: *JSGlobalObject, evp: *EVP, - input: JSC.Node.StringOrBuffer, + input: JSC.Node.SliceOrBuffer, output: ?JSC.ArrayBuffer, ) JSC.JSValue { var output_digest_buf: Digest = undefined; var output_digest_slice: []u8 = &output_digest_buf; + defer input.deinit(); if (output) |output_buf| { const size = evp.size(); var bytes = output_buf.byteSlice(); @@ -2513,21 +2520,22 @@ pub const Crypto = struct { if (output) |output_buf| { return output_buf.value; } else { - var array_buffer_out = JSC.ArrayBuffer.fromBytes(bun.default_allocator.dupe(u8, output_digest_slice[0..len]) catch unreachable, .Uint8Array); - return array_buffer_out.toJSUnchecked(globalThis, null); + // Clone to GC-managed memory + return JSC.ArrayBuffer.create(globalThis, output_digest_slice[0..len], .Buffer); } } pub fn hash_( globalThis: *JSGlobalObject, algorithm: ZigString, - input: JSC.Node.StringOrBuffer, + input: JSC.Node.SliceOrBuffer, output: ?JSC.Node.StringOrBuffer, ) JSC.JSValue { var evp = EVP.byName(algorithm, globalThis) orelse { globalThis.throwInvalidArguments("Unsupported algorithm \"{any}\"", .{algorithm}); return .zero; }; + defer evp.deinit(); if (output) |string_or_buffer| { switch (string_or_buffer) { @@ -2624,13 +2632,14 @@ pub const Crypto = struct { pub fn digest_( this: *@This(), globalThis: *JSGlobalObject, - output: ?JSC.Node.StringOrBuffer, + output: ?JSC.Node.SliceOrBuffer, ) JSC.JSValue { if (output) |string_or_buffer| { switch (string_or_buffer) { .string => |str| { - const encoding = JSC.Node.Encoding.from(str) orelse { - globalThis.throwInvalidArguments("Unknown encoding: {s}", .{str}); + defer str.deinit(); + const encoding = JSC.Node.Encoding.from(str.slice()) orelse { + globalThis.throwInvalidArguments("Unknown encoding: {}", .{str}); return JSC.JSValue.zero; }; @@ -2667,8 +2676,8 @@ pub const Crypto = struct { if (output) |output_buf| { return output_buf.value; } else { - var array_buffer_out = JSC.ArrayBuffer.fromBytes(bun.default_allocator.dupe(u8, result) catch unreachable, .Uint8Array); - return array_buffer_out.toJSUnchecked(globalThis, null); + // Clone to GC-managed memory + return JSC.ArrayBuffer.create(globalThis, result, .Buffer); } } @@ -2683,7 +2692,10 @@ pub const Crypto = struct { } pub fn finalize(this: *CryptoHasher) callconv(.C) void { - VirtualMachine.get().allocator.destroy(this); + // https://github.com/oven-sh/bun/issues/3250 + this.evp.deinit(); + + bun.default_allocator.destroy(this); } }; diff --git a/src/bun.js/base.zig b/src/bun.js/base.zig index 9b9cacbe7..cd0684398 100644 --- a/src/bun.js/base.zig +++ b/src/bun.js/base.zig @@ -3125,6 +3125,29 @@ pub fn wrapStaticMethod( args[i] = null; } }, + JSC.Node.SliceOrBuffer => { + const arg = iter.nextEat() orelse { + globalThis.throwInvalidArguments("expected string or buffer", .{}); + iter.deinit(); + return JSC.JSValue.zero; + }; + args[i] = JSC.Node.SliceOrBuffer.fromJS(globalThis.ptr(), iter.arena.allocator(), arg) orelse { + globalThis.throwInvalidArguments("expected string or buffer", .{}); + iter.deinit(); + return JSC.JSValue.zero; + }; + }, + ?JSC.Node.SliceOrBuffer => { + if (iter.nextEat()) |arg| { + args[i] = JSC.Node.SliceOrBuffer.fromJS(globalThis.ptr(), iter.arena.allocator(), arg) orelse { + globalThis.throwInvalidArguments("expected string or buffer", .{}); + iter.deinit(); + return JSC.JSValue.zero; + }; + } else { + args[i] = null; + } + }, JSC.ArrayBuffer => { if (iter.nextEat()) |arg| { args[i] = arg.asArrayBuffer(globalThis.ptr()) orelse { diff --git a/src/sha.zig b/src/sha.zig index 64539eff0..cd9fd0f0a 100644 --- a/src/sha.zig +++ b/src/sha.zig @@ -74,6 +74,10 @@ fn NewEVP( pub fn final(this: *@This(), out: *Digest) void { std.debug.assert(BoringSSL.EVP_DigestFinal(&this.ctx, out, null) == 1); } + + pub fn deinit(this: *@This()) void { + _ = BoringSSL.EVP_MD_CTX_cleanup(&this.ctx); + } }; } pub const EVP = struct { @@ -331,4 +335,3 @@ pub fn main() anyerror!void { // std.crypto.hash.sha2.Sha256.hash(value, &hash2, .{}); // try std.testing.expectEqual(hash, hash2); // } - |