Skip to content

Commit a9fe5cf

Browse files
authored
Avoid creating references to out params (#256)
Creating a reference to uninitialized memory is undefined behavior. Callers of this library are likely to pass pointers to uninitialized memory as out params. We should support that by not turning out params into references. Instead, keep them as raw pointers and use an unsafe block where we actually write the param. Fixes #245
1 parent 5434bfc commit a9fe5cf

File tree

5 files changed

+97
-67
lines changed

5 files changed

+97
-67
lines changed

src/cipher.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,14 @@ impl rustls_certificate {
4747
) -> rustls_result {
4848
ffi_panic_boundary! {
4949
let cert = try_ref_from_ptr!(cert);
50-
let out_der_data: &mut *const u8 = try_mut_from_ptr!(out_der_data);
51-
let out_der_len: &mut size_t = try_mut_from_ptr!(out_der_len);
50+
if out_der_data.is_null() || out_der_len.is_null() {
51+
return NullParameter
52+
}
5253
let der = cert.as_ref();
53-
*out_der_data = der.as_ptr();
54-
*out_der_len = der.len();
54+
unsafe {
55+
*out_der_data = der.as_ptr();
56+
*out_der_len = der.len();
57+
}
5558
rustls_result::Ok
5659
}
5760
}

src/connection.rs

Lines changed: 55 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::io::{ErrorKind, Read, Write};
22
use std::{ffi::c_void, ptr::null};
33
use std::{ptr::null_mut, slice};
44

5-
use libc::{size_t, EIO};
5+
use libc::{size_t, EINVAL, EIO};
66
use rustls::{
77
Certificate, ClientConnection, ServerConnection, SupportedCipherSuite, ALL_CIPHER_SUITES,
88
};
@@ -18,7 +18,7 @@ use crate::{
1818
cipher::{rustls_certificate, rustls_supported_ciphersuite},
1919
error::{map_error, rustls_io_result, rustls_result},
2020
io::{rustls_read_callback, rustls_write_callback},
21-
try_callback, try_mut_slice,
21+
try_callback,
2222
};
2323
use crate::{ffi_panic_boundary, try_ref_from_ptr};
2424
use crate::{try_mut_from_ptr, try_slice, userdata_push, CastPtr};
@@ -148,15 +148,19 @@ impl rustls_connection {
148148
) -> rustls_io_result {
149149
ffi_panic_boundary! {
150150
let conn: &mut Connection = try_mut_from_ptr!(conn);
151-
let out_n: &mut size_t = try_mut_from_ptr!(out_n);
151+
if out_n.is_null() {
152+
return rustls_io_result(EINVAL)
153+
}
152154
let callback: ReadCallback = try_callback!(callback);
153155

154156
let mut reader = CallbackReader { callback, userdata };
155157
let n_read: usize = match conn.read_tls(&mut reader) {
156158
Ok(n) => n,
157159
Err(e) => return rustls_io_result(e.raw_os_error().unwrap_or(EIO)),
158160
};
159-
*out_n = n_read;
161+
unsafe {
162+
*out_n = n_read;
163+
}
160164

161165
rustls_io_result(0)
162166
}
@@ -181,15 +185,19 @@ impl rustls_connection {
181185
) -> rustls_io_result {
182186
ffi_panic_boundary! {
183187
let conn: &mut Connection = try_mut_from_ptr!(conn);
184-
let out_n: &mut size_t = try_mut_from_ptr!(out_n);
188+
if out_n.is_null() {
189+
return rustls_io_result(EINVAL)
190+
}
185191
let callback: WriteCallback = try_callback!(callback);
186192

187193
let mut writer = CallbackWriter { callback, userdata };
188194
let n_written: usize = match conn.write_tls(&mut writer) {
189195
Ok(n) => n,
190196
Err(e) => return rustls_io_result(e.raw_os_error().unwrap_or(EIO)),
191197
};
192-
*out_n = n_written;
198+
unsafe {
199+
*out_n = n_written;
200+
}
193201

194202
rustls_io_result(0)
195203
}
@@ -214,15 +222,19 @@ impl rustls_connection {
214222
) -> rustls_io_result {
215223
ffi_panic_boundary! {
216224
let conn: &mut Connection = try_mut_from_ptr!(conn);
217-
let out_n: &mut size_t = try_mut_from_ptr!(out_n);
225+
if out_n.is_null() {
226+
return rustls_io_result(EINVAL)
227+
}
218228
let callback: VectoredWriteCallback = try_callback!(callback);
219229

220230
let mut writer = VectoredCallbackWriter { callback, userdata };
221231
let n_written: usize = match conn.write_tls(&mut writer) {
222232
Ok(n) => n,
223233
Err(e) => return rustls_io_result(e.raw_os_error().unwrap_or(EIO)),
224234
};
225-
*out_n = n_written;
235+
unsafe {
236+
*out_n = n_written;
237+
}
226238

227239
rustls_io_result(0)
228240
}
@@ -345,14 +357,15 @@ impl rustls_connection {
345357
) {
346358
ffi_panic_boundary! {
347359
let conn: &Connection = try_ref_from_ptr!(conn);
348-
let protocol_out = try_mut_from_ptr!(protocol_out);
349-
let protocol_out_len = try_mut_from_ptr!(protocol_out_len);
360+
if protocol_out.is_null() || protocol_out_len.is_null() {
361+
return
362+
}
350363
match conn.alpn_protocol() {
351-
Some(p) => {
364+
Some(p) => unsafe {
352365
*protocol_out = p.as_ptr();
353366
*protocol_out_len = p.len();
354367
},
355-
None => {
368+
None => unsafe {
356369
*protocol_out = null();
357370
*protocol_out_len = 0;
358371
}
@@ -421,17 +434,16 @@ impl rustls_connection {
421434
ffi_panic_boundary! {
422435
let conn: &mut Connection = try_mut_from_ptr!(conn);
423436
let write_buf: &[u8] = try_slice!(buf, count);
424-
let out_n: &mut size_t = unsafe {
425-
match out_n.as_mut() {
426-
Some(out_n) => out_n,
427-
None => return NullParameter,
428-
}
429-
};
437+
if out_n.is_null() {
438+
return NullParameter
439+
}
430440
let n_written: usize = match conn.writer().write(write_buf) {
431441
Ok(n) => n,
432442
Err(_) => return rustls_result::Io,
433443
};
434-
*out_n = n_written;
444+
unsafe {
445+
*out_n = n_written;
446+
}
435447
rustls_result::Ok
436448
}
437449
}
@@ -457,16 +469,28 @@ impl rustls_connection {
457469
) -> rustls_result {
458470
ffi_panic_boundary! {
459471
let conn: &mut Connection = try_mut_from_ptr!(conn);
460-
let read_buf: &mut [u8] = try_mut_slice!(buf, count);
461-
let out_n: &mut size_t = try_mut_from_ptr!(out_n);
472+
if buf.is_null() {
473+
return NullParameter
474+
}
475+
if out_n.is_null() {
476+
return NullParameter
477+
}
478+
479+
// Safety: the memory pointed at by buf must be initialized
480+
// (required by documentation of this function).
481+
let read_buf: &mut [u8] = unsafe {
482+
slice::from_raw_parts_mut(buf, count)
483+
};
462484

463485
let n_read: usize = match conn.reader().read(read_buf) {
464486
Ok(n) => n,
465487
Err(e) if e.kind() == ErrorKind::UnexpectedEof => return rustls_result::UnexpectedEof,
466488
Err(e) if e.kind() == ErrorKind::WouldBlock => return rustls_result::PlaintextEmpty,
467489
Err(_) => return rustls_result::Io,
468490
};
469-
*out_n = n_read;
491+
unsafe {
492+
*out_n = n_read;
493+
}
470494
rustls_result::Ok
471495
}
472496
}
@@ -494,8 +518,12 @@ impl rustls_connection {
494518
) -> rustls_result {
495519
ffi_panic_boundary! {
496520
let conn: &mut Connection = try_mut_from_ptr!(conn);
497-
let read_buf: &mut [std::mem::MaybeUninit<u8>] = try_mut_slice!(buf, count);
498-
let out_n: &mut size_t = try_mut_from_ptr!(out_n);
521+
if buf.is_null() || out_n.is_null() {
522+
return NullParameter
523+
}
524+
let read_buf: &mut [std::mem::MaybeUninit<u8>] = unsafe {
525+
slice::from_raw_parts_mut(buf, count)
526+
};
499527

500528
let mut read_buf = std::io::ReadBuf::uninit(read_buf);
501529

@@ -505,7 +533,9 @@ impl rustls_connection {
505533
Err(e) if e.kind() == ErrorKind::WouldBlock => return rustls_result::PlaintextEmpty,
506534
Err(_) => return rustls_result::Io,
507535
};
508-
*out_n = n_read;
536+
unsafe {
537+
*out_n = n_read;
538+
}
509539
rustls_result::Ok
510540
}
511541
}

src/error.rs

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
use std::{cmp::min, convert::TryFrom, fmt::Display, slice};
1+
use std::cmp::min;
2+
use std::convert::TryFrom;
3+
use std::fmt::Display;
24

35
use crate::ffi_panic_boundary;
46
use libc::{c_char, c_uint, size_t};
@@ -25,23 +27,18 @@ impl rustls_result {
2527
out_n: *mut size_t,
2628
) {
2729
ffi_panic_boundary! {
28-
let write_buf: &mut [u8] = unsafe {
29-
let out_n: &mut size_t = match out_n.as_mut() {
30-
Some(out_n) => out_n,
31-
None => return,
32-
};
33-
*out_n = 0;
34-
if buf.is_null() {
35-
return;
36-
}
37-
slice::from_raw_parts_mut(buf as *mut u8, len as usize)
38-
};
30+
if buf.is_null() {
31+
return
32+
}
33+
if out_n.is_null() {
34+
return
35+
}
3936
let result: rustls_result = rustls_result::try_from(result).unwrap_or(rustls_result::InvalidParameter);
4037
let error_str = result.to_string();
41-
let len: usize = min(write_buf.len() - 1, error_str.len());
42-
write_buf[..len].copy_from_slice(&error_str.as_bytes()[..len]);
38+
let out_len: usize = min(len - 1, error_str.len());
4339
unsafe {
44-
*out_n = len;
40+
std::ptr::copy_nonoverlapping(error_str.as_ptr() as *mut c_char, buf, out_len);
41+
*out_n = out_len;
4542
}
4643
}
4744
}

src/lib.rs

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
//! [You may also want to read the rustls-ffi README](https://github.com/rustls/rustls-ffi#rustls-ffi-bindings).
1414
1515
use crate::rslice::rustls_str;
16-
use libc::{c_void, size_t};
16+
use libc::c_void;
1717
use std::cell::RefCell;
1818
use std::mem;
1919
use std::sync::Arc;
@@ -436,14 +436,6 @@ where
436436
F::to_arc(from)
437437
}
438438

439-
impl CastPtr for size_t {
440-
type RustType = size_t;
441-
}
442-
443-
impl CastPtr for *const u8 {
444-
type RustType = *const u8;
445-
}
446-
447439
/// If the provided pointer is non-null, convert it to a reference.
448440
/// Otherwise, return NullParameter, or an appropriate default (false, 0, NULL)
449441
/// based on the context;

src/server.rs

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ use crate::session::{
2828
SessionStoreGetCallback, SessionStorePutCallback,
2929
};
3030
use crate::{
31-
ffi_panic_boundary, try_arc_from_ptr, try_box_from_ptr, try_mut_from_ptr, try_mut_slice,
32-
try_ref_from_ptr, try_slice, userdata_get, ArcCastPtr, BoxCastPtr, CastConstPtr, CastPtr,
31+
ffi_panic_boundary, try_arc_from_ptr, try_box_from_ptr, try_mut_from_ptr, try_ref_from_ptr,
32+
try_slice, userdata_get, ArcCastPtr, BoxCastPtr, CastConstPtr, CastPtr,
3333
};
3434

3535
/// A server config being constructed. A builder can be modified by,
@@ -371,8 +371,12 @@ pub extern "C" fn rustls_server_connection_get_sni_hostname(
371371
) -> rustls_result {
372372
ffi_panic_boundary! {
373373
let conn: &Connection = try_ref_from_ptr!(conn);
374-
let write_buf: &mut [u8] = try_mut_slice!(buf, count);
375-
let out_n: &mut size_t = try_mut_from_ptr!(out_n);
374+
if buf.is_null() {
375+
return NullParameter
376+
}
377+
if out_n.is_null() {
378+
return NullParameter
379+
}
376380
let server_connection = match conn.as_server() {
377381
Some(s) => s,
378382
_ => return rustls_result::InvalidParameter,
@@ -384,11 +388,16 @@ pub extern "C" fn rustls_server_connection_get_sni_hostname(
384388
},
385389
};
386390
let len: usize = sni_hostname.len();
387-
if len > write_buf.len() {
391+
if len > count {
392+
unsafe {
393+
*out_n = 0
394+
}
388395
return rustls_result::InsufficientSize;
389396
}
390-
write_buf[..len].copy_from_slice(sni_hostname.as_bytes());
391-
*out_n = len;
397+
unsafe {
398+
std::ptr::copy_nonoverlapping(sni_hostname.as_ptr(), buf, len);
399+
*out_n = len;
400+
}
392401
rustls_result::Ok
393402
}
394403
}
@@ -625,17 +634,16 @@ pub extern "C" fn rustls_client_hello_select_certified_key(
625634
ffi_panic_boundary! {
626635
let hello = try_ref_from_ptr!(hello);
627636
let schemes: Vec<SignatureScheme> = sigschemes(try_slice!(hello.signature_schemes.data, hello.signature_schemes.len));
628-
let out_key: &mut *const rustls_certified_key = unsafe {
629-
match out_key.as_mut() {
630-
Some(out_key) => out_key,
631-
None => return NullParameter,
632-
}
633-
};
637+
if out_key.is_null() {
638+
return NullParameter
639+
}
634640
let keys_ptrs: &[*const rustls_certified_key] = try_slice!(certified_keys, certified_keys_len);
635641
for &key_ptr in keys_ptrs {
636642
let key_ref: &CertifiedKey = try_ref_from_ptr!(key_ptr);
637643
if key_ref.key.choose_scheme(&schemes).is_some() {
638-
*out_key = key_ptr;
644+
unsafe {
645+
*out_key = key_ptr;
646+
}
639647
return rustls_result::Ok;
640648
}
641649
}

0 commit comments

Comments
 (0)