Skip to content

Commit

Permalink
Remote list updates for link decoration filtering fail in Safari 17
Browse files Browse the repository at this point in the history
https://bugs.webkit.org/show_bug.cgi?id=260391
rdar://114047664

Reviewed by Tim Horton.

On macOS Monterey (but not macOS Ventura or later), calling:

```
dlopen("/System/Library/PrivateFrameworks/WebPrivacy.framework/WebPrivacy", RTLD_NOW);
```

...fails to load WebPrivacy.framework from the Safari staged framework directory. This causes
`PAL::isWebPrivacyFrameworkAvailable()` to return `false`, which in turn breaks link decoration
filtering when advanced privacy protections are enabled. In comparison, the main built-in tracker
blocker loaded by Safari actually *successfully* loads, because we only use `objc_getClass` to look
up `WPResources`, and don't depend on a successful `dlopen`.

On downlevels, this call to `dlopen` is actually unnecessary, since we already link WebPrivacy via
`-weak_framework`; as such, it's sufficient to simply check whether any one of the framework API
classes (e.g. `WPResources`) have been loaded.

* Source/WebCore/PAL/pal/cocoa/WebPrivacySoftLink.h:
* Source/WebCore/PAL/pal/cocoa/WebPrivacySoftLink.mm:
* Source/WebKit/Platform/cocoa/WebPrivacyHelpers.mm:

Also, remove unnecessary soft link helpers for `WPNetworkAddressRange` (we don't need this because
we never need to create one of these in WebKit).

(WebKit::canUseWebPrivacyFramework):
(WebKit::resourceDataChangedNotificationName):
(WebKit::notificationUserInfoResourceTypeKey):
(-[WKWebPrivacyNotificationListener init]):
(-[WKWebPrivacyNotificationListener dealloc]):
(-[WKWebPrivacyNotificationListener didUpdate:]):
(WebKit::LinkDecorationFilteringController::updateStrings):
(WebKit::requestLinkDecorationFilteringData):
(WebKit::TrackerAddressLookupInfo::populateIfNeeded):
(WebKit::TrackerDomainLookupInfo::populateIfNeeded):

Canonical link: https://commits.webkit.org/267051@main
  • Loading branch information
whsieh committed Aug 18, 2023
1 parent d0daa33 commit ccf8724
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 19 deletions.
5 changes: 2 additions & 3 deletions Source/WebCore/PAL/pal/cocoa/WebPrivacySoftLink.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,10 @@
#import <wtf/SoftLinking.h>

SOFT_LINK_FRAMEWORK_FOR_HEADER(PAL, WebPrivacy)
SOFT_LINK_CLASS_FOR_HEADER(PAL, WPNetworkAddressRange)
SOFT_LINK_CLASS_FOR_HEADER(PAL, WPResourceRequestOptions)
SOFT_LINK_CLASS_FOR_HEADER(PAL, WPResources)
SOFT_LINK_CLASS_FOR_HEADER(PAL, WPLinkFilteringData)
SOFT_LINK_CONSTANT_FOR_HEADER(PAL, WebPrivacy, WPNotificationUserInfoResourceTypeKey, NSString *)
SOFT_LINK_CONSTANT_FOR_HEADER(PAL, WebPrivacy, WPResourceDataChangedNotificationName, NSNotificationName)
SOFT_LINK_CONSTANT_MAY_FAIL_FOR_HEADER(PAL, WebPrivacy, WPNotificationUserInfoResourceTypeKey, NSString *)
SOFT_LINK_CONSTANT_MAY_FAIL_FOR_HEADER(PAL, WebPrivacy, WPResourceDataChangedNotificationName, NSNotificationName)

#endif // ENABLE(ADVANCED_PRIVACY_PROTECTIONS)
11 changes: 5 additions & 6 deletions Source/WebCore/PAL/pal/cocoa/WebPrivacySoftLink.mm
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,10 @@
#import <wtf/SoftLinking.h>

