interceptor-rs 0.1.0

Interceptor is a lib based on `ptrace` that intercepts and modifies Linux system calls.
Documentation
#![allow(clippy::type_complexity)]

use paste::paste;

pub enum PassthroughVariant<A1, A2, A3, A4, A5, A6> {
    Func0(fn()),
    Func1(fn(A1) -> (A1,)),
    Func2(fn(A1, A2) -> (A1, A2)),
    Func3(fn(A1, A2, A3) -> (A1, A2, A3)),
    Func4(fn(A1, A2, A3, A4) -> (A1, A2, A3, A4)),
    Func5(fn(A1, A2, A3, A4, A5) -> (A1, A2, A3, A4, A5)),
    Func6(fn(A1, A2, A3, A4, A5, A6) -> (A1, A2, A3, A4, A5, A6)),
}

pub enum BlockVariant<R, A1, A2, A3, A4, A5, A6> {
    Func0(fn() -> R),
    Func1(fn(A1) -> R),
    Func2(fn(A1, A2) -> R),
    Func3(fn(A1, A2, A3) -> R),
    Func4(fn(A1, A2, A3, A4) -> R),
    Func5(fn(A1, A2, A3, A4, A5) -> R),
    Func6(fn(A1, A2, A3, A4, A5, A6) -> R),
}

pub enum Variant<R, A1, A2, A3, A4, A5, A6> {
    Passthrough(PassthroughVariant<A1, A2, A3, A4, A5, A6>),
    Block(BlockVariant<R, A1, A2, A3, A4, A5, A6>),
}

pub enum ReturnVariant<R, A1, A2, A3, A4, A5, A6> {
    PackedArgs(PackedArgs<A1, A2, A3, A4, A5, A6>),
    Normal(R),
}

type PackedArgs<A1, A2, A3, A4, A5, A6> = (
    Option<A1>,
    Option<A2>,
    Option<A3>,
    Option<A4>,
    Option<A5>,
    Option<A6>,
);

trait VariantInto<A1, A2, A3, A4, A5, A6> {
    fn to_pa(self) -> PackedArgs<A1, A2, A3, A4, A5, A6>;
}

macro_rules! impl_variant_into {
    ($($n: literal),* | $($m: tt),*) => {
        paste! {
            impl<A0, A1, A2, A3, A4, A5> VariantInto<A0, A1, A2, A3, A4, A5> for ($([<A $n>],)*) {
                fn to_pa(self) -> PackedArgs<A0, A1, A2, A3, A4, A5> {
                    ($(Some(self.$n),)* $($m,)*)
                }
            }
        }
    };
}

impl_variant_into!(| None, None, None, None, None, None);
impl_variant_into!(0 | None, None, None, None, None);
impl_variant_into!(0, 1 | None, None, None, None);
impl_variant_into!(0, 1, 2 | None, None, None);
impl_variant_into!(0, 1, 2, 3 | None, None);
impl_variant_into!(0, 1, 2, 3, 4 | None);
impl_variant_into!(0, 1, 2, 3, 4, 5 |);

pub struct SysCall<R, A1, A2, A3, A4, A5, A6> {
    pub name: &'static str,
    pub pre: Variant<R, A1, A2, A3, A4, A5, A6>,
    pub post: fn(R) -> R,
}

impl<R, A1, A2, A3, A4, A5, A6> SysCall<R, A1, A2, A3, A4, A5, A6> {
    pub fn call_pre(
        &self,
        a1: A1,
        a2: A2,
        a3: A3,
        a4: A4,
        a5: A5,
        a6: A6,
    ) -> ReturnVariant<R, A1, A2, A3, A4, A5, A6> {
        match &self.pre {
            Variant::Passthrough(pv) => ReturnVariant::PackedArgs(match pv {
                PassthroughVariant::Func0(f) => {
                    f();
                    ().to_pa()
                }
                PassthroughVariant::Func1(f) => f(a1).to_pa(),
                PassthroughVariant::Func2(f) => f(a1, a2).to_pa(),
                PassthroughVariant::Func3(f) => f(a1, a2, a3).to_pa(),
                PassthroughVariant::Func4(f) => f(a1, a2, a3, a4).to_pa(),
                PassthroughVariant::Func5(f) => f(a1, a2, a3, a4, a5).to_pa(),
                PassthroughVariant::Func6(f) => f(a1, a2, a3, a4, a5, a6).to_pa(),
            }),
            Variant::Block(bv) => ReturnVariant::Normal(match bv {
                BlockVariant::Func0(f) => f(),
                BlockVariant::Func1(f) => f(a1),
                BlockVariant::Func2(f) => f(a1, a2),
                BlockVariant::Func3(f) => f(a1, a2, a3),
                BlockVariant::Func4(f) => f(a1, a2, a3, a4),
                BlockVariant::Func5(f) => f(a1, a2, a3, a4, a5),
                BlockVariant::Func6(f) => f(a1, a2, a3, a4, a5, a6),
            }),
        }
    }

    pub fn call_post(&self, r: R) -> R {
        (self.post)(r)
    }
}

pub(crate) enum ReturnVariantWrapper {
    PackedArgs(
        (
            Option<u64>,
            Option<u64>,
            Option<u64>,
            Option<u64>,
            Option<u64>,
            Option<u64>,
        ),
    ),
    Normal(u64),
}

pub(crate) struct SysCallWrapper {
    pub(crate) name: &'static str,
    pub(crate) pre:
        Box<dyn Fn(&mut pete::Tracee, u64, u64, u64, u64, u64, u64) -> ReturnVariantWrapper>,
    pub(crate) post: Box<dyn Fn(u64) -> u64>,
}