Skip to content

Commit be95cc5

Browse files
Restore working overflow protection code from before rebase
1 parent 650bef0 commit be95cc5

File tree

1 file changed

+36
-41
lines changed

1 file changed

+36
-41
lines changed

src/uu/timeout/src/timeout.rs

Lines changed: 36 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -60,50 +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-
// Try standard parsing first
64-
match parse_time::from_str(duration_str, true) {
65-
Ok(duration) => Ok(duration),
66-
Err(_) => {
67-
// If parsing fails, check if it's due to overflow with huge values
68-
// Only try to handle simple numeric patterns: digits + optional unit suffix
69-
let numeric_end = duration_str
70-
.find(|c: char| !c.is_ascii_digit())
71-
.unwrap_or(duration_str.len());
72-
73-
if numeric_end > 0 {
74-
let numeric_part = &duration_str[..numeric_end];
75-
let unit_suffix = &duration_str[numeric_end..];
76-
77-
if let Ok(num) = numeric_part.parse::<u128>() {
78-
// Check if this looks like a huge value that would overflow
79-
let max_safe = match unit_suffix {
80-
"" | "s" => u64::MAX,
81-
"m" => u64::MAX / 60,
82-
"h" => u64::MAX / 3600,
83-
"d" => u64::MAX / 86400,
84-
_ => {
85-
return Err(UUsageError::new(
86-
ExitStatus::TimeoutFailed.into(),
87-
format!("invalid time interval {duration_str}"),
88-
));
89-
}
90-
};
91-
92-
if num > max_safe as u128 {
93-
// Cap at a safe maximum (~34 years) that works on all platforms
94-
const MAX_SAFE_TIMEOUT_SECS: u64 = (i32::MAX / 2) as u64;
95-
return Ok(Duration::from_secs(MAX_SAFE_TIMEOUT_SECS));
96-
}
97-
}
98-
}
99-
100-
// If it wasn't an overflow case, return the original error
101-
Err(UUsageError::new(
102-
ExitStatus::TimeoutFailed.into(),
103-
format!("invalid time interval {duration_str}"),
63+
// Pre-check for extremely large values that would overflow
64+
// Only intercept if it's a simple integer + unit suffix pattern
65+
let numeric_end = duration_str
66+
.find(|c: char| !c.is_ascii_digit())
67+
.unwrap_or(duration_str.len());
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')
10475
))
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));
95+
}
10596
}
10697
}
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))
107102
}
108103

109104
impl Config {

0 commit comments

Comments
 (0)