Bug 203214

Summary: Mach lookup to com.apple.webinspector should not be allowed in WebKit's WebContent process
Product: WebKit Reporter: Per Arne Vollan <pvollan>
Component: WebKit Misc.Assignee: Per Arne Vollan <pvollan>
Status: RESOLVED FIXED    
Severity: Normal CC: achristensen, bfulgham, ews-watchlist, ggaren, hi, joepeck, keith_miller, mark.lam, msaboff, saam, tzagallo, webkit-bug-importer
Priority: P2 Keywords: InRadar
Version: WebKit Nightly Build   
Hardware: Unspecified   
OS: Unspecified   
Bug Depends on:    
Bug Blocks: 207170    
Attachments:
Description Flags
Patch
none
Patch
none
Patch
none
Patch
none
Patch
none
Patch
none
Patch
none
Patch
none
Patch
none
Patch
none
Patch
none
Patch
none
Patch
none
Patch
none
Patch bfulgham: review+

Description Per Arne Vollan 2019-10-21 14:55:49 PDT
Currently, mach lookup to com.apple.webinspector is allowed in the WebContent process, but instead of always allowing this, we should issue a mach sandbox extension in the UI process when the user is enabling the Web inspector.
Comment 1 Per Arne Vollan 2019-10-21 15:57:34 PDT
Created attachment 381472 [details]
Patch
Comment 2 Per Arne Vollan 2019-10-21 16:33:52 PDT
Created attachment 381481 [details]
Patch
Comment 3 Joseph Pecoraro 2019-10-21 16:59:51 PDT
Comment on attachment 381472 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=381472&action=review

> Source/JavaScriptCore/inspector/remote/RemoteInspector.cpp:43
> +#if PLATFORM(COCOA)
> +std::atomic<bool> RemoteInspector::needMachSandboxExtension = true;
> +#endif

Hmm. Since the default is false, this looks like like it could break remote debugging of a JSContext:

    (1) Applications/Daemons should already have access to the port in the default sandbox rules
    (2) Disabling RemoteInspector by default means JSContext only applications would not be debuggable

I see that you relax the restriction for +[WebView initialization] (WebView / UIWebView), but it seems we would also need to do the same for JSContext / JSContextRef.

However maybe the default should be that the sandbox requirement is not necessary, and it is only turned on in WebContentProcess? That seems less likely to be problematic for Remote Inspection in the future.

> Source/JavaScriptCore/inspector/remote/RemoteInspector.h:111
> +#if PLATFORM(COCOA)
> +    static void setNeedMachSandboxExtension(bool needExtension) { needMachSandboxExtension = needExtension; }
> +#endif

This is only ever called with `false`. How about renaming it to describe what it is effectively doing?

    static void relaxSandboxExtensionRequirement() { needMachSandboxExtension = false; }

> Source/WebKit/ChangeLog:12
> +        If the Web inspector is enabled when the WebContent process is started, a sandbox extension is created
> +        for 'com.apple.webinspectord' and a message is sent to the WebContent process, where the extension will
> +        be consumed, and the remote Web inspector will be started. The same happens if Web inspector is enabled
> +        by the user while Safari is running. When RemoteInspector::singleton() is called in the UI process there
> +        is no need for an extension, since access to the Web inspector daemon is already allowed.

Given we now go through the UIProcess... does the WebContent process ever need access to this mach port now? Hmm, it probably needs it for direct Service-Worker debugging.

