fix(headers): prevent 2 panics in QualityItem parsing
1. index out of bounds if semicolon is the last character 2. not a char boundary on non-ASCII input (only allow ASCII now) Bugs found using `cargo fuzz`
This commit is contained in:
		| @@ -114,6 +114,11 @@ header! { | |||||||
|                     SubLevel::Plain, vec![(Attr::Charset, Value::Utf8)]), |                     SubLevel::Plain, vec![(Attr::Charset, Value::Utf8)]), | ||||||
|                     Quality(500)), |                     Quality(500)), | ||||||
|             ]))); |             ]))); | ||||||
|  |         test_header!( | ||||||
|  |             test_fuzzing1, | ||||||
|  |             vec![b"chunk#;e"], | ||||||
|  |             None | ||||||
|  |         ); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,3 +1,4 @@ | |||||||
|  | use std::ascii::AsciiExt; | ||||||
| use std::cmp; | use std::cmp; | ||||||
| use std::default::Default; | use std::default::Default; | ||||||
| use std::fmt; | use std::fmt; | ||||||
| @@ -73,12 +74,18 @@ impl<T: fmt::Display> fmt::Display for QualityItem<T> { | |||||||
| impl<T: str::FromStr> str::FromStr for QualityItem<T> { | impl<T: str::FromStr> str::FromStr for QualityItem<T> { | ||||||
|     type Err = ::Error; |     type Err = ::Error; | ||||||
|     fn from_str(s: &str) -> ::Result<QualityItem<T>> { |     fn from_str(s: &str) -> ::Result<QualityItem<T>> { | ||||||
|  |         if !s.is_ascii() { | ||||||
|  |             return Err(::Error::Header); | ||||||
|  |         } | ||||||
|         // Set defaults used if parsing fails. |         // Set defaults used if parsing fails. | ||||||
|         let mut raw_item = s; |         let mut raw_item = s; | ||||||
|         let mut quality = 1f32; |         let mut quality = 1f32; | ||||||
|  |  | ||||||
|         let parts: Vec<&str> = s.rsplitn(2, ';').map(|x| x.trim()).collect(); |         let parts: Vec<&str> = s.rsplitn(2, ';').map(|x| x.trim()).collect(); | ||||||
|         if parts.len() == 2 { |         if parts.len() == 2 { | ||||||
|  |             if parts[0].len() < 2 { | ||||||
|  |                 return Err(::Error::Header); | ||||||
|  |             } | ||||||
|             let start = &parts[0][0..2]; |             let start = &parts[0][0..2]; | ||||||
|             if start == "q=" || start == "Q=" { |             if start == "q=" || start == "Q=" { | ||||||
|                 let q_part = &parts[0][2..parts[0].len()]; |                 let q_part = &parts[0][2..parts[0].len()]; | ||||||
| @@ -212,4 +219,10 @@ mod tests { | |||||||
|     fn test_quality_invalid2() { |     fn test_quality_invalid2() { | ||||||
|         q(2.0); |         q(2.0); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     #[test] | ||||||
|  |     fn test_fuzzing_bugs() { | ||||||
|  |         assert!("99999;".parse::<QualityItem<String>>().is_err()); | ||||||
|  |         assert!("\x0d;;;=\u{d6aa}==".parse::<QualityItem<String>>().is_err()) | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user