SOFT_LINK_PRIVATE_FRAMEWORK_FOR_SOURCE_WITH_EXPORT(PAL, WebPrivacy, PAL_EXPORT)
SOFT_LINK_CLASS_FOR_SOURCE_WITH_EXPORT(PAL, WebPrivacy, WPNetworkAddressRange, PAL_EXPORT)
SOFT_LINK_CLASS_FOR_SOURCE_WITH_EXPORT(PAL, WebPrivacy, WPResourceRequestOptions, PAL_EXPORT)
SOFT_LINK_CLASS_FOR_SOURCE_WITH_EXPORT(PAL, WebPrivacy, WPResources, PAL_EXPORT)
SOFT_LINK_CLASS_FOR_SOURCE_WITH_EXPORT(PAL, WebPrivacy, WPLinkFilteringData, PAL_EXPORT)
SOFT_LINK_CONSTANT_FOR_SOURCE_WITH_EXPORT(PAL, WebPrivacy, WPNotificationUserInfoResourceTypeKey, NSString *, PAL_EXPORT)
SOFT_LINK_CONSTANT_FOR_SOURCE_WITH_EXPORT(PAL, WebPrivacy, WPResourceDataChangedNotificationName, NSNotificationName, PAL_EXPORT)
SOFT_LINK_CLASS_FOR_SOURCE_OPTIONAL_WITH_EXPORT(PAL, WebPrivacy, WPResourceRequestOptions, PAL_EXPORT)
SOFT_LINK_CLASS_FOR_SOURCE_OPTIONAL_WITH_EXPORT(PAL, WebPrivacy, WPResources, PAL_EXPORT)
SOFT_LINK_CLASS_FOR_SOURCE_OPTIONAL_WITH_EXPORT(PAL, WebPrivacy, WPLinkFilteringData, PAL_EXPORT)
SOFT_LINK_CONSTANT_MAY_FAIL_FOR_SOURCE_WITH_EXPORT(PAL, WebPrivacy, WPNotificationUserInfoResourceTypeKey, NSString *, PAL_EXPORT)
SOFT_LINK_CONSTANT_MAY_FAIL_FOR_SOURCE_WITH_EXPORT(PAL, WebPrivacy, WPResourceDataChangedNotificationName, NSNotificationName, PAL_EXPORT)

#endif // ENABLE(ADVANCED_PRIVACY_PROTECTIONS)
63 changes: 53 additions & 10 deletions Source/WebKit/Platform/cocoa/WebPrivacyHelpers.mm
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,49 @@
SOFT_LINK_OPTIONAL(libnetwork, nw_context_set_tracker_lookup_callback, void, __cdecl, (nw_context_t, nw_context_tracker_lookup_callback_t))
#endif

namespace WebKit {

static bool canUseWebPrivacyFramework()
{
#if HAVE(SYSTEM_SUPPORT_FOR_ADVANCED_PRIVACY_PROTECTIONS)
return PAL::isWebPrivacyFrameworkAvailable();
#else
// On macOS Monterey where WebPrivacy is present as a staged framework, attempts to soft-link the framework may fail.
// Instead of using dlopen, we instead check for the presence of `WPResources`; the call to dlopen is not necessary because
// we weak-link against the framework, so the class should be present as long as the framework has been successfully linked.
// FIXME: This workaround can be removed once we drop support for macOS Monterey, and we can use the standard soft-linking
// helpers from WebPrivacySoftLink.
static bool hasWPResourcesClass = [&] {
return !!PAL::getWPResourcesClass();
}();
return hasWPResourcesClass;
#endif
}

static NSNotificationName resourceDataChangedNotificationName()
{
#if HAVE(SYSTEM_SUPPORT_FOR_ADVANCED_PRIVACY_PROTECTIONS)
return PAL::get_WebPrivacy_WPResourceDataChangedNotificationName();
#else
// FIXME: This workaround can be removed once we drop support for macOS Monterey, and we can use the standard soft-linking
// helpers from WebPrivacySoftLink.
return @"WPResourceDataChangedNotificationName";
#endif
}

static NSString *notificationUserInfoResourceTypeKey()
{
#if HAVE(SYSTEM_SUPPORT_FOR_ADVANCED_PRIVACY_PROTECTIONS)
return PAL::get_WebPrivacy_WPNotificationUserInfoResourceTypeKey();
#else
// FIXME: This workaround can be removed once we drop support for macOS Monterey, and we can use the standard soft-linking
// helpers from WebPrivacySoftLink.
return @"ResourceType";
#endif
}

} // namespace WebKit

