Skip to content

Commit

Permalink
Cherry-pick 272448.386@safari-7618-branch (dd435ec). https://bugs.web…
Browse files Browse the repository at this point in the history
…kit.org/show_bug.cgi?id=268183

    Remote worker processes may not obey the lockdown mode setting
    https://bugs.webkit.org/show_bug.cgi?id=268183
    rdar://121617300

    Reviewed by Youenn Fablet.

    Make sure we carry over the requesting process' lockdown mode state to the
    newly created process when we decide to launch a remote worker process.

    Also make sure that the settings that are meant to be disabled in lockdown
    mode also get disabled in the remote worker contexts, not just in page/window
    contexts.

    * Source/WebKit/UIProcess/API/Cocoa/WKProcessPool.mm:
    (-[WKProcessPool _isJITDisabledInAllServiceWorkerProcesses:]):
    * Source/WebKit/UIProcess/API/Cocoa/WKProcessPoolPrivate.h:
    * Source/WebKit/UIProcess/WebProcessPool.cpp:
    (WebKit::WebProcessPool::establishRemoteWorkerContextConnectionToNetworkProcess):
    (WebKit::WebProcessPool::isJITDisabledInAllServiceWorkerProcesses const):
    * Source/WebKit/UIProcess/WebProcessPool.h:
    * Source/WebKit/UIProcess/WebProcessProxy.cpp:
    (WebKit::WebProcessProxy::createForRemoteWorkers):
    * Source/WebKit/UIProcess/WebProcessProxy.h:
    * Tools/TestWebKitAPI/Tests/WebKitCocoa/ServiceWorkerBasic.mm:

    Canonical link: https://commits.webkit.org/272448.386@safari-7618-branch

Canonical link: https://commits.webkit.org/266719.406@webkitglib/2.42
  • Loading branch information
cdumez authored and aperezdc committed Mar 14, 2024
1 parent f257018 commit ecd593f
Show file tree
Hide file tree
Showing 11 changed files with 160 additions and 13 deletions.
7 changes: 7 additions & 0 deletions Source/WebKit/UIProcess/API/Cocoa/WKProcessPool.mm
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,13 @@ - (size_t)_serviceWorkerProcessCount
#endif
}

- (void)_isJITDisabledInAllRemoteWorkerProcesses:(void(^)(BOOL))completionHandler
{
_processPool->isJITDisabledInAllRemoteWorkerProcesses([completionHandler = makeBlockPtr(completionHandler)] (bool result) {
completionHandler(result);
});
}

