Skip to content

Commit 0052926

Browse files
committedAug 15, 2018
buffer: avoid overrun on UCS-2 string write
CVE-2018-12115 Discovered by ChALkeR - Сковорода Никита Андреевич Fix by Anna Henningsen Writing to the second-to-last byte with UCS-2 encoding will cause a -1 length to be send to String::Write(), writing all of the provided Buffer from that point and beyond. Fixes: nodejs-private/security#203 PR-URL: nodejs-private/node-private#138
1 parent 08a150f commit 0052926

File tree

2 files changed

+26
-1
lines changed

2 files changed

+26
-1
lines changed
 

‎src/string_bytes.cc

+5-1
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,11 @@ size_t StringBytes::WriteUCS2(char* buf,
226226
size_t* chars_written) {
227227
uint16_t* const dst = reinterpret_cast<uint16_t*>(buf);
228228

229-
size_t max_chars = (buflen / sizeof(*dst));
229+
size_t max_chars = buflen / sizeof(*dst);
230+
if (max_chars == 0) {
231+
return 0;
232+
}
233+
230234
size_t nchars;
231235
size_t alignment = reinterpret_cast<uintptr_t>(dst) % sizeof(*dst);
232236
if (alignment == 0) {

‎test/parallel/test-buffer.js

+21
Original file line numberDiff line numberDiff line change
@@ -1506,3 +1506,24 @@ assert.strictEqual(SlowBuffer.prototype.offset, undefined);
15061506
// Check pool offset after that by trying to write string into the pool.
15071507
assert.doesNotThrow(() => Buffer.from('abc'));
15081508
}
1509+
1510+
// UCS-2 overflow CVE-2018-12115
1511+
for (let i = 1; i < 4; i++) {
1512+
// Allocate two Buffers sequentially off the pool. Run more than once in case
1513+
// we hit the end of the pool and don't get sequential allocations
1514+
const x = Buffer.allocUnsafe(4).fill(0);
1515+
const y = Buffer.allocUnsafe(4).fill(1);
1516+
// Should not write anything, pos 3 doesn't have enough room for a 16-bit char
1517+
assert.strictEqual(x.write('ыыыыыы', 3, 'ucs2'), 0);
1518+
// CVE-2018-12115 experienced via buffer overrun to next block in the pool
1519+
assert.strictEqual(Buffer.compare(y, Buffer.alloc(4, 1)), 0);
1520+
}
1521+
1522+
// Should not write any data when there is no space for 16-bit chars
1523+
const z = Buffer.alloc(4, 0);
1524+
assert.strictEqual(z.write('\u0001', 3, 'ucs2'), 0);
1525+
assert.strictEqual(Buffer.compare(z, Buffer.alloc(4, 0)), 0);
1526+
1527+
// Large overrun could corrupt the process
1528+
assert.strictEqual(Buffer.alloc(4)
1529+
.write('ыыыыыы'.repeat(100), 3, 'utf16le'), 0);

0 commit comments

Comments
 (0)
Please sign in to comment.