Bug 205967 - [Media in GPU process] Extend the GPU process sandbox to allow access to local files when necessary
Summary: [Media in GPU process] Extend the GPU process sandbox to allow access to loca...
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: Media (show other bugs)
Version: Other
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Eric Carlson
URL:
Keywords: InRadar
Depends on:
Blocks: 205123
  Show dependency treegraph
 
Reported: 2020-01-08 15:53 PST by Eric Carlson
Modified: 2020-01-10 21:32 PST (History)
11 users (show)

See Also:


Attachments
Patch (39.94 KB, patch)
2020-01-08 16:03 PST, Eric Carlson
no flags Details | Formatted Diff | Diff
Patch (55.19 KB, patch)
2020-01-09 13:24 PST, Eric Carlson
no flags Details | Formatted Diff | Diff
Patch (55.23 KB, patch)
2020-01-09 13:33 PST, Eric Carlson
no flags Details | Formatted Diff | Diff
Patch for landing. (45.12 KB, patch)
2020-01-10 12:44 PST, Eric Carlson
no flags Details | Formatted Diff | Diff
Patch for landing. (45.12 KB, patch)
2020-01-10 20:45 PST, Eric Carlson
no flags Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Eric Carlson 2020-01-08 15:53:57 PST
Extend the GPU process sandbox to allow access to local files before opening a file:// url
Comment 1 Radar WebKit Bug Importer 2020-01-08 15:54:11 PST
<rdar://problem/58425020>
Comment 2 Eric Carlson 2020-01-08 16:03:42 PST
Created attachment 387155 [details]
Patch
Comment 3 Tim Horton 2020-01-08 17:12:51 PST
Comment on attachment 387155 [details]
Patch

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

> Source/WebKit/GPUProcess/GPUProcess.cpp:141
> +    for (auto& url : urls) {
> +        auto extension = m_mediaCaptureSandboxExtensions.take(url);

Iterating while taking looks wrong. I think you want a while (!urls.isEmpty()) or something
Comment 4 Tim Horton 2020-01-08 17:13:10 PST
Comment on attachment 387155 [details]
Patch

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

>> Source/WebKit/GPUProcess/GPUProcess.cpp:141
>> +        auto extension = m_mediaCaptureSandboxExtensions.take(url);
> 
> Iterating while taking looks wrong. I think you want a while (!urls.isEmpty()) or something

Oh wait it's a different set
Comment 5 Tim Horton 2020-01-08 17:14:20 PST
Comment on attachment 387155 [details]
Patch

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

> Source/WebKit/GPUProcess/GPUProcess.cpp:121
> +void GPUProcess::issueMediaFileAccessSandboxExtension(URL&& url, SandboxExtension::Handle&& sandboxExtensionHandle)
> +{

Should this be specific to "media" files, or just a generic "please issue/revoke this sandbox extension" for the whole process? You never operate on all of them as a set (which is why I initially thought this made sense)
Comment 6 Simon Fraser (smfr) 2020-01-08 17:15:26 PST
Comment on attachment 387155 [details]
Patch

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

> Source/WebKit/UIProcess/GPU/GPUProcessProxy.cpp:114
> +std::pair<uint64_t&, uint64_t&> GPUProcessProxy::useCountsForURL(WebCore::ProcessIdentifier pid, const URL& url)

This is really icky, returning references to values in a hashMap. It would be way too easy to write code that stores those references, deletes an entry, then assigns a value to the reference.

> Source/WebKit/UIProcess/GPU/GPUProcessProxy.cpp:209
> +    processCount = globalCount = 1;

Like right here; it's very unclear that this is changing values in the hashmap.
Comment 7 youenn fablet 2020-01-09 03:23:21 PST
Comment on attachment 387155 [details]
Patch

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

> Source/WebKit/WebProcess/GPU/media/MediaPlayerPrivateRemote.cpp:95
> +    m_manager.parentProcess().canLoadRemoteMediaPlayerURL(url, [this, url, contentType, keySystem, weakThis = makeWeakPtr(*this)](bool canLoad) {

We should be able to simplify this approach a bit, for instance by reusing the approach done for local files between WebProcess and NetworkProcess.
In the current model, the WebProcess should have received a sandbox extension that will allow to get access to the file (which probably allows in-process media loading).
This should allow the WebProcess to directly create the sandbox extension for the media file and send it to the GPUProcess as part of this media load request.
A bonus would be to manage the sandbox extension revocation inside MediaPlayerPrivateRemote.

> Source/WebKit/WebProcess/GPU/media/MediaPlayerPrivateRemote.cpp:97
> +            return;

In case the sandbox extension cannot be sent to GPUProcess, we should probably make sure the load fails and WebProcess gets notified of it.
If we generate the sandbox extension in WebProcess and it fails, this could be done inside MediaPlayerPrivateRemote::MediaPlayerPrivateRemote::load.
Comment 8 Eric Carlson 2020-01-09 13:24:23 PST
Created attachment 387264 [details]
Patch
Comment 9 Eric Carlson 2020-01-09 13:33:37 PST
Created attachment 387266 [details]
Patch
Comment 10 youenn fablet 2020-01-10 00:40:18 PST
Comment on attachment 387266 [details]
Patch

LGTM.
I think we can improve the handling of mediaCacheDirectory/mediaKeyStorageDirectory here or as follow-up.

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

> Source/WebKit/GPUProcess/GPUProcess.h:87
> +    HashMap<URL, RefPtr<SandboxExtension>> m_mediaCaptureSandboxExtensions;

s/RefPtr/Ref/

> Source/WebKit/GPUProcess/GPUProcessMediaConfiguration.h:44
> +    String mediaKeyStorageDirectory;

I do not see mediaCacheDirectory and mediaKeyStorageDirectory being used, probably because we are sending this information for each remote player.

> Source/WebKit/GPUProcess/media/RemoteMediaPlayerProxy.cpp:102
> +            return;

Rethinking about it, we might not need to error the load here.
If the sandbox extension cannot be created, the load will ultimately fail, there will be a sandbox violation reported in the console.

> Source/WebKit/UIProcess/GPU/GPUProcessProxy.cpp:131
> +    if (!m_haveExtendedProcessSandbox) {

We cannot really use a boolean since GPUProcess might support more than one sessionID.
I guess for now, I would remove m_haveExtendedProcessSandbox and always send this information.

As follow-up, it seems we should improve the handling of mediaCacheDirectory/mediaKeyStorageDirectory:

We currently send mediaCacheDirectory/mediaKeyStorageDirectory to GPUProcess when creating a remote player.
It would seem more consistent to send both sandbox extensions and directory paths together.
We could send the sandboxes for each remote player but this creates some overhead for each remote player.

I guess it might be best to store in GPUProcess a map SessionID -> MediaCache configuration parameters.
GPUProcessProxy would send IPC messages to add entries in this map and remove an entry when a WebsiteDataStore gets deleted.
When creating a remote player in GPU Process, we would query the map to get the corresponding cache directory paths.

Also, if we are sending the mediaCacheDirectory/mediaKeyStorageDirectory sandboxes from GPUProcessProxy to GPUProcess, we probably do not need to send the same sandbox extensions to WebProcess in that configuration.

> Source/WebKit/WebProcess/GPU/media/MediaPlayerPrivateRemote.cpp:102
> +        Optional<audit_token_t> auditToken = m_manager.gpuProcessConnection().auditToken();

s/Optional<audit_token_t>/auto/

> Source/WebKit/WebProcess/GPU/media/RemoteMediaPlayerManager.cpp:340
> +    return *m_gpuProcessConnection;

Why not just "return WebProcess::singleton().ensureGPUProcessConnection();" and remove m_gpuProcessConnection?

> Source/WebKit/WebProcess/WebProcess.cpp:1303
> +        m_gpuProcessConnection->setAuditToken(WTFMove(connectionInfo.auditToken));

Should we assert here that auditToken is not null?

> LayoutTests/gpu-process/TestExpectations:220
> +media/video-play-audio-require-user-gesture.html [ Pass ]

Nice!
Comment 11 Eric Carlson 2020-01-10 12:33:08 PST
Comment on attachment 387266 [details]
Patch

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

>> Source/WebKit/GPUProcess/GPUProcess.h:87
>> +    HashMap<URL, RefPtr<SandboxExtension>> m_mediaCaptureSandboxExtensions;
> 
> s/RefPtr/Ref/

This was cruft left over from an earlier version, removed.

>> Source/WebKit/GPUProcess/media/RemoteMediaPlayerProxy.cpp:102
>> +            return;
> 
> Rethinking about it, we might not need to error the load here.
> If the sandbox extension cannot be created, the load will ultimately fail, there will be a sandbox violation reported in the console.

Good point, reverted.

>> Source/WebKit/UIProcess/GPU/GPUProcessProxy.cpp:131
>> +    if (!m_haveExtendedProcessSandbox) {
> 
> We cannot really use a boolean since GPUProcess might support more than one sessionID.
> I guess for now, I would remove m_haveExtendedProcessSandbox and always send this information.
> 
> As follow-up, it seems we should improve the handling of mediaCacheDirectory/mediaKeyStorageDirectory:
> 
> We currently send mediaCacheDirectory/mediaKeyStorageDirectory to GPUProcess when creating a remote player.
> It would seem more consistent to send both sandbox extensions and directory paths together.
> We could send the sandboxes for each remote player but this creates some overhead for each remote player.
> 
> I guess it might be best to store in GPUProcess a map SessionID -> MediaCache configuration parameters.
> GPUProcessProxy would send IPC messages to add entries in this map and remove an entry when a WebsiteDataStore gets deleted.
> When creating a remote player in GPU Process, we would query the map to get the corresponding cache directory paths.
> 
> Also, if we are sending the mediaCacheDirectory/mediaKeyStorageDirectory sandboxes from GPUProcessProxy to GPUProcess, we probably do not need to send the same sandbox extensions to WebProcess in that configuration.

Great idea. I implemented your suggestion, but it is a lot of new code so I removed the configuration code and will post a new patch for that change.

>> Source/WebKit/WebProcess/GPU/media/MediaPlayerPrivateRemote.cpp:102
>> +        Optional<audit_token_t> auditToken = m_manager.gpuProcessConnection().auditToken();
> 
> s/Optional<audit_token_t>/auto/

Fixed

>> Source/WebKit/WebProcess/GPU/media/RemoteMediaPlayerManager.cpp:340
>> +    return *m_gpuProcessConnection;
> 
> Why not just "return WebProcess::singleton().ensureGPUProcessConnection();" and remove m_gpuProcessConnection?

This is called a lot, so caching the connection saves two function calls every time.

>> Source/WebKit/WebProcess/WebProcess.cpp:1303
>> +        m_gpuProcessConnection->setAuditToken(WTFMove(connectionInfo.auditToken));
> 
> Should we assert here that auditToken is not null?

Yes, added.
Comment 12 Eric Carlson 2020-01-10 12:44:06 PST
Created attachment 387364 [details]
Patch for landing.
Comment 13 WebKit Commit Bot 2020-01-10 17:07:30 PST
Comment on attachment 387364 [details]
Patch for landing.

Rejecting attachment 387364 [details] from commit-queue.

Failed to run "['/Volumes/Data/EWS/WebKit/Tools/Scripts/webkit-patch', '--status-host=webkit-queues.webkit.org', '--bot-id=webkit-cq-01', 'validate-changelog', '--check-oops', '--non-interactive', 387364, '--port=mac']" exit_code: 1 cwd: /Volumes/Data/EWS/WebKit

ChangeLog entry in LayoutTests/ChangeLog contains OOPS!.

Full output: https://webkit-queues.webkit.org/results/13302928
Comment 14 Eric Carlson 2020-01-10 20:45:45 PST
Created attachment 387418 [details]
Patch for landing.
Comment 15 WebKit Commit Bot 2020-01-10 21:32:31 PST
Comment on attachment 387418 [details]
Patch for landing.

Clearing flags on attachment: 387418

Committed r254392: <https://trac.webkit.org/changeset/254392>
Comment 16 WebKit Commit Bot 2020-01-10 21:32:33 PST
All reviewed patches have been landed.  Closing bug.