diff --git a/browser/components/sessionstore/SessionCookies.sys.mjs b/browser/components/sessionstore/SessionCookies.sys.mjs index 4ab1f9962f30..a46b8784632b 100644 --- a/browser/components/sessionstore/SessionCookies.sys.mjs +++ b/browser/components/sessionstore/SessionCookies.sys.mjs @@ -74,7 +74,8 @@ var SessionCookiesInternal = { expiry, cookie.originAttributes || {}, cookie.sameSite || Ci.nsICookie.SAMESITE_NONE, - cookie.schemeMap || Ci.nsICookie.SCHEME_HTTPS + cookie.schemeMap || Ci.nsICookie.SCHEME_HTTPS, + cookie.isPartitioned ); } catch (ex) { console.error( @@ -256,6 +257,10 @@ var CookieStore = { jscookie.schemeMap = cookie.schemeMap; } + if (cookie.isPartitioned) { + jscookie.isPartitioned = true; + } + this._entries.set(this._getKeyForCookie(cookie), jscookie); }, diff --git a/netwerk/cookie/CookieCommons.cpp b/netwerk/cookie/CookieCommons.cpp index 675f97a41854..c6f7965e4923 100644 --- a/netwerk/cookie/CookieCommons.cpp +++ b/netwerk/cookie/CookieCommons.cpp @@ -545,6 +545,39 @@ bool CookieCommons::ShouldIncludeCrossSiteCookie(int32_t aSameSiteAttr, return aSameSiteAttr == nsICookie::SAMESITE_NONE; } +// static +bool CookieCommons::IsFirstPartyPartitionedCookieWithoutCHIPS( + Cookie* aCookie, const nsACString& aBaseDomain, + const OriginAttributes& aOriginAttributes) { + MOZ_ASSERT(aCookie); + + // The cookie is set with partitioned attribute. This is a CHIPS cookies. + if (aCookie->RawIsPartitioned()) { + return false; + } + + // The originAttributes is not partitioned. This is not a partitioned cookie. + if (aOriginAttributes.mPartitionKey.IsEmpty()) { + return false; + } + + nsAutoString scheme; + nsAutoString baseDomain; + int32_t port; + bool foreignByAncestorContext; + // Bail out early if the partition key is not valid. + if (!OriginAttributes::ParsePartitionKey(aOriginAttributes.mPartitionKey, + scheme, baseDomain, port, + foreignByAncestorContext)) { + return false; + } + + // Check whether the base domain of the cookie match the base domain in the + // partitionKey and it is not an ABA context + return aBaseDomain.Equals(NS_ConvertUTF16toUTF8(baseDomain)) && + !foreignByAncestorContext; +} + bool CookieCommons::IsSafeTopLevelNav(nsIChannel* aChannel) { if (!aChannel) { return false; diff --git a/netwerk/cookie/CookieCommons.h b/netwerk/cookie/CookieCommons.h index ef7e57745a13..8d52730872b7 100644 --- a/netwerk/cookie/CookieCommons.h +++ b/netwerk/cookie/CookieCommons.h @@ -126,6 +126,10 @@ class CookieCommons final { bool aInPrivateBrowsing, bool aUsingStorageAccess); + static bool IsFirstPartyPartitionedCookieWithoutCHIPS( + Cookie* aCookie, const nsACString& aBaseDomain, + const OriginAttributes& aOriginAttributes); + static bool IsSchemeSupported(nsIPrincipal* aPrincipal); static bool IsSchemeSupported(nsIURI* aURI); static bool IsSchemeSupported(const nsACString& aScheme); diff --git a/netwerk/cookie/CookieService.cpp b/netwerk/cookie/CookieService.cpp index 70ea389004ce..f2b7f190a49e 100644 --- a/netwerk/cookie/CookieService.cpp +++ b/netwerk/cookie/CookieService.cpp @@ -696,7 +696,7 @@ CookieService::Add(const nsACString& aHost, const nsACString& aPath, bool aIsSecure, bool aIsHttpOnly, bool aIsSession, int64_t aExpiry, JS::Handle aOriginAttributes, int32_t aSameSite, nsICookie::schemeType aSchemeMap, - JSContext* aCx) { + bool aIsPartitioned, JSContext* aCx) { OriginAttributes attrs; if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) { @@ -704,8 +704,8 @@ CookieService::Add(const nsACString& aHost, const nsACString& aPath, } return AddNative(aHost, aPath, aName, aValue, aIsSecure, aIsHttpOnly, - aIsSession, aExpiry, &attrs, aSameSite, aSchemeMap, false, - nullptr); + aIsSession, aExpiry, &attrs, aSameSite, aSchemeMap, + aIsPartitioned, nullptr); } NS_IMETHODIMP_(nsresult) diff --git a/netwerk/cookie/CookieServiceChild.cpp b/netwerk/cookie/CookieServiceChild.cpp index d4aeb7be6660..a76031d4b8a1 100644 --- a/netwerk/cookie/CookieServiceChild.cpp +++ b/netwerk/cookie/CookieServiceChild.cpp @@ -308,6 +308,15 @@ CookieServiceChild::RecordDocumentCookie(Cookie* aCookie, CookieCommons::GetBaseDomainFromHost(mTLDService, aCookie->Host(), baseDomain); + if (CookieCommons::IsFirstPartyPartitionedCookieWithoutCHIPS( + aCookie, baseDomain, aAttrs)) { + COOKIE_LOGSTRING(LogLevel::Error, + ("Invalid first-party partitioned cookie without " + "partitioned cookie attribution from the document.")); + MOZ_DIAGNOSTIC_ASSERT(false); + return CookieNotificationAction::NoActionNeeded; + } + CookieKey key(baseDomain, aAttrs); CookiesList* cookiesList = nullptr; mCookiesMap.Get(key, &cookiesList); diff --git a/netwerk/cookie/CookieStorage.cpp b/netwerk/cookie/CookieStorage.cpp index 096f1ff96587..a5c7dc16fa8e 100644 --- a/netwerk/cookie/CookieStorage.cpp +++ b/netwerk/cookie/CookieStorage.cpp @@ -602,6 +602,15 @@ void CookieStorage::AddCookie(CookieParser* aCookieParser, bool aFromHttp, bool aIsThirdParty, dom::BrowsingContext* aBrowsingContext, const nsID* aOperationID) { + if (CookieCommons::IsFirstPartyPartitionedCookieWithoutCHIPS( + aCookie, aBaseDomain, aOriginAttributes)) { + COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, aCookieHeader, + "Invalid first-party partitioned cookie without " + "partitioned cookie attribution."); + MOZ_DIAGNOSTIC_ASSERT(false); + return; + } + int64_t currentTime = aCurrentTimeInUsec / PR_USEC_PER_SEC; CookieListIter exactIter{}; diff --git a/netwerk/cookie/nsICookieManager.idl b/netwerk/cookie/nsICookieManager.idl index 0e1a1ebcdc1c..a747167be088 100644 --- a/netwerk/cookie/nsICookieManager.idl +++ b/netwerk/cookie/nsICookieManager.idl @@ -118,6 +118,10 @@ interface nsICookieManager : nsISupports * the originAttributes of this cookie. * @param aSameSite * the SameSite attribute. + * @param aSchemeMap + * the schemes this cookie has been set on. See nsICookie.idl. + * @param aIsPartitioned + * true if the cookie should be stored with the Partitioned attribute. */ [implicit_jscontext] void add(in AUTF8String aHost, @@ -130,7 +134,8 @@ interface nsICookieManager : nsISupports in int64_t aExpiry, in jsval aOriginAttributes, in int32_t aSameSite, - in nsICookie_schemeType aSchemeMap); + in nsICookie_schemeType aSchemeMap, + [optional] in boolean aIsPartitioned); [notxpcom] nsresult addNative(in AUTF8String aHost, diff --git a/remote/webdriver-bidi/modules/root/storage.sys.mjs b/remote/webdriver-bidi/modules/root/storage.sys.mjs index 5fdedcc3607e..cc42ed187efb 100644 --- a/remote/webdriver-bidi/modules/root/storage.sys.mjs +++ b/remote/webdriver-bidi/modules/root/storage.sys.mjs @@ -298,6 +298,8 @@ class StorageModule extends RootBiDiModule { schemeType = Ci.nsICookie.SCHEME_HTTP; } + const isPartitioned = originAttributes.partitionKey?.length > 0; + try { Services.cookies.add( domain, @@ -311,7 +313,8 @@ class StorageModule extends RootBiDiModule { expiry === null ? MAX_COOKIE_EXPIRY : expiry, originAttributes, this.#getSameSitePlatformProperty(sameSite), - schemeType + schemeType, + isPartitioned ); } catch (e) { throw new lazy.error.UnableToSetCookieError(e); diff --git a/testing/web-platform/meta/webdriver/tests/bidi/storage/get_cookies/partition.py.ini b/testing/web-platform/meta/webdriver/tests/bidi/storage/get_cookies/partition.py.ini index 478dbf5b002e..35b823e614f7 100644 --- a/testing/web-platform/meta/webdriver/tests/bidi/storage/get_cookies/partition.py.ini +++ b/testing/web-platform/meta/webdriver/tests/bidi/storage/get_cookies/partition.py.ini @@ -10,8 +10,3 @@ [test_partition_user_context] disabled: if os == "android": bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1877953 - - [test_partition_context_iframe[cross_origin\]] - bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1865198 - expected: - if not nightly_build: FAIL diff --git a/testing/web-platform/mozilla/meta/webdriver/bidi/storage/set_cookie/partition.py.ini b/testing/web-platform/mozilla/meta/webdriver/bidi/storage/set_cookie/partition.py.ini deleted file mode 100644 index ec3af176bf7f..000000000000 --- a/testing/web-platform/mozilla/meta/webdriver/bidi/storage/set_cookie/partition.py.ini +++ /dev/null @@ -1,10 +0,0 @@ -[partition.py] - [test_partition_context] - bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1865198 - expected: - if not nightly_build: FAIL - - [test_partition_context_iframe[cross_origin\]] - bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1865198 - expected: - if not nightly_build: FAIL diff --git a/toolkit/components/extensions/parent/ext-cookies.js b/toolkit/components/extensions/parent/ext-cookies.js index ad32602cd0b1..f8021c4debce 100644 --- a/toolkit/components/extensions/parent/ext-cookies.js +++ b/toolkit/components/extensions/parent/ext-cookies.js @@ -702,6 +702,8 @@ this.cookies = class extends ExtensionAPIPersistent { schemeType = Ci.nsICookie.SCHEME_FILE; } + let isPartitioned = originAttributes.partitionKey?.length > 0; + // The permission check may have modified the domain, so use // the new value instead. Services.cookies.add( @@ -715,7 +717,8 @@ this.cookies = class extends ExtensionAPIPersistent { expiry, originAttributes, sameSite, - schemeType + schemeType, + isPartitioned ); return self.cookies.get(details);