Bug 1638358 - Cookie Schemeful Same-Site - part 2 - schemeMap in the cookie DB, r=mayhemer

Differential Revision: https://phabricator.services.mozilla.com/D75626
This commit is contained in:
Andrea Marchesini 2020-06-01 10:28:18 +00:00
Родитель 4afe05e324
Коммит 8d0f3f353b
14 изменённых файлов: 162 добавлений и 16 удалений

Просмотреть файл

@ -96,6 +96,9 @@ class Cookie final : public nsICookie {
// Set the creation time manually, overriding the monotonicity checks in
// Create(). Use with caution!
inline void SetCreationTime(int64_t aTime) { mData.creationTime() = aTime; }
inline void SetSchemeMap(uint8_t aSchemeMap) {
mData.schemeMap() = aSchemeMap;
}
bool IsStale() const;

Просмотреть файл

@ -27,7 +27,7 @@
// This is a hack to hide HttpOnly cookies from older browsers
#define HTTP_ONLY_PREFIX "#HttpOnly_"
constexpr auto COOKIES_SCHEMA_VERSION = 11;
constexpr auto COOKIES_SCHEMA_VERSION = 12;
// parameter indexes; see |Read|
constexpr auto IDX_NAME = 0;
@ -42,6 +42,7 @@ constexpr auto IDX_HTTPONLY = 8;
constexpr auto IDX_ORIGIN_ATTRIBUTES = 9;
constexpr auto IDX_SAME_SITE = 10;
constexpr auto IDX_RAW_SAME_SITE = 11;
constexpr auto IDX_SCHEME_MAP = 12;
#define COOKIES_FILE "cookies.sqlite"
@ -112,6 +113,10 @@ void BindCookieParameters(mozIStorageBindingParamsArray* aParamsArray,
aCookie->RawSameSite());
MOZ_ASSERT(NS_SUCCEEDED(rv));
rv = params->BindInt32ByName(NS_LITERAL_CSTRING("schemeMap"),
aCookie->SchemeMap());
MOZ_ASSERT(NS_SUCCEEDED(rv));
// Bind the params to the array.
rv = aParamsArray->AddParams(params);
MOZ_ASSERT(NS_SUCCEEDED(rv));
@ -1384,6 +1389,17 @@ CookiePersistentStorage::OpenDBResult CookiePersistentStorage::TryInitDB(
COOKIE_LOGSTRING(LogLevel::Debug,
("Upgraded database to schema version 11"));
}
[[fallthrough]];
case 11: {
// Add the schemeMap column to the table.
rv = mSyncConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"ALTER TABLE moz_cookies ADD schemeMap INTEGER DEFAULT 0;"));
NS_ENSURE_SUCCESS(rv, RESULT_RETRY);
COOKIE_LOGSTRING(LogLevel::Debug,
("Upgraded database to schema version 12"));
// No more upgrades. Update the schema version.
rv = mSyncConn->SetSchemaVersion(COOKIES_SCHEMA_VERSION);
@ -1430,7 +1446,8 @@ CookiePersistentStorage::OpenDBResult CookiePersistentStorage::TryInitDB(
"isSecure, "
"isHttpOnly, "
"sameSite, "
"rawSameSite "
"rawSameSite, "
"schemeMap "
"FROM moz_cookies"),
getter_AddRefs(stmt));
if (NS_SUCCEEDED(rv)) {
@ -1604,7 +1621,8 @@ CookiePersistentStorage::OpenDBResult CookiePersistentStorage::Read() {
"isHttpOnly, "
"originAttributes, "
"sameSite, "
"rawSameSite "
"rawSameSite, "
"schemeMap "
"FROM moz_cookies"),
getter_AddRefs(stmt));
@ -1684,11 +1702,13 @@ UniquePtr<CookieStruct> CookiePersistentStorage::GetCookieFromRow(
bool isHttpOnly = 0 != aRow->AsInt32(IDX_HTTPONLY);
int32_t sameSite = aRow->AsInt32(IDX_SAME_SITE);
int32_t rawSameSite = aRow->AsInt32(IDX_RAW_SAME_SITE);
int32_t schemeMap = aRow->AsInt32(IDX_SCHEME_MAP);
// Create a new constCookie and assign the data.
return MakeUnique<CookieStruct>(
name, value, host, path, expiry, lastAccessed, creationTime, isHttpOnly,
false, isSecure, sameSite, rawSameSite, nsICookie::SCHEME_UNSET);
false, isSecure, sameSite, rawSameSite,
static_cast<nsICookie::schemeType>(schemeMap));
}
void CookiePersistentStorage::EnsureReadComplete() {
@ -1824,7 +1844,8 @@ nsresult CookiePersistentStorage::InitDBConnInternal() {
"isSecure, "
"isHttpOnly, "
"sameSite, "
"rawSameSite "
"rawSameSite, "
"schemeMap "
") VALUES ("
":originAttributes, "
":name, "
@ -1837,7 +1858,8 @@ nsresult CookiePersistentStorage::InitDBConnInternal() {
":isSecure, "
":isHttpOnly, "
":sameSite, "
":rawSameSite "
":rawSameSite, "
":schemeMap "
")"),
getter_AddRefs(mStmtInsert));
NS_ENSURE_SUCCESS(rv, rv);
@ -1881,6 +1903,7 @@ nsresult CookiePersistentStorage::CreateTableWorker(const char* aName) {
"inBrowserElement INTEGER DEFAULT 0, "
"sameSite INTEGER DEFAULT 0, "
"rawSameSite INTEGER DEFAULT 0, "
"schemeMap INTEGER DEFAULT 0, "
"CONSTRAINT moz_uniqueid UNIQUE (name, host, path, originAttributes)"
")");
return mSyncConn->ExecuteSimpleSQL(command);

Просмотреть файл

@ -976,6 +976,16 @@ bool CookieService::CanSetCookie(
// init expiryTime such that session cookies won't prematurely expire
aCookieData.expiry() = INT64_MAX;
if (aHostURI->SchemeIs("https")) {
aCookieData.schemeMap() = nsICookie::SCHEME_HTTPS;
} else if (aHostURI->SchemeIs("http")) {
aCookieData.schemeMap() = nsICookie::SCHEME_HTTP;
} else if (aHostURI->SchemeIs("file")) {
aCookieData.schemeMap() = nsICookie::SCHEME_FILE;
} else {
MOZ_CRASH("Unsupported scheme type");
}
// aCookieHeader is an in/out param to point to the next cookie, if
// there is one. Save the present value for logging purposes
nsCString savedCookieHeader(aCookieHeader);

Просмотреть файл

@ -481,6 +481,7 @@ void CookieStorage::AddCookie(const nsACString& aBaseDomain,
oldCookie->IsSession() == aCookie->IsSession() &&
oldCookie->IsHttpOnly() == aCookie->IsHttpOnly() &&
oldCookie->SameSite() == aCookie->SameSite() &&
oldCookie->SchemeMap() == aCookie->SchemeMap() &&
// We don't want to perform this optimization if the cookie is
// considered stale, since in this case we would need to update the
// database.
@ -491,6 +492,10 @@ void CookieStorage::AddCookie(const nsACString& aBaseDomain,
return;
}
// Merge the scheme map in case the old cookie and the new cookie are
// used with different schemes.
MergeCookieSchemeMap(oldCookie, aCookie);
// Remove the old cookie.
RemoveCookieFromList(exactIter);
@ -589,6 +594,11 @@ void CookieStorage::UpdateCookieOldestTime(Cookie* aCookie) {
}
}
void CookieStorage::MergeCookieSchemeMap(Cookie* aOldCookie,
Cookie* aNewCookie) {
aNewCookie->SetSchemeMap(aOldCookie->SchemeMap() | aNewCookie->SchemeMap());
}
void CookieStorage::AddCookieToList(const nsACString& aBaseDomain,
const OriginAttributes& aOriginAttributes,
Cookie* aCookie) {

Просмотреть файл

@ -178,6 +178,8 @@ class CookieStorage : public nsIObserver, public nsSupportsWeakReference {
void UpdateCookieOldestTime(Cookie* aCookie);
void MergeCookieSchemeMap(Cookie* aOldCookie, Cookie* aNewCookie);
static already_AddRefed<nsIArray> CreatePurgeList(nsICookie* aCookie);
virtual already_AddRefed<nsIArray> PurgeCookies(int64_t aCurrentTimeInUsec,

Просмотреть файл

@ -61,7 +61,7 @@ conn.executeSimpleSQL(
// Get sessionCookies to wait for the initialization in cookie thread
const cookies = Services.cookies.sessionCookies;
Assert.equal(conn.schemaVersion, 11);
Assert.equal(conn.schemaVersion, 12);
let stmt = conn.createStatement(
"SELECT sql FROM sqlite_master " +
"WHERE type = 'table' AND " +

Просмотреть файл

@ -102,7 +102,7 @@ add_task(async _ => {
await promise;
conn = storage.openDatabase(dbFile);
Assert.equal(conn.schemaVersion, 11);
Assert.equal(conn.schemaVersion, 12);
let stmt = conn.createStatement(
"SELECT sameSite, rawSameSite FROM moz_cookies"

Просмотреть файл

@ -221,7 +221,8 @@ function Cookie(
inBrowserElement = false,
originAttributes = {},
sameSite = Ci.nsICookie.SAMESITE_NONE,
rawSameSite = Ci.nsICookie.SAMESITE_NONE
rawSameSite = Ci.nsICookie.SAMESITE_NONE,
schemeMap = Ci.nsICookie.SCHEME_UNSET
) {
this.name = name;
this.value = value;
@ -237,6 +238,7 @@ function Cookie(
this.originAttributes = originAttributes;
this.sameSite = sameSite;
this.rawSameSite = rawSameSite;
this.schemeMap = schemeMap;
let strippedHost = host.charAt(0) == "." ? host.slice(1) : host;
@ -628,6 +630,80 @@ function CookieDatabaseConnection(file, schema) {
break;
}
case 12: {
if (!exists) {
this.db.executeSimpleSQL(
"CREATE TABLE moz_cookies ( \
id INTEGER PRIMARY KEY, \
originAttributes TEXT NOT NULL DEFAULT '', \
name TEXT, \
value TEXT, \
host TEXT, \
path TEXT, \
expiry INTEGER, \
lastAccessed INTEGER, \
creationTime INTEGER, \
isSecure INTEGER, \
isHttpOnly INTEGER, \
inBrowserElement INTEGER DEFAULT 0, \
sameSite INTEGER DEFAULT 0, \
rawSameSite INTEGER DEFAULT 0, \
schemeMap INTEGER DEFAULT 0, \
CONSTRAINT moz_uniqueid UNIQUE (name, host, path, originAttributes))"
);
this.db.executeSimpleSQL("PRAGMA journal_mode = WAL");
this.db.executeSimpleSQL("PRAGMA wal_autocheckpoint = 16");
}
this.stmtInsert = this.db.createStatement(
"INSERT INTO moz_cookies ( \
name, \
value, \
host, \
path, \
expiry, \
lastAccessed, \
creationTime, \
isSecure, \
isHttpOnly, \
inBrowserElement, \
originAttributes, \
sameSite, \
rawSameSite, \
schemeMap \
) VALUES ( \
:name, \
:value, \
:host, \
:path, \
:expiry, \
:lastAccessed, \
:creationTime, \
:isSecure, \
:isHttpOnly, \
:inBrowserElement, \
:originAttributes, \
:sameSite, \
:rawSameSite, \
:schemeMap)"
);
this.stmtDelete = this.db.createStatement(
"DELETE FROM moz_cookies \
WHERE name = :name AND host = :host AND path = :path AND \
originAttributes = :originAttributes"
);
this.stmtUpdate = this.db.createStatement(
"UPDATE moz_cookies SET lastAccessed = :lastAccessed \
WHERE name = :name AND host = :host AND path = :path AND \
originAttributes = :originAttributes"
);
break;
}
default:
do_throw("unrecognized schemaVersion!");
}
@ -728,6 +804,26 @@ CookieDatabaseConnection.prototype = {
this.stmtInsert.bindByName("rawSameSite", cookie.rawSameSite);
break;
case 12:
this.stmtInsert.bindByName("name", cookie.name);
this.stmtInsert.bindByName("value", cookie.value);
this.stmtInsert.bindByName("host", cookie.host);
this.stmtInsert.bindByName("path", cookie.path);
this.stmtInsert.bindByName("expiry", cookie.expiry);
this.stmtInsert.bindByName("lastAccessed", cookie.lastAccessed);
this.stmtInsert.bindByName("creationTime", cookie.creationTime);
this.stmtInsert.bindByName("isSecure", cookie.isSecure);
this.stmtInsert.bindByName("isHttpOnly", cookie.isHttpOnly);
this.stmtInsert.bindByName("inBrowserElement", cookie.inBrowserElement);
this.stmtInsert.bindByName(
"originAttributes",
ChromeUtils.originAttributesToSuffix(cookie.originAttributes)
);
this.stmtInsert.bindByName("sameSite", cookie.sameSite);
this.stmtInsert.bindByName("rawSameSite", cookie.rawSameSite);
this.stmtInsert.bindByName("schemeMap", cookie.schemeMap);
break;
default:
do_throw("unrecognized schemaVersion!");
}
@ -755,6 +851,7 @@ CookieDatabaseConnection.prototype = {
case 10:
case 11:
case 12:
this.stmtDelete.bindByName("name", cookie.name);
this.stmtDelete.bindByName("host", cookie.host);
this.stmtDelete.bindByName("path", cookie.path);
@ -798,6 +895,7 @@ CookieDatabaseConnection.prototype = {
case 10:
case 11:
case 12:
this.stmtDelete.bindByName("name", cookie.name);
this.stmtDelete.bindByName("host", cookie.host);
this.stmtDelete.bindByName("path", cookie.path);

Просмотреть файл

@ -123,7 +123,7 @@ async function run_test_1() {
// Open a database connection now, before we load the profile and begin
// asynchronous write operations.
let db = new CookieDatabaseConnection(do_get_cookie_file(profile), 11);
let db = new CookieDatabaseConnection(do_get_cookie_file(profile), 12);
Assert.equal(do_count_cookies_in_db(db.db), 1);
// Load the profile, and wait for async read completion...
@ -481,7 +481,7 @@ async function run_test_5() {
// Open a database connection, and write a row that will trigger a constraint
// violation.
let db = new CookieDatabaseConnection(do_get_cookie_file(profile), 11);
let db = new CookieDatabaseConnection(do_get_cookie_file(profile), 12);
db.insertCookie(cookie);
Assert.equal(do_count_cookies_in_db(db.db, "bar.com"), 1);
Assert.equal(do_count_cookies_in_db(db.db), 1);

Просмотреть файл

@ -26,7 +26,7 @@ add_task(async () => {
// completed. We may not be able to open one later once asynchronous writing
// begins.
Assert.ok(do_get_cookie_file(profile).exists());
let db = new CookieDatabaseConnection(do_get_cookie_file(profile), 11);
let db = new CookieDatabaseConnection(do_get_cookie_file(profile), 12);
let uri = NetUtil.newURI("http://foo.com/");
let channel = NetUtil.newChannel({

Просмотреть файл

@ -28,7 +28,7 @@ let now;
let futureExpiry;
let cookie;
var COOKIE_DATABASE_SCHEMA_CURRENT = 11;
var COOKIE_DATABASE_SCHEMA_CURRENT = 12;
var test_generator = do_run_test();

Просмотреть файл

@ -49,7 +49,7 @@ add_task(async function() {
Services.obs.notifyObservers(null, "profile-before-change");
// check for upgraded schema.
Assert.equal(11, getDBVersion(destFile));
Assert.equal(12, getDBVersion(destFile));
// Check that the index was deleted
Assert.ok(!indexExists(destFile, "moz_basedomain"));

Просмотреть файл

@ -2,7 +2,7 @@
http://creativecommons.org/publicdomain/zero/1.0/ */
// Test cookie database migration from version 10 (prerelease Gecko 2.0) to the
// current version, presently 11.
// current version, presently 12.
"use strict";
var test_generator = do_run_test();

Просмотреть файл

@ -193,7 +193,7 @@ skip-if = true # Bug 863738
[test_cookies_sync_failure.js]
[test_cookies_thirdparty.js]
[test_cookies_thirdparty_session.js]
[test_cookies_upgrade_10-11.js]
[test_cookies_upgrade_10.js]
[test_dns_cancel.js]
[test_data_protocol.js]
[test_dns_service.js]