Hello, thank you for your contribute in this work. I am testing my static analysis tool in this project and I notice the following code:
fn cm_connect_helper(rdma: &mut Rdma, node: &str, service: &str) -> io::Result<()> {
// SAFETY: POD FFI type
use error_utilities::log_ret_last_os_err;
let mut hints = unsafe { std::mem::zeroed::<rdma_addrinfo>() };
let mut info: *mut rdma_addrinfo = null_mut();
hints.ai_port_space = rdma_port_space::RDMA_PS_TCP.cast();
// Safety: ffi
let mut ret = unsafe {
rdma_getaddrinfo(
node.as_ptr().cast(),
service.as_ptr().cast(),
&hints,
&mut info,
)
};
if ret != 0_i32 {
return Err(log_ret_last_os_err());
}
let mut id: *mut rdma_cm_id = null_mut();
// Safety: ffi
ret = unsafe { rdma_create_ep(&mut id, info, rdma.pd.as_ptr(), null_mut()) };
if ret != 0_i32 {
// Safety: ffi
unsafe {
rdma_freeaddrinfo(info);
}
return Err(log_ret_last_os_err());
}
// Safety: id was initialized by `rdma_create_ep`
unsafe {
debug!(
"cm_id: {:?},{:?},{:?},{:?},{:?},{:?},{:?}",
(*id).qp,
(*id).pd,
(*id).verbs,
(*id).recv_cq_channel,
(*id).send_cq_channel,
(*id).recv_cq,
(*id).send_cq
);
(*id).qp = rdma.qp.as_ptr();
(*id).pd = rdma.pd.as_ptr();
(*id).verbs = rdma.ctx.as_ptr();
(*id).recv_cq_channel = rdma.qp.cq_event_listener().cq.event_channel().as_ptr();
(*id).recv_cq_channel = rdma.qp.cq_event_listener().cq.event_channel().as_ptr();
(*id).recv_cq = rdma.qp.cq_event_listener().cq.as_ptr();
(*id).send_cq = rdma.qp.cq_event_listener().cq.as_ptr();
debug!(
"cm_id: {:?},{:?},{:?},{:?},{:?},{:?},{:?}",
(*id).qp,
(*id).pd,
(*id).verbs,
(*id).recv_cq_channel,
(*id).send_cq_channel,
(*id).recv_cq,
(*id).send_cq
);
}
// Safety: ffi
ret = unsafe { rdma_connect(id, null_mut()) };
if ret != 0_i32 {
// Safety: ffi
unsafe {
let _ = rdma_disconnect(id);
}
return Err(log_ret_last_os_err());
}
Ok(())
}
The issue is in the cm_connect_helper function where node.as_ptr().cast() and service.as_ptr().cast() are passed directly to C functions like rdma_getaddrinfo. While Rust strings (&str) are valid UTF-8, they are not guaranteed to be null-terminated and may contain null bytes internally.
When these strings are passed to C functions that expect null-terminated strings, any null bytes will cause the string to be interpreted as terminated at that point, potentially leading to undefined behavior if the application logic depends on the complete string being processed.
I found a valid path form pub fn cm_connect to cm_connect_helper
A possible PoC is
fn main() {
// Call cm_connect with a string containing null bytes
// The null byte will terminate the string prematurely in C functions
let result = cm_connect("malicious\0injection", "service", 1, 0, 1024);
// The function will process "malicious" as the node name in rdma_getaddrinfo
// and ignore everything after the null byte
}
Sorry I can't run this crate in my platform, I would be appriciate if the author can double check if the issue is true.
Hello, thank you for your contribute in this work. I am testing my static analysis tool in this project and I notice the following code:
The issue is in the cm_connect_helper function where node.as_ptr().cast() and service.as_ptr().cast() are passed directly to C functions like rdma_getaddrinfo. While Rust strings (&str) are valid UTF-8, they are not guaranteed to be null-terminated and may contain null bytes internally.
When these strings are passed to C functions that expect null-terminated strings, any null bytes will cause the string to be interpreted as terminated at that point, potentially leading to undefined behavior if the application logic depends on the complete string being processed.
I found a valid path form pub fn cm_connect to cm_connect_helper
A possible PoC is
Sorry I can't run this crate in my platform, I would be appriciate if the author can double check if the issue is true.