Merge branch 'fix-out-of-bounds-panic-netdb-gethostbyname' into 'master'

fix(netdb): Out of bounds in gethostbyaddr and less transmutes

See merge request redox-os/relibc!535
This commit is contained in:
Jeremy Soller
2024-10-29 12:26:46 +00:00
3 changed files with 37 additions and 26 deletions
+1 -1
View File
@@ -85,7 +85,7 @@ pub unsafe extern "C" fn gethostent() -> *mut hostent {
inet_aton(addr_cstr, addr.as_mut_ptr());
let addr = addr.assume_init();
_HOST_ADDR_LIST = mem::transmute::<u32, [u8; 4]>(addr.s_addr);
_HOST_ADDR_LIST = addr.s_addr.to_ne_bytes();
HOST_ADDR_LIST = [_HOST_ADDR_LIST.as_mut_ptr() as *mut c_char, ptr::null_mut()];
HOST_ADDR = Some(addr);
+9 -11
View File
@@ -47,7 +47,7 @@ pub fn lookup_host(host: &str) -> Result<LookupHost, c_int> {
for (i, octet) in dns_vec.iter().enumerate() {
dns_arr[i] = *octet;
}
let dns_addr = unsafe { mem::transmute::<[u8; 4], u32>(dns_arr) };
let dns_addr = u32::from_ne_bytes(dns_arr);
let mut timespec = timespec::default();
unsafe {
@@ -112,14 +112,12 @@ pub fn lookup_host(host: &str) -> Result<LookupHost, c_int> {
if answer.a_type == 0x0001 && answer.a_class == 0x0001 && answer.data.len() == 4
{
let addr = in_addr {
s_addr: unsafe {
mem::transmute::<[u8; 4], u32>([
answer.data[0],
answer.data[1],
answer.data[2],
answer.data[3],
])
},
s_addr: u32::from_ne_bytes([
answer.data[0],
answer.data[1],
answer.data[2],
answer.data[3],
]),
};
addrs.push(addr);
}
@@ -148,7 +146,7 @@ pub fn lookup_addr(addr: in_addr) -> Result<Vec<Vec<u8>>, c_int> {
dns_arr[i] = *octet;
}
let mut addr_vec: Vec<u8> = unsafe { mem::transmute::<u32, [u8; 4]>(addr.s_addr).to_vec() };
let mut addr_vec: Vec<u8> = addr.s_addr.to_ne_bytes().to_vec();
addr_vec.reverse();
let mut name: Vec<u8> = vec![];
for octet in addr_vec {
@@ -187,7 +185,7 @@ pub fn lookup_addr(addr: in_addr) -> Result<Vec<Vec<u8>>, c_int> {
sin_family: AF_INET as u16,
sin_port: htons(53),
sin_addr: in_addr {
s_addr: unsafe { mem::transmute::<[u8; 4], u32>(dns_arr) },
s_addr: u32::from_ne_bytes(dns_arr),
},
..Default::default()
};
+27 -14
View File
@@ -229,11 +229,10 @@ pub unsafe extern "C" fn gethostbyaddr(
host_aliases.push(ptr::null_mut());
HOST_ALIASES = Some(_host_aliases);
match lookup_addr(addr) {
Ok(s) => {
_HOST_ADDR_LIST = mem::transmute::<u32, [u8; 4]>(addr.s_addr);
match lookup_addr(addr).map(|host_names| host_names.into_iter().next()) {
Ok(Some(host_name)) => {
_HOST_ADDR_LIST = addr.s_addr.to_ne_bytes();
HOST_ADDR_LIST = [_HOST_ADDR_LIST.as_mut_ptr() as *mut c_char, ptr::null_mut()];
let host_name = s[0].to_vec();
HOST_NAME = Some(host_name);
HOST_ENTRY = hostent {
h_name: HOST_NAME.as_mut().unwrap().as_mut_ptr() as *mut c_char,
@@ -244,6 +243,13 @@ pub unsafe extern "C" fn gethostbyaddr(
};
&mut HOST_ENTRY
}
// `glibc` sets errno if an address doesn't have a host name
// `musl` uses the address as the host name in said case
Ok(None) => {
// TODO: Set h_errno instead to match spec
platform::ERRNO.set(EIO);
ptr::null_mut()
}
Err(e) => {
platform::ERRNO.set(e);
ptr::null_mut()
@@ -253,9 +259,18 @@ pub unsafe extern "C" fn gethostbyaddr(
#[no_mangle]
pub unsafe extern "C" fn gethostbyname(name: *const c_char) -> *mut hostent {
// check if some idiot gave us an address instead of a name
let name_cstr = CStr::from_ptr(name);
let mut octets = str::from_utf8_unchecked(name_cstr.to_bytes()).split('.');
let name_cstr =
CStr::from_nullable_ptr(name).expect("gethostbyname() called with a NULL pointer");
let Ok(name_str) = str::from_utf8(name_cstr.to_bytes()) else {
// TODO Set h_errno instead of errno (spec)
platform::ERRNO.set(EINVAL);
return ptr::null_mut();
};
// Addresses and hostnames are both valid, so we'll check addresses first
// The standard doesn't define what to do when called with addresses
// Some implementations just skip resolution and copy the address to h_name
let mut octets = name_str.split('.');
let mut s_addr = [0u8; 4];
let mut is_addr = true;
for item in &mut s_addr {
@@ -263,6 +278,7 @@ pub unsafe extern "C" fn gethostbyname(name: *const c_char) -> *mut hostent {
*item = n;
} else {
is_addr = false;
break;
}
}
if octets.next() != None {
@@ -270,9 +286,8 @@ pub unsafe extern "C" fn gethostbyname(name: *const c_char) -> *mut hostent {
}
if is_addr {
let addr = in_addr {
s_addr: mem::transmute::<[u8; 4], u32>(s_addr),
};
let s_addr = u32::from_ne_bytes(s_addr);
let addr = in_addr { s_addr };
return gethostbyaddr(&addr as *const _ as *const c_void, 4, AF_INET);
}
@@ -303,9 +318,7 @@ pub unsafe extern "C" fn gethostbyname(name: *const c_char) -> *mut hostent {
}
}
let name_cstr = CStr::from_ptr(name);
let mut host = match lookup_host(str::from_utf8_unchecked(name_cstr.to_bytes())) {
let mut host = match lookup_host(name_str) {
Ok(lookuphost) => lookuphost,
Err(e) => {
platform::ERRNO.set(e);
@@ -322,7 +335,7 @@ pub unsafe extern "C" fn gethostbyname(name: *const c_char) -> *mut hostent {
let host_name: Vec<u8> = name_cstr.to_bytes().to_vec();
HOST_NAME = Some(host_name);
_HOST_ADDR_LIST = mem::transmute::<u32, [u8; 4]>(host_addr.s_addr);
_HOST_ADDR_LIST = host_addr.s_addr.to_ne_bytes();
HOST_ADDR_LIST = [_HOST_ADDR_LIST.as_mut_ptr() as *mut c_char, ptr::null_mut()];
HOST_ADDR = Some(host_addr);