@interface WKWebPrivacyNotificationListener : NSObject

@end
Expand All @@ -58,8 +101,8 @@ - (instancetype)init
if (!(self = [super init]))
return nil;

if (PAL::isWebPrivacyFrameworkAvailable())
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didUpdate:) name:PAL::get_WebPrivacy_WPResourceDataChangedNotificationName() object:nil];
if (WebKit::canUseWebPrivacyFramework())
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didUpdate:) name:WebKit::resourceDataChangedNotificationName() object:nil];
return self;
}

Expand All @@ -70,15 +113,15 @@ - (void)listenForLinkFilteringDataChanges:(void(^)())callback

- (void)dealloc
{
if (PAL::isWebPrivacyFrameworkAvailable())
[[NSNotificationCenter defaultCenter] removeObserver:self name:PAL::get_WebPrivacy_WPResourceDataChangedNotificationName() object:nil];
if (WebKit::canUseWebPrivacyFramework())
[[NSNotificationCenter defaultCenter] removeObserver:self name:WebKit::resourceDataChangedNotificationName() object:nil];
[super dealloc];
}

- (void)didUpdate:(NSNotification *)notification
{
ASSERT(PAL::isWebPrivacyFrameworkAvailable());
auto type = dynamic_objc_cast<NSNumber>([notification.userInfo objectForKey:PAL::get_WebPrivacy_WPNotificationUserInfoResourceTypeKey()]);
ASSERT(WebKit::canUseWebPrivacyFramework());
auto type = dynamic_objc_cast<NSNumber>([notification.userInfo objectForKey:WebKit::notificationUserInfoResourceTypeKey()]);
if (!type)
return;

Expand Down Expand Up @@ -120,7 +163,7 @@ - (void)didUpdate:(NSNotification *)notification

void LinkDecorationFilteringController::updateStrings(CompletionHandler<void()>&& callback)
{
if (!PAL::isWebPrivacyFrameworkAvailable()) {
if (!WebKit::canUseWebPrivacyFramework()) {
callback();
return;
}
Expand Down Expand Up @@ -153,7 +196,7 @@ - (void)didUpdate:(NSNotification *)notification
using LinkFilteringRulesCallback = CompletionHandler<void(Vector<WebCore::LinkDecorationFilteringData>&&)>;
void requestLinkDecorationFilteringData(LinkFilteringRulesCallback&& callback)
{
if (!PAL::isWebPrivacyFrameworkAvailable()) {
if (!WebKit::canUseWebPrivacyFramework()) {
callback({ });
return;
}
Expand Down Expand Up @@ -258,7 +301,7 @@ static void populateIfNeeded()
{
static std::once_flag onceFlag;
std::call_once(onceFlag, [&] {
if (!PAL::isWebPrivacyFrameworkAvailable())
if (!WebKit::canUseWebPrivacyFramework())
return;

auto options = adoptNS([PAL::allocWPResourceRequestOptionsInstance() init]);
Expand Down Expand Up @@ -388,7 +431,7 @@ static void populateIfNeeded()
{
static std::once_flag onceFlag;
std::call_once(onceFlag, [&] {
if (!PAL::isWebPrivacyFrameworkAvailable())
if (!WebKit::canUseWebPrivacyFramework())
return;

static BOOL canRequestTrackerDomainNames = [] {
Expand Down

0 comments on commit ccf8724

Please sign in to comment.