tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 37f622b02d485c52faa15a1ad2a4293a0d9caf76
parent d35af18f06cb7096d1e4c9d3260d6ca53be256d6
Author: Andrea Marchesini <amarchesini@mozilla.com>
Date:   Thu,  9 Oct 2025 14:54:32 +0000

Bug 1992536 - Use cookie creation time instead or PR_Now() to validate the expiration time, r=valentin,cookie-reviewers

Differential Revision: https://phabricator.services.mozilla.com/D267977

Diffstat:
Mnetwerk/cookie/CookieCommons.cpp | 8++++----
Mnetwerk/cookie/CookieCommons.h | 4++--
Mnetwerk/cookie/CookieParser.cpp | 17++++++++++-------
Mnetwerk/cookie/CookieParser.h | 6+++---
Mnetwerk/cookie/CookieService.cpp | 2+-
Mnetwerk/cookie/CookieValidation.cpp | 2+-
6 files changed, 21 insertions(+), 18 deletions(-)

diff --git a/netwerk/cookie/CookieCommons.cpp b/netwerk/cookie/CookieCommons.cpp @@ -377,7 +377,7 @@ already_AddRefed<Cookie> CookieCommons::CreateCookieFromDocument( aCookieParser.Parse(baseDomain, requireHostMatch, cookieStatus, cookieString, EmptyCString(), false, isForeignAndNotAddon, mustBePartitioned, aDocument->IsInPrivateBrowsing(), - on3pcbException, PR_Now() / PR_USEC_PER_MSEC); + on3pcbException, PR_Now()); if (!aCookieParser.ContainsCookie()) { return nullptr; @@ -1023,17 +1023,17 @@ bool CookieCommons::IsSubdomainOf(const nsACString& a, const nsACString& b) { } // static -int64_t CookieCommons::GetCurrentTimeFromChannel(nsIChannel* aChannel) { +int64_t CookieCommons::GetCurrentTimeInUSecFromChannel(nsIChannel* aChannel) { nsCOMPtr<nsITimedChannel> timedChannel = do_QueryInterface(aChannel); if (timedChannel) { PRTime currentTimeInUSec = 0; nsresult rv = timedChannel->GetResponseStartTime(&currentTimeInUSec); if (NS_SUCCEEDED(rv) && currentTimeInUSec) { - return currentTimeInUSec / PR_USEC_PER_MSEC; + return currentTimeInUSec; } } - return PR_Now() / PR_USEC_PER_MSEC; + return PR_Now(); } } // namespace net diff --git a/netwerk/cookie/CookieCommons.h b/netwerk/cookie/CookieCommons.h @@ -183,9 +183,9 @@ class CookieCommons final { // assuming no leading dots are present. static bool IsSubdomainOf(const nsACString& a, const nsACString& b); - // Returns the current time in msecs using a nsIChannel, which corresponds to + // Returns the current time in USecs using a nsIChannel, which corresponds to // the response start time. - static int64_t GetCurrentTimeFromChannel(nsIChannel* aChannel); + static int64_t GetCurrentTimeInUSecFromChannel(nsIChannel* aChannel); }; } // namespace net diff --git a/netwerk/cookie/CookieParser.cpp b/netwerk/cookie/CookieParser.cpp @@ -498,9 +498,10 @@ bool CookieParser::ParseMaxAgeAttribute(const nsACString& aMaxage, bool CookieParser::GetExpiry(CookieStruct& aCookieData, const nsACString& aExpires, const nsACString& aMaxage, - int64_t aCurrentTimeInMSec, const nsACString& aDateHeader, bool aFromHttp) { int64_t maxageCap = StaticPrefs::network_cookie_maxageCap(); + int64_t creationTimeInMSec = + aCookieData.creationTime() / int64_t(PR_USEC_PER_MSEC); /* Determine when the cookie should expire. This is done by taking the * difference between the server time and the time the server wants the cookie @@ -516,7 +517,7 @@ bool CookieParser::GetExpiry(CookieStruct& aCookieData, if (maxage == INT64_MIN) { aCookieData.expiry() = maxage; } else { - CheckedInt<int64_t> value(aCurrentTimeInMSec); + CheckedInt<int64_t> value(creationTimeInMSec); value += (maxageCap ? std::min(maxage, maxageCap) : maxage) * 1000; aCookieData.expiry() = value.isValid() ? value.value() : INT64_MAX; @@ -549,7 +550,7 @@ bool CookieParser::GetExpiry(CookieStruct& aCookieData, StaticPrefs::network_cookie_useServerTime()) { int64_t serverTimeInMSec = dateHeaderTimeInUSec / int64_t(PR_USEC_PER_MSEC); - int64_t delta = aCurrentTimeInMSec - serverTimeInMSec; + int64_t delta = creationTimeInMSec - serverTimeInMSec; expiresInMSec += delta; } } @@ -561,7 +562,7 @@ bool CookieParser::GetExpiry(CookieStruct& aCookieData, // The cookie item have to be used to the expired cookie. aCookieData.expiry() = - CookieCommons::MaybeCapExpiry(aCurrentTimeInMSec, expiresInMSec); + CookieCommons::MaybeCapExpiry(creationTimeInMSec, expiresInMSec); return false; } @@ -656,11 +657,13 @@ void CookieParser::Parse(const nsACString& aBaseDomain, bool aRequireHostMatch, const nsACString& aDateHeader, bool aFromHttp, bool aIsForeignAndNotAddon, bool aPartitionedOnly, bool aIsInPrivateBrowsing, bool aOn3pcbException, - int64_t aCurrentTimeInMSec) { + int64_t aCurrentTimeInUSec) { MOZ_ASSERT(!mValidation); // init expiryTime such that session cookies won't prematurely expire mCookieData.expiry() = INT64_MAX; + mCookieData.creationTime() = + Cookie::GenerateUniqueCreationTime(aCurrentTimeInUSec); mCookieData.schemeMap() = CookieCommons::URIToSchemeType(mHostURI); @@ -679,8 +682,8 @@ void CookieParser::Parse(const nsACString& aBaseDomain, bool aRequireHostMatch, } // calculate expiry time of cookie. - mCookieData.isSession() = GetExpiry( - mCookieData, expires, maxage, aCurrentTimeInMSec, aDateHeader, aFromHttp); + mCookieData.isSession() = + GetExpiry(mCookieData, expires, maxage, aDateHeader, aFromHttp); if (aStatus == STATUS_ACCEPT_SESSION) { // force lifetime to session. note that the expiration time, if set above, // will still apply. diff --git a/netwerk/cookie/CookieParser.h b/netwerk/cookie/CookieParser.h @@ -70,10 +70,10 @@ class CookieParser final { void ParseAttributes(nsCString& aCookieHeader, nsACString& aExpires, nsACString& aMaxage, bool& aAcceptedByParser); - // aCurrentTime is in milliseconds, and expiry will be stored in milliseconds. + // expiry will be stored in milliseconds. bool GetExpiry(CookieStruct& aCookieData, const nsACString& aExpires, - const nsACString& aMaxage, int64_t aCurrentTime, - const nsACString& aDateHeader, bool aFromHttp); + const nsACString& aMaxage, const nsACString& aDateHeader, + bool aFromHttp); static bool CheckAttributeSize(const nsACString& currentValue, const char* aAttribute, diff --git a/netwerk/cookie/CookieService.cpp b/netwerk/cookie/CookieService.cpp @@ -588,7 +588,7 @@ CookieService::SetCookieStringFromHttp(nsIURI* aHostURI, dateHeader, true, isForeignAndNotAddon, mustBePartitioned, storagePrincipalOriginAttributes.IsPrivateBrowsing(), loadInfo->GetIsOn3PCBExceptionList(), - CookieCommons::GetCurrentTimeFromChannel(aChannel)); + CookieCommons::GetCurrentTimeInUSecFromChannel(aChannel)); if (!cookieParser.ContainsCookie()) { return NS_OK; diff --git a/netwerk/cookie/CookieValidation.cpp b/netwerk/cookie/CookieValidation.cpp @@ -115,7 +115,7 @@ void CookieValidation::ValidateInternal() { // This part checks if the caleers have set the expiry value to max 400 days. if (!mCookieData.isSession()) { int64_t maxageCap = StaticPrefs::network_cookie_maxageCap(); - int64_t currentTimeInMSec = PR_Now() / PR_USEC_PER_MSEC; + int64_t currentTimeInMSec = mCookieData.creationTime() / PR_USEC_PER_MSEC; int64_t expiry = mCookieData.expiry(); if (maxageCap && expiry > currentTimeInMSec + maxageCap * 1000) { mResult = eRejectedAttributeExpiryOversize;