瀏覽代碼

Fix another overflow in punycode encode_into (#880)

* add another overflowing test

* fix overflow in case the input has more than u32::MAX characters

* detect hugh length early
Bennet Bleßmann 2 年之前
父節點
當前提交
464b1f7d8f
共有 1 個文件被更改,包括 17 次插入2 次删除
  1. 17 2
      idna/src/punycode.rs

+ 17 - 2
idna/src/punycode.rs

@@ -215,6 +215,9 @@ impl<'a> ExactSizeIterator for Decode<'a> {
 /// This is a convenience wrapper around `encode`.
 /// This is a convenience wrapper around `encode`.
 #[inline]
 #[inline]
 pub fn encode_str(input: &str) -> Option<String> {
 pub fn encode_str(input: &str) -> Option<String> {
+    if input.len() > u32::MAX as usize {
+        return None;
+    }
     let mut buf = String::with_capacity(input.len());
     let mut buf = String::with_capacity(input.len());
     encode_into(input.chars(), &mut buf).ok().map(|()| buf)
     encode_into(input.chars(), &mut buf).ok().map(|()| buf)
 }
 }
@@ -224,6 +227,9 @@ pub fn encode_str(input: &str) -> Option<String> {
 /// Return None on overflow, which can only happen on inputs that would take more than
 /// Return None on overflow, which can only happen on inputs that would take more than
 /// 63 encoded bytes, the DNS limit on domain name labels.
 /// 63 encoded bytes, the DNS limit on domain name labels.
 pub fn encode(input: &[char]) -> Option<String> {
 pub fn encode(input: &[char]) -> Option<String> {
+    if input.len() > u32::MAX as usize {
+        return None;
+    }
     let mut buf = String::with_capacity(input.len());
     let mut buf = String::with_capacity(input.len());
     encode_into(input.iter().copied(), &mut buf)
     encode_into(input.iter().copied(), &mut buf)
         .ok()
         .ok()
@@ -235,9 +241,9 @@ where
     I: Iterator<Item = char> + Clone,
     I: Iterator<Item = char> + Clone,
 {
 {
     // Handle "basic" (ASCII) code points. They are encoded as-is.
     // Handle "basic" (ASCII) code points. They are encoded as-is.
-    let (mut input_length, mut basic_length) = (0, 0);
+    let (mut input_length, mut basic_length) = (0u32, 0);
     for c in input.clone() {
     for c in input.clone() {
-        input_length += 1;
+        input_length = input_length.checked_add(1).ok_or(())?;
         if c.is_ascii() {
         if c.is_ascii() {
             output.push(c);
             output.push(c);
             basic_length += 1;
             basic_length += 1;
@@ -311,3 +317,12 @@ fn value_to_digit(value: u32) -> char {
         _ => panic!(),
         _ => panic!(),
     }
     }
 }
 }
+
+#[test]
+#[ignore = "slow"]
+#[cfg(target_pointer_width = "64")]
+fn huge_encode() {
+    let mut buf = String::new();
+    assert!(encode_into(std::iter::repeat('ß').take(u32::MAX as usize + 1), &mut buf).is_err());
+    assert_eq!(buf.len(), 0);
+}