Skip to content

Commit 2087021

Browse files
refactored the overflow protection function to be more conservative. Now the function only intercepts the specific case we're trying to fix
1 parent 1221370 commit 2087021

File tree

1 file changed

+33
-32
lines changed

1 file changed

+33
-32
lines changed

src/uu/timeout/src/timeout.rs

Lines changed: 33 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -60,44 +60,45 @@ struct Config {
6060
/// Parse a duration string with overflow protection
6161
/// Caps extremely large values at a safe maximum that works on all platforms
6262
fn parse_duration_with_overflow_protection(duration_str: &str) -> UResult<Duration> {
63-
// Find where the unit suffix starts (first non-digit character)
63+
// Pre-check for extremely large values that would overflow
64+
// Only intercept if it's a simple integer + unit suffix pattern
6465
let numeric_end = duration_str
6566
.find(|c: char| !c.is_ascii_digit())
6667
.unwrap_or(duration_str.len());
67-
let numeric_part = &duration_str[..numeric_end];
68-
let unit_suffix = &duration_str[numeric_end..];
69-
70-
if let Ok(num) = numeric_part.parse::<u128>() {
71-
match unit_suffix {
72-
"" | "s" | "m" | "h" | "d" => {
73-
let (multiplier, max_safe) = match unit_suffix {
74-
"" | "s" => (1u64, u64::MAX),
75-
"m" => (60, u64::MAX / 60),
76-
"h" => (3600, u64::MAX / 3600),
77-
"d" => (86400, u64::MAX / 86400),
78-
_ => unreachable!(),
79-
};
80-
81-
if num > max_safe as u128 {
82-
// Cap at a safe maximum (~34 years) that works on all platforms
83-
// This matches the cap in process.rs for kqueue/sigtimedwait
84-
const MAX_SAFE_TIMEOUT_SECS: u64 = (i32::MAX / 2) as u64;
85-
Ok(Duration::from_secs(MAX_SAFE_TIMEOUT_SECS))
86-
} else {
87-
let secs = (num as u64) * multiplier;
88-
Ok(Duration::from_secs(secs))
89-
}
90-
}
91-
_ => {
92-
// Unknown suffix, fallback to parse_time
93-
parse_time::from_str(duration_str, true)
94-
.map_err(|err| UUsageError::new(ExitStatus::TimeoutFailed.into(), err))
68+
69+
// Only apply overflow protection if we have a simple pattern: all digits followed by optional unit
70+
if numeric_end > 0
71+
&& (numeric_end == duration_str.len()
72+
|| matches!(
73+
duration_str.chars().nth(numeric_end),
74+
Some('s') | Some('m') | Some('h') | Some('d')
75+
))
76+
{
77+
let numeric_part = &duration_str[..numeric_end];
78+
let unit_suffix = &duration_str[numeric_end..];
79+
80+
if let Ok(num) = numeric_part.parse::<u128>() {
81+
// Check if this would cause overflow
82+
let (_multiplier, max_safe) = match unit_suffix {
83+
"" | "s" => (1u64, u64::MAX),
84+
"m" => (60, u64::MAX / 60),
85+
"h" => (3600, u64::MAX / 3600),
86+
"d" => (86400, u64::MAX / 86400),
87+
_ => (1u64, u64::MAX), // Shouldn't reach here
88+
};
89+
90+
if num > max_safe as u128 {
91+
// Cap at a safe maximum (~34 years) that works on all platforms
92+
// This matches the cap in process.rs for kqueue/sigtimedwait
93+
const MAX_SAFE_TIMEOUT_SECS: u64 = (i32::MAX / 2) as u64;
94+
return Ok(Duration::from_secs(MAX_SAFE_TIMEOUT_SECS));
9595
}
9696
}
97-
} else {
98-
parse_time::from_str(duration_str, true)
99-
.map_err(|err| UUsageError::new(ExitStatus::TimeoutFailed.into(), err))
10097
}
98+
99+
// For all other cases (including normal values), use the standard parser
100+
parse_time::from_str(duration_str, true)
101+
.map_err(|err| UUsageError::new(ExitStatus::TimeoutFailed.into(), err))
101102
}
102103

103104
impl Config {

0 commit comments

Comments
 (0)