Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 40 additions & 22 deletions runtime/libia2/memory_maps.c
Original file line number Diff line number Diff line change
Expand Up @@ -166,17 +166,16 @@ static void label_memory_map(FILE *log, uintptr_t start_addr) {}
// so we need to free what `getline` allocated with `__real_free`.
typeof(IA2_IGNORE(free)) __real_free;

void ia2_log_memory_maps(FILE *log) {
FILE *maps = fopen("/proc/self/maps", "r");
assert(maps);

// Skip dev and inode.
fprintf(log, " start addr-end addr perms offset path\n");
void ia2_memory_map_foreach(FILE *maps_file,
void (*each_cb)(const char *line, ssize_t line_len, int path_index, uintptr_t start_addr, uintptr_t end_addr, char perms[static 4], uintptr_t offset, void *context),
void (*error_cb)(const char *line, void *context),
void *context) {
assert(maps_file);

char *line = NULL;
size_t line_cap = 0;
while (true) {
const ssize_t line_len = getline(&line, &line_cap, maps);
const ssize_t line_len = getline(&line, &line_cap, maps_file);
if (line_len == -1) {
break;
}
Expand All @@ -198,27 +197,46 @@ void ia2_log_memory_maps(FILE *log) {
const int vars_matched = sscanf(line, "%lx-%lx %4c %lx %x:%x %lu %n", &start_addr, &end_addr, perms, &offset, &dev_major, &dev_minor, &inode, &path_index);
const int expected_vars_matched = 7; // Note that "%n" doesn't count as a matched var.
if (vars_matched != expected_vars_matched) {
fprintf(log, "%s\n", line);
fprintf(stderr, "error parsing /proc/self/maps line (matched %d vars instead of %d): %s\n",
error_cb(line, context);
fprintf(stderr, "error parsing /proc/<pid>/maps line (matched %d vars instead of %d): %s\n",
vars_matched, expected_vars_matched, line);
continue;
}
const char *path = line + path_index;
each_cb(line, line_len, path_index, start_addr, end_addr, perms, offset, context);
}

// Skip dev and inode.
fprintf(log, "%08lx-%08lx %.4s %08lx ", start_addr, end_addr, perms, offset);
__real_free(line);
}

const size_t path_len = (size_t)line_len - path_index - 1;
if (path_len != 0) {
fprintf(log, "%s", path);
} else {
// No path, try to identify it.
label_memory_map(log, start_addr);
}
static void log_memory_map_error(const char *line, void *context) {
FILE *log = (FILE *)context;
fprintf(log, "%s\n", line);
}

fprintf(log, "\n");
static void log_memory_map_entry(const char *line, ssize_t line_len, int path_index, uintptr_t start_addr, uintptr_t end_addr, char perms[static 4], uintptr_t offset, void *context) {
FILE *log = (FILE *)context;
// Skip dev and inode.
fprintf(log, "%08lx-%08lx %.4s %08lx ", start_addr, end_addr, perms, offset);

const char *path = line + path_index;

const size_t path_len = (size_t)line_len - path_index - 1;
if (path_len != 0) {
fprintf(log, "%s", path);
} else {
// No path, try to identify it.
label_memory_map(log, start_addr);
}

__real_free(line);
fclose(maps);
fprintf(log, "\n");
}

void ia2_log_memory_maps(FILE *log) {
FILE *maps_file = fopen("/proc/self/maps", "r");
assert(maps_file);

// Skip dev and inode.
fprintf(log, " start addr-end addr perms offset path\n");
ia2_memory_map_foreach(maps_file, log_memory_map_entry, log_memory_map_error, (void *)log);
fclose(maps_file);
}
104 changes: 68 additions & 36 deletions runtime/tracer/memory-map/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,16 @@ impl fmt::Debug for Range {
}

impl Range {
pub fn from_bounds(start: usize, end: usize) -> Option<Range> {
if start < end {
Some(Range {
start,
len: end - start,
})
} else {
None
}
}
pub fn end(&self) -> usize {
self.start + self.len
}
Expand All @@ -59,6 +69,25 @@ impl Range {
self.start = self.start & !0xFFF;
self.len = end_round_up - self.start;
}

pub fn overlap(&self, other: &Range) -> Option<Range> {
let start = self.start.max(other.start);
let end = self.end().min(other.end());
Self::from_bounds(start, end)
}

/// Remove the other range from this one.
/// If they do not overlap, returns None.
/// Otherwise, returns a pair of any prefix remaining from this range and any suffix remaining from this range.
pub fn subtract(&self, other: &Range) -> Option<(Option<Range>, Option<Range>)> {
match self.overlap(other) {
None => None,
Some(overlap) => Some((
Self::from_bounds(self.start, overlap.start),
Self::from_bounds(self.end(), overlap.end()),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

won't this always return None, if self.end() >= overlap.end() (given the ordering of the args), and is that a problem?

)),
}
}
}

/// The state of a contiguous region of memory
Expand Down Expand Up @@ -178,45 +207,48 @@ impl MemoryMap {
})
}

/* removes exactly the specified range from an existing region, leaving any other parts of that region mapped */
fn split_out_region(&mut self, mut subrange: Range) -> Option<State> {
/* removes exactly the specified range from all existing regions, leaving any other parts of that region mapped */
fn split_out_region(&mut self, mut subrange: Range) -> Result<State, usize> {
subrange.round_to_4k();

// return None if the subrange does not overlap or is not fully contained
let r = match self.find_overlapping_region(subrange) {
Some(r) => r,
None => {
#[cfg(debug)]
printerrln!("{:?} has no overlap", subrange);
return None;
let mut removed_state = None;
let mut count = 0;
while let Some(r) = self.find_overlapping_region(subrange) {
// remove the range containing the subrange; this should not fail
let found = self.remove_region(r.range).is_some();
assert!(found);

// re-add any prefix range
let before = Range {
start: r.range.start,
len: subrange.start - r.range.start,
};
self.add_region(before, r.state);

// re-add any suffix range
let after = Range {
start: subrange.end(),
len: r.range.end() - subrange.end(),
};
self.add_region(after, r.state);

if count == 0 {
removed_state = Some(r.state);
}
};
if !r.range.subsumes(subrange) {
count += 1;
}
/*if !r.range.subsumes(subrange) {
#[cfg(debug)]
printerrln!("{:?} does not subsume {:?}", r.range, subrange);
return None;
}

// remove the range containing the subrange; this should not fail
let found = self.remove_region(r.range).is_some();
assert!(found);
}*/

// re-add any prefix range
let before = Range {
start: r.range.start,
len: subrange.start - r.range.start,
};
self.add_region(before, r.state);

// re-add any suffix range
let after = Range {
start: subrange.end(),
len: r.range.end() - subrange.end(),
};
self.add_region(after, r.state);

// return the split-out range
Some(r.state)
// return the split-out range's state, or the count ranges if not exactly 1
if count == 1 {
Ok(removed_state.unwrap())
} else {
Err(count)
}
}

pub fn split_region(
Expand All @@ -225,7 +257,7 @@ impl MemoryMap {
owner_pkey: u8,
prot: u32,
) -> Option<MemRegion> {
let state = self.split_out_region(subrange)?;
let state = self.split_out_region(subrange).ok()?;

// add the new split-off range
let new_state = State {
Expand Down Expand Up @@ -361,7 +393,7 @@ pub extern "C" fn memory_map_region_get_owner_pkey(map: &MemoryMap, needle: Rang

#[no_mangle]
pub extern "C" fn memory_map_unmap_region(map: &mut MemoryMap, needle: Range) -> bool {
map.split_out_region(needle).is_some()
map.split_out_region(needle).is_ok()
}

#[no_mangle]
Expand Down Expand Up @@ -398,7 +430,7 @@ pub extern "C" fn memory_map_pkey_mprotect_region(
range: Range,
pkey: u8,
) -> bool {
if let Some(mut state) = map.split_out_region(range) {
if let Some(mut state) = map.split_out_region(range).ok() {
/* forbid pkey_mprotect of owned by another compartment other than 0 */
if state.owner_pkey != pkey && state.owner_pkey != 0 {
printerrln!(
Expand Down Expand Up @@ -429,7 +461,7 @@ pub extern "C" fn memory_map_pkey_mprotect_region(

#[no_mangle]
pub extern "C" fn memory_map_mprotect_region(map: &mut MemoryMap, range: Range, prot: u32) -> bool {
if let Some(mut state) = map.split_out_region(range) {
if let Some(mut state) = map.split_out_region(range).ok() {
if state.mprotected == false {
state.mprotected = true;
state.prot = prot;
Expand Down
2 changes: 2 additions & 0 deletions runtime/tracer/mmap_event.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ enum mmap_event event_from_syscall(uint64_t syscall_nr) {
case __NR_execve:
case __NR_execveat:
return EVENT_EXEC;
case __NR_exit:
return EVENT_EXIT;
default:
return EVENT_NONE;
}
Expand Down
4 changes: 4 additions & 0 deletions runtime/tracer/mmap_event.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ enum mmap_event {
EVENT_PKEY_MPROTECT,
EVENT_CLONE,
EVENT_EXEC,
EVENT_EXIT,
EVENT_NONE,
};

Expand All @@ -71,6 +72,7 @@ static const char *event_names[] = {
"PKEY_MPROTECT",
"CLONE",
"EXEC",
"EXIT",
"NONE",
};

Expand All @@ -96,6 +98,8 @@ static inline const struct range *event_target_range(enum mmap_event event, cons
return NULL;
case EVENT_EXEC:
return NULL;
case EVENT_EXIT:
return NULL;
case EVENT_NONE:
return NULL;
break;
Expand Down
Loading
Loading