Skip to content

Commit 154ff58

Browse files
bors[bot]asomers
andauthored
Merge #1214
1214: Fix UB in getsockopt r=asomers a=asomers The old code tried to zero-initialize an enum for which 0 is not a valid value. That worked for older compilers, but triggers a panic with Rust 1.44.0. The correct technique is to use mem::MaybeUninit. Fixes #1212 Co-authored-by: Alan Somers <[email protected]>
2 parents b5ee610 + 35be3af commit 154ff58

File tree

2 files changed

+46
-37
lines changed

2 files changed

+46
-37
lines changed

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ This project adheres to [Semantic Versioning](http://semver.org/).
2525

2626
### Fixed
2727

28+
- Fixed `getsockopt`. The old code produced UB which triggers a panic with
29+
Rust 1.44.0.
30+
(#[1214](https://github.com/nix-rust/nix/pull/1214))
31+
2832
- Fixed a bug in nix::unistd that would result in an infinite loop
2933
when a group or user lookup required a buffer larger than
3034
16KB. (#[1198](https://github.com/nix-rust/nix/pull/1198))

src/sys/socket/sockopt.rs

+42-37
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@ use Result;
33
use errno::Errno;
44
use sys::time::TimeVal;
55
use libc::{self, c_int, c_void, socklen_t};
6-
use std::mem;
6+
use std::mem::{
7+
self,
8+
MaybeUninit
9+
};
710
use std::os::unix::io::RawFd;
811
use std::ffi::{OsStr, OsString};
912
#[cfg(target_family = "unix")]
@@ -84,14 +87,14 @@ macro_rules! getsockopt_impl {
8487

8588
fn get(&self, fd: RawFd) -> Result<$ty> {
8689
unsafe {
87-
let mut getter: $getter = Get::blank();
90+
let mut getter: $getter = Get::uninit();
8891

8992
let res = libc::getsockopt(fd, $level, $flag,
9093
getter.ffi_ptr(),
9194
getter.ffi_len());
9295
Errno::result(res)?;
9396

94-
Ok(getter.unwrap())
97+
Ok(getter.assume_init())
9598
}
9699
}
97100
}
@@ -364,16 +367,16 @@ impl<T> SetSockOpt for AlgSetKey<T> where T: AsRef<[u8]> + Clone {
364367

365368
/// Helper trait that describes what is expected from a `GetSockOpt` getter.
366369
unsafe trait Get<T> {
367-
/// Returns an empty value.
368-
unsafe fn blank() -> Self;
370+
/// Returns an uninitialized value.
371+
unsafe fn uninit() -> Self;
369372
/// Returns a pointer to the stored value. This pointer will be passed to the system's
370373
/// `getsockopt` call (`man 3p getsockopt`, argument `option_value`).
371374
fn ffi_ptr(&mut self) -> *mut c_void;
372375
/// Returns length of the stored value. This pointer will be passed to the system's
373376
/// `getsockopt` call (`man 3p getsockopt`, argument `option_len`).
374377
fn ffi_len(&mut self) -> *mut socklen_t;
375-
/// Returns the stored value.
376-
unsafe fn unwrap(self) -> T;
378+
/// Returns the hopefully initialized inner value.
379+
unsafe fn assume_init(self) -> T;
377380
}
378381

379382
/// Helper trait that describes what is expected from a `SetSockOpt` setter.
@@ -391,28 +394,28 @@ unsafe trait Set<'a, T> {
391394
/// Getter for an arbitrary `struct`.
392395
struct GetStruct<T> {
393396
len: socklen_t,
394-
val: T,
397+
val: MaybeUninit<T>,
395398
}
396399

397400
unsafe impl<T> Get<T> for GetStruct<T> {
398-
unsafe fn blank() -> Self {
401+
unsafe fn uninit() -> Self {
399402
GetStruct {
400403
len: mem::size_of::<T>() as socklen_t,
401-
val: mem::zeroed(),
404+
val: MaybeUninit::uninit(),
402405
}
403406
}
404407

405408
fn ffi_ptr(&mut self) -> *mut c_void {
406-
&mut self.val as *mut T as *mut c_void
409+
self.val.as_mut_ptr() as *mut c_void
407410
}
408411

409412
fn ffi_len(&mut self) -> *mut socklen_t {
410413
&mut self.len
411414
}
412415

413-
unsafe fn unwrap(self) -> T {
416+
unsafe fn assume_init(self) -> T {
414417
assert_eq!(self.len as usize, mem::size_of::<T>(), "invalid getsockopt implementation");
415-
self.val
418+
self.val.assume_init()
416419
}
417420
}
418421

@@ -438,28 +441,28 @@ unsafe impl<'a, T> Set<'a, T> for SetStruct<'a, T> {
438441
/// Getter for a boolean value.
439442
struct GetBool {
440443
len: socklen_t,
441-
val: c_int,
444+
val: MaybeUninit<c_int>,
442445
}
443446

444447
unsafe impl Get<bool> for GetBool {
445-
unsafe fn blank() -> Self {
448+
unsafe fn uninit() -> Self {
446449
GetBool {
447450
len: mem::size_of::<c_int>() as socklen_t,
448-
val: mem::zeroed(),
451+
val: MaybeUninit::uninit(),
449452
}
450453
}
451454

452455
fn ffi_ptr(&mut self) -> *mut c_void {
453-
&mut self.val as *mut c_int as *mut c_void
456+
self.val.as_mut_ptr() as *mut c_void
454457
}
455458

456459
fn ffi_len(&mut self) -> *mut socklen_t {
457460
&mut self.len
458461
}
459462

460-
unsafe fn unwrap(self) -> bool {
463+
unsafe fn assume_init(self) -> bool {
461464
assert_eq!(self.len as usize, mem::size_of::<c_int>(), "invalid getsockopt implementation");
462-
self.val != 0
465+
self.val.assume_init() != 0
463466
}
464467
}
465468

@@ -485,28 +488,28 @@ unsafe impl<'a> Set<'a, bool> for SetBool {
485488
/// Getter for an `u8` value.
486489
struct GetU8 {
487490
len: socklen_t,
488-
val: u8,
491+
val: MaybeUninit<u8>,
489492
}
490493

491494
unsafe impl Get<u8> for GetU8 {
492-
unsafe fn blank() -> Self {
495+
unsafe fn uninit() -> Self {
493496
GetU8 {
494497
len: mem::size_of::<u8>() as socklen_t,
495-
val: mem::zeroed(),
498+
val: MaybeUninit::uninit(),
496499
}
497500
}
498501

499502
fn ffi_ptr(&mut self) -> *mut c_void {
500-
&mut self.val as *mut u8 as *mut c_void
503+
self.val.as_mut_ptr() as *mut c_void
501504
}
502505

503506
fn ffi_len(&mut self) -> *mut socklen_t {
504507
&mut self.len
505508
}
506509

507-
unsafe fn unwrap(self) -> u8 {
510+
unsafe fn assume_init(self) -> u8 {
508511
assert_eq!(self.len as usize, mem::size_of::<u8>(), "invalid getsockopt implementation");
509-
self.val as u8
512+
self.val.assume_init()
510513
}
511514
}
512515

@@ -532,28 +535,28 @@ unsafe impl<'a> Set<'a, u8> for SetU8 {
532535
/// Getter for an `usize` value.
533536
struct GetUsize {
534537
len: socklen_t,
535-
val: c_int,
538+
val: MaybeUninit<c_int>,
536539
}
537540

538541
unsafe impl Get<usize> for GetUsize {
539-
unsafe fn blank() -> Self {
542+
unsafe fn uninit() -> Self {
540543
GetUsize {
541544
len: mem::size_of::<c_int>() as socklen_t,
542-
val: mem::zeroed(),
545+
val: MaybeUninit::uninit(),
543546
}
544547
}
545548

546549
fn ffi_ptr(&mut self) -> *mut c_void {
547-
&mut self.val as *mut c_int as *mut c_void
550+
self.val.as_mut_ptr() as *mut c_void
548551
}
549552

550553
fn ffi_len(&mut self) -> *mut socklen_t {
551554
&mut self.len
552555
}
553556

554-
unsafe fn unwrap(self) -> usize {
557+
unsafe fn assume_init(self) -> usize {
555558
assert_eq!(self.len as usize, mem::size_of::<c_int>(), "invalid getsockopt implementation");
556-
self.val as usize
559+
self.val.assume_init() as usize
557560
}
558561
}
559562

@@ -579,27 +582,29 @@ unsafe impl<'a> Set<'a, usize> for SetUsize {
579582
/// Getter for a `OsString` value.
580583
struct GetOsString<T: AsMut<[u8]>> {
581584
len: socklen_t,
582-
val: T,
585+
val: MaybeUninit<T>,
583586
}
584587

585588
unsafe impl<T: AsMut<[u8]>> Get<OsString> for GetOsString<T> {
586-
unsafe fn blank() -> Self {
589+
unsafe fn uninit() -> Self {
587590
GetOsString {
588591
len: mem::size_of::<T>() as socklen_t,
589-
val: mem::zeroed(),
592+
val: MaybeUninit::uninit(),
590593
}
591594
}
592595

593596
fn ffi_ptr(&mut self) -> *mut c_void {
594-
&mut self.val as *mut T as *mut c_void
597+
self.val.as_mut_ptr() as *mut c_void
595598
}
596599

597600
fn ffi_len(&mut self) -> *mut socklen_t {
598601
&mut self.len
599602
}
600603

601-
unsafe fn unwrap(mut self) -> OsString {
602-
OsStr::from_bytes(self.val.as_mut()).to_owned()
604+
unsafe fn assume_init(self) -> OsString {
605+
let len = self.len as usize;
606+
let mut v = self.val.assume_init();
607+
OsStr::from_bytes(&v.as_mut()[0..len]).to_owned()
603608
}
604609
}
605610

0 commit comments

Comments
 (0)