src: fix out-of-bounds write when transcoding odd-length ucs2

Signed-off-by: Nashit-h <nashit@bugqore.com>
PR-URL: https://github.com/nodejs/node/pull/64512
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: René <contact.9a5d6388@renegade334.me.uk>
This commit is contained in:
nashit hayat authored and GitHub committed 2026-08-22 17:44:15 +00:00
1 parent 467c0431d7
commit 70c189bd9d
2 files changed
+20 -2

No files matched your search

+5 -2
View File
@@ -121,10 +121,13 @@ MaybeLocal<Object> ToBufferEndian(Environment* env, MaybeStackBuffer<T>* buf) {
void CopySourceBuffer(MaybeStackBuffer<UChar>* dest,
const char* data,
const size_t length,
const size_t length_in_chars) {
dest->AllocateSufficientStorage(length_in_chars);
char* dst = reinterpret_cast<char*>(**dest);
// The destination holds length_in_chars UChar units. Copy that many whole
// units and ignore a trailing odd byte; copying the raw byte length would
// write one byte past the buffer when the source length is not even.
const size_t length = length_in_chars * sizeof(UChar);
memcpy(dst, data, length);
if constexpr (IsBigEndian()) {
CHECK(nbytes::SwapBytes16(dst, length));
@@ -197,7 +200,7 @@ MaybeLocal<Object> TranscodeFromUcs2(Environment* env,
to.set_subst_chars(sub.c_str());
const size_t length_in_chars = source_length / sizeof(UChar);
CopySourceBuffer(&sourcebuf, source, source_length, length_in_chars);
CopySourceBuffer(&sourcebuf, source, length_in_chars);
MaybeStackBuffer<char> destbuf(length_in_chars);
const uint32_t len = ucnv_fromUChars(to.conv(), *destbuf, length_in_chars,
*sourcebuf, length_in_chars, status);
+15
View File
@@ -88,3 +88,18 @@ assert.deepStrictEqual(
{
buffer.transcode(new buffer.Buffer.allocUnsafeSlow(1), 'utf16le', 'ucs2');
}
// An odd-length ucs2 source must only convert whole 2-byte code units and
// leave the trailing byte untouched, without reading or writing past the
// conversion buffer. Lengths are chosen to exercise both the on-stack and the
// heap-allocated code paths.
for (const len of [2049, 4099]) {
const src = Buffer.alloc(len, 0x61);
const wholeUnits = src.subarray(0, len - 1);
for (const to of ['latin1', 'ascii']) {
assert.deepStrictEqual(
buffer.transcode(src, 'utf16le', to),
buffer.transcode(wholeUnits, 'utf16le', to),
`ucs2->${to} odd length ${len}`);
}
}