hardening against bad regexes

This commit is contained in:
gorhill 2015-10-26 11:23:56 -04:00
parent ba20843e07
commit 72201527d3
2 changed files with 67 additions and 16 deletions

View File

@ -39,6 +39,16 @@ var µb = µBlock;
var encode = JSON.stringify; var encode = JSON.stringify;
var decode = JSON.parse; var decode = JSON.parse;
var isBadRegex = function(s) {
try {
void new RegExp(s);
} catch (ex) {
isBadRegex.message = ex.toString();
return true;
}
return false;
};
/******************************************************************************/ /******************************************************************************/
/* /*
var histogram = function(label, buckets) { var histogram = function(label, buckets) {
@ -252,11 +262,11 @@ FilterParser.prototype.reset = function() {
/******************************************************************************/ /******************************************************************************/
FilterParser.prototype.parse = function(s) { FilterParser.prototype.parse = function(raw) {
// important! // important!
this.reset(); this.reset();
var matches = this.reParser.exec(s); var matches = this.reParser.exec(raw);
if ( matches === null || matches.length !== 4 ) { if ( matches === null || matches.length !== 4 ) {
this.cosmetic = false; this.cosmetic = false;
return this; return this;
@ -301,20 +311,43 @@ FilterParser.prototype.parse = function(s) {
// Examples: // Examples:
// focus.de##script:contains(/uabInject/) // focus.de##script:contains(/uabInject/)
// focus.de##script:contains(uabInject) // focus.de##script:contains(uabInject)
if ( this.suffix.charAt(0) === 's' && this.reScriptContains.test(this.suffix) ) {
// Inline script tag filter?
if (
this.suffix.charAt(0) !== 's' ||
this.reScriptContains.test(this.suffix) === false )
{
return this;
}
// Currently supported only as non-generic selector. Also, exception // Currently supported only as non-generic selector. Also, exception
// script tag filter makes no sense, ignore. // script tag filter makes no sense, ignore.
if ( this.hostnames.length === 0 || this.unhide === 1 ) { if ( this.hostnames.length === 0 || this.unhide === 1 ) {
this.invalid = true; this.invalid = true;
return this; return this;
} }
var suffix = this.suffix; var suffix = this.suffix;
this.suffix = 'script//:'; this.suffix = 'script//:';
// Plain string-based?
if ( suffix.charAt(16) !== '/' || suffix.slice(-2) !== '/)' ) { if ( suffix.charAt(16) !== '/' || suffix.slice(-2) !== '/)' ) {
this.suffix += suffix.slice(16, -1).replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); this.suffix += suffix.slice(16, -1).replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
} else { return this;
this.suffix += suffix.slice(17, -2).replace(/\\/g, '\\');
} }
// Regex-based
this.suffix += suffix.slice(17, -2).replace(/\\/g, '\\');
// Valid regex?
if ( isBadRegex(this.suffix) ) {
console.error(
"uBlock Origin> discarding bad regular expression-based cosmetic filter '%s': '%s'",
raw,
isBadRegex.message
);
this.invalid = true;
return this;
} }
return this; return this;

View File

@ -176,6 +176,16 @@ var isFirstParty = function(firstPartyDomain, hostname) {
return c === '.' || c === ''; return c === '.' || c === '';
}; };
var isBadRegex = function(s) {
try {
void new RegExp(s);
} catch (ex) {
isBadRegex.message = ex.toString();
return true;
}
return false;
};
var alwaysTruePseudoRegex = { var alwaysTruePseudoRegex = {
match: { '0': '', index: 0 }, match: { '0': '', index: 0 },
exec: function(s) { exec: function(s) {
@ -1539,6 +1549,14 @@ FilterParser.prototype.parse = function(raw) {
if ( s.charAt(0) === '/' && s.slice(-1) === '/' && s.length > 2 ) { if ( s.charAt(0) === '/' && s.slice(-1) === '/' && s.length > 2 ) {
this.isRegex = true; this.isRegex = true;
this.f = s.slice(1, -1); this.f = s.slice(1, -1);
if ( isBadRegex(this.f) ) {
console.error(
"uBlock Origin> discarding bad regular expression-based network filter '%s': '%s'",
raw,
isBadRegex.message
);
this.unsupported = true;
}
return this; return this;
} }