diff --git a/src/uu/dd/src/dd.rs b/src/uu/dd/src/dd.rs index 782d2664c21..a173a8875b2 100644 --- a/src/uu/dd/src/dd.rs +++ b/src/uu/dd/src/dd.rs @@ -161,7 +161,10 @@ impl Num { fn to_bytes(self, block_size: u64) -> u64 { match self { - Self::Blocks(n) => n * block_size, + // Saturate on overflow: a byte count above `u64::MAX` is far beyond + // the `i64::MAX` (intmax_t) limit that callers enforce, so clamping + // here turns a would-be panic into that clean "too large" error. + Self::Blocks(n) => n.saturating_mul(block_size), Self::Bytes(n) => n, } } diff --git a/src/uu/dd/src/parseargs.rs b/src/uu/dd/src/parseargs.rs index a2bc1103651..3e70cd9c70a 100644 --- a/src/uu/dd/src/parseargs.rs +++ b/src/uu/dd/src/parseargs.rs @@ -266,6 +266,16 @@ impl Parser { } let count = self.count.map(|c| c.force_bytes_if(self.iflag.count_bytes)); + // GNU coreutils has a limit of i64 (intmax_t) + if let Some(count) = count { + let count_bytes = count.to_bytes(ibs as u64); + if count_bytes > i64::MAX as u64 { + return Err(ParseError::InvalidNumberWithErrMsg( + format!("{count_bytes}"), + "Value too large for defined data type".to_string(), + )); + } + } Ok(Settings { skip, diff --git a/tests/by-util/test_dd.rs b/tests/by-util/test_dd.rs index 309a93ac020..c77e3cb617e 100644 --- a/tests/by-util/test_dd.rs +++ b/tests/by-util/test_dd.rs @@ -132,6 +132,26 @@ fn test_out_of_memory_skip() { .stderr_contains("memory"); } +#[test] +fn test_large_numeric_operands_do_not_panic() { + // Regression test for GH #12843, #12845, #12846, #12848: a huge + // count/skip/seek/iseek/oseek operand overflowed an internal multiplication + // and panicked instead of reporting a clean "too large" error. + for operand in [ + "count=177817277272177278", + "skip=99999999999999999999", + "seek=99999999999999999999", + "iseek=166727721627616621762772", + "oseek=166727721627616621762772", + ] { + new_ucmd!() + .arg(operand) + .pipe_in("") + .fails_with_code(1) + .stderr_contains("Value too large for defined data type"); + } +} + #[test] fn test_stdin_stdout() { let input = build_ascii_block(521);