aboutsummaryrefslogtreecommitdiff
path: root/src/rust/protover/ffi.rs
diff options
context:
space:
mode:
authorIsis Lovecruft <isis@torproject.org>2018-02-06 14:15:33 +0000
committerIsis Lovecruft <isis@torproject.org>2018-02-07 22:51:58 +0000
commitb85436c5961d1b2168c3954a7e718e03a121473f (patch)
tree6b03f9cc9384c31cb17bf4c92bf67c1259e6141d /src/rust/protover/ffi.rs
parent7ea9e080c58f16fecefa5a0a20406635a2034366 (diff)
downloadtor-b85436c5961d1b2168c3954a7e718e03a121473f.tar.gz
tor-b85436c5961d1b2168c3954a7e718e03a121473f.zip
protover: Fix memleak in Rust impl of protover_compute_for_old_tor.
* FIXES #25127: https://bugs.torproject.org/25127 * ADDS a new module to the Rust tor_util crate for small utilities for working with static strings between languages. * CHANGES the return type of protover_compute_for_old_tor to point to immutable data. * CHANGES the code from the previous commit to use the new static string utilities.
Diffstat (limited to 'src/rust/protover/ffi.rs')
-rw-r--r--src/rust/protover/ffi.rs40
1 files changed, 28 insertions, 12 deletions
diff --git a/src/rust/protover/ffi.rs b/src/rust/protover/ffi.rs
index 5fefa8f7c0..5519b75ea4 100644
--- a/src/rust/protover/ffi.rs
+++ b/src/rust/protover/ffi.rs
@@ -12,6 +12,9 @@ use std::ffi::CString;
use protover::*;
use smartlist::*;
use tor_allocate::allocate_and_copy_string;
+use tor_util::strings::byte_slice_is_c_like;
+use tor_util::strings::empty_static_cstr;
+
/// Translate C enums to Rust Proto enums, using the integer value of the C
/// enum to map to its associated Rust enum
@@ -144,8 +147,7 @@ pub extern "C" fn protover_get_supported_protocols() -> *const c_char {
// bytes. An assert is okay here, since changing the const byte slice
// in protover.rs to contain a NUL byte somewhere in the middle would be a
// programming error.
- assert!(!SUPPORTED_PROTOCOLS[..SUPPORTED_PROTOCOLS.len() - 1].contains(&0x00));
- assert!(SUPPORTED_PROTOCOLS[SUPPORTED_PROTOCOLS.len() - 1] == 0x00);
+ assert!(byte_slice_is_c_like(SUPPORTED_PROTOCOLS));
// It's okay to call the "unchecked" version of the function because
// we can see that the bytes we're passing into it 1) are valid UTF-8,
@@ -200,15 +202,15 @@ pub extern "C" fn protover_is_supported_here(
/// Provide an interface for C to translate arguments and return types for
/// protover::compute_for_old_tor
#[no_mangle]
-pub extern "C" fn protover_compute_for_old_tor(
- version: *const c_char,
-) -> *mut c_char {
- // Not handling errors when unwrapping as the content is controlled
- // and is an empty string
- let empty = String::new();
+pub extern "C" fn protover_compute_for_old_tor(version: *const c_char) -> *const c_char {
+ let supported: &'static CStr;
+ let elder_protocols: &'static [u8];
+ let empty: &'static CStr;
+
+ empty = empty_static_cstr();
if version.is_null() {
- return allocate_and_copy_string(&empty);
+ return empty.as_ptr();
}
// Require an unsafe block to read the version from a C string. The pointer
@@ -217,10 +219,24 @@ pub extern "C" fn protover_compute_for_old_tor(
let version = match c_str.to_str() {
Ok(n) => n,
- Err(_) => return allocate_and_copy_string(&empty),
+ Err(_) => return empty.as_ptr(),
};
- let supported = compute_for_old_tor(&version);
+ elder_protocols = compute_for_old_tor(&version);
+
+ // If we're going to pass it to C, there cannot be any intermediate NUL
+ // bytes. An assert is okay here, since changing the const byte slice
+ // in protover.rs to contain a NUL byte somewhere in the middle would be a
+ // programming error.
+ assert!(byte_slice_is_c_like(elder_protocols));
+
+ // It's okay to call the "unchecked" version of the function because
+ // we can see that the bytes we're passing into it 1) are valid UTF-8,
+ // 2) have no intermediate NUL bytes, and 3) are terminated with a NUL
+ // byte.
+ unsafe {
+ supported = CStr::from_bytes_with_nul_unchecked(elder_protocols);
+ }
- allocate_and_copy_string(&supported)
+ supported.as_ptr()
}