Skip to content

Commit

Permalink
feat: base safe test suite
Browse files Browse the repository at this point in the history
  • Loading branch information
LeoDog896 committed Mar 7, 2024
1 parent e54d536 commit 80c66dd
Show file tree
Hide file tree
Showing 7 changed files with 81 additions and 13 deletions.
5 changes: 3 additions & 2 deletions crates/redos/src/ilq.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,11 @@ pub fn scan_ilq(expr: &Expr) -> IlqReturn {
// luckily, we can just pretend as if the child is the root of its own tree
Expr::Repeat(e) => scan_ilq(e),

// TODO: proper support for lookarounds
Expr::LookAround(e, _) => scan_ilq(e),

// TODO: atomic groups and lookarounds
_ => IlqReturn::new(true),
// TODO: proper support for atomic groups
Expr::AtomicGroup(e) => scan_ilq(e),
}
}

Expand Down
2 changes: 1 addition & 1 deletion crates/redos/src/ir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ pub fn to_expr(
let range = hi - lo;

let expression = to_expr(child, config, group_increment);
let expression = if range > config.max_quantifier {
let expression = if range > config.four_max_quantifier {
expression.map(|child| Expr::Repeat(Box::new(child)))
} else {
expression
Expand Down
2 changes: 1 addition & 1 deletion crates/redos/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ impl RegexInfo {
///
/// A regex must meet the following criteria to be even considered to be vulnerable:
/// - It must contain a repeat
/// - The repeat must have a bound size greater than `config.max_quantifier`
/// - The repeat must have a bound size greater than `config.second_max_quantifier`
/// - The regex must have a terminating state (to allow for backtracking) (TODO: this is not implemented yet)
fn regex_pre_scan(expr: &Expr) -> RegexInfo {
match expr {
Expand Down
13 changes: 11 additions & 2 deletions crates/redos/src/vulnerability.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ pub enum Vulnerability {
impl Default for VulnerabilityConfig {
fn default() -> Self {
Self {
max_quantifier: 100,
two_max_quantifier: 1000,
three_max_quantifier: 100,
four_max_quantifier: 10,
}
}
}
Expand All @@ -23,5 +25,12 @@ pub enum Complexity {
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct VulnerabilityConfig {
/// The max size an upper bound can be before it is considered "large"
pub max_quantifier: usize,
/// in a superlinear fashion
pub two_max_quantifier: usize,
/// The max size an upper bound can be before it is considered "large"
/// for 3rd degree polynomials
pub three_max_quantifier: usize,
/// The max size an upper bound can be before it is considered "large"
/// for 4th degree polynomials
pub four_max_quantifier: usize,
}
41 changes: 35 additions & 6 deletions crates/redos/tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,48 @@
mod tests {
use redos::vulnerabilities;

fn assert_safe(regex: &str) {
static SAFE: &str = include_str!("safe.txt");

/// Takes a test file and returns pairs
/// of test names and their contents
fn parse_test_file(file: &str) -> Vec<(String, Vec<String>)> {
let mut tests: Vec<(String, Vec<String>)> = vec![];

for line in file.lines() {
if line.starts_with('#') {
continue;
}

if line.starts_with('\t') {
let mut line = line.to_string();
line.pop();
tests.last_mut().unwrap().1.push(line);
} else {
tests.push((line.to_string(), vec![]));
}
}

tests
}

fn assert_safe(regex: &str, message: &str) {
assert_eq!(
vulnerabilities(regex, &Default::default())
.unwrap()
.vulnerabilities,
vec![]
vec![],
"{} failed: {}",
message,
regex
);
}

#[test]
fn trivial_regexes() {
assert_safe("abc");
assert_safe("(abc|def)|[nhi]?");
assert_safe("a{1,43}");
fn check_safe() {
for (name, tests) in parse_test_file(SAFE) {
for test in tests {
assert_safe(&test, &name);
}
}
}
}
30 changes: 30 additions & 0 deletions crates/redos/tests/safe.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
base example
abc
lets try out groups
(abc|def)|[nhi]?
tiny repeating string
a{1,10}
bigger repeated string that's just right
a{}
nested group
(((a)))
try putting some quantifiers outside
((a+)+)+
are optionals detected?
(a?)+
lets try lookarounds
(?<=a)
(?<!a)
(?!a)
(?=a)
(?>a)
(?>a+)
can we decompose alternations?
(a+)|(b+)|(((a)))
how about alternations in lookarounds?
(?<=a|b)
(?<!a|b)
(?!a|b)
(?=a|b)
(?>a|b)
(?>a+|b+)
1 change: 0 additions & 1 deletion fixtures/redos.toml

This file was deleted.

0 comments on commit 80c66dd

Please sign in to comment.