Skip to content

Unchecked string length in referer function can lead to Undefined Behavior #617

@zeroy0410

Description

@zeroy0410

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)
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions