Bug 1427229 - Perform validation when sending an EnumSet over IPC. r=botond,froydnj
authorDaniel Zielas <zielas.daniel@gmail.com>
Sun, 21 Jan 2018 21:23:21 +0100
changeset 453817 1810b8f69bf358c3bf6c89d20d2a54b17cb8839f
parent 453816 ed4ebaacc8b79cf0c92e4e623c9ae0827e64df1c
child 453818 4114e1e168ea61deb48d00b89e4ad42f11ca74e3
push id8799
push usermtabara@mozilla.com
push dateThu, 01 Mar 2018 16:46:23 +0000
treeherdermozilla-beta@15334014dc67 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbotond, froydnj
bugs1427229
milestone60.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1427229 - Perform validation when sending an EnumSet over IPC. r=botond,froydnj MozReview-Commit-ID: Cmugi1ldc1Z
ipc/glue/IPCMessageUtils.h
mfbt/EnumSet.h
mfbt/EnumTypeTraits.h
--- a/ipc/glue/IPCMessageUtils.h
+++ b/ipc/glue/IPCMessageUtils.h
@@ -10,26 +10,29 @@
 #include "base/process_util.h"
 #include "chrome/common/ipc_message_utils.h"
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/dom/ipc/StructuredCloneData.h"
 #include "mozilla/EnumSet.h"
+#include "mozilla/EnumTypeTraits.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/net/WebSocketFrame.h"
 #include "mozilla/TimeStamp.h"
 #ifdef XP_WIN
 #include "mozilla/TimeStamp_windows.h"
 #endif
 #include "mozilla/TypeTraits.h"
 #include "mozilla/IntegerTypeTraits.h"
 
+#include <limits>
 #include <stdint.h>
+#include <type_traits>
 
 #include "nsExceptionHandler.h"
 #include "nsID.h"
 #include "nsIWidget.h"
 #include "nsMemory.h"
 #include "nsString.h"
 #include "nsTArray.h"
 #include "js/StructuredClone.h"
@@ -929,31 +932,53 @@ struct ParamTraits<mozilla::Maybe<T>>
     return true;
   }
 };
 
 template<typename T>
 struct ParamTraits<mozilla::EnumSet<T>>
 {
   typedef mozilla::EnumSet<T> paramType;
+  typedef typename mozilla::EnumSet<T>::serializedType serializedType;
 
   static void Write(Message* msg, const paramType& param)
   {
+    MOZ_RELEASE_ASSERT(IsLegalValue(param.serialize()));
     WriteParam(msg, param.serialize());
   }
 
   static bool Read(const Message* msg, PickleIterator* iter, paramType* result)
   {
-    decltype(result->serialize()) tmp;
+    serializedType tmp;
+
     if (ReadParam(msg, iter, &tmp)) {
-      result->deserialize(tmp);
-      return true;
+      if (IsLegalValue(tmp)) {
+        result->deserialize(tmp);
+        return true;
+      }
     }
+
     return false;
   }
+
+  static constexpr serializedType AllEnumBits()
+  {
+    return ~serializedType(0) >>
+           (std::numeric_limits<serializedType>::digits - (mozilla::MaxEnumValue<T>::value + 1));
+  }
+
+  static constexpr bool IsLegalValue(const serializedType value)
+  {
+    static_assert(mozilla::MaxEnumValue<T>::value < std::numeric_limits<serializedType>::digits,
+                  "Enum max value is not in the range!");
+    static_assert(std::is_unsigned<decltype(mozilla::MaxEnumValue<T>::value)>::value,
+                  "Type of MaxEnumValue<T>::value specialization should be unsigned!");
+
+    return (value & AllEnumBits()) == value;
+  }
 };
 
 template<class... Ts>
 struct ParamTraits<mozilla::Variant<Ts...>>
 {
   typedef mozilla::Variant<Ts...> paramType;
   using Tag = typename mozilla::detail::VariantTag<Ts...>::Type;
 
--- a/mfbt/EnumSet.h
+++ b/mfbt/EnumSet.h
@@ -22,16 +22,18 @@ namespace mozilla {
  * EnumSet<T> is a set of values defined by an enumeration. It is implemented
  * using a 32 bit mask for each value so it will only work for enums with an int
  * representation less than 32. It works both for enum and enum class types.
  */
 template<typename T>
 class EnumSet
 {
 public:
+  typedef uint32_t serializedType;
+
   EnumSet()
     : mBitField(0)
   {
   }
 
   MOZ_IMPLICIT EnumSet(T aEnum)
     : mBitField(bitFor(aEnum))
   { }
@@ -204,22 +206,22 @@ public:
     return count;
   }
 
   bool isEmpty() const
   {
     return mBitField == 0;
   }
 
-  uint32_t serialize() const
+  serializedType serialize() const
   {
     return mBitField;
   }
 
-  void deserialize(uint32_t aValue)
+  void deserialize(serializedType aValue)
   {
     incVersion();
     mBitField = aValue;
   }
 
   class ConstIterator
   {
     const EnumSet<T>* mSet;
@@ -315,17 +317,17 @@ private:
 
   void incVersion() {
 #ifdef DEBUG
     mVersion++;
 #endif
   }
 
   static const size_t kMaxBits = 32;
-  uint32_t mBitField;
+  serializedType mBitField;
 
 #ifdef DEBUG
   uint64_t mVersion = 0;
 #endif
 };
 
 } // namespace mozilla
 
--- a/mfbt/EnumTypeTraits.h
+++ b/mfbt/EnumTypeTraits.h
@@ -60,11 +60,34 @@ struct EnumTypeFitsWithin
       sizeof(Storage),
       std::is_signed<Storage>::value
     >
 {
   static_assert(std::is_enum<T>::value, "must provide an enum type");
   static_assert(std::is_integral<Storage>::value, "must provide an integral type");
 };
 
+/*
+ * Provides information about highest enum member value.
+ * Each specialization of struct MaxEnumValue should define
+ * "static constexpr unsigned int value".
+ *
+ * example:
+ *
+ *   enum ExampleEnum
+ *   {
+ *     CAT = 0,
+ *     DOG,
+ *     HAMSTER
+ *   };
+ *
+ *   template <>
+ *   struct MaxEnumValue<ExampleEnum>
+ *   {
+ *     static constexpr unsigned int value = static_cast<unsigned int>(HAMSTER);
+ *   };
+ */
+template <typename T>
+struct MaxEnumValue;  // no need to define the primary template
+
 } // namespace mozilla
 
 #endif /* mozilla_EnumTypeTraits_h */