Fix potential corruption when reading serialized data

Corrpution would occur when reading back serialized data which
contained multiple references to same instance of an object.

The issue could manifest when reading cache storage-related
data from the browser storage API, since the serializer is not
used when reading from indexedDB. Private/incognito mode
fall back on using browser storage API as cache storage.

Off the top of my head, I think the following conditions all
together could result in high likelihood of malfunction caused
by improperly deserializing data at launch time:

- Load from a selfie
- Selfie created after uBO ran for a while
- Selfie loaded from browser storage API (not the case by
  default)

Possibly related to reports of uBO malfunctioning:
https://github.com/uBlockOrigin/uBlock-issues/issues/3217#event-12686416838
This commit is contained in:
Raymond Hill 2024-05-02 20:21:47 -04:00
parent e891465775
commit c098eb8625
No known key found for this signature in database
GPG Key ID: 25E1490B761470C2
1 changed files with 10 additions and 11 deletions

View File

@ -747,6 +747,8 @@ const _deserialize = ( ) => {
}
case I_OBJECT_SMALL:
case I_OBJECT_LARGE: {
const out = {};
readRefs.set(refCounter++, out);
const entries = [];
const size = type === I_OBJECT_SMALL
? charCodeToInt[readStr.charCodeAt(readPtr++)]
@ -756,48 +758,45 @@ const _deserialize = ( ) => {
const v = _deserialize();
entries.push([ k, v ]);
}
const out = Object.fromEntries(entries);
readRefs.set(refCounter++, out);
Object.assign(out, Object.fromEntries(entries));
return out;
}
case I_ARRAY_SMALL:
case I_ARRAY_LARGE: {
const out = [];
readRefs.set(refCounter++, out);
const size = type === I_ARRAY_SMALL
? charCodeToInt[readStr.charCodeAt(readPtr++)]
: deserializeLargeUint();
for ( let i = 0; i < size; i++ ) {
out.push(_deserialize());
}
readRefs.set(refCounter++, out);
return out;
}
case I_SET_SMALL:
case I_SET_LARGE: {
const entries = [];
const out = new Set();
readRefs.set(refCounter++, out);
const size = type === I_SET_SMALL
? charCodeToInt[readStr.charCodeAt(readPtr++)]
: deserializeLargeUint();
for ( let i = 0; i < size; i++ ) {
entries.push(_deserialize());
out.add(_deserialize());
}
const out = new Set(entries);
readRefs.set(refCounter++, out);
return out;
}
case I_MAP_SMALL:
case I_MAP_LARGE: {
const entries = [];
const out = new Map();
readRefs.set(refCounter++, out);
const size = type === I_MAP_SMALL
? charCodeToInt[readStr.charCodeAt(readPtr++)]
: deserializeLargeUint();
for ( let i = 0; i < size; i++ ) {
const k = _deserialize();
const v = _deserialize();
entries.push([ k, v ]);
out.set(k, v);
}
const out = new Map(entries);
readRefs.set(refCounter++, out);
return out;
}
case I_ARRAYBUFFER: {