InjectedBundle parameters often need initialization function called before unarchiving
authorbfulgham@apple.com <bfulgham@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 20 Sep 2018 23:11:19 +0000 (23:11 +0000)
committerbfulgham@apple.com <bfulgham@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 20 Sep 2018 23:11:19 +0000 (23:11 +0000)
https://bugs.webkit.org/show_bug.cgi?id=189709
<rdar://problem/44573653>

Reviewed by Chris Dumez.

Handle the case where the InjectedBundle parameters do not successfully decode because they contain
an unexpected class from the embedding program. If this happens, try decoding the bundle parameters
after the bundle initialiation function runs, which gives the embedding program the opportunity to
register additional classes that are safe for serialization.

Create a new 'decodeBundleParameters' method that contains the logic that used to live in 'initialize'.
This new method returns 'true' if the serialization was successful, otherwise it returns false.

Revise 'initialize' to call this new method and check the return value. If it fails, try decoding the
bundle parameters after the bundle's initialization function is called.

* WebProcess/InjectedBundle/InjectedBundle.h:
* WebProcess/InjectedBundle/mac/InjectedBundleMac.mm:
(WebKit::InjectedBundle::initialize): Use the new method.
(WebKit::InjectedBundle::decodeBundleParameters): Added.
(WebKit::InjectedBundle::setBundleParameters): Use 'decodeObjectOfClasses' with the more complete
'classesForCoder' method to unarchive the passed bundle parameters, rather than the
NSDictionary-specific method, since InjectedBundles often encode other types of objects, and the
NSDictionary object may itself hold other kinds of objects.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@236289 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebKit/ChangeLog
Source/WebKit/WebProcess/InjectedBundle/InjectedBundle.h
Source/WebKit/WebProcess/InjectedBundle/mac/InjectedBundleMac.mm

index d80ff36..1ab5ee5 100644 (file)
@@ -1,3 +1,31 @@
+2018-09-20  Brent Fulgham  <bfulgham@apple.com>
+
+        InjectedBundle parameters often need initialization function called before unarchiving
+        https://bugs.webkit.org/show_bug.cgi?id=189709
+        <rdar://problem/44573653>
+
+        Reviewed by Chris Dumez.
+
+        Handle the case where the InjectedBundle parameters do not successfully decode because they contain
+        an unexpected class from the embedding program. If this happens, try decoding the bundle parameters
+        after the bundle initialiation function runs, which gives the embedding program the opportunity to
+        register additional classes that are safe for serialization.
+        
+        Create a new 'decodeBundleParameters' method that contains the logic that used to live in 'initialize'.
+        This new method returns 'true' if the serialization was successful, otherwise it returns false.
+
+        Revise 'initialize' to call this new method and check the return value. If it fails, try decoding the
+        bundle parameters after the bundle's initialization function is called.
+
+        * WebProcess/InjectedBundle/InjectedBundle.h:
+        * WebProcess/InjectedBundle/mac/InjectedBundleMac.mm:
+        (WebKit::InjectedBundle::initialize): Use the new method.
+        (WebKit::InjectedBundle::decodeBundleParameters): Added.
+        (WebKit::InjectedBundle::setBundleParameters): Use 'decodeObjectOfClasses' with the more complete
+        'classesForCoder' method to unarchive the passed bundle parameters, rather than the
+        NSDictionary-specific method, since InjectedBundles often encode other types of objects, and the
+        NSDictionary object may itself hold other kinds of objects.
+
 2018-09-20  Jer Noble  <jer.noble@apple.com>
 
         Enable Modern EME by default
index 257ebb7..5c15191 100644 (file)
@@ -168,6 +168,10 @@ public:
 private:
     explicit InjectedBundle(const WebProcessCreationParameters&);
 
+#if PLATFORM(COCOA) && WK_API_ENABLED
+    void decodeBundleParameters(API::Data*);
+#endif
+
     String m_path;
     PlatformBundle m_platformBundle; // This is leaked right now, since we never unload the bundle/module.
 
index a0a3e83..dcb0fd3 100644 (file)
@@ -98,35 +98,21 @@ bool InjectedBundle::initialize(const WebProcessCreationParameters& parameters,
         }
     }
 
