Add checksum validation when loading trie buffers in selfie

Related issue:
https://github.com/uBlockOrigin/uBlock-issues/issues/3217#issuecomment-2103048654
This commit is contained in:
Raymond Hill 2024-05-09 21:25:10 -04:00
parent bb479b0a66
commit 0e6d607484
No known key found for this signature in database
GPG Key ID: 25E1490B761470C2
2 changed files with 35 additions and 24 deletions

View File

@ -19,10 +19,6 @@
Home: https://github.com/gorhill/uBlock
*/
/* globals WebAssembly, vAPI */
'use strict';
/*******************************************************************************
A BidiTrieContainer is mostly a large buffer in which distinct but related
@ -124,6 +120,15 @@ const BCELL_EXTRA_MAX = 0x00FFFFFF;
const toSegmentInfo = (aL, l, r) => ((r - l) << 24) | (aL + l);
const roundToPageSize = v => (v + PAGE_SIZE-1) & ~(PAGE_SIZE-1);
// http://www.cse.yorku.ca/~oz/hash.html#djb2
const i32Checksum = (buf32) => {
const n = buf32.length;
let hash = 177573 ^ n;
for ( let i = 0; i < n; i++ ) {
hash = (hash << 5) + hash ^ buf32[i];
}
return hash;
};
class BidiTrieContainer {
@ -577,18 +582,18 @@ class BidiTrieContainer {
}
toSelfie() {
return this.buf32.subarray(
0,
this.buf32[CHAR1_SLOT] + 3 >>> 2
);
const buf32 = this.buf32.subarray(0, this.buf32[CHAR1_SLOT] + 3 >>> 2);
return { buf32, checksum: i32Checksum(buf32) };
}
fromSelfie(selfie) {
if ( selfie instanceof Uint32Array === false ) { return false; }
let byteLength = selfie.length << 2;
if ( selfie instanceof Object === false ) { return false; }
if ( selfie.buf32 instanceof Uint32Array === false ) { return false; }
if ( selfie.checksum !== i32Checksum(selfie.buf32) ) { return false; }
const byteLength = selfie.buf32.length << 2;
if ( byteLength === 0 ) { return false; }
this.reallocateBuf(byteLength);
this.buf32.set(selfie);
this.buf32.set(selfie.buf32);
return true;
}

View File

@ -19,10 +19,6 @@
Home: https://github.com/gorhill/uBlock
*/
/* globals WebAssembly */
'use strict';
/*******************************************************************************
The original prototype was to develop an idea I had about using jump indices
@ -115,7 +111,7 @@
*/
const PAGE_SIZE = 65536;
// i32 / i8
// i32 / i8
const TRIE0_SLOT = 256 >>> 2; // 64 / 256
const TRIE1_SLOT = TRIE0_SLOT + 1; // 65 / 260
const CHAR0_SLOT = TRIE0_SLOT + 2; // 66 / 264
@ -124,6 +120,16 @@ const TRIE0_START = TRIE0_SLOT + 4 << 2; // 272
const roundToPageSize = v => (v + PAGE_SIZE-1) & ~(PAGE_SIZE-1);
// http://www.cse.yorku.ca/~oz/hash.html#djb2
const i32Checksum = (buf32) => {
const n = buf32.length;
let hash = 177573 ^ n;
for ( let i = 0; i < n; i++ ) {
hash = (hash << 5) + hash ^ buf32[i];
}
return hash;
};
class HNTrieContainer {
constructor() {
@ -446,16 +452,16 @@ class HNTrieContainer {
}
toSelfie() {
return this.buf32.subarray(
0,
this.buf32[CHAR1_SLOT] + 3 >>> 2
);
const buf32 = this.buf32.subarray(0, this.buf32[CHAR1_SLOT] + 3 >>> 2);
return { buf32, checksum: i32Checksum(buf32) };
}
fromSelfie(selfie) {
if ( selfie instanceof Uint32Array === false ) { return false; }
if ( selfie instanceof Object === false ) { return false; }
if ( selfie.buf32 instanceof Uint32Array === false ) { return false; }
if ( selfie.checksum !== i32Checksum(selfie.buf32) ) { return false; }
this.needle = '';
let byteLength = selfie.length << 2;
let byteLength = selfie.buf32.length << 2;
if ( byteLength === 0 ) { return false; }
byteLength = roundToPageSize(byteLength);
if ( this.wasmMemory !== null ) {
@ -466,9 +472,9 @@ class HNTrieContainer {
this.buf = new Uint8Array(this.wasmMemory.buffer);
this.buf32 = new Uint32Array(this.buf.buffer);
}
this.buf32.set(selfie);
this.buf32.set(selfie.buf32);
} else {
this.buf32 = selfie;
this.buf32 = selfie.buf32;
this.buf = new Uint8Array(this.buf32.buffer);
}
// https://github.com/uBlockOrigin/uBlock-issues/issues/2925