Bug 1303273 part.5 UniCharsAndModifiers should hide mChars r?m_kato draft
authorMasayuki Nakano <masayuki@d-toybox.com>
Fri, 07 Oct 2016 12:04:49 +0900
changeset 423629 1cc32f460f3c4fef0a288587ddcdebd49110e64e
parent 423628 4060330fe71ba599363a1c46a603eba55e2ebd73
child 423630 2eb220fe3e7cb3e7d0834d69f53018d0d01e5766
push id31948
push usermasayuki@d-toybox.com
push dateTue, 11 Oct 2016 12:46:29 +0000
reviewersm_kato
bugs1303273
milestone52.0a1
Bug 1303273 part.5 UniCharsAndModifiers should hide mChars r?m_kato Now, we have an security issue. mCommittedCharsAndModifiers may be initialized with multiple WM_(SYS)CHAR messages. However, if it's generated by odd (or malicious) middleware, mCommittedCharsAndModifiers may be overflown because it has only fixed array. For fixing this issue, first, we should hide the members for making the users not depend on the design of UniCharsAndModifiers. This patch changes UniCharsAndModifiers to a class and hiding mChars and adding |CharAt() const|. MozReview-Commit-ID: 5EjrIhmCdE4
widget/windows/KeyboardLayout.cpp
widget/windows/KeyboardLayout.h
--- a/widget/windows/KeyboardLayout.cpp
+++ b/widget/windows/KeyboardLayout.cpp
@@ -620,26 +620,26 @@ ToString(const MSG& aMSG)
 static const nsCString
 ToString(const UniCharsAndModifiers& aUniCharsAndModifiers)
 {
   if (aUniCharsAndModifiers.IsEmpty()) {
     return NS_LITERAL_CSTRING("{}");
   }
   nsAutoCString result;
   result.AssignLiteral("{ ");
-  result.Append(GetCharacterCodeName(aUniCharsAndModifiers.mChars[0]));
+  result.Append(GetCharacterCodeName(aUniCharsAndModifiers.CharAt(0)));
   for (uint32_t i = 1; i < aUniCharsAndModifiers.mLength; ++i) {
     if (aUniCharsAndModifiers.mModifiers[i - 1] !=
           aUniCharsAndModifiers.mModifiers[i]) {
       result.AppendLiteral(" [");
       result.Append(GetModifiersName(aUniCharsAndModifiers.mModifiers[0]));
       result.AppendLiteral("]");
     }
     result.AppendLiteral(", ");
-    result.Append(GetCharacterCodeName(aUniCharsAndModifiers.mChars[i]));
+    result.Append(GetCharacterCodeName(aUniCharsAndModifiers.CharAt(i)));
   }
   result.AppendLiteral(" [");
   uint32_t lastIndex = aUniCharsAndModifiers.mLength - 1;
   result.Append(GetModifiersName(aUniCharsAndModifiers.mModifiers[lastIndex]));
   result.AppendLiteral("] }");
   return result;
 }
 
