Merge remote-tracking branch 'origin/tracking' into custom

This commit is contained in:
roytam1 2025-07-25 07:33:44 +08:00
commit be6796bb20
9 changed files with 401 additions and 65 deletions

View file

@ -2316,28 +2316,32 @@ nsObjectLoadingContent::LoadObject(bool aNotify,
} }
} }
// Don't allow view-source scheme. // https://html.spec.whatwg.org/multipage/iframe-embed-object.html#the-object-element
// view-source is the only scheme to which this applies at the moment due to // requires that `embed` and `object` go through `Fetch` with mode=navigate,
// potential timing attacks to read data from cross-origin documents. If this // see 1.3.5. This will in https://fetch.spec.whatwg.org/#fetching plumb us
// widens we should add a protocol flag for whether the scheme is only allowed // through to https://fetch.spec.whatwg.org/#concept-main-fetch where in step
// in top and use something like nsNetUtil::NS_URIChainHasFlags. // 12 a switch is performed. Since `object` and `embed` have mode=navigate the
// result of https://fetch.spec.whatwg.org/#concept-scheme-fetch will decide
// if main fetch proceeds. We short-circuit that scheme-fetch here, inspecting
// if the scheme of `mURI` is one that would return a network error. The
// following schemes are allowed through in scheme fetch:
// "about", "blob", "data", "file", "http", "https".
// XXXMC: Should we include "ftp" as well?
//
// Some accessibility tests use our internal "chrome" scheme.
if (mType != eType_Null) { if (mType != eType_Null) {
nsCOMPtr<nsIURI> tempURI = mURI; bool isCandidate = false;
nsCOMPtr<nsINestedURI> nestedURI = do_QueryInterface(tempURI); for (const auto& candidate :
while (nestedURI) { {"about", "blob", "chrome", "data", "file", "http", "https"}) {
// view-source should always be an nsINestedURI, loop and check the rv = mURI->SchemeIs(candidate, &isCandidate);
// scheme on this and all inner URIs that are also nested URIs. if (NS_SUCCEEDED(rv) && isCandidate) {
bool isViewSource = false;
rv = tempURI->SchemeIs("view-source", &isViewSource);
if (NS_FAILED(rv) || isViewSource) {
LOG(("OBJLC [%p]: Blocking as effective URI has view-source scheme",
this));
mType = eType_Null;
break; break;
} }
}
nestedURI->GetInnerURI(getter_AddRefs(tempURI)); if (!isCandidate) {
nestedURI = do_QueryInterface(tempURI); LOG(("OBJLC [%p]: Blocking as effective URI does not have an allowed scheme",
this));
mType = eType_Null;
} }
} }

View file

