我在调用libsystemd.so
的sd_journal_sendv
遇到一个问题
use std::os::raw::{c_int, c_void};
#[link(name="systemd", kind="dylib")]
extern "C" {
fn sd_journal_sendv(iov: *const iovec, n: c_int) -> c_int;
}
#[repr(C)]
struct iovec {
iov_base: *const c_void,
iov_len: usize
}
impl From<&str> for iovec {
fn from(s: &str) -> Self {
Self {
iov_base: s.as_ptr() as *const c_void,
iov_len: s.len()
}
}
}
#[test]
fn test_sd_journal_sendv() {
let priority_iovec: iovec = "PRIORITY=3".into();
// 错误写法: `format!("").as_str().into()` 或 `"MESSAGE=log1".to_string().as_str().into()`
// 错误写法不能正确得到字符串地址
// 正确写法: let msg_iovec: iovec = "MESSAGE=log1".into();
let msg_iovec: iovec = format!("MESSAGE={}", "log1").as_str().into();
let iovecs = vec![priority_iovec, msg_iovec];
let ret: Vec<iovec> = vec!["PRIORITY=3", "MESSAGE=log2", "UNIT=api"].into_iter().map(|x| x.into()).collect();
unsafe {
sd_journal_sendv(iovecs.as_ptr(), iovecs.len() as c_int);
sd_journal_sendv(ret.as_ptr(), ret.len() as c_int);
}
}
上面代码中只有log2会被打印,log1则不会(调用失败,也没报错)
经过我调查发现问题出在这行:
let msg_iovec: iovec = format!("MESSAGE={}", "log1").as_str().into();
改成以下形式就对了
let msg_iovec: iovec = "MESSAGE=log1".into();
所以我怀疑String::as_str().as_ptr() as *const c_void 在FFI时可能导致C语言那边不能找到正确的字符串内存地址?
1
共 1 条评论, 1 页
评论区
写评论粗看了一眼,你的iovec是引用format之后生成的String,这个String在执行完这条语句之后便释放了。而第二种用的是static str,这个不存在释放,所以结果正确,所以是一个经典的UAF问题。