> Source/WebKit/UIProcess/WebProcessProxy.cpp:869
> +    if (CFPreferencesGetAppIntegerValue(CFSTR("RemoteInspectorEnabled"), CFSTR("com.apple.webinspectord"), &keyExistsAndHasValidFormat) && keyExistsAndHasValidFormat) {

Is it normal to have access to this? I would not expect this.
Comment 4 Alex Christensen 2019-10-22 07:12:38 PDT
Comment on attachment 381481 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=381481&action=review

> Source/WebKit/UIProcess/WebProcessPool.cpp:1041
> +    Inspector::RemoteInspector::setNeedMachSandboxExtension(false);

This doesn't look right.  Shouldn't we be consuming a sandbox extension before calling this?

> Source/WebKit/WebProcess/WebProcess.messages.in:135
> +    RemoteWebInspectorEnabled(WebKit::SandboxExtension::Handle handle);

This sounds like it should return a bool.  EnableRemoteWebInspector?
Comment 5 Per Arne Vollan 2019-10-22 11:23:56 PDT
(In reply to Joseph Pecoraro from comment #3)
> Comment on attachment 381472 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=381472&action=review
> 
> > Source/JavaScriptCore/inspector/remote/RemoteInspector.cpp:43
> > +#if PLATFORM(COCOA)
> > +std::atomic<bool> RemoteInspector::needMachSandboxExtension = true;
> > +#endif
> 
> Hmm. Since the default is false, this looks like like it could break remote
> debugging of a JSContext:
> 
>     (1) Applications/Daemons should already have access to the port in the
> default sandbox rules
>     (2) Disabling RemoteInspector by default means JSContext only
> applications would not be debuggable
> 
> I see that you relax the restriction for +[WebView initialization] (WebView
> / UIWebView), but it seems we would also need to do the same for JSContext /
> JSContextRef.
> 
> However maybe the default should be that the sandbox requirement is not
> necessary, and it is only turned on in WebContentProcess? That seems less
> likely to be problematic for Remote Inspection in the future.
> 

Good point, I'll change the default to not require a sandbox extension.

> > Source/JavaScriptCore/inspector/remote/RemoteInspector.h:111
> > +#if PLATFORM(COCOA)
> > +    static void setNeedMachSandboxExtension(bool needExtension) { needMachSandboxExtension = needExtension; }
> > +#endif
> 
> This is only ever called with `false`. How about renaming it to describe
> what it is effectively doing?
> 
>     static void relaxSandboxExtensionRequirement() {
> needMachSandboxExtension = false; }
> 

By changing the default of the flag to not needing a sandbox extension, I think the WebContent process will need to pass both true and false to this method.

> > Source/WebKit/ChangeLog:12
> > +        If the Web inspector is enabled when the WebContent process is started, a sandbox extension is created
> > +        for 'com.apple.webinspectord' and a message is sent to the WebContent process, where the extension will
> > +        be consumed, and the remote Web inspector will be started. The same happens if Web inspector is enabled
> > +        by the user while Safari is running. When RemoteInspector::singleton() is called in the UI process there
> > +        is no need for an extension, since access to the Web inspector daemon is already allowed.
> 
> Given we now go through the UIProcess... does the WebContent process ever
> need access to this mach port now? Hmm, it probably needs it for direct
> Service-Worker debugging.
> 

Oh, that is interesting! How can I test if it's needed for Service-Worker debugging?

> > Source/WebKit/UIProcess/WebProcessProxy.cpp:869
> > +    if (CFPreferencesGetAppIntegerValue(CFSTR("RemoteInspectorEnabled"), CFSTR("com.apple.webinspectord"), &keyExistsAndHasValidFormat) && keyExistsAndHasValidFormat) {
> 
> Is it normal to have access to this? I would not expect this.

You're right. This requires a new sandbox rule for the UI process (Safari), which will be added in separate patch.

Thanks for reviewing!
Comment 6 Joseph Pecoraro 2019-10-22 11:40:28 PDT
> > > Source/WebKit/ChangeLog:12
> > > +        If the Web inspector is enabled when the WebContent process is started, a sandbox extension is created
> > > +        for 'com.apple.webinspectord' and a message is sent to the WebContent process, where the extension will
> > > +        be consumed, and the remote Web inspector will be started. The same happens if Web inspector is enabled
> > > +        by the user while Safari is running. When RemoteInspector::singleton() is called in the UI process there
> > > +        is no need for an extension, since access to the Web inspector daemon is already allowed.
> > 
> > Given we now go through the UIProcess... does the WebContent process ever
> > need access to this mach port now? Hmm, it probably needs it for direct
> > Service-Worker debugging.
> > 
> 
> Oh, that is interesting! How can I test if it's needed for Service-Worker
> debugging?

You can visit a page like `https://airhorner.com` and you should continue to see the airhorner.com Service Worker in the Develop menu:

    macOS: Develop > Service Worker > airhorner
    iOS:   Develop > (Device Name) > airhorner

> > > Source/WebKit/UIProcess/WebProcessProxy.cpp:869
> > > +    if (CFPreferencesGetAppIntegerValue(CFSTR("RemoteInspectorEnabled"), CFSTR("com.apple.webinspectord"), &keyExistsAndHasValidFormat) && keyExistsAndHasValidFormat) {
> > 
> > Is it normal to have access to this? I would not expect this.
> 
> You're right. This requires a new sandbox rule for the UI process (Safari),
> which will be added in separate patch.

I'm not exactly a fan of this approach. If this `RemoteInspectorEnabled` setting changes, then someone will have to remember to change WebKit. Currently that setting (on COCOA) is only set in one place and checked in one place.
Comment 7 Per Arne Vollan 2019-10-22 13:46:36 PDT
(In reply to Alex Christensen from comment #4)
> Comment on attachment 381481 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=381481&action=review
> 
> > Source/WebKit/UIProcess/WebProcessPool.cpp:1041
> > +    Inspector::RemoteInspector::setNeedMachSandboxExtension(false);
> 
> This doesn't look right.  Shouldn't we be consuming a sandbox extension
> before calling this?
> 

Not in this case, since the UI process does not need to consume a web inspector extension. However, this line will not be needed when the default flag for needing a sandbox extension is being changed to false.

> > Source/WebKit/WebProcess/WebProcess.messages.in:135
> > +    RemoteWebInspectorEnabled(WebKit::SandboxExtension::Handle handle);
> 
> This sounds like it should return a bool.  EnableRemoteWebInspector?

Yes, that is much better. Thanks for reviewing!
Comment 8 Per Arne Vollan 2019-10-22 14:39:38 PDT
Created attachment 381609 [details]
Patch
Comment 9 Per Arne Vollan 2019-10-22 15:46:11 PDT
(In reply to Joseph Pecoraro from comment #6)
> > > > Source/WebKit/ChangeLog:12
> > > > +        If the Web inspector is enabled when the WebContent process is started, a sandbox extension is created
> > > > +        for 'com.apple.webinspectord' and a message is sent to the WebContent process, where the extension will
> > > > +        be consumed, and the remote Web inspector will be started. The same happens if Web inspector is enabled
> > > > +        by the user while Safari is running. When RemoteInspector::singleton() is called in the UI process there
> > > > +        is no need for an extension, since access to the Web inspector daemon is already allowed.
> > > 
> > > Given we now go through the UIProcess... does the WebContent process ever
> > > need access to this mach port now? Hmm, it probably needs it for direct
> > > Service-Worker debugging.
> > > 
> > 
> > Oh, that is interesting! How can I test if it's needed for Service-Worker
> > debugging?
> 
> You can visit a page like `https://airhorner.com` and you should continue to
> see the airhorner.com Service Worker in the Develop menu:
> 
>     macOS: Develop > Service Worker > airhorner
>     iOS:   Develop > (Device Name) > airhorner
> 
> > > > Source/WebKit/UIProcess/WebProcessProxy.cpp:869
> > > > +    if (CFPreferencesGetAppIntegerValue(CFSTR("RemoteInspectorEnabled"), CFSTR("com.apple.webinspectord"), &keyExistsAndHasValidFormat) && keyExistsAndHasValidFormat) {
> > > 
> > > Is it normal to have access to this? I would not expect this.
> > 
> > You're right. This requires a new sandbox rule for the UI process (Safari),
> > which will be added in separate patch.
> 
> I'm not exactly a fan of this approach. If this `RemoteInspectorEnabled`
> setting changes, then someone will have to remember to change WebKit.
> Currently that setting (on COCOA) is only set in one place and checked in
> one place.

Yes, that is a good point. Perhaps these strings could be added to a header file?
Comment 10 Brent Fulgham 2019-10-22 21:25:26 PDT
Comment on attachment 381609 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=381609&action=review

Looks good. I think we should get an okay from a WebInsoector person like Joe before landing.

> Source/WebKit/UIProcess/Cocoa/WebProcessPoolCocoa.mm:502
> +    CFNotificationCenterRemoveObserver(CFNotificationCenterGetDarwinNotifyCenter(), this, static_cast<CFStringRef>(CFSTR(WIRServiceEnabledNotification)) , nullptr);

Extra white space around the commas.
Comment 11 Per Arne Vollan 2019-10-23 10:45:11 PDT
Created attachment 381693 [details]
Patch
Comment 12 Per Arne Vollan 2019-10-23 10:45:51 PDT
(In reply to Brent Fulgham from comment #10)
> Comment on attachment 381609 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=381609&action=review
> 
> Looks good. I think we should get an okay from a WebInsoector person like
> Joe before landing.
> 
> > Source/WebKit/UIProcess/Cocoa/WebProcessPoolCocoa.mm:502
> > +    CFNotificationCenterRemoveObserver(CFNotificationCenterGetDarwinNotifyCenter(), this, static_cast<CFStringRef>(CFSTR(WIRServiceEnabledNotification)) , nullptr);
> 
> Extra white space around the commas.

Good catch, I have uploaded a new patch.

Thanks for reviewing!
Comment 13 Per Arne Vollan 2019-10-23 11:12:25 PDT
Created attachment 381699 [details]
Patch
Comment 14 Per Arne Vollan 2019-10-23 11:20:52 PDT
Created attachment 381703 [details]
Patch
Comment 15 Per Arne Vollan 2019-10-23 17:11:17 PDT
Created attachment 381756 [details]
Patch
Comment 16 Joseph Pecoraro 2019-10-23 17:32:37 PDT
Comment on attachment 381756 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=381756&action=review

> Source/WebKit/UIProcess/Cocoa/WebProcessPoolCocoa.mm:501
> +    CFNotificationCenterRemoveObserver(CFNotificationCenterGetDarwinNotifyCenter(), this, static_cast<CFStringRef>(CFSTR(WIRServiceEnabledNotification)), nullptr);

Would you have to static_cast a string that is already a CFSTR? Seems like you should be able to drop the `static_cast<CFStringRef>` cast.

> Source/WebKit/UIProcess/Cocoa/WebProcessProxyCocoa.mm:219
> +    if (!CFPreferencesGetAppIntegerValue(CFSTR(WIRRemoteInspectorEnabledKey), CFSTR(WIRRemoteInspectorDomainName), nullptr))
> +        return;

How will we guarantee that all UIProcesses have access to this setting? Do we want to expose all of their sandboxes to this?
Comment 17 Per Arne Vollan 2019-10-24 10:06:20 PDT
Created attachment 381821 [details]
Patch
Comment 18 Brent Fulgham 2019-10-24 10:10:29 PDT
Comment on attachment 381756 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=381756&action=review

>> Source/WebKit/UIProcess/Cocoa/WebProcessProxyCocoa.mm:219
>> +        return;
> 
> How will we guarantee that all UIProcesses have access to this setting? Do we want to expose all of their sandboxes to this?

I'm not sure I understand the question here. It seems like this setting would be available to any WebKit client that links to a new build of WebKit.
Comment 19 Brent Fulgham 2019-10-24 10:25:56 PDT
Comment on attachment 381821 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=381821&action=review

> Source/JavaScriptCore/inspector/remote/RemoteInspectorConstants.h:123
> +#define WIRRemoteInspectorDomainName            "com.apple.webinspectord"

You always cast this as CFSTR; should these be defined as @"Remote.." and @"com.apple.webinspectord"?

> Source/WebKit/UIProcess/Cocoa/WebProcessPoolCocoa.mm:420
> +        process->enableRemoteInspectorIfNeeded();

Is the remote inspector needed for every web process? Should it be tied to a specific active tab when the user chose to enable (or show) the WebInspector?
Comment 20 Per Arne Vollan 2019-10-24 10:30:33 PDT
(In reply to Brent Fulgham from comment #18)
> Comment on attachment 381756 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=381756&action=review
> 
> >> Source/WebKit/UIProcess/Cocoa/WebProcessProxyCocoa.mm:219
> >> +        return;
> > 
> > How will we guarantee that all UIProcesses have access to this setting? Do we want to expose all of their sandboxes to this?
> 
> I'm not sure I understand the question here. It seems like this setting
> would be available to any WebKit client that links to a new build of WebKit.

I believe we need to extend the sandbox in the UI process with the right to read this preference. Additionally, the UI process' sandbox needs a new rule to allow creating the mach sandbox extension to 'com.apple.webinspector'.

All apps that wants to be inspectable will have to add these two rules to their sandbox. I will make sure these two rules are added to the sandbox profile which most apps are using.

Thanks for reviewing, all!
Comment 21 Per Arne Vollan 2019-10-24 10:38:08 PDT
Created attachment 381822 [details]
Patch
Comment 22 Per Arne Vollan 2019-10-24 11:00:49 PDT
(In reply to Brent Fulgham from comment #19)
> Comment on attachment 381821 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=381821&action=review
> 
> > Source/JavaScriptCore/inspector/remote/RemoteInspectorConstants.h:123
> > +#define WIRRemoteInspectorDomainName            "com.apple.webinspectord"
> 
> You always cast this as CFSTR; should these be defined as @"Remote.." and
> @"com.apple.webinspectord"?
> 

Done. Declared as CFSTR in the latest patch.

> > Source/WebKit/UIProcess/Cocoa/WebProcessPoolCocoa.mm:420
> > +        process->enableRemoteInspectorIfNeeded();
> 
> Is the remote inspector needed for every web process? Should it be tied to a
> specific active tab when the user chose to enable (or show) the WebInspector?

I believe it needs to be enabled for every web process, since I believe it is possible to inspect many Service workers at the same time.
Comment 23 Per Arne Vollan 2019-11-05 17:15:52 PST
Created attachment 382869 [details]
Patch
Comment 24 Per Arne Vollan 2019-11-13 15:35:49 PST
rdar://problem/56372204
Comment 25 Per Arne Vollan 2020-02-06 10:59:39 PST
Created attachment 389973 [details]
Patch
Comment 26 Per Arne Vollan 2020-02-06 15:09:49 PST
Created attachment 390010 [details]
Patch
Comment 27 Brent Fulgham 2020-02-11 15:09:27 PST
Comment on attachment 390010 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=390010&action=review

> Source/JavaScriptCore/inspector/remote/RemoteInspector.cpp:41
> +#if PLATFORM(IOS)

What about macOS? What about macCatalyst?

> Source/JavaScriptCore/inspector/remote/RemoteInspector.h:118
> +    static void setNeedMachSandboxExtension(bool needExtension) { needMachSandboxExtension = needExtension; }

Do we need to do a std::swap() here to benefit from the atomic type? I can't remember.

> Source/JavaScriptCore/inspector/remote/RemoteInspector.h:242
> +#if PLATFORM(IOS)

Why can't we do this on macOS, too?
Comment 28 Per Arne Vollan 2020-02-12 07:37:10 PST
(In reply to Brent Fulgham from comment #27)
> Comment on attachment 390010 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=390010&action=review
> 
> > Source/JavaScriptCore/inspector/remote/RemoteInspector.cpp:41
> > +#if PLATFORM(IOS)
> 
> What about macOS? What about macCatalyst?
> 

Good point! I will change the code to include maOS as well. Some parts are iOS specific, like the setting to enable remote inspection and the notification name. Are you OK with fixing the remaining macOS specific things in a separate patch?

> > Source/JavaScriptCore/inspector/remote/RemoteInspector.h:118
> > +    static void setNeedMachSandboxExtension(bool needExtension) { needMachSandboxExtension = needExtension; }
> 
> Do we need to do a std::swap() here to benefit from the atomic type? I can't
> remember.
> 

I am not 100% sure, but I think it should be safe to to an assignment here.

> > Source/JavaScriptCore/inspector/remote/RemoteInspector.h:242
> > +#if PLATFORM(IOS)
> 
> Why can't we do this on macOS, too?

I will enable this for macOS as well.

Thanks for reviewing!
Comment 29 Per Arne Vollan 2020-02-12 17:22:35 PST
Created attachment 390596 [details]
Patch
Comment 30 Per Arne Vollan 2020-02-13 08:54:53 PST
Created attachment 390653 [details]
Patch
Comment 31 Per Arne Vollan 2020-02-13 09:18:09 PST
Created attachment 390657 [details]
Patch
Comment 32 Brent Fulgham 2020-02-16 20:50:26 PST
Comment on attachment 390657 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=390657&action=review

> Source/WebKit/UIProcess/Cocoa/WebProcessPoolCocoa.mm:513
> +    for (size_t i = 0; i < pool->m_processes.size(); ++i) {

Can we use a modern C++ loop here?

> Source/WebKit/UIProcess/Cocoa/WebProcessPoolCocoa.mm:574
> +    CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), this, remoteWebInspectorEnabledCallback, static_cast<CFStringRef>(CFSTR(WIRServiceEnabledNotification)), nullptr, CFNotificationSuspensionBehaviorCoalesce);

Do we not need this for macOS?

> Source/WebKit/WebProcess/WebProcess.cpp:436
> +    Inspector::RemoteInspector::setNeedMachSandboxExtension(true);

Why isn't this needed on macOS, too? And what about MacCatalyst?
Comment 33 Brent Fulgham 2020-02-16 20:52:15 PST
Comment on attachment 390657 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=390657&action=review

Thank you for reviewing it again. r=me

>> Source/WebKit/UIProcess/Cocoa/WebProcessPoolCocoa.mm:574
>> +    CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), this, remoteWebInspectorEnabledCallback, static_cast<CFStringRef>(CFSTR(WIRServiceEnabledNotification)), nullptr, CFNotificationSuspensionBehaviorCoalesce);
> 
> Do we not need this for macOS?

Oh -- I see, you already answered this. Never mind.

>> Source/WebKit/WebProcess/WebProcess.cpp:436
>> +    Inspector::RemoteInspector::setNeedMachSandboxExtension(true);
> 
> Why isn't this needed on macOS, too? And what about MacCatalyst?

Never mind!
Comment 34 Per Arne Vollan 2020-02-17 10:23:05 PST
(In reply to Brent Fulgham from comment #33)
> Comment on attachment 390657 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=390657&action=review
> 
> Thank you for reviewing it again. r=me
> 
> >> Source/WebKit/UIProcess/Cocoa/WebProcessPoolCocoa.mm:574
> >> +    CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), this, remoteWebInspectorEnabledCallback, static_cast<CFStringRef>(CFSTR(WIRServiceEnabledNotification)), nullptr, CFNotificationSuspensionBehaviorCoalesce);
> > 
> > Do we not need this for macOS?
> 
> Oh -- I see, you already answered this. Never mind.
> 
> >> Source/WebKit/WebProcess/WebProcess.cpp:436
> >> +    Inspector::RemoteInspector::setNeedMachSandboxExtension(true);
> > 
> > Why isn't this needed on macOS, too? And what about MacCatalyst?
> 
> Never mind!

Thanks for reviewing!
Comment 35 Per Arne Vollan 2020-02-17 10:31:36 PST
Committed r256742: <https://trac.webkit.org/changeset/256742/webkit>