Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Don't leak when overwriting ex data #2102

Merged
merged 3 commits into from
Nov 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions openssl/src/cipher_ctx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -582,6 +582,7 @@ impl CipherCtxRef {
/// buffer size control is maintained by the caller.
///
/// # Safety
///
/// The caller is expected to provide `output` buffer
/// large enough to contain correct number of bytes. For streaming
/// ciphers the output buffer size should be at least as big as
Expand Down Expand Up @@ -695,6 +696,7 @@ impl CipherCtxRef {
/// the output buffer size check removed.
///
/// # Safety
///
/// The caller is expected to provide `output` buffer
/// large enough to contain correct number of bytes. For streaming
/// ciphers the output buffer can be empty, for block ciphers the
Expand Down
42 changes: 32 additions & 10 deletions openssl/src/ssl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1572,16 +1572,34 @@ impl SslContextBuilder {
///
/// This can be used to provide data to callbacks registered with the context. Use the
/// `SslContext::new_ex_index` method to create an `Index`.
// FIXME should return a result
#[corresponds(SSL_CTX_set_ex_data)]
pub fn set_ex_data<T>(&mut self, index: Index<SslContext, T>, data: T) {
self.set_ex_data_inner(index, data);
}

fn set_ex_data_inner<T>(&mut self, index: Index<SslContext, T>, data: T) -> *mut c_void {
match self.ex_data_mut(index) {
Some(v) => {
*v = data;
(v as *mut T).cast()
}
_ => unsafe {
let data = Box::into_raw(Box::new(data)) as *mut c_void;
ffi::SSL_CTX_set_ex_data(self.as_ptr(), index.as_raw(), data);
data
},
}
}

fn ex_data_mut<T>(&mut self, index: Index<SslContext, T>) -> Option<&mut T> {
unsafe {
let data = Box::into_raw(Box::new(data)) as *mut c_void;
ffi::SSL_CTX_set_ex_data(self.as_ptr(), index.as_raw(), data);
data
let data = ffi::SSL_CTX_get_ex_data(self.as_ptr(), index.as_raw());
if data.is_null() {
None
} else {
Some(&mut *data.cast())
}
}
}

Expand Down Expand Up @@ -2965,15 +2983,19 @@ impl SslRef {
///
/// This can be used to provide data to callbacks registered with the context. Use the
/// `Ssl::new_ex_index` method to create an `Index`.
// FIXME should return a result
#[corresponds(SSL_set_ex_data)]
pub fn set_ex_data<T>(&mut self, index: Index<Ssl, T>, data: T) {
unsafe {
let data = Box::new(data);
ffi::SSL_set_ex_data(
self.as_ptr(),
index.as_raw(),
Box::into_raw(data) as *mut c_void,
);
match self.ex_data_mut(index) {
Some(v) => *v = data,
None => unsafe {
let data = Box::new(data);
ffi::SSL_set_ex_data(
self.as_ptr(),
index.as_raw(),
Box::into_raw(data) as *mut c_void,
);
},
}
}

Expand Down
49 changes: 48 additions & 1 deletion openssl/src/ssl/test/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use std::net::UdpSocket;
use std::net::{SocketAddr, TcpListener, TcpStream};
use std::path::Path;
use std::process::{Child, ChildStdin, Command, Stdio};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::thread;
use std::time::Duration;

Expand Down Expand Up @@ -1638,3 +1638,50 @@ fn set_security_level() {
let ssl = ssl;
assert_eq!(4, ssl.security_level());
}

#[test]
fn ssl_ctx_ex_data_leak() {
static DROPS: AtomicUsize = AtomicUsize::new(0);

struct DropTest;

impl Drop for DropTest {
fn drop(&mut self) {
DROPS.fetch_add(1, Ordering::Relaxed);
}
}

let idx = SslContext::new_ex_index().unwrap();

let mut ctx = SslContext::builder(SslMethod::tls()).unwrap();
ctx.set_ex_data(idx, DropTest);
ctx.set_ex_data(idx, DropTest);
assert_eq!(DROPS.load(Ordering::Relaxed), 1);

drop(ctx);
assert_eq!(DROPS.load(Ordering::Relaxed), 2);
}

#[test]
fn ssl_ex_data_leak() {
static DROPS: AtomicUsize = AtomicUsize::new(0);

struct DropTest;

impl Drop for DropTest {
fn drop(&mut self) {
DROPS.fetch_add(1, Ordering::Relaxed);
}
}

let idx = Ssl::new_ex_index().unwrap();

let ctx = SslContext::builder(SslMethod::tls()).unwrap().build();
let mut ssl = Ssl::new(&ctx).unwrap();
ssl.set_ex_data(idx, DropTest);
ssl.set_ex_data(idx, DropTest);
assert_eq!(DROPS.load(Ordering::Relaxed), 1);

drop(ssl);
assert_eq!(DROPS.load(Ordering::Relaxed), 2);
}