+ (void)_forceGameControllerFramework
{
#if ENABLE(GAMEPAD)
Expand Down
1 change: 1 addition & 0 deletions Source/WebKit/UIProcess/API/Cocoa/WKProcessPoolPrivate.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@
- (size_t)_webProcessCountIgnoringPrewarmedAndCached WK_API_AVAILABLE(macos(10.14.4), ios(12.2));
- (size_t)_pluginProcessCount WK_API_AVAILABLE(macos(10.13.4), ios(11.3));
- (size_t)_serviceWorkerProcessCount WK_API_AVAILABLE(macos(10.14), ios(12.0));
- (void)_isJITDisabledInAllRemoteWorkerProcesses:(void(^)(BOOL))completionHandler;
- (void)_makeNextWebProcessLaunchFailForTesting WK_API_AVAILABLE(macos(10.14), ios(12.0));
- (NSUInteger)_maximumSuspendedPageCount WK_API_AVAILABLE(macos(10.14.4), ios(12.2));
- (NSUInteger)_processCacheCapacity WK_API_AVAILABLE(macos(10.14.4), ios(12.2));
Expand Down
38 changes: 36 additions & 2 deletions Source/WebKit/UIProcess/WebProcessPool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -537,7 +537,8 @@ void WebProcessPool::establishRemoteWorkerContextConnectionToNetworkProcess(Remo
if (!processPools().size())
static NeverDestroyed<Ref<WebProcessPool>> remoteWorkerProcessPool(WebProcessPool::create(API::ProcessPoolConfiguration::create().get()));

RefPtr<WebProcessProxy> requestingProcess = requestingProcessIdentifier ? WebProcessProxy::processForIdentifier(*requestingProcessIdentifier) : nullptr;
RefPtr requestingProcess = requestingProcessIdentifier ? WebProcessProxy::processForIdentifier(*requestingProcessIdentifier) : nullptr;
auto lockdownMode = requestingProcess ? requestingProcess->lockdownMode() : (lockdownModeEnabledBySystem() ? WebProcessProxy::LockdownMode::Enabled : WebProcessProxy::LockdownMode::Disabled);
WebProcessPool* processPool = requestingProcess ? &requestingProcess->processPool() : processPools()[0];
ASSERT(processPool);

Expand Down Expand Up @@ -573,6 +574,8 @@ void WebProcessPool::establishRemoteWorkerContextConnectionToNetworkProcess(Remo
continue;
if (!process->isMatchingRegistrableDomain(registrableDomain))
continue;
if (process->lockdownMode() != lockdownMode)
continue;

useProcessForRemoteWorkers(process);

Expand All @@ -582,7 +585,7 @@ void WebProcessPool::establishRemoteWorkerContextConnectionToNetworkProcess(Remo
}

if (!remoteWorkerProcessProxy) {
auto newProcessProxy = WebProcessProxy::createForRemoteWorkers(workerType, *processPool, RegistrableDomain { registrableDomain }, *websiteDataStore);
Ref newProcessProxy = WebProcessProxy::createForRemoteWorkers(workerType, *processPool, RegistrableDomain { registrableDomain }, *websiteDataStore, lockdownMode);
remoteWorkerProcessProxy = newProcessProxy.ptr();

WEBPROCESSPOOL_RELEASE_LOG_STATIC(ServiceWorker, "establishRemoteWorkerContextConnectionToNetworkProcess creating a new service worker process (process=%p, workerType=%" PUBLIC_LOG_STRING ", PID=%d)", remoteWorkerProcessProxy, workerType == RemoteWorkerType::ServiceWorker ? "service" : "shared", remoteWorkerProcessProxy->processID());
Expand Down Expand Up @@ -2271,6 +2274,37 @@ size_t WebProcessPool::serviceWorkerProxiesCount() const
return count;
}

void WebProcessPool::isJITDisabledInAllRemoteWorkerProcesses(CompletionHandler<void(bool)>&& completionHandler) const
{
class JITDisabledCallbackAggregator : public RefCounted<JITDisabledCallbackAggregator> {
public:
static auto create(CompletionHandler<void(bool)>&& callback) { return adoptRef(*new JITDisabledCallbackAggregator(WTFMove(callback))); }

~JITDisabledCallbackAggregator()
{
if (m_callback)
m_callback(m_isJITDisabled);
}

void setJITEnabled(bool isJITEnabled) { m_isJITDisabled &= !isJITEnabled; }

private:
explicit JITDisabledCallbackAggregator(CompletionHandler<void(bool)>&& callback)
: m_callback(WTFMove(callback))
{ }

CompletionHandler<void(bool)> m_callback;
bool m_isJITDisabled { true };
};

Ref callbackAggregator = JITDisabledCallbackAggregator::create(WTFMove(completionHandler));
remoteWorkerProcesses().forEach([&](auto& process) {
process.sendWithAsyncReply(Messages::WebProcess::IsJITEnabled(), [callbackAggregator](bool isJITEnabled) {
callbackAggregator->setJITEnabled(isJITEnabled);
}, 0);
});
}

bool WebProcessPool::hasServiceWorkerForegroundActivityForTesting() const
{
return WTF::anyOf(remoteWorkerProcesses(), [](auto& process) {
Expand Down
1 change: 1 addition & 0 deletions Source/WebKit/UIProcess/WebProcessPool.h
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,7 @@ class WebProcessPool final

#if ENABLE(SERVICE_WORKER)
size_t serviceWorkerProxiesCount() const;
void isJITDisabledInAllRemoteWorkerProcesses(CompletionHandler<void(bool)>&&) const;
bool hasServiceWorkerForegroundActivityForTesting() const;
bool hasServiceWorkerBackgroundActivityForTesting() const;
#endif
Expand Down
4 changes: 2 additions & 2 deletions Source/WebKit/UIProcess/WebProcessProxy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -231,9 +231,9 @@ Ref<WebProcessProxy> WebProcessProxy::create(WebProcessPool& processPool, Websit
return proxy;
}

Ref<WebProcessProxy> WebProcessProxy::createForRemoteWorkers(RemoteWorkerType workerType, WebProcessPool& processPool, RegistrableDomain&& registrableDomain, WebsiteDataStore& websiteDataStore)
Ref<WebProcessProxy> WebProcessProxy::createForRemoteWorkers(RemoteWorkerType workerType, WebProcessPool& processPool, RegistrableDomain&& registrableDomain, WebsiteDataStore& websiteDataStore, LockdownMode lockdownMode)
{
auto proxy = adoptRef(*new WebProcessProxy(processPool, &websiteDataStore, IsPrewarmed::No, CrossOriginMode::Shared, LockdownMode::Disabled));
Ref proxy = adoptRef(*new WebProcessProxy(processPool, &websiteDataStore, IsPrewarmed::No, CrossOriginMode::Shared, lockdownMode));
proxy->m_registrableDomain = WTFMove(registrableDomain);
proxy->enableRemoteWorkers(workerType, processPool.userContentControllerIdentifierForRemoteWorkers());
proxy->connect();
Expand Down
2 changes: 1 addition & 1 deletion Source/WebKit/UIProcess/WebProcessProxy.h
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ class WebProcessProxy : public AuxiliaryProcessProxy, private ProcessThrottlerCl
enum class LockdownMode : bool { Disabled, Enabled };

static Ref<WebProcessProxy> create(WebProcessPool&, WebsiteDataStore*, LockdownMode, IsPrewarmed, WebCore::CrossOriginMode = WebCore::CrossOriginMode::Shared, ShouldLaunchProcess = ShouldLaunchProcess::Yes);
static Ref<WebProcessProxy> createForRemoteWorkers(RemoteWorkerType, WebProcessPool&, WebCore::RegistrableDomain&&, WebsiteDataStore&);
static Ref<WebProcessProxy> createForRemoteWorkers(RemoteWorkerType, WebProcessPool&, WebCore::RegistrableDomain&&, WebsiteDataStore&, LockdownMode);

#if ENABLE(WEBCONTENT_CRASH_TESTING)
static Ref<WebProcessProxy> createForWebContentCrashy(WebProcessPool&);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,9 @@ void WebSWContextManagerConnection::installServiceWorker(ServiceWorkerContextDat
WebPage::updateSettingsGenerated(*m_preferencesStore, page->settings());
page->settings().setStorageBlockingPolicy(static_cast<StorageBlockingPolicy>(m_preferencesStore->getUInt32ValueForKey(WebPreferencesKey::storageBlockingPolicyKey())));
}
if (WebProcess::singleton().isLockdownModeEnabled())
WebPage::adjustSettingsForLockdownMode(page->settings(), m_preferencesStore ? &m_preferencesStore.value() : nullptr);

page->setupForRemoteWorker(contextData.scriptURL, contextData.registration.key.topOrigin(), contextData.referrerPolicy);

std::unique_ptr<WebCore::NotificationClient> notificationClient;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ void WebSharedWorkerContextManagerConnection::launchSharedWorker(WebCore::Client
WebPage::updateSettingsGenerated(*m_preferencesStore, page->settings());
page->settings().setStorageBlockingPolicy(static_cast<WebCore::StorageBlockingPolicy>(m_preferencesStore->getUInt32ValueForKey(WebPreferencesKey::storageBlockingPolicyKey())));
}
if (WebProcess::singleton().isLockdownModeEnabled())
WebPage::adjustSettingsForLockdownMode(page->settings(), m_preferencesStore ? &m_preferencesStore.value() : nullptr);

if (!initializationData.userAgent.isEmpty())
initializationData.userAgent = m_userAgent;
Expand Down
18 changes: 10 additions & 8 deletions Source/WebKit/WebProcess/WebPage/WebPage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4437,7 +4437,7 @@ bool WebPage::isParentProcessAWebBrowser() const
return false;
}

static void adjustSettingsForLockdownMode(Settings& settings, const WebPreferencesStore& store)
void WebPage::adjustSettingsForLockdownMode(Settings& settings, const WebPreferencesStore* store)
{
// Disable unstable Experimental settings, even if the user enabled them for local use.
settings.disableUnstableFeaturesForModernWebKit();
Expand Down Expand Up @@ -4510,16 +4510,18 @@ static void adjustSettingsForLockdownMode(Settings& settings, const WebPreferenc
settings.setWebLocksAPIEnabled(false);
settings.setCacheAPIEnabled(false);

settings.setAllowedMediaContainerTypes(store.getStringValueForKey(WebPreferencesKey::mediaContainerTypesAllowedInLockdownModeKey()));
settings.setAllowedMediaCodecTypes(store.getStringValueForKey(WebPreferencesKey::mediaCodecTypesAllowedInLockdownModeKey()));
settings.setAllowedMediaVideoCodecIDs(store.getStringValueForKey(WebPreferencesKey::mediaVideoCodecIDsAllowedInLockdownModeKey()));
settings.setAllowedMediaAudioCodecIDs(store.getStringValueForKey(WebPreferencesKey::mediaAudioCodecIDsAllowedInLockdownModeKey()));
settings.setAllowedMediaCaptionFormatTypes(store.getStringValueForKey(WebPreferencesKey::mediaCaptionFormatTypesAllowedInLockdownModeKey()));

// FIXME: This seems like an odd place to put logic for setting global state in CoreGraphics.
#if HAVE(LOCKDOWN_MODE_PDF_ADDITIONS)
CGEnterLockdownModeForPDF();
#endif

if (store) {
settings.setAllowedMediaContainerTypes(store->getStringValueForKey(WebPreferencesKey::mediaContainerTypesAllowedInLockdownModeKey()));
settings.setAllowedMediaCodecTypes(store->getStringValueForKey(WebPreferencesKey::mediaCodecTypesAllowedInLockdownModeKey()));
settings.setAllowedMediaVideoCodecIDs(store->getStringValueForKey(WebPreferencesKey::mediaVideoCodecIDsAllowedInLockdownModeKey()));
settings.setAllowedMediaAudioCodecIDs(store->getStringValueForKey(WebPreferencesKey::mediaAudioCodecIDsAllowedInLockdownModeKey()));
settings.setAllowedMediaCaptionFormatTypes(store->getStringValueForKey(WebPreferencesKey::mediaCaptionFormatTypesAllowedInLockdownModeKey()));
}
}

void WebPage::updatePreferences(const WebPreferencesStore& store)
Expand Down Expand Up @@ -4652,7 +4654,7 @@ void WebPage::updatePreferences(const WebPreferencesStore& store)
// FIXME: This should be automated by adding a new field in WebPreferences*.yaml
// that indicates override state for Lockdown mode. https://webkit.org/b/233100.
if (WebProcess::singleton().isLockdownModeEnabled())
adjustSettingsForLockdownMode(settings, store);
adjustSettingsForLockdownMode(settings, &store);

#if ENABLE(ARKIT_INLINE_PREVIEW)
m_useARKitForModel = store.getBoolValueForKey(WebPreferencesKey::useARKitForModelKey());
Expand Down
2 changes: 2 additions & 0 deletions Source/WebKit/WebProcess/WebPage/WebPage.h
Original file line number Diff line number Diff line change
Expand Up @@ -1489,6 +1489,8 @@ class WebPage : public API::ObjectImpl<API::Object::Type::BundlePage>, public IP
bool userIsInteracting() const { return m_userIsInteracting; }
void setUserIsInteracting(bool userIsInteracting) { m_userIsInteracting = userIsInteracting; }

static void adjustSettingsForLockdownMode(WebCore::Settings&, const WebPreferencesStore*);

#if PLATFORM(IOS_FAMILY)
// This excludes layout overflow, includes borders.
static WebCore::IntRect rootViewBounds(const WebCore::Node&);
Expand Down
95 changes: 95 additions & 0 deletions Tools/TestWebKitAPI/Tests/WebKitCocoa/ServiceWorkerBasic.mm
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,18 @@ function log(msg)

)SWRESOURCE"_s;

static constexpr auto scriptWithEvalBytes = R"SWRESOURCE(

self.addEventListener("message", (event) => {
if (event.data == "Hello from the web page") {
event.source.postMessage("ServiceWorker received: " + event.data);
return;
}
event.source.postMessage("Evaluation result: " + eval(event.data));
});

)SWRESOURCE"_s;

static constexpr auto mainForFetchTestBytes = R"SWRESOURCE(
<html>
<body>
Expand Down Expand Up @@ -1903,6 +1915,89 @@ static size_t launchServiceWorkerProcess(bool useSeparateServiceWorkerProcess, b
EXPECT_EQ(2u, launchServiceWorkerProcess(useSeparateServiceWorkerProcess, firstLoadAboutBlank));
}

TEST(ServiceWorkers, LockdownModeInServiceWorkerProcess)
{
// Turn on lockdown mode globally.
[WKProcessPool _setCaptivePortalModeEnabledGloballyForTesting:YES];
[WKWebsiteDataStore _allowWebsiteDataRecordsForAllOrigins];
TestWebKitAPI::Util::spinRunLoop();

// Start with a clean slate data store.
[[WKWebsiteDataStore defaultDataStore] removeDataOfTypes:[WKWebsiteDataStore allWebsiteDataTypes] modifiedSince:[NSDate distantPast] completionHandler:^() {
done = true;
}];
TestWebKitAPI::Util::run(&done);
done = false;

RetainPtr configuration = adoptNS([[WKWebViewConfiguration alloc] init]);

RetainPtr messageHandler = adoptNS([[SWMessageHandlerForRestoreFromDiskTest alloc] initWithExpectedMessage:@"Message from worker: ServiceWorker received: Hello from the web page"]);
[[configuration userContentController] addScriptMessageHandler:messageHandler.get() name:@"sw"];

TestWebKitAPI::HTTPServer server({
{ "/"_s, { mainBytes } },
{ "/sw.js"_s, { {{ "Content-Type"_s, "application/javascript"_s }}, scriptWithEvalBytes } }
});

RetainPtr processPool = retainPtr(configuration.get().processPool);

// Make sure that the service worker launches in its own process.
[processPool _setUseSeparateServiceWorkerProcess:YES];

RetainPtr webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);

RetainPtr navigationDelegate = adoptNS([[TestNavigationDelegate alloc] init]);
[navigationDelegate setDidFinishNavigation:^(WKWebView *, WKNavigation *) {
didFinishNavigationBoolean = true;
}];
[webView setNavigationDelegate:navigationDelegate.get()];
[webView loadRequest:server.request()];

TestWebKitAPI::Util::run(&done);
done = false;

EXPECT_TRUE(waitUntilEvaluatesToTrue([&] { return [processPool _serviceWorkerProcessCount] == 1; }));

// Check that JIT is disabled in the service worker process.
done = false;
[processPool _isJITDisabledInAllRemoteWorkerProcesses:^(BOOL isJITDisabled) {
EXPECT_TRUE(isJITDisabled);
done = true;
}];
TestWebKitAPI::Util::run(&done);

auto runJSCheck = [&](const String& jsToEvalInWorker) {
bool finishedRunningScript = false;
done = false;
String js = makeString("worker.postMessage('", jsToEvalInWorker,"');");
[webView evaluateJavaScript:js completionHandler:[&] (id result, NSError *error) {
EXPECT_NULL(error);
finishedRunningScript = true;
}];
TestWebKitAPI::Util::run(&finishedRunningScript);
TestWebKitAPI::Util::run(&done);
};

[messageHandler resetExpectedMessage:@"Message from worker: Evaluation result: true"];
runJSCheck("!!self.URL"_s);

// Check individual settings that are meant to be disabled in lockdown mode.
[messageHandler resetExpectedMessage:@"Message from worker: Evaluation result: false"];
runJSCheck("!!self.WebGL2RenderingContext"_s);
runJSCheck("!!self.FileSystemHandle"_s); // File System Access.
#if ENABLE(NOTIFICATIONS)
runJSCheck("!!self.Notification"_s); // Notification API.
#endif
runJSCheck("!!self.Cache"_s); // Cache API.
runJSCheck("!!self.CacheStorage"_s); // Cache API.
runJSCheck("!!self.FileReader"_s); // FileReader API.
runJSCheck("!!self.FileSystemFileHandle"_s); // File System Access API.
runJSCheck("!!self.PushManager"_s); // Push API.
runJSCheck("!!self.PushSubscription"_s); // Push API.
runJSCheck("!!self.PushSubscriptionOptions"_s); // Push API.
runJSCheck("!!self.LockManager"_s); // WebLockManager API.
}

enum class UseSeparateServiceWorkerProcess : bool { No, Yes };
void testSuspendServiceWorkerProcessBasedOnClientProcesses(UseSeparateServiceWorkerProcess useSeparateServiceWorkerProcess)
{
Expand Down

0 comments on commit ecd593f

Please sign in to comment.