@ -808,33 +808,51 @@ StripURIForReporting(nsIURI* aURI,
nsIURI* aSelfURI, nsIURI* aSelfURI,
nsACString& outStrippedURI) nsACString& outStrippedURI)
{ {
// 1) If the origin of uri is a globally unique identifier (for example, bool isAllowedScheme =
// aURI has a scheme of data, blob, or filesystem), then return the (NS_SUCCEEDED(aURI->SchemeIs("http", &isAllowedScheme)) && isAllowedScheme) ||
// ASCII serialization of uri’s scheme. (NS_SUCCEEDED(aURI->SchemeIs("https", &isAllowedScheme)) && isAllowedScheme) ||
bool isHttpOrFtp = (NS_SUCCEEDED(aURI->SchemeIs("ftp", &isAllowedScheme)) && isAllowedScheme) ||
(NS_SUCCEEDED(aURI->SchemeIs("http", &isHttpOrFtp)) && isHttpOrFtp) || (NS_SUCCEEDED(aURI->SchemeIs("ws", &isAllowedScheme)) && isAllowedScheme) ||
(NS_SUCCEEDED(aURI->SchemeIs("https", &isHttpOrFtp)) && isHttpOrFtp) || (NS_SUCCEEDED(aURI->SchemeIs("wss", &isAllowedScheme)) && isAllowedScheme);
(NS_SUCCEEDED(aURI->SchemeIs("ftp", &isHttpOrFtp)) && isHttpOrFtp);
if (!isHttpOrFtp) { if (!isAllowedScheme) {
// not strictly spec compliant, but what we really care about is // Step 1. If url's scheme is not an allowed scheme, then just return url's scheme,
// http/https and also ftp. If it's not http/https or ftp, then treat aURI // i.e. treat aURI as a globally unique identifier.
// as if it's a globally unique identifier and just return the scheme. // What we really care about reporting is http/https/ftp.
// https://github.com/w3c/webappsec-csp/issues/735: We also allow WS(S) schemes.
aURI->GetScheme(outStrippedURI); aURI->GetScheme(outStrippedURI);
return; return;
} }
// 2) If the origin of uri is not the same as the origin of the protected // Step 2. Set url's fragment to the empty string.
// resource, then return the ASCII serialization of uri’s origin. // Implicit in GetSpecIgnoringRef() below.
if (!NS_SecurityCompareURIs(aSelfURI, aURI, false)) {
// cross origin redirects also fall into this category, see: // Step 3. Set url's username/password to the empty string.
// http://www.w3.org/TR/CSP/#violation-reports nsCOMPtr<nsIURI> stripped;
aURI->GetPrePath(outStrippedURI); nsresult rv = aURI->Clone(getter_AddRefs(stripped));
if (NS_FAILED(rv)) {
// Cloning the URI failed for some reason, just return the scheme.
aURI->GetScheme(outStrippedURI);
return;
}
rv = stripped->SetUserPass(EmptyCString());
if (NS_FAILED(rv)) {
// Mutating the URI failed for some reason, just return the scheme.
aURI->GetScheme(outStrippedURI);
return; return;
} }
// 3) Return uri, with any fragment component removed. // Non-standard: https://github.com/w3c/webappsec-csp/issues/735
aURI->GetSpecIgnoringRef(outStrippedURI); // We match other browsers here: To avoid leaking the whole URL when blocking
// (or reporting!) cross-origin navigations inside a frame, we restrict the URLs
// to just the (ASCII serialization of) uri's origin.
if (!NS_SecurityCompareURIs(aSelfURI, stripped, false)) {
stripped->GetPrePath(outStrippedURI);
return;
}
// Step 4. Return uri, with any unwanted component removed.
stripped->GetSpecIgnoringRef(outStrippedURI);
} }
nsresult nsresult

View file

