Reviewers: danno, svenpanne,

Message:
This is a security issue for node.js, io.js and maybe chromium!

Description:
unicode-decoder: fix out-of-bands write in utf16

`WriteUtf16Slow` should not assume that the output buffer has enough
bytes to hold both words of surrogate pair. It should pass the number of
remaining bytes to the `Utf8::ValueOf` instead, just as we already do in
`Utf8DecoderBase::Reset`. Otherwise it will attempt to write the trail
uint16_t past the buffer boundary, leading to memory corruption and
possible crash.

Originally reported by: Kris Reeves <[email protected]>

BUG=
R=danno
R=svenpanne

Please review this at https://codereview.chromium.org/1226493003/

Base URL: https://chromium.googlesource.com/v8/v8.git@master

Affected files (+22, -1 lines):
  M src/unicode-decoder.cc
  M test/cctest/test-api.cc


Index: src/unicode-decoder.cc
diff --git a/src/unicode-decoder.cc b/src/unicode-decoder.cc
index a3bf829522688b27a84b74e3322eed5a0c4088f3..4e7ebb878669d7aa3fa276a061ac66044c63ac3a 100644
--- a/src/unicode-decoder.cc
+++ b/src/unicode-decoder.cc
@@ -59,7 +59,7 @@ void Utf8DecoderBase::WriteUtf16Slow(const uint8_t* stream, uint16_t* data,
                                      size_t data_length) {
   while (data_length != 0) {
     size_t cursor = 0;
- uint32_t character = Utf8::ValueOf(stream, Utf8::kMaxEncodedSize, &cursor);
+    uint32_t character = Utf8::ValueOf(stream, data_length, &cursor);
     // There's a total lack of bounds checking for stream
     // as it was already done in Reset.
     stream += cursor;
Index: test/cctest/test-api.cc
diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
index 4b911f95c8e8e60388f768230c2a51fd56dd66d2..2957cc06b1ae6cf8d66953b5e3520757018f5922 100644
--- a/test/cctest/test-api.cc
+++ b/test/cctest/test-api.cc
@@ -7418,6 +7418,27 @@ THREADED_TEST(Utf16Symbol) {
 }


+THREADED_TEST(Utf16MissingTrailing) {
+  LocalContext context;
+  v8::HandleScope scope(context->GetIsolate());
+
+  // Make sure it will go past the buffer, so it will call `WriteUtf16Slow`
+  int size = 1024 * 64;
+  uint8_t* buffer = new uint8_t[size];
+  for (int i = 0; i < size; i += 4) {
+    buffer[i] = 0xf0;
+    buffer[i + 1] = 0x9d;
+    buffer[i + 2] = 0x80;
+    buffer[i + 3] = 0x9e;
+  }
+
+  // Now invoke the decoder without last 3 bytes
+  v8::Handle<v8::String> str = v8::String::NewFromUtf8(
+      context->GetIsolate(), reinterpret_cast<char*>(buffer),
+      v8::String::kNormalString, size - 3);
+}
+
+
 THREADED_TEST(ToArrayIndex) {
   LocalContext context;
   v8::Isolate* isolate = context->GetIsolate();


--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
--- You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to