diff --git a/src/string_bytes.cc b/src/string_bytes.cc index 83c74d2f182..da54ca60237 100644 --- a/src/string_bytes.cc +++ b/src/string_bytes.cc @@ -265,7 +265,11 @@ size_t StringBytes::WriteUCS2(char* buf, size_t* chars_written) { uint16_t* const dst = reinterpret_cast(buf); - size_t max_chars = (buflen / sizeof(*dst)); + size_t max_chars = buflen / sizeof(*dst); + if (max_chars == 0) { + return 0; + } + size_t nchars; size_t alignment = reinterpret_cast(dst) % sizeof(*dst); if (alignment == 0) { diff --git a/test/parallel/test-buffer-write.js b/test/parallel/test-buffer-write.js index 06117f614e8..c0c5e9c88fb 100644 --- a/test/parallel/test-buffer-write.js +++ b/test/parallel/test-buffer-write.js @@ -70,3 +70,24 @@ for (let i = 1; i < 10; i++) { assert.ok(!Buffer.isEncoding(encoding)); assert.throws(() => Buffer.alloc(9).write('foo', encoding), error); } + +// UCS-2 overflow CVE-2018-12115 +for (let i = 1; i < 4; i++) { + // Allocate two Buffers sequentially off the pool. Run more than once in case + // we hit the end of the pool and don't get sequential allocations + const x = Buffer.allocUnsafe(4).fill(0); + const y = Buffer.allocUnsafe(4).fill(1); + // Should not write anything, pos 3 doesn't have enough room for a 16-bit char + assert.strictEqual(x.write('ыыыыыы', 3, 'ucs2'), 0); + // CVE-2018-12115 experienced via buffer overrun to next block in the pool + assert.strictEqual(Buffer.compare(y, Buffer.alloc(4, 1)), 0); +} + +// Should not write any data when there is no space for 16-bit chars +const z = Buffer.alloc(4, 0); +assert.strictEqual(z.write('\u0001', 3, 'ucs2'), 0); +assert.strictEqual(Buffer.compare(z, Buffer.alloc(4, 0)), 0); + +// Large overrun could corrupt the process +assert.strictEqual(Buffer.alloc(4) + .write('ыыыыыы'.repeat(100), 3, 'utf16le'), 0);