-
Notifications
You must be signed in to change notification settings - Fork 254
Description
Description
The referer function in curl-rust provides a safe interface for setting the CURLOPT_REFERER option. Internally, it calls the libcurl C function curl_easy_setopt through a series of helper functions.
According to the official libcurl documentation for curl_easy_setopt:
This function does not accept input strings longer than CURL_MAX_INPUT_LENGTH (8 MB).
The current implementation of referer and its internal helpers do not validate the length of the input string before passing it to the C function. The referer function converts the input &str to a CString and passes its pointer to curl_easy_setopt without any length validation.
// In `src/easy/handler.rs`:
unsafe fn setopt_ptr(&self, opt: curl_sys::CURLoption, val: *const c_char) -> Result<(), Error> {
unsafe { self.cvt(curl_sys::curl_easy_setopt(self.inner.handle, opt, val)) }
}
unsafe fn setopt_str(&mut self, opt: curl_sys::CURLoption, val: &CStr) -> Result<(), Error> {
self.setopt_ptr(opt, val.as_ptr())
}
/// Sets the HTTP referer header
///
/// By default this option is not set and corresponds to `CURLOPT_REFERER`.
pub fn referer(&mut self, referer: &str) -> Result<(), Error> {
// <-- VULNERABILITY: No check if referer.len() > CURL_MAX_INPUT_LENGTH
let referer = CString::new(referer)?;
self.setopt_str(curl_sys::CURLOPT_REFERER, &referer)
}This omission allows a caller from safe Rust to violate the C function's contract, which the documentation explicitly warns may cause libcurl to "behave badly." This can lead to Undefined Behavior (UB) within the C library.
Impact
An attacker can trigger this vulnerability by passing a string slice larger than 8 MB to the referer function. This violates the documented precondition of curl_easy_setopt and can lead to memory corruption, denial of service (crash), or other unpredictable program behavior. Because this can be triggered from safe Rust, it constitutes a soundness vulnerability in the crate.
Suggested Fix
The referer function must validate the input string's length before passing it to the unsafe C function. If the length exceeds CURL_MAX_INPUT_LENGTH, the function should panic or return an error to prevent the unsafe call.
A possible implementation:
// Define the constant based on libcurl's documentation
const CURL_MAX_INPUT_LENGTH: usize = 8 * 1024 * 1024;
// In `fn referer`:
pub fn referer(&mut self, referer: &str) -> Result<(), Error> {
if referer.len() > CURL_MAX_INPUT_LENGTH {
// Or return an Err(..). Panicking is often appropriate for contract violations.
panic!(
"Input length ({}) exceeds the maximum allowed by libcurl ({})",
referer.len(),
CURL_MAX_INPUT_LENGTH
);
}
let referer = CString::new(referer)?;
self.setopt_str(curl_sys::CURLOPT_REFERER, &referer)
}