InjectedBundle parameters often need initialization function called before unarchiving
authorbfulgham@apple.com <bfulgham@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 15 Apr 2019 22:21:59 +0000 (22:21 +0000)
committerbfulgham@apple.com <bfulgham@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 15 Apr 2019 22:21:59 +0000 (22:21 +0000)
https://bugs.webkit.org/show_bug.cgi?id=189709
<rdar://problem/44573653>

Reviewed by Ryosuke Niwa.

Source/WebKit:

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.

Extend WKWebProcessPlugIn with a method that returns the names of any custom classes that need
to be serialized by the InjectedBundle.

Create a new 'decodeBundleParameters' method that contains the logic that used to live in 'initialize'.
Revise 'initialize' to call this new method.

* 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.
* WebProcess/InjectedBundle/API/mac/WKWebProcessPlugIn.h:
(WebKit::WKWebProcessPlugIn::additionalClassesForParameterCoder): Added.

Tools:

* TestWebKitAPI/cocoa/WebProcessPlugIn/WebProcessPlugIn.mm:
(-[WebProcessPlugIn additionalClassesForParameterCoder]): Added.

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

Source/WebKit/ChangeLog
Source/WebKit/WebProcess/InjectedBundle/API/mac/WKWebProcessPlugIn.h
Source/WebKit/WebProcess/InjectedBundle/InjectedBundle.h
Source/WebKit/WebProcess/InjectedBundle/mac/InjectedBundleMac.mm
Tools/ChangeLog
Tools/TestWebKitAPI/cocoa/WebProcessPlugIn/WebProcessPlugIn.mm

index f6c4d70..93ca58e 100644 (file)
@@ -1,3 +1,33 @@
+2019-04-15  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 Ryosuke Niwa.
+
+        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.
+
+        Extend WKWebProcessPlugIn with a method that returns the names of any custom classes that need
+        to be serialized by the InjectedBundle.
+        
+        Create a new 'decodeBundleParameters' method that contains the logic that used to live in 'initialize'.
+        Revise 'initialize' to call this new method.
+
+        * 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.
+        * WebProcess/InjectedBundle/API/mac/WKWebProcessPlugIn.h:
+        (WebKit::WKWebProcessPlugIn::additionalClassesForParameterCoder): Added.
+
 2019-04-15  Dean Jackson  <dino@apple.com>
 
         Provide option to not create a longpress gesture recognizer
index 8fb4671..b604b1e 100644 (file)
@@ -37,6 +37,7 @@
 - (void)webProcessPlugIn:(WKWebProcessPlugInController *)plugInController initializeWithObject:(id)initializationObject;
 - (void)webProcessPlugIn:(WKWebProcessPlugInController *)plugInController didCreateBrowserContextController:(WKWebProcessPlugInBrowserContextController *)browserContextController;
 - (void)webProcessPlugIn:(WKWebProcessPlugInController *)plugInController willDestroyBrowserContextController:(WKWebProcessPlugInBrowserContextController *)browserContextController;
+- (NSArray *)additionalClassesForParameterCoder;
 @end
 
 WK_CLASS_AVAILABLE(macos(10.10), ios(8.0))
index 1ffe2c3..b3b1b9a 100644 (file)
@@ -167,6 +167,10 @@ public:
 private:
     explicit InjectedBundle(const WebProcessCreationParameters&);
 
+#if PLATFORM(COCOA)
+    void decodeBundleParameters(API::Data*);
+#endif
+
     String m_path;
     PlatformBundle m_platformBundle; // This is leaked right now, since we never unload the bundle/module.
 
index 52f825d..d3e7308 100644 (file)
@@ -73,6 +73,28 @@ static NSEventModifierFlags currentModifierFlags(id self, SEL _cmd)
 }
 #endif
 
+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]);
+}
+
 bool InjectedBundle::initialize(const WebProcessCreationParameters& parameters, API::Object* initializationUserData)
 {
     if (m_sandboxExtension) {
@@ -120,23 +142,6 @@ bool InjectedBundle::initialize(const WebProcessCreationParameters& parameters,
         }
     }
 
-    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]);
-    }
-    
 #if ENABLE(WEBPROCESS_WINDOWSERVER_BLOCKING)
     // Swizzle [NSEvent modiferFlags], since it always returns 0 when the WindowServer is blocked.
     Method method = class_getClassMethod([NSEvent class], @selector(modifierFlags));
@@ -149,6 +154,7 @@ bool InjectedBundle::initialize(const WebProcessCreationParameters& parameters,
     // First check to see if the bundle has a WKBundleInitialize function.
     if (initializeFunction) {
         initializeFunction(toAPI(this), toAPI(initializationUserData));
+        decodeBundleParameters(parameters.bundleParameterData.get());
         return true;
     }
 
@@ -173,6 +179,11 @@ bool InjectedBundle::initialize(const WebProcessCreationParameters& parameters,
     WKWebProcessPlugInController* plugInController = WebKit::wrapper(*this);
     [plugInController _setPrincipalClassInstance:instance];
 
+    if ([instance respondsToSelector:@selector(additionalClassesForParameterCoder)])
+        [plugInController extendClassesForParameterCoder:[instance additionalClassesForParameterCoder]];
+
+    decodeBundleParameters(parameters.bundleParameterData.get());
+
     if ([instance respondsToSelector:@selector(webProcessPlugIn:initializeWithObject:)]) {
         RetainPtr<id> objCInitializationUserData;
         if (initializationUserData && initializationUserData->type() == API::Object::Type::ObjCObjectGraph)
@@ -255,7 +266,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);
     }
@@ -263,6 +274,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;
index ae4481a..2382b22 100644 (file)
@@ -1,3 +1,14 @@
+2019-04-15  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 Ryosuke Niwa.
+
+        * TestWebKitAPI/cocoa/WebProcessPlugIn/WebProcessPlugIn.mm:
+        (-[WebProcessPlugIn additionalClassesForParameterCoder]): Added.
+
 2019-04-12  Ryosuke Niwa  <rniwa@webkit.org>
 
         HashTable::removeIf always shrinks the hash table by half even if there is nothing left
index 40746ab..363ad1f 100644 (file)
     RetainPtr<id <WKWebProcessPlugIn>> _testPlugIn;
 }
 
+- (NSArray *)additionalClassesForParameterCoder
+{
+    return @[@"MockContentFilterEnabler"];
+}
+
 - (void)webProcessPlugIn:(WKWebProcessPlugInController *)plugInController initializeWithObject:(id)initializationObject
 {
     NSString *testPlugInClassName = [plugInController.parameters valueForKey:TestWebKitAPI::Util::TestPlugInClassNameParameter];