Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Vdso

Functions to load symboles: dlopen, dlclose, dlsym

LD_PRELOAD=./libmfilter.so python to overwrite functions

To print the aux vector

https://lwn.net/Articles/519085/ https://lwn.net/Articles/615809/

#![allow(unused)]
fn main() {
use core::ffi::CStr;
use core::mem::transmute;

use crate::types::*;
use crate::error::{Result, result};

#[repr(C)]
#[derive(Debug, Clone)]
pub struct Ehdr {
    pub e_ident: [u8;16],
    pub e_type: u16,
    pub e_machine: u16,
    pub e_version: u32,
    pub e_entry: u64,
    pub e_phoff: u64,
    pub e_shoff: u64,
    pub e_flags: u32,
    pub e_ehsize: u16,
    pub e_phentsize: u16,
    pub e_phnum: u16,
    pub e_shentsize: u16,
    pub e_shnum: u16,
    pub e_shstrndx: u16,
}

#[repr(C)]
#[derive(Debug, Clone)]
pub struct Phdr {
    pub p_type: u32,
    pub p_flags: u32,
    pub p_offset: u64,
    pub p_vaddr: u64,
    pub p_paddr: u64,
    pub p_filesz: u64,
    pub p_memsz: u64,
    pub p_align: u64,
}

#[repr(C)]
#[derive(Debug, Clone)]
pub struct Shdr {
    pub sh_name: u32,
    pub sh_type: u32,
    pub sh_flags: u64,
    pub sh_addr: u64,
    pub sh_offset: u64,
    pub sh_size: u64,
    pub sh_link: u32,
    pub sh_info: u32,
    pub sh_addralign: u64,
    pub sh_entsize: u64,
}

#[repr(C)]
#[derive(Debug, Clone)]
pub struct Sym {
    pub st_name: u32,
    pub st_info: u8,
    pub st_other: u8,
    pub st_shndx: u16,
    pub st_value: u64,
    pub st_size: u64,
}

pub struct Vdso {
    time: extern "C" fn(*mut time_t) -> time_t,
    getcpu: extern "C" fn(*mut u32, *mut u32) -> isize,
    gettimeofday: extern "C" fn(*mut timeval, *mut timezone) -> isize,
    clock_getres: extern "C" fn(clockid_t, *mut timespec) -> isize,
    clock_gettime: extern "C" fn(clockid_t, *mut timespec) -> isize,
}

impl Vdso {
    pub(crate) unsafe fn from_ptr(p: *const u8) -> Self {
        let header = &*(p as *const Ehdr);

        let section_headers = core::slice::from_raw_parts(
            p.offset(header.e_shoff as isize) as *const Shdr,
            header.e_shnum as usize
        );

        let dynstr = section_headers.iter().find(|e| e.sh_type == 3).map(|h| {
            p.offset(h.sh_offset as isize) as *const u8
        }).unwrap();

        let dynsym = section_headers.iter().find(|e| e.sh_type == 11).map(|h| {
            core::slice::from_raw_parts(
                p.offset(h.sh_offset as isize) as *const Sym,
                h.sh_size as usize / core::mem::size_of::<Sym>(),
            )
        }).unwrap();

        let mut time = None;
        let mut getcpu = None;
        let mut gettimeofday = None;
        let mut clock_getres = None;
        let mut clock_gettime = None;

        for symbole in dynsym {
            let s = dynstr.add(symbole.st_name as usize) as *const i8;
            match CStr::from_ptr(s).to_str() {
                Ok("time") => { time = transmute(p.add(symbole.st_value as usize)); }
                Ok("getcpu") => { getcpu = transmute(p.add(symbole.st_value as usize)); }
                Ok("gettimeofday") => { gettimeofday = transmute(p.add(symbole.st_value as usize)); }
                Ok("clock_getres") => { clock_getres = transmute(p.add(symbole.st_value as usize)); }
                Ok("clock_gettime") => { clock_gettime = transmute(p.add(symbole.st_value as usize)); }
                _ => { /* ignore */ }
            }
        }

        Self {
            time: time.unwrap(),
            getcpu: getcpu.unwrap(),
            gettimeofday: gettimeofday.unwrap(),
            clock_getres: clock_getres.unwrap(),
            clock_gettime: clock_gettime.unwrap(),
        }
    }

    #[inline(always)]
    pub fn time(&self, time: &mut time_t) -> time_t {
        (self.time)(time as *mut _)
    }

    /// The signature of this system call is different from the one documented in the man pages.
    /// This is because there is only way make this system call fail which is providing invalid pointers
    /// Since returning Result<()> has the same effect as returning a tuple with two numbers we simply
    /// make sure that it never fails by putting these variables on the stack.
    ///
    /// TODO: Is this really true about the Result<()>????
    #[inline(always)]
    pub fn getcpu(&self) -> (u32, u32) {
        let mut cpu = 0;
        let mut node = 0;
        (self.getcpu)(&mut cpu as *mut _, &mut node as *mut _);
        (cpu, node)
    }

    #[inline(always)]
    pub fn gettimeofday(&self, tv: &mut timeval, tz: &mut timezone) -> Result<()> {
        result((self.gettimeofday)(tv as *mut _, tz as *mut _)).map(|_| ())
    }

    #[inline(always)]
    pub fn clock_getres(&self, clock: clockid_t, spec: &mut timespec) -> Result<()> {
        result((self.clock_getres)(clock, spec as *mut _)).map(|_| ())
    }

    #[inline(always)]
    pub fn clock_gettime(&self, clock: clockid_t, spec: &mut timespec) -> Result<()> {
        result((self.clock_gettime)(clock, spec as *mut _)).map(|_| ())
    }
}
}