Skip to content

Commit 0a154ce

Browse files
Pre-validates duration parsing to detect overflow before calling parse_time, preventing the EINVAL error by capping huge values at i64::MAX seconds instead of letting them overflow during string-to-Duration conversion
1 parent e3de5ce commit 0a154ce

File tree

1 file changed

+23
-16
lines changed

1 file changed

+23
-16
lines changed

src/uu/timeout/src/timeout.rs

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -93,25 +93,32 @@ impl Config {
9393
let numeric_part = &duration_str[..numeric_end];
9494
let unit_suffix = &duration_str[numeric_end..];
9595

96-
// Use u128 for robust overflow detection without precision loss
9796
if let Ok(num) = numeric_part.parse::<u128>() {
98-
// Check if value will overflow when converted to seconds based on unit
99-
// Days are the largest common unit: 1 day = 86400 seconds
100-
let max_safe_value = match unit_suffix {
101-
"d" => u64::MAX / 86400, // days to seconds
102-
"h" => u64::MAX / 3600, // hours to seconds
103-
"m" => u64::MAX / 60, // minutes to seconds
104-
_ => u64::MAX, // seconds or unknown unit
105-
};
106-
107-
if num > max_safe_value as u128 {
108-
Duration::from_secs(libc::time_t::MAX as u64)
109-
} else {
110-
parse_time::from_str(duration_str, true)
111-
.map_err(|err| UUsageError::new(ExitStatus::TimeoutFailed.into(), err))?
97+
match unit_suffix {
98+
"" | "s" | "m" | "h" | "d" => {
99+
let (multiplier, max_safe) = match unit_suffix {
100+
"" | "s" => (1u64, u64::MAX),
101+
"m" => (60, u64::MAX / 60),
102+
"h" => (3600, u64::MAX / 3600),
103+
"d" => (86400, u64::MAX / 86400),
104+
_ => unreachable!(),
105+
};
106+
107+
if num > max_safe as u128 {
108+
Duration::from_secs(i64::MAX as u64)
109+
} else {
110+
let secs = (num as u64) * multiplier;
111+
Duration::from_secs(secs)
112+
}
113+
}
114+
_ => {
115+
// Unknown suffix, fallback to parse_time
116+
parse_time::from_str(duration_str, true).map_err(|err| {
117+
UUsageError::new(ExitStatus::TimeoutFailed.into(), err)
118+
})?
119+
}
112120
}
113121
} else {
114-
// Fallback for non-integer durations like "1.5d"
115122
parse_time::from_str(duration_str, true)
116123
.map_err(|err| UUsageError::new(ExitStatus::TimeoutFailed.into(), err))?
117124
}

0 commit comments

Comments
 (0)