darfink / region-rs

A cross-platform virtual memory API written in Rust
https://darfink.github.io/region-rs/
MIT License
119 stars 23 forks source link

cumbersome when region::protect deals with Elf64_Phdr.p_flags #28

Closed ghost closed 6 months ago

ghost commented 6 months ago

I need to protect the content of one segment in memory with its protection flags. So far I managed in this way

            unsafe {
                region::protect(
                    ph.p_vaddr as *const u8,
                    ph.p_memsz.try_into().unwrap(),
                    flags_to_prot(ph.p_flags),
                )
                .unwrap();
            }

...

fn flags_to_prot(mut flags: u32) -> region::Protection {
    let mut prot = region::Protection::NONE;
    [4, 2, 1].iter().for_each(|e| {
        if flags >= *e {
            match e {
                4 => prot |= Protection::READ,
                2 => prot |= Protection::WRITE,
                1 => prot |= Protection::EXECUTE,
                _ => prot |= Protection::NONE,
            }
            flags -= e;
        }
    });
    prot
}

I was wondering why the library doesn't provide any method to turn u32 value into a region::Protection value

darfink commented 6 months ago

Doesn't Protection::from_bits_truncate cover your use case?

darfink commented 6 months ago

I realize the above won't work for the current release.

I had always intended for the protection flags to correspond to their UNIX constants, but I discovered today that that has not been the case. Although not problematic, since they've always been explicitly mapped to their native counterparts, it prevented from_bits_* to works as expected. Fix pushed as 03fd93c.

darfink commented 6 months ago

Supported with version 3.0.1.

ghost commented 6 months ago

the patch didn't fix the problem image

load_phdrs_iter
        .clone()
        .filter(|ph| ph.p_memsz > 0)
        .for_each(|ph| unsafe {
            println!(
                "{}, {}, {}",
                ph.p_flags,
                flags_to_prot(ph.p_flags),
                Protection::from_bits_truncate(ph.p_flags.try_into().unwrap())
            );
fn flags_to_prot(mut p_flags: u32) -> region::Protection {
    [4, 2, 1].iter().fold(Protection::NONE, |mut acc, x| {
        if p_flags >= *x {
            match x {
                4 => acc |= Protection::READ,
                2 => acc |= Protection::WRITE,
                1 => acc |= Protection::EXECUTE,
                _ => acc |= Protection::NONE,
            }
            p_flags -= x;
        }
        acc
    })
}