-#if WK_API_ENABLED
-    if (parameters.bundleParameterData) {
-        auto bundleParameterData = adoptNS([[NSData alloc] initWithBytesNoCopy:const_cast<void*>(static_cast<const void*>(parameters.bundleParameterData->bytes())) length:parameters.bundleParameterData->size() freeWhenDone:NO]);
-
-        auto unarchiver = secureUnarchiverFromData(bundleParameterData.get());
-
-        NSDictionary *dictionary = nil;
-        @try {
-            dictionary = [unarchiver.get() decodeObjectOfClass:[NSObject class] forKey:@"parameters"];
-            ASSERT([dictionary isKindOfClass:[NSDictionary class]]);
-        } @catch (NSException *exception) {
-            LOG_ERROR("Failed to decode bundle parameters: %@", exception);
-        }
-
-        ASSERT(!m_bundleParameters);
-        m_bundleParameters = adoptNS([[WKWebProcessBundleParameters alloc] initWithDictionary:dictionary]);
-    }
-#endif
-    
     if (!initializeFunction)
         initializeFunction = bitwise_cast<WKBundleInitializeFunctionPtr>(CFBundleGetFunctionPointerForName([m_platformBundle _cfBundle], CFSTR("WKBundleInitialize")));
 
     // First check to see if the bundle has a WKBundleInitialize function.
     if (initializeFunction) {
         initializeFunction(toAPI(this), toAPI(initializationUserData));
+#if WK_API_ENABLED
+        decodeBundleParameters(parameters.bundleParameterData.get());
+#endif
         return true;
     }
 
 #if WK_API_ENABLED
+    decodeBundleParameters(parameters.bundleParameterData.get());
+
     // Otherwise, look to see if the bundle has a principal class
     Class principalClass = [m_platformBundle principalClass];
     if (!principalClass) {
@@ -205,6 +191,29 @@ NSSet* InjectedBundle::classesForCoder()
 
     return m_classesForCoder.get();
 }
+
+void InjectedBundle::decodeBundleParameters(API::Data* bundleParameterDataPtr)
+{
+    if (!bundleParameterDataPtr)
+        return;
+
+    auto bundleParameterData = adoptNS([[NSData alloc] initWithBytesNoCopy:const_cast<void*>(static_cast<const void*>(bundleParameterDataPtr->bytes())) length:bundleParameterDataPtr->size() freeWhenDone:NO]);
+    
+    auto unarchiver = secureUnarchiverFromData(bundleParameterData.get());
+    
+    NSDictionary *dictionary = nil;
+    @try {
+        dictionary = [unarchiver.get() decodeObjectOfClasses:classesForCoder() forKey:@"parameters"];
+        ASSERT([dictionary isKindOfClass:[NSDictionary class]]);
+    } @catch (NSException *exception) {
+        LOG_ERROR("Failed to decode bundle parameters: %@", exception);
+        return;
+    }
+    
+    ASSERT(!m_bundleParameters || m_bundleParameters.get());
+    m_bundleParameters = adoptNS([[WKWebProcessBundleParameters alloc] initWithDictionary:dictionary]);
+}
+
 #endif
 
 void InjectedBundle::setBundleParameter(const String& key, const IPC::DataReference& value)
@@ -238,7 +247,7 @@ void InjectedBundle::setBundleParameters(const IPC::DataReference& value)
 
     NSDictionary *parameters = nil;
     @try {
-        parameters = [unarchiver decodeObjectOfClass:[NSDictionary class] forKey:@"parameters"];
+        parameters = [unarchiver decodeObjectOfClasses:classesForCoder() forKey:@"parameters"];
     } @catch (NSException *exception) {
         LOG_ERROR("Failed to decode bundle parameter: %@", exception);
     }
@@ -246,6 +255,8 @@ void InjectedBundle::setBundleParameters(const IPC::DataReference& value)
     if (!parameters)
         return;
 
+    RELEASE_ASSERT_WITH_SECURITY_IMPLICATION([parameters isKindOfClass:[NSDictionary class]]);
+
     if (!m_bundleParameters) {
         m_bundleParameters = adoptNS([[WKWebProcessBundleParameters alloc] initWithDictionary:parameters]);
         return;