@@ -3142,30 +3142,30 @@ NativeKey::ComputeInputtingStringWithKey
                                           &mUnshiftedLatinChar,
                                           &mShiftedLatinChar);
 
   // If the mShiftedLatinChar isn't 0, the key code is NS_VK_[A-Z].
   if (mShiftedLatinChar) {
     // If the produced characters of the key on current keyboard layout
     // are same as computed Latin characters, we shouldn't append the
     // Latin characters to alternativeCharCode.
-    if (mUnshiftedLatinChar == mUnshiftedString.mChars[0] &&
-        mShiftedLatinChar == mShiftedString.mChars[0]) {
+    if (mUnshiftedLatinChar == mUnshiftedString.CharAt(0) &&
+        mShiftedLatinChar == mShiftedString.CharAt(0)) {
       mShiftedLatinChar = mUnshiftedLatinChar = 0;
     }
   } else if (mUnshiftedLatinChar) {
     // If the mShiftedLatinChar is 0, the mKeyCode doesn't produce
     // alphabet character.  At that time, the character may be produced
     // with Shift key.  E.g., on French keyboard layout, NS_VK_PERCENT
     // key produces LATIN SMALL LETTER U WITH GRAVE (U+00F9) without
     // Shift key but with Shift key, it produces '%'.
     // If the mUnshiftedLatinChar is produced by the key on current
     // keyboard layout, we shouldn't append it to alternativeCharCode.
-    if (mUnshiftedLatinChar == mUnshiftedString.mChars[0] ||
-        mUnshiftedLatinChar == mShiftedString.mChars[0]) {
+    if (mUnshiftedLatinChar == mUnshiftedString.CharAt(0) ||
+        mUnshiftedLatinChar == mShiftedString.CharAt(0)) {
       mUnshiftedLatinChar = 0;
     }
   }
 
   if (!mModKeyState.IsControl()) {
     return;
   }
 
@@ -3373,17 +3373,17 @@ NativeKey::WillDispatchKeyboardEvent(Wid
         mInputtingStringAndModifiers.mModifiers[aIndex - skipUniChars]);
       modKeyState.InitInputEvent(aKeyboardEvent);
       MOZ_LOG(sNativeKeyLogger, LogLevel::Info,
         ("%p   NativeKey::WillDispatchKeyboardEvent(), "
          "setting %uth modifier state to %s",
          this, aIndex + 1, ToString(modKeyState).get()));
     }
     uint16_t uniChar =
-      mInputtingStringAndModifiers.mChars[aIndex - skipUniChars];
+      mInputtingStringAndModifiers.CharAt(aIndex - skipUniChars);
 
     // The mCharCode was set from mKeyValue. However, for example, when Ctrl key
     // is pressed, its value should indicate an ASCII character for backward
     // compatibility rather than inputting character without the modifiers.
     // Therefore, we need to modify mCharCode value here.
     aKeyboardEvent.SetCharCode(uniChar);
     MOZ_LOG(sNativeKeyLogger, LogLevel::Info,
       ("%p   NativeKey::WillDispatchKeyboardEvent(), "
@@ -3409,20 +3409,20 @@ NativeKey::WillDispatchKeyboardEvent(Wid
       count = longestLength - aIndex;
     }
   } else {
     count = longestLength;
   }
   for (size_t i = 0; i < count; ++i) {
     uint16_t shiftedChar = 0, unshiftedChar = 0;
     if (skipShiftedChars <= aIndex + i) {
-      shiftedChar = mShiftedString.mChars[aIndex + i - skipShiftedChars];
+      shiftedChar = mShiftedString.CharAt(aIndex + i - skipShiftedChars);
     }
     if (skipUnshiftedChars <= aIndex + i) {
-      unshiftedChar = mUnshiftedString.mChars[aIndex + i - skipUnshiftedChars];
+      unshiftedChar = mUnshiftedString.CharAt(aIndex + i - skipUnshiftedChars);
     }
 
     if (shiftedChar || unshiftedChar) {
       AlternativeCharCode chars(unshiftedChar, shiftedChar);
       altArray.AppendElement(chars);
     }
 
     if (!isLastIndex) {
@@ -3443,18 +3443,18 @@ NativeKey::WillDispatchKeyboardEvent(Wid
     char16_t charForOEMKeyCode = 0;
     switch (mVirtualKeyCode) {
       case VK_OEM_PLUS:   charForOEMKeyCode = '+'; break;
       case VK_OEM_COMMA:  charForOEMKeyCode = ','; break;
       case VK_OEM_MINUS:  charForOEMKeyCode = '-'; break;
       case VK_OEM_PERIOD: charForOEMKeyCode = '.'; break;
     }
     if (charForOEMKeyCode &&
-        charForOEMKeyCode != mUnshiftedString.mChars[0] &&
-        charForOEMKeyCode != mShiftedString.mChars[0] &&
+        charForOEMKeyCode != mUnshiftedString.CharAt(0) &&
+        charForOEMKeyCode != mShiftedString.CharAt(0) &&
         charForOEMKeyCode != mUnshiftedLatinChar &&
         charForOEMKeyCode != mShiftedLatinChar) {
       AlternativeCharCode OEMChars(charForOEMKeyCode, charForOEMKeyCode);
       altArray.AppendElement(OEMChars);
     }
   }
 }
 
@@ -3780,22 +3780,22 @@ KeyboardLayout::MaybeInitNativeKeyWithCo
 
   if (NS_WARN_IF(!IsPrintableCharKey(mActiveDeadKey)) ||
       NS_WARN_IF(!IsPrintableCharKey(aNativeKey.mOriginalVirtualKeyCode))) {
     return false;
   }
 
   UniCharsAndModifiers baseChars =
     GetUniCharsAndModifiers(aNativeKey.mOriginalVirtualKeyCode, aModKeyState);
-  if (baseChars.IsEmpty() || !baseChars.mChars[0]) {
+  if (baseChars.IsEmpty() || !baseChars.CharAt(0)) {
     return false;
   }
 
   char16_t compositeChar =
-    GetCompositeChar(mActiveDeadKey, mDeadKeyShiftState, baseChars.mChars[0]);
+    GetCompositeChar(mActiveDeadKey, mDeadKeyShiftState, baseChars.CharAt(0));
   if (!compositeChar) {
     return false;
   }
 
   // Active dead-key and base character does produce exactly one composite
   // character.
   aNativeKey.mCommittedCharsAndModifiers.Append(compositeChar,
                                                 baseChars.mModifiers[0]);
@@ -4429,25 +4429,25 @@ KeyboardLayout::ConvertNativeKeyCodeToDO
     case VK_ABNT_C1:
     {
       NS_ASSERTION(IsPrintableCharKey(aNativeKeyCode),
                    "The key must be printable");
       ModifierKeyState modKeyState(0);
       UniCharsAndModifiers uniChars =
         GetUniCharsAndModifiers(aNativeKeyCode, modKeyState);
       if (uniChars.mLength != 1 ||
-          uniChars.mChars[0] < ' ' || uniChars.mChars[0] > 0x7F) {
+          uniChars.CharAt(0) < ' ' || uniChars.CharAt(0) > 0x7F) {
         modKeyState.Set(MODIFIER_SHIFT);
         uniChars = GetUniCharsAndModifiers(aNativeKeyCode, modKeyState);
         if (uniChars.mLength != 1 ||
-            uniChars.mChars[0] < ' ' || uniChars.mChars[0] > 0x7F) {
+            uniChars.CharAt(0) < ' ' || uniChars.CharAt(0) > 0x7F) {
           return 0;
         }
       }
-      return WidgetUtils::ComputeKeyCodeFromChar(uniChars.mChars[0]);
+      return WidgetUtils::ComputeKeyCodeFromChar(uniChars.CharAt(0));
     }
 
     // IE sets 0xC2 to the DOM keyCode for VK_ABNT_C2.  However, we're already
     // using NS_VK_SEPARATOR for the separator key on Mac and Linux.  Therefore,
     // We should keep consistency between Gecko on all platforms rather than
     // with other browsers since a lot of keyCode values are already different
     // between browsers.
     case VK_ABNT_C2:
--- a/widget/windows/KeyboardLayout.h
+++ b/widget/windows/KeyboardLayout.h
@@ -52,41 +52,49 @@ static const uint32_t sModifierKeyMap[][
   { nsIWidget::CTRL_L,    VK_CONTROL, VK_LCONTROL },
   { nsIWidget::CTRL_R,    VK_CONTROL, VK_RCONTROL },
   { nsIWidget::ALT_L,     VK_MENU,    VK_LMENU },
   { nsIWidget::ALT_R,     VK_MENU,    VK_RMENU }
 };
 
 class KeyboardLayout;
 
-struct UniCharsAndModifiers
+class UniCharsAndModifiers final
 {
+public:
   // Dead-key + up to 4 characters
-  char16_t mChars[5];
   Modifiers mModifiers[5];
   uint32_t  mLength;
 
   UniCharsAndModifiers() : mLength(0) {}
   UniCharsAndModifiers operator+(const UniCharsAndModifiers& aOther) const;
   UniCharsAndModifiers& operator+=(const UniCharsAndModifiers& aOther);
 
   /**
    * Append a pair of unicode character and the final modifier.
    */
   void Append(char16_t aUniChar, Modifiers aModifiers);
   void Clear() { mLength = 0; }
   bool IsEmpty() const { return !mLength; }
 
+  char16_t CharAt(size_t aIndex) const
+  {
+    MOZ_ASSERT(aIndex < mLength);
+    return mChars[aIndex];
+  }
   void FillModifiers(Modifiers aModifiers);
 
   bool UniCharsEqual(const UniCharsAndModifiers& aOther) const;
   bool UniCharsCaseInsensitiveEqual(const UniCharsAndModifiers& aOther) const;
   bool BeginsWith(const UniCharsAndModifiers& aOther) const;
 
   nsString ToString() const { return nsString(mChars, mLength); }
+
+private:
+  char16_t mChars[5];
 };
 
 struct DeadKeyEntry;
 class DeadKeyTable;
 
 
 class VirtualKey
 {