-
Notifications
You must be signed in to change notification settings - Fork 1
/
maps.rs
143 lines (129 loc) · 3.97 KB
/
maps.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
//! Deprecated
use crate::utils::AddressRange;
use byteorder::ReadBytesExt;
use smallvec::SmallVec;
use std::ffi::CStr;
use std::fs::File;
use std::io;
use std::io::ErrorKind;
const MAX_MAPS_LEN: usize = 256;
const READ_BUFFER_SIZE: usize = 1024;
thread_local! {
static MAPS: SmallVec<[AddressRange; MAX_MAPS_LEN]> = MapsReader::open().unwrap().read_maps().unwrap();
}
/// Determine whether the target address is readable.
pub fn address_is_readable(target: u64) -> bool {
MAPS.with(|maps| {
for m in maps {
if m.contains(target) {
return true;
}
}
false
})
}
struct MapsReader {
file: File,
buffer: [u8; READ_BUFFER_SIZE],
}
impl MapsReader {
fn open() -> io::Result<Self> {
unsafe {
let mut buffer = [0u8; READ_BUFFER_SIZE];
libc::sprintf(
&mut buffer[0] as *mut u8 as _,
"/proc/%d/task/%d/maps\0".as_ptr() as _,
libc::getpid(),
libc::gettid(),
);
let filename = CStr::from_ptr(&buffer[0] as *const u8 as _).to_str().unwrap();
let file = File::open(filename)?;
Ok(Self { file, buffer })
}
}
fn read_maps(&mut self) -> io::Result<SmallVec<[AddressRange; MAX_MAPS_LEN]>> {
let mut v = SmallVec::new();
while v.len() < MAX_MAPS_LEN {
// There may be nothing to read here, UnexpectedEof is considered
// to have completed the parsing normally.
if let Err(err) = self.read_into_buffer_until(b'-') {
if err.kind() == ErrorKind::UnexpectedEof {
break;
}
return Err(err);
}
let s = self.str_in_buffer();
let start = u64::from_str_radix(s, 16).unwrap();
self.read_into_buffer_until(b' ')?;
let s = self.str_in_buffer();
let end = u64::from_str_radix(s, 16).unwrap();
let mut readable = false;
self.read_then_callback_until(b' ', |c| {
if c == b'r' {
readable = true;
}
})?;
// The last line may not have b'\n', and UnexpectedEof is
// considered to be parsed normally.
if let Err(err) = self.skip_util(b'\n') {
if err.kind() == ErrorKind::UnexpectedEof {
break;
}
return Err(err);
}
if readable {
v.push(AddressRange { start, end });
}
}
Ok(v)
}
fn read_into_buffer_until(&mut self, target: u8) -> io::Result<()> {
let mut index = 0;
loop {
let c = self.file.read_u8()?;
if c == target {
self.buffer[index] = 0;
break;
} else {
self.buffer[index] = c;
}
index += 1;
}
Ok(())
}
fn read_then_callback_until(&mut self, target: u8, mut f: impl FnMut(u8)) -> io::Result<()> {
loop {
let c = self.file.read_u8()?;
if c == target {
break;
}
f(c);
}
Ok(())
}
fn skip_util(&mut self, target: u8) -> io::Result<()> {
while self.file.read_u8()? != target {}
Ok(())
}
fn str_in_buffer(&self) -> &str {
unsafe { CStr::from_ptr(&self.buffer[0] as *const u8 as _).to_str().unwrap() }
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_read_maps() -> io::Result<()> {
let maps = MapsReader::open()?.read_maps()?;
assert!(maps.len() > 0);
assert!(maps.len() < MAX_MAPS_LEN - 1);
Ok(())
}
#[test]
fn test_address_is_readable() {
let v = 0;
assert!(address_is_readable(&v as *const i32 as u64));
assert!(!address_is_readable(0));
assert!(!address_is_readable(0xffffffffffffffff));
}
}