| OLD | NEW | 
|    1 /* |    1 /* | 
|    2  * Copyright (C) 2010 Google Inc. All rights reserved. |    2  * Copyright (C) 2010 Google Inc. All rights reserved. | 
|    3  * |    3  * | 
|    4  * Redistribution and use in source and binary forms, with or without |    4  * Redistribution and use in source and binary forms, with or without | 
|    5  * modification, are permitted provided that the following conditions are |    5  * modification, are permitted provided that the following conditions are | 
|    6  * met: |    6  * met: | 
|    7  * |    7  * | 
|    8  *     * Redistributions of source code must retain the above copyright |    8  *     * Redistributions of source code must retain the above copyright | 
|    9  * notice, this list of conditions and the following disclaimer. |    9  * notice, this list of conditions and the following disclaimer. | 
|   10  *     * Redistributions in binary form must reproduce the above |   10  *     * Redistributions in binary form must reproduce the above | 
| (...skipping 24 matching lines...) Expand all  Loading... | 
|   35 #include "bindings/v8/V8Utilities.h" |   35 #include "bindings/v8/V8Utilities.h" | 
|   36 #include "bindings/v8/WrapperTypeInfo.h" |   36 #include "bindings/v8/WrapperTypeInfo.h" | 
|   37 #include "core/dom/WebCoreMemoryInstrumentation.h" |   37 #include "core/dom/WebCoreMemoryInstrumentation.h" | 
|   38 #include <v8.h> |   38 #include <v8.h> | 
|   39  |   39  | 
|   40 namespace WebCore { |   40 namespace WebCore { | 
|   41  |   41  | 
|   42 class ScriptWrappable : public MemoryReporterTag { |   42 class ScriptWrappable : public MemoryReporterTag { | 
|   43     friend class WeakHandleListener<ScriptWrappable>; |   43     friend class WeakHandleListener<ScriptWrappable>; | 
|   44 public: |   44 public: | 
|   45     ScriptWrappable() : m_maskedStorage(0) { } |   45     ScriptWrappable() : m_wrapperOrTypeInfo(0) { } | 
|   46  |   46  | 
|   47     // Wrappables need to be initialized with their most derrived type for which |   47     // Wrappables need to be initialized with their most derrived type for which | 
|   48     // bindings exist, in much the same way that certain other types need to be |   48     // bindings exist, in much the same way that certain other types need to be | 
|   49     // adopted and so forth. The overloaded initializeScriptWrappableForInterfac
     e() |   49     // adopted and so forth. The overloaded initializeScriptWrappableForInterfac
     e() | 
|   50     // functions are implemented by the generated V8 bindings code. Declaring th
     e |   50     // functions are implemented by the generated V8 bindings code. Declaring th
     e | 
|   51     // extern function in the template avoids making a centralized header of all |   51     // extern function in the template avoids making a centralized header of all | 
|   52     // the bindings in the universe. C++11's extern template feature may provide |   52     // the bindings in the universe. C++11's extern template feature may provide | 
|   53     // a cleaner solution someday. |   53     // a cleaner solution someday. | 
|   54     template <class C> static void init(C* object) |   54     template <class C> static void init(C* object) | 
|   55     { |   55     { | 
|   56         void initializeScriptWrappableForInterface(C*); |   56         void initializeScriptWrappableForInterface(C*); | 
|   57         initializeScriptWrappableForInterface(object); |   57         initializeScriptWrappableForInterface(object); | 
|   58     } |   58     } | 
|   59  |   59  | 
|   60     void setWrapper(v8::Handle<v8::Object> wrapper, v8::Isolate* isolate, const 
     WrapperConfiguration& configuration) |   60     void setWrapper(v8::Handle<v8::Object> wrapper, v8::Isolate* isolate, const 
     WrapperConfiguration& configuration) | 
|   61     { |   61     { | 
|   62         ASSERT(!containsWrapper()); |   62         ASSERT(!containsWrapper()); | 
|   63         if (!*wrapper) { |   63         if (!*wrapper) { | 
|   64             m_maskedStorage = 0; |   64             m_wrapperOrTypeInfo = 0; | 
|   65             return; |   65             return; | 
|   66         } |   66         } | 
|   67         v8::Persistent<v8::Object> persistent(isolate, wrapper); |   67         v8::Persistent<v8::Object> persistent(isolate, wrapper); | 
|   68         configuration.configureWrapper(persistent, isolate); |   68         configuration.configureWrapper(persistent, isolate); | 
|   69         WeakHandleListener<ScriptWrappable>::makeWeak(isolate, persistent, this)
     ; |   69         WeakHandleListener<ScriptWrappable>::makeWeak(isolate, persistent, this)
     ; | 
|   70         m_maskedStorage = maskOrUnmaskValue(reinterpret_cast<uintptr_t>(*persist
     ent)); |   70         m_wrapperOrTypeInfo = reinterpret_cast<uintptr_t>(*persistent) | 1; | 
|   71         ASSERT(containsWrapper()); |   71         ASSERT(containsWrapper()); | 
|   72     } |   72     } | 
|   73  |   73  | 
|   74     const WrapperTypeInfo* typeInfo() |   74     const WrapperTypeInfo* typeInfo() | 
|   75     { |   75     { | 
|   76         if (containsTypeInfo()) |   76         if (containsTypeInfo()) | 
|   77             return reinterpret_cast<const WrapperTypeInfo*>(m_maskedStorage); |   77             return reinterpret_cast<const WrapperTypeInfo*>(m_wrapperOrTypeInfo)
     ; | 
|   78  |   78  | 
|   79         if (containsWrapper()) { |   79         if (containsWrapper()) { | 
|   80             v8::Persistent<v8::Object> unsafeWrapper; |   80             v8::Persistent<v8::Object> unsafeWrapper; | 
|   81             unsafePersistent().copyTo(&unsafeWrapper); |   81             unsafePersistent().copyTo(&unsafeWrapper); | 
|   82             return toWrapperTypeInfo(unsafeWrapper); |   82             return toWrapperTypeInfo(unsafeWrapper); | 
|   83         } |   83         } | 
|   84  |   84  | 
|   85         return 0; |   85         return 0; | 
|   86     } |   86     } | 
|   87  |   87  | 
|   88     void setTypeInfo(const WrapperTypeInfo* info) |   88     void setTypeInfo(const WrapperTypeInfo* info) | 
|   89     { |   89     { | 
|   90         m_maskedStorage = reinterpret_cast<uintptr_t>(info); |   90         m_wrapperOrTypeInfo = reinterpret_cast<uintptr_t>(info); | 
|   91         ASSERT(containsTypeInfo()); |   91         ASSERT(containsTypeInfo()); | 
|   92     } |   92     } | 
|   93  |   93  | 
|   94     void reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const |   94     void reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const | 
|   95     { |   95     { | 
|   96         MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::DOM); |   96         MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::DOM); | 
|   97         info.ignoreMember(m_maskedStorage); |   97         info.ignoreMember(m_wrapperOrTypeInfo); | 
|   98     } |   98     } | 
|   99  |   99  | 
|  100     static bool wrapperCanBeStoredInObject(const void*) { return false; } |  100     static bool wrapperCanBeStoredInObject(const void*) { return false; } | 
|  101     static bool wrapperCanBeStoredInObject(const ScriptWrappable*) { return true
     ; } |  101     static bool wrapperCanBeStoredInObject(const ScriptWrappable*) { return true
     ; } | 
|  102  |  102  | 
|  103     static void setWrapperInObject(void*, v8::Handle<v8::Object>, v8::Isolate*, 
     const WrapperConfiguration&) |  103     static void setWrapperInObject(void*, v8::Handle<v8::Object>, v8::Isolate*, 
     const WrapperConfiguration&) | 
|  104     { |  104     { | 
|  105         ASSERT_NOT_REACHED(); |  105         ASSERT_NOT_REACHED(); | 
|  106     } |  106     } | 
|  107  |  107  | 
| (...skipping 19 matching lines...) Expand all  Loading... | 
|  127     } |  127     } | 
|  128  |  128  | 
|  129     static void setTypeInfoInObject(ScriptWrappable* object, const WrapperTypeIn
     fo* info) |  129     static void setTypeInfoInObject(ScriptWrappable* object, const WrapperTypeIn
     fo* info) | 
|  130     { |  130     { | 
|  131         object->setTypeInfo(info); |  131         object->setTypeInfo(info); | 
|  132     } |  132     } | 
|  133  |  133  | 
|  134 protected: |  134 protected: | 
|  135     ~ScriptWrappable() |  135     ~ScriptWrappable() | 
|  136     { |  136     { | 
|  137         ASSERT(m_maskedStorage);  // Assert initialization via init() even if no
     t subsequently wrapped. |  137         ASSERT(m_wrapperOrTypeInfo);  // Assert initialization via init() even i
     f not subsequently wrapped. | 
|  138         m_maskedStorage = 0;      // Break UAF attempts to wrap. |  138         m_wrapperOrTypeInfo = 0;      // Break UAF attempts to wrap. | 
|  139     } |  139     } | 
|  140  |  140  | 
|  141 private: |  141 private: | 
|  142     // For calling unsafePersistent and getWrapperFromObject. |  142     // For calling unsafePersistent and getWrapperFromObject. | 
|  143     friend class MinorGCWrapperVisitor; |  143     friend class MinorGCWrapperVisitor; | 
|  144     friend class DOMDataStore; |  144     friend class DOMDataStore; | 
|  145  |  145  | 
|  146     UnsafePersistent<v8::Object> unsafePersistent() const |  146     UnsafePersistent<v8::Object> unsafePersistent() const | 
|  147     { |  147     { | 
|  148         v8::Object* object = containsWrapper() ? reinterpret_cast<v8::Object*>(m
     askOrUnmaskValue(m_maskedStorage)) : 0; |  148         v8::Object* object = containsWrapper() ? reinterpret_cast<v8::Object*>(m
     _wrapperOrTypeInfo & ~1) : 0; | 
|  149         return UnsafePersistent<v8::Object>(object); |  149         return UnsafePersistent<v8::Object>(object); | 
|  150     } |  150     } | 
|  151  |  151  | 
|  152     static UnsafePersistent<v8::Object> getUnsafeWrapperFromObject(void*) |  152     static UnsafePersistent<v8::Object> getUnsafeWrapperFromObject(void*) | 
|  153     { |  153     { | 
|  154         ASSERT_NOT_REACHED(); |  154         ASSERT_NOT_REACHED(); | 
|  155         return UnsafePersistent<v8::Object>(); |  155         return UnsafePersistent<v8::Object>(); | 
|  156     } |  156     } | 
|  157  |  157  | 
|  158     static UnsafePersistent<v8::Object> getUnsafeWrapperFromObject(ScriptWrappab
     le* object) |  158     static UnsafePersistent<v8::Object> getUnsafeWrapperFromObject(ScriptWrappab
     le* object) | 
|  159     { |  159     { | 
|  160         return object->unsafePersistent(); |  160         return object->unsafePersistent(); | 
|  161     } |  161     } | 
|  162  |  162  | 
|  163     inline bool containsWrapper() const { return (m_maskedStorage & 1) == 1; } |  163     inline bool containsWrapper() const { return (m_wrapperOrTypeInfo & 1) == 1;
      } | 
|  164     inline bool containsTypeInfo() const { return m_maskedStorage && ((m_maskedS
     torage & 1) == 0); } |  164     inline bool containsTypeInfo() const { return m_wrapperOrTypeInfo && (m_wrap
     perOrTypeInfo & 1) == 0; } | 
|  165  |  | 
|  166     static inline uintptr_t maskOrUnmaskValue(uintptr_t value) |  | 
|  167     { |  | 
|  168         // Entropy via ASLR, bottom bit set to always toggle the bottom bit in t
     he result. Since masking is only |  | 
|  169         // applied to wrappers, not wrapper type infos, and these are aligned po
     itners with zeros in the bottom |  | 
|  170         // bit(s), this automatically set the wrapper flag in the bottom bit upo
     n encoding. Simiarlry,this |  | 
|  171         // automatically zeros out the bit upon decoding. Additionally, since se
     tWrapper() now performs an explicit |  | 
|  172         // null test, and wrapper() requires the bottom bit to be set, there is 
     no need to preserve null here. |  | 
|  173         const uintptr_t randomMask = ~((reinterpret_cast<uintptr_t>(&WebCoreMemo
     ryTypes::DOM) >> 13)) | 1; |  | 
|  174         return value ^ randomMask; |  | 
|  175     } |  | 
|  176  |  165  | 
|  177     inline void disposeWrapper(v8::Persistent<v8::Value> value, v8::Isolate* iso
     late, const WrapperTypeInfo* info) |  166     inline void disposeWrapper(v8::Persistent<v8::Value> value, v8::Isolate* iso
     late, const WrapperTypeInfo* info) | 
|  178     { |  167     { | 
|  179         ASSERT(containsWrapper()); |  168         ASSERT(containsWrapper()); | 
|  180         ASSERT(reinterpret_cast<uintptr_t>(*value) == maskOrUnmaskValue(m_masked
     Storage)); |  169         ASSERT(reinterpret_cast<uintptr_t>(*value) == (m_wrapperOrTypeInfo & ~1)
     ); | 
|  181         value.Dispose(isolate); |  170         value.Dispose(isolate); | 
|  182         setTypeInfo(info); |  171         setTypeInfo(info); | 
|  183     } |  172     } | 
|  184  |  173  | 
|  185     // If zero, then this contains nothing, otherwise: |  174     // If zero, then this contains nothing, otherwise: | 
|  186     //   If the bottom bit it set, then this contains a masked pointer to a wrap
     per object in the remainging bits. |  175     //   If the bottom bit it set, then this contains a pointer to a wrapper obj
     ect in the remainging bits. | 
|  187     //   If the bottom bit is clear, then this contains a pointer to the wrapper
      type info in the remaining bits. |  176     //   If the bottom bit is clear, then this contains a pointer to the wrapper
      type info in the remaining bits. | 
|  188     // Masking wrappers prevents attackers from overwriting this field with poin
     ters to sprayed data. |  177     uintptr_t m_wrapperOrTypeInfo; | 
|  189     // Pointers to (and inside) WrapperTypeInfo are already protected by ASLR. |  | 
|  190     uintptr_t m_maskedStorage; |  | 
|  191 }; |  178 }; | 
|  192  |  179  | 
|  193 template<> |  180 template<> | 
|  194 inline void WeakHandleListener<ScriptWrappable>::callback(v8::Isolate* isolate, 
     v8::Persistent<v8::Value> value, ScriptWrappable* key) |  181 inline void WeakHandleListener<ScriptWrappable>::callback(v8::Isolate* isolate, 
     v8::Persistent<v8::Value> value, ScriptWrappable* key) | 
|  195 { |  182 { | 
|  196     ASSERT(value->IsObject()); |  183     ASSERT(value->IsObject()); | 
|  197     v8::Persistent<v8::Object> wrapper = v8::Persistent<v8::Object>::Cast(value)
     ; |  184     v8::Persistent<v8::Object> wrapper = v8::Persistent<v8::Object>::Cast(value)
     ; | 
|  198     ASSERT(key->unsafePersistent().handle() == wrapper); |  185     ASSERT(key->unsafePersistent().handle() == wrapper); | 
|  199  |  186  | 
|  200     // Note: |object| might not be equal to |key|, e.g., if ScriptWrappable isn'
     t a left-most base class. |  187     // Note: |object| might not be equal to |key|, e.g., if ScriptWrappable isn'
     t a left-most base class. | 
|  201     void* object = toNative(wrapper); |  188     void* object = toNative(wrapper); | 
|  202     WrapperTypeInfo* info = toWrapperTypeInfo(wrapper); |  189     WrapperTypeInfo* info = toWrapperTypeInfo(wrapper); | 
|  203     ASSERT(info->derefObjectFunction); |  190     ASSERT(info->derefObjectFunction); | 
|  204  |  191  | 
|  205     key->disposeWrapper(value, isolate, info); |  192     key->disposeWrapper(value, isolate, info); | 
|  206     // FIXME: I noticed that 50%~ of minor GC cycle times can be consumed |  193     // FIXME: I noticed that 50%~ of minor GC cycle times can be consumed | 
|  207     // inside key->deref(), which causes Node destructions. We should |  194     // inside key->deref(), which causes Node destructions. We should | 
|  208     // make Node destructions incremental. |  195     // make Node destructions incremental. | 
|  209     info->derefObject(object); |  196     info->derefObject(object); | 
|  210 } |  197 } | 
|  211  |  198  | 
|  212 } // namespace WebCore |  199 } // namespace WebCore | 
|  213  |  200  | 
|  214 #endif // ScriptWrappable_h |  201 #endif // ScriptWrappable_h | 
| OLD | NEW |