alexcrichton / alexcrichton/curl-rust

Unchecked string length in `referer` function can lead to Undefined Behavior

Open
#617 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Rust
Stars
1.1k
Forks
258
PR merge metrics
No merged PRs in 30d

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.

```rust
// 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:

```rust
// 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)
}

```

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.