Skip to content
Permalink
Browse files
Blob URLs with fragment from opaque/unique origins cannot be loaded
https://bugs.webkit.org/show_bug.cgi?id=243996

Reviewed by Darin Adler.

To keep track of the opaque/unique security origins from blob URLs, we rely
on an originMap() in ThreadableBlobRegistry.cpp. This is needed because the
origin is serialized as "null" in the blob URL.

However, unlike the blob storage which always strips any fragment identifier
from Blob URLs because add/removing/querying, we were failing to do so when
using the originMap(). This patch fixes that.

* LayoutTests/imported/w3c/web-platform-tests/FileAPI/url/sandboxed-iframe-expected.txt:
* Source/WTF/wtf/HashMap.h:
(WTF::Y>::remove):
* Source/WTF/wtf/text/StringHash.h:
(WTF::StringViewHashTranslator::translate):
* Source/WTF/wtf/text/StringImpl.h:
* Source/WebCore/fileapi/ThreadableBlobRegistry.cpp:
(WebCore::ThreadableBlobRegistry::registerBlobURL):
(WebCore::ThreadableBlobRegistry::unregisterBlobURL):
(WebCore::ThreadableBlobRegistry::getCachedOrigin):

Canonical link: https://commits.webkit.org/253498@main
  • Loading branch information
cdumez committed Aug 17, 2022
1 parent 6bd8e23 commit 2424b6bdaf38c9dd1dd99a2f86a6f11f08561da2
Show file tree
Hide file tree
Showing 5 changed files with 26 additions and 8 deletions.
@@ -7,11 +7,9 @@ PASS Blob URL parses correctly
PASS Origin of Blob URL matches our origin for Files
PASS Blob URLs can be used in <script> tags
FAIL Blob URLs can be used in iframes, and are treated same origin Sandbox access violation: Blocked a frame at "null" from accessing a cross-origin frame. Both frames are sandboxed and lack the "allow-same-origin" flag.
FAIL Blob URL fragment is implemented. null is not an object (evaluating 'frame.contentWindow.onscroll = t.step_func_done(() => {
assert_equals(frame.contentWindow.scrollY, 5000);
})')
FAIL Blob URL fragment is implemented. Sandbox access violation: Blocked a frame at "null" from accessing a cross-origin frame. Both frames are sandboxed and lack the "allow-same-origin" flag.
PASS Blob URLs can be used in XHR
FAIL XHR with a fragment should succeed promise_test: Unhandled rejection with value: "Got unexpected error event"
PASS XHR with a fragment should succeed
PASS XHR of a revoked URL should fail
PASS Only exact matches should revoke URLs, using XHR
PASS Appending a query string should cause XHR to fail
@@ -25,7 +23,7 @@ PASS XHR with method "CUSTOM" should fail
PASS XHR should return Content-Type from Blob
FAIL Revoke blob URL after open(), will fetch assert_unreached: Got unexpected error event Reached unreachable code
PASS Blob URLs can be used in fetch
FAIL fetch with a fragment should succeed promise_test: Unhandled rejection with value: object "TypeError: Load failed"
PASS fetch with a fragment should succeed
PASS fetch of a revoked URL should fail
PASS Only exact matches should revoke URLs, using fetch
PASS Appending a query string should cause fetch to fail
@@ -176,6 +176,7 @@ class HashMap final {
template<typename HashTranslator, typename T> bool contains(const T&) const;
template<typename HashTranslator, typename T> MappedPeekType get(const T&) const;
template<typename HashTranslator, typename T> MappedPeekType inlineGet(const T&) const;
template<typename HashTranslator, typename T> bool remove(const T&);

// An alternate version of add() that finds the object by hashing and comparing
// with some other type, to avoid the cost of type conversion if the object is already
@@ -363,6 +364,17 @@ inline bool HashMap<T, U, V, W, X, Y>::contains(const TYPE& value) const
return m_impl.template contains<HashMapTranslatorAdapter<KeyValuePairTraits, HashTranslator>>(value);
}

template<typename T, typename U, typename V, typename W, typename X, typename Y>
template<typename HashTranslator, typename TYPE>
inline bool HashMap<T, U, V, W, X, Y>::remove(const TYPE& value)
{
auto it = find<HashTranslator>(value);
if (it == end())
return false;
remove(it);
return true;
}

template<typename KeyArg, typename MappedArg, typename HashArg, typename KeyTraitsArg, typename MappedTraitsArg, typename TableTraitsArg>
template<typename K, typename V>
auto HashMap<KeyArg, MappedArg, HashArg, KeyTraitsArg, MappedTraitsArg, TableTraitsArg>::inlineSet(K&& key, V&& value) -> AddResult
@@ -237,6 +237,12 @@ namespace WTF {
{
return a == b;
}

static void translate(String& location, StringView view, unsigned hash)
{
location = view.toString();
location.impl()->setHash(hash);
}
};

// FIXME: Find a way to incorporate this functionality into ASCIICaseInsensitiveHash and allow
@@ -71,6 +71,7 @@ struct CStringTranslator;
struct HashAndUTF8CharactersTranslator;
struct HashTranslatorASCIILiteral;
struct LCharBufferTranslator;
struct StringViewHashTranslator;
struct SubstringTranslator;
struct UCharBufferTranslator;

@@ -190,6 +191,7 @@ class StringImpl : private StringImplShape {
friend struct WTF::HashAndUTF8CharactersTranslator;
friend struct WTF::HashTranslatorASCIILiteral;
friend struct WTF::LCharBufferTranslator;
friend struct WTF::StringViewHashTranslator;
friend struct WTF::SubstringTranslator;
friend struct WTF::UCharBufferTranslator;

@@ -103,7 +103,7 @@ void ThreadableBlobRegistry::registerBlobURL(SecurityOrigin* origin, PolicyConta
{
// If the blob URL contains null origin, as in the context with unique security origin or file URL, save the mapping between url and origin so that the origin can be retrived when doing security origin check.
if (origin && isBlobURLContainsNullOrigin(url))
originMap()->add(url.string(), origin);
originMap()->add<StringViewHashTranslator>(url.viewWithoutFragmentIdentifier(), origin);

if (isMainThread()) {
blobRegistry().registerBlobURL(url, srcURL, policyContainer);
@@ -153,7 +153,7 @@ unsigned long long ThreadableBlobRegistry::blobSize(const URL& url)
void ThreadableBlobRegistry::unregisterBlobURL(const URL& url)
{
if (isBlobURLContainsNullOrigin(url))
originMap()->remove(url.string());
originMap()->remove<StringViewHashTranslator>(url.viewWithoutFragmentIdentifier());

ensureOnMainThread([url = url.isolatedCopy()] {
blobRegistry().unregisterBlobURL(url);
@@ -176,7 +176,7 @@ void ThreadableBlobRegistry::unregisterBlobURLHandle(const URL& url)

RefPtr<SecurityOrigin> ThreadableBlobRegistry::getCachedOrigin(const URL& url)
{
if (auto cachedOrigin = originMap()->get(url.string()))
if (auto cachedOrigin = originMap()->get<StringViewHashTranslator>(url.viewWithoutFragmentIdentifier()))
return cachedOrigin;

if (!url.protocolIsBlob() || !isBlobURLContainsNullOrigin(url))

0 comments on commit 2424b6b

Please sign in to comment.