Use After Free Bugs in netdb
Following #130 (closed) That bug is briefed as follows:
- Create a local vector
host_alias
- Call
as_mut_slice()
and thenas_mut_ptr()
, to get the ptr - Store the ptr to a global struct
HOST_ENTRY
. -
host_alias
is out of scope and is dropped. - Now The ptr inside
HOST_ENTRY
is dangling!
The fix is to store the local variable to a global variable
_HOST_ALIASES = Some(host_aliases)
to prevent dropping of host_alias
.
Based on the pattern of that bug, I searched the whole project and found 4 more similar bugs. All of them are in src/header/netdb/mod.rs.
- In function gethostbyaddr()
https://gitlab.redox-os.org/redox-os/relibc/blob/master/src/header/netdb/mod.rs#L218-242
let mut host_aliases: Vec<*mut i8> = Vec::new();
host_aliases.push(ptr::null_mut());
HOST_ALIASES = Some(_host_aliases); // You did not store host_aliases, but _host_aliases!
...
HOST_ENTRY = hostent {
h_name: HOST_NAME.as_mut().unwrap().as_mut_ptr() as *mut c_char,
h_aliases: host_aliases.as_mut_slice().as_mut_ptr() as *mut *mut i8 // Store ptr to HOST_ENTRY
...
// host_aliases is droped, HOST_ENTRY.h_aliases dangles!
- In function gethostbyname()
https://gitlab.redox-os.org/redox-os/relibc/blob/master/src/header/netdb/mod.rs#L322-336
let mut host_aliases: Vec<*mut i8> = Vec::new();
host_aliases.push(ptr::null_mut());
host_aliases.push(ptr::null_mut());
HOST_ALIASES = Some(_host_aliases); // You did not store host_aliases, but _host_aliases!
HOST_ENTRY = hostent {
h_name: HOST_NAME.as_mut().unwrap().as_mut_ptr() as *mut c_char,
h_aliases: host_aliases.as_mut_slice().as_mut_ptr() as *mut *mut i8, // Store ptr to HOST_ENTRY
h_addrtype: AF_INET,
h_length: 4,
h_addr_list: HOST_ADDR_LIST.as_mut_ptr(),
};
...
// host_aliases is dropped, HOST_ENTRY.h_aliases dangles!
- In function getprotoent()
https://gitlab.redox-os.org/redox-os/relibc/blob/master/src/header/netdb/mod.rs#L443-456
let mut proto_aliases: Vec<*mut i8> = _proto_aliases
.iter_mut()
.map(|x| x.as_mut_ptr() as *mut i8)
.collect();
proto_aliases.push(ptr::null_mut());
PROTO_ALIASES = Some(_proto_aliases); // You did not store proto_aliases, but _proto_aliases!
PROTO_NAME = Some(proto_name);
PROTO_ENTRY = protoent {
p_name: PROTO_NAME.as_mut().unwrap().as_mut_slice().as_mut_ptr() as *mut c_char,
p_aliases: proto_aliases.as_mut_slice().as_mut_ptr() as *mut *mut i8, // Store ptr to PROTO_ENTRY
p_proto: PROTO_NUM.unwrap(),
};
...
// proto_aliases is dropped, PROTO_ENTRY.p_aliases dangles!
- In function getservent()
https://gitlab.redox-os.org/redox-os/relibc/blob/master/src/header/netdb/mod.rs#L587-600
let mut serv_aliases: Vec<*mut i8> = Vec::new();
serv_aliases.push(ptr::null_mut());
serv_aliases.push(ptr::null_mut());
SERV_ALIASES = Some(_serv_aliases); // You did not store serv_aliases, but _serv_aliases!
SERV_NAME = Some(serv_name);
SERV_PROTO = Some(proto);
SERV_ENTRY = servent {
s_name: SERV_NAME.as_mut().unwrap().as_mut_slice().as_mut_ptr() as *mut c_char,
s_aliases: serv_aliases.as_mut_slice().as_mut_ptr() as *mut *mut i8, // Store ptr to SERV_ENTRY
s_port: SERV_PORT.unwrap(),
s_proto: SERV_PROTO.as_mut().unwrap().as_mut_slice().as_mut_ptr() as *mut c_char,
};
...
// s_aliases is dropped, SERV_ENTRY.s_aliases dangles!
Edited by Boqin Qin