@ -448,7 +448,7 @@ class gfxFontEntry::FontTableBlobData {
public: public:
explicit FontTableBlobData(nsTArray<uint8_t>&& aBuffer) explicit FontTableBlobData(nsTArray<uint8_t>&& aBuffer)
: mTableData(Move(aBuffer)) : mTableData(Move(aBuffer))
, mHashtable(nullptr) , mFontEntry(nullptr)
, mHashKey(0) , mHashKey(0)
{ {
MOZ_COUNT_CTOR(FontTableBlobData); MOZ_COUNT_CTOR(FontTableBlobData);
@ -456,8 +456,9 @@ public:
~FontTableBlobData() { ~FontTableBlobData() {
MOZ_COUNT_DTOR(FontTableBlobData); MOZ_COUNT_DTOR(FontTableBlobData);
if (mHashtable && mHashKey) { if (mFontEntry && mHashKey) {
mHashtable->RemoveEntry(mHashKey); RefPtr<gfxFontEntry> kungFuDeathGrip(mFontEntry);
mFontEntry->mFontTableCache->RemoveEntry(mHashKey);
} }
} }
@ -470,10 +471,10 @@ public:
// Tell this FontTableBlobData to remove the HashEntry when this is // Tell this FontTableBlobData to remove the HashEntry when this is
// destroyed. // destroyed.
void ManageHashEntry(nsTHashtable<FontTableHashEntry> *aHashtable, void ManageHashEntry(gfxFontEntry* aFontEntry,
uint32_t aHashKey) uint32_t aHashKey)
{ {
mHashtable = aHashtable; mFontEntry = aFontEntry;
mHashKey = aHashKey; mHashKey = aHashKey;
} }
@ -481,7 +482,7 @@ public:
// removed from the hashtable). // removed from the hashtable).
void ForgetHashEntry() void ForgetHashEntry()
{ {
mHashtable = nullptr; mFontEntry = nullptr;
mHashKey = 0; mHashKey = 0;
} }
@ -496,10 +497,11 @@ private:
// The font table data block // The font table data block
nsTArray<uint8_t> mTableData; nsTArray<uint8_t> mTableData;
// The blob destroy function needs to know the owning hashtable // The blob destroy function needs to know the owning font entry
// and the hashtable key, so that it can remove the entry. // so that it can hold the font-entry's reference while modifying the
nsTHashtable<FontTableHashEntry> *mHashtable; // hashtable; and the hashtable key, so that it can remove the entry.
uint32_t mHashKey; gfxFontEntry* mFontEntry;
uint32_t mHashKey;
// not implemented // not implemented
FontTableBlobData(const FontTableBlobData&); FontTableBlobData(const FontTableBlobData&);
@ -508,7 +510,7 @@ private:
hb_blob_t * hb_blob_t *
gfxFontEntry::FontTableHashEntry:: gfxFontEntry::FontTableHashEntry::
ShareTableAndGetBlob(nsTArray<uint8_t>&& aTable, ShareTableAndGetBlob(nsTArray<uint8_t>&& aTable,
nsTHashtable<FontTableHashEntry> *aHashtable) gfxFontEntry* aFontEntry)
{ {
Clear(); Clear();
// adopts elements of aTable // adopts elements of aTable
@ -528,7 +530,7 @@ ShareTableAndGetBlob(nsTArray<uint8_t>&& aTable,
// Tell the FontTableBlobData to remove this hash entry when destroyed. // Tell the FontTableBlobData to remove this hash entry when destroyed.
// The hashtable does not keep a strong reference. // The hashtable does not keep a strong reference.
mSharedBlobData->ManageHashEntry(aHashtable, GetKey()); mSharedBlobData->ManageHashEntry(aFontEntry, GetKey());
return mBlob; return mBlob;
} }
@ -600,7 +602,7 @@ gfxFontEntry::ShareFontTableAndGetBlob(uint32_t aTag,
return nullptr; return nullptr;
} }
return entry->ShareTableAndGetBlob(Move(*aBuffer), mFontTableCache.get()); return entry->ShareTableAndGetBlob(Move(*aBuffer), this);
} }
already_AddRefed<gfxCharacterMap> already_AddRefed<gfxCharacterMap>

View file

@ -534,11 +534,11 @@ private:
// Transfer (not copy) elements of aTable to a new hb_blob_t and // Transfer (not copy) elements of aTable to a new hb_blob_t and
// return ownership to the caller. A weak reference to the blob is // return ownership to the caller. A weak reference to the blob is
// recorded in the hashtable entry so that others may use the same // recorded in the font entry's table cache so that others may use
// table. // the same table.
hb_blob_t * hb_blob_t *
ShareTableAndGetBlob(nsTArray<uint8_t>&& aTable, ShareTableAndGetBlob(nsTArray<uint8_t>&& aTable,
nsTHashtable<FontTableHashEntry> *aHashtable); gfxFontEntry* aFontEntry);
// Return a strong reference to the blob. // Return a strong reference to the blob.
// Callers must hb_blob_destroy the returned blob. // Callers must hb_blob_destroy the returned blob.

View file

@ -148,11 +148,11 @@ var exp = asmLink(asmCompile(USE_ASM + "var x=0; function a() { return x|0 } fun
assertEq(exp.c(10), undefined); assertEq(exp.c(10), undefined);
assertEq(exp.a(), 10); assertEq(exp.a(), 10);
var f = asmLink(asmCompile(USE_ASM + "function f(i) { i=i|0; switch(i|0) { case 1: i=-1; break; case 133742: i=2; break; default: i=42; break } return i|0 } return f")); var f = asmLink(asmCompile(USE_ASM + "function f(i) { i=i|0; switch(i|0) { case 1: i=-1; break; case 65520: i=2; break; default: i=42; break } return i|0 } return f"));
assertEq(f(1), -1); assertEq(f(1), -1);
assertEq(f(2), 42); assertEq(f(2), 42);
assertEq(f(133742), 2); assertEq(f(65520), 2);
assertEq(f(133743), 42); assertEq(f(65521), 42);
var f = asmLink(asmCompile(USE_ASM + "function f(i) { i=i|0; switch(i|0) { case 1: i=42; break; default: i=13 } return i|0 } return f")); var f = asmLink(asmCompile(USE_ASM + "function f(i) { i=i|0; switch(i|0) { case 1: i=42; break; default: i=13 } return i|0 } return f"));
assertEq(f(-1), 13); assertEq(f(-1), 13);

View file

@ -1332,7 +1332,7 @@ static const unsigned MaxTableElems = 1024 * 1024;
static const unsigned MaxDataSegments = 64 * 1024; static const unsigned MaxDataSegments = 64 * 1024;
static const unsigned MaxElemSegments = 64 * 1024; static const unsigned MaxElemSegments = 64 * 1024;
static const unsigned MaxArgsPerFunc = 4 * 1024; static const unsigned MaxArgsPerFunc = 4 * 1024;
static const unsigned MaxBrTableElems = 4 * 1024 * 1024; static const unsigned MaxBrTableElems = 65520;
// To be able to assign function indices during compilation while the number of // To be able to assign function indices during compilation while the number of
// imports is still unknown, asm.js sets a maximum number of imports so it can // imports is still unknown, asm.js sets a maximum number of imports so it can

View file

@ -0,0 +1,304 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CSS Conditional Tests: @supports selector() - Complete Test Suite</title>
<style>
body {
font-family: Arial, sans-serif;
line-height: 1.4;
margin: 20px;
max-width: 800px;
}
h1 {
text-align: center;
border-bottom: 1px solid #ccc;
padding-bottom: 10px;
}
.test {
border: 1px solid #ddd;
margin: 20px 0;
padding: 15px;
}
.test h2 {
margin: 0 0 10px 0;
font-size: 1.1em;
}
.test-output {
height: 100px;
width: 100px;
border: 1px solid #999;
margin: 10px 0;
}
.expected {
font-weight: bold;
color: green;
}
code {
background: #f5f5f5;
padding: 2px 4px;
}
</style>
</head>
<body>
<h1>CSS Conditional Tests: @supports selector() - Complete Test Suite</h1>
<!-- Test 1 -->
<div class="test">
<h2>Test 1: @supports selector() with multiple selectors doesn't work</h2>
<p>Test passes if there is a <strong class="expected">filled green square</strong> and <strong>no red</strong>.</p>
<p>This tests whether browsers correctly fail the condition for multiple selectors in <code>selector()</code>.</p>
<div class="test-output" id="test1-output"></div>
</div>
<!-- Test 2 -->
<div class="test">
<h2>Test 2: @supports selector() with -webkit- unknown pseudo-elements and negation</h2>
<p>Test passes if there is a <strong class="expected">filled green square</strong> and <strong>no red</strong>.</p>
<p>This tests whether browsers correctly handle negation with an unknown pseudo-element.</p>
<div class="test-output" id="test2-output"></div>
</div>
<!-- Test 3 -->
<div class="test">
<h2>Test 3: @supports selector() with pseudo-elements</h2>
<p>Test passes if there is a <strong class="expected">filled green square</strong> and <strong>no red</strong>.</p>
<p>This tests whether browsers recognize pseudo-elements in the <code>selector()</code> function.</p>
<div class="test-output" id="test3-output"></div>
</div>
<!-- Test 4 -->
<div class="test">
<h2>Test 4: @supports selector() with compound selector</h2>
<p>Test passes if there is a <strong class="expected">filled green square</strong> and <strong>no red</strong>.</p>
<p>This tests whether browsers can handle complex compound selectors in the <code>selector()</code> function.</p>
<div class="test-output" id="test4-output"></div>
</div>
<!-- Test 5 -->
<div class="test">
<h2>Test 5: @supports selector() with unsupported but valid pseudo and negation</h2>
<p>Test passes if there is a <strong class="expected">filled green square</strong> and <strong>no red</strong>.</p>
<p>This tests whether browsers give back a valid syntax selector<br />
(obscure edge case CSS used: <b>:nth-child(1 of .foo)</b>) that isn't actually supported.</p>
<div class="test-output" id="test5-output"></div>
</div>
<!-- Test 6 -->
<div class="test">
<h2>Test 6: @supports selector() with cascade of selectors</h2>
<p>Test passes if there is a <strong class="expected">filled green square</strong> and <strong>no red</strong>.</p>
<p>This tests whether browsers can handle passing cascaded selectors.</p>
<div class="test-output" id="test6-output"></div>
</div>
<!-- Test 7 -->
<div class="test">
<h2>Test 7: @supports selector() with :has() pseudo-class and negation</h2>
<p>Test passes if there is a <strong class="expected">filled green square</strong> and <strong>no red</strong>.</p>
<p>This tests whether browsers correctly identify support for the :has() pseudo-class. This is not supported yet.</p>
<div class="test-output" id="test7-output"></div>
</div>
<!-- Test 8.1 -->
<div class="test">
<h2>Test 8.1: @supports selector(:nth-child(5n))</h2>
<p>Test passes if there is a <strong class="expected">filled green square</strong>.</p>
<div class="test-output" id="test8-output-1"></div>
</div>
<!-- Test 8.2 -->
<div class="test">
<h2>Test 8.2: @supports selector(:nth-child(2n))</h2>
<p>Test passes if there is a <strong class="expected">filled green square</strong>.</p>
<div class="test-output" id="test8-output-2"></div>
</div>
<!-- Test 8.3 -->
<div class="test">
<h2>Test 8.3: @supports selector(li:nth-child(2n))</h2>
<p>Test passes if there is a <strong class="expected">filled green square</strong>.</p>
<div class="test-output" id="test8-output-3"></div>
</div>
<!-- Test 8.4 -->
<div class="test">
<h2>Test 8.4: @supports selector(:nth-child(odd))</h2>
<p>Test passes if there is a <strong class="expected">filled green square</strong>.</p>
<div class="test-output" id="test8-output-4"></div>
</div>
<!-- Test 8.5 -->
<div class="test">
<h2>Test 8.5: @supports selector(:nth-child(even))</h2>
<p>Test passes if there is a <strong class="expected">filled green square</strong>.</p>
<div class="test-output" id="test8-output-5"></div>
</div>
<!-- Test 8.6 -->
<div class="test">
<h2>Test 8.6: @supports selector(:nth-child(3n+1))</h2>
<p>Test passes if there is a <strong class="expected">filled green square</strong>.</p>
<div class="test-output" id="test8-output-6"></div>
</div>
<!-- Test 8.7 -->
<div class="test">
<h2>Test 8.7: @supports selector(:nth-child(2n + 2))</h2>
<p>Test passes if there is a <strong class="expected">filled green square</strong>.</p>
<div class="test-output" id="test8-output-7"></div>
</div>
<!-- Test 9 -->
<div class="test">
<h2>Test 9: @supports not selector(div)</h2>
<p>Test passes if there is a <strong class="expected">filled green square</strong>.</p>
<div class="test-output" id="test9-output"></div>
</div>
<!-- Test 10 -->
<div class="test">
<h2>Test 10: Complex selector chain<br>
@supports selector(section > div:nth-child(2n+1):not(.foo, .bar):hover)</h2>
<p>Test passes if there is a <strong class="expected">filled green square</strong>.</p>
<div class="test-output" id="test10-output"></div>
</div>
<style>
/* Test 1 Styles */
#test1-output {
background-color: green;
}
@supports selector(div, div) {
#test1-output { background: red; }
}
/* Test 2 Styles */
#test2-output {
background-color: red;
}
@supports not selector(::-webkit-unknown-pseudo) {
#test2-output { background: green; }
}
/* Test 3 Styles */
#test3-output {
background-color: red;
}
@supports selector(::before) {
#test3-output { background: green; }
}
/* Test 4 Styles */
#test4-output {
background-color: red;
}
@supports selector(a:link.class#ident) {
#test4-output { background: green; }
}
/* Test 5 Styles */
#test5-output {
background-color: red;
}
@supports not selector(:nth-child(1 of .foo)) {
#test5-output { background: green; }
}
/* Test 6 Styles */
#test6-output {
background-color: red;
}
@supports selector(div > h2 + p) {
#test6-output { background: green; }
}
/* Test 7 Styles */
#test7-output {
background-color: red;
}
@supports not selector(div:has(p)) {
#test7-output { background: green; }
}
/* Test 8.1 Styles */
#test8-output-1 {
background-color: red;
}
@supports selector(:nth-child(5n)) {
#test8-output-1 { background: green; }
}
/* Test 8.2 Styles */
#test8-output-2 {
background-color: red;
}
@supports selector(:nth-child(2n)) {
#test8-output-2 { background: green; }
}
/* Test 8.3 Styles */
#test8-output-3 {
background-color: red;
}
@supports selector(li:nth-child(2n)) {
#test8-output-3 { background: green; }
}
/* Test 8.4 Styles */
#test8-output-4 {
background-color: red;
}
@supports selector(:nth-child(odd)) {
#test8-output-4 { background: green; }
}
/* Test 8.5 Styles */
#test8-output-5 {
background-color: red;
}
@supports selector(:nth-child(even)) {
#test8-output-5 { background: green; }
}
/* Test 8.6 Styles */
#test8-output-6 {
background-color: red;
}
@supports selector(:nth-child(3n+1)) {
#test8-output-6 { background: green; }
}
/* Test 8.7 Styles */
#test8-output-7 {
background-color: red;
}
@supports selector(:nth-child(2n + 2)) {
#test8-output-7 { background: green; }
}
/* Test 9 Styles */
#test9-output {
background-color: green;
}
@supports not selector(div) {
#test9-output { background: red; }
}
/* Test 10 Styles */
#test10-output {
background-color: red;
}
@supports selector(section > div:nth-child(2n+1):not(.foo, .bar):hover) {
#test10-output { background: green; }
}
</style>
</body>
</html>

View file

@ -3126,6 +3126,15 @@ nsCookieService::SetCookieInternal(nsIURI *aHostURI,
return newCookie; return newCookie;
} }
// RFC 6265 *explicitly* forbids nameless cookies (5.2 step 5)
// Note: we ignore RFC 6265 (bis)'s conflicting stipulation and treat equal-less cookies
// as value-less cookies, not nameless ones.
// This aligns with webkit/Safari and avoids serious sec issues like CVE-2025-8037.
if (cookieAttributes.name.IsEmpty()) {
COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, savedCookieHeader, "nameless cookies are not allowed");
return newCookie;
}
// domain & path checks // domain & path checks
if (!CheckDomain(cookieAttributes, aHostURI, aKey.mBaseDomain, aRequireHostMatch)) { if (!CheckDomain(cookieAttributes, aHostURI, aKey.mBaseDomain, aRequireHostMatch)) {
COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, savedCookieHeader, "failed the domain tests"); COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, savedCookieHeader, "failed the domain tests");
@ -3574,15 +3583,11 @@ nsCookieService::ParseAttributes(nsDependentCString &aCookieHeader,
// extract cookie <NAME> & <VALUE> (first attribute), and copy the strings. // extract cookie <NAME> & <VALUE> (first attribute), and copy the strings.
// if we find multiple cookies, return for processing // if we find multiple cookies, return for processing
// note: if there's no '=', we assume token is <VALUE>. this is required by // note: if there's no '=', we assume token is <NAME>.
// some sites (see bug 169091).
// XXX fix the parser to parse according to <VALUE> grammar for this case
newCookie = GetTokenValue(cookieStart, cookieEnd, tokenString, tokenValue, equalsFound); newCookie = GetTokenValue(cookieStart, cookieEnd, tokenString, tokenValue, equalsFound);
aCookieAttributes.name = tokenString;
if (equalsFound) { if (equalsFound) {
aCookieAttributes.name = tokenString;
aCookieAttributes.value = tokenValue; aCookieAttributes.value = tokenValue;
} else {
aCookieAttributes.value = tokenString;
} }
// extract remaining attributes // extract remaining attributes

View file

@ -3164,6 +3164,9 @@ XREMain::XRE_mainStartup(bool* aExitFlag)
#endif #endif
#if defined(MOZ_WIDGET_GTK) #if defined(MOZ_WIDGET_GTK)
// Set up fontconfig.
FcInit();
// setup for private colormap. Ideally we'd like to do this // setup for private colormap. Ideally we'd like to do this
// in nsAppShell::Create, but we need to get in before gtk // in nsAppShell::Create, but we need to get in before gtk
// has been initialized to make sure everything is running // has been initialized to make sure everything is running