# eBPF for Cybersecurity - Part 3

previously we learned the basics of Ebpf and How to use the BPF library for the Rust programming language here will see eBPF program attached to `sys_enter_exeve` tracepoint in the Linux kernel and is executed for each `sys_execve` syscall.

#### Unsafe Rust

for eBPF programs written using rust, it is often required to access Linux kernel data structure or call Linux kernel helper functions. Unsafe Rust is the glue that helps achieve this functionality

following are the two essential functionalities enabled by unsafe Rust concerning eBPF programs

* ability to dereference a raw memory pointer that points to Linux kernel data structure
    
* ability to call a Linux kernel helper function implemented in C
    

Unsafe code in Rust is enclosed in a code block or a function block marked with an unsafe keyword the best way to understand how unsafe rust enables an eBPF program to interface with the Linux kernel is via the following two simple programs

#### Kernel Data Structure Access

every eBPF program gets calked with context passes as an input parameter. The context is the kernel data structure pointer, its type depends on the eBPF program type. the memory referenced by the context can access only with unsafe Rust code

```bash
unsafe fn ptr_at<T>(ctx: &Xdpcontext,offset: unsize)

-> Result<*const T ,()> {

    let start = ctx.data();
    let end = ctx.data_end();
    let len = mem::size_of::<T>();

  if start + offset + len > end {
    return Err(());
  }  

  Ok((start + offser) as *const T)

}
```

In the code snippet above, the `ptr_at` the function used by an eBPF program of the type `BPF_PROG_TYPE_XDP` the function takes `ctx` as an input parameter, a reference to an object type `XdpContext` this reference represents a `C` struct variable of type `struct xdp_md` in the Linux kernel. The `xdp_md` data structure points to a region in memory where a network packet resides. the `start` and `end` variables store the starting and ending memory address for the packet, while `offset` represent an offset within the packet. `ptr_at` the function returns a pointer to a valid offset within the packet's memory representation

```bash
fn try_xdp_firewall(ctx: XdpContext) ->
   Result<u32, () > {


    let eth_type = u16::from_be(unsafe {
    *ptr_at(&ctx, offset_of!(ethhdr,h_proto))?

    });

    if eth_type != ETH_P_IP {

        return Ok(XdpContext::XDP_PASS);
    }

    let source = u32::from_be(unsafe {
        *ptr_at(&ctx, ETH_HDR_LEN + offset_of!(iphdr,saddr))?
    });
   if blocked_ip(source){

    return Ok(xdp_action::XDP_DROP)
   }

   Ok(xdp_action::XDP_PASS)
   }
```

the `try_xdp_firewall` uses the `ptr_at` function to get the `EtherType` from the raw packet. if the packet encapsulated in the ethernet frame is an IP packet, the source IP is extracted using `ptr-at` function. if the source IP address is blocked the packet is dropped by return `XDP_DROP` action.

#### kernel Function call

unsafe rust code also enables the calling of certain Linux kernel helper function from the eBPF programs. The kernel helper functions that the eBPF program is permitted to call are contingent on the type of the program

```bash
use aya_bpf::{

    programs::ProbeContext,

    helpers::bpf_ktime_get_ns, 
};

fn try_nfs_file_read(ctx:ProbeContext)

  - > Result<u32,u32> {

    let start_mount_ns = 

    unsafe { bpf_ktime_get_ns()};
    ok(0)
  }
```

In the code snippet above, `bpf_ktime_get_ns` is a Linux kernel helper function that returns the number of nanoseconds since boot time and is used to compute the time delta between events or as a timestamp in this example the `bpf_ktime_get_ns` the function is called to record the start time of the NFS file read encapsulating the helper function call in an unsafe block.

let's install lima with ubuntu

```bash
limactl start ubuntu-lts       
INFO[0000] Creating an instance "ubuntu-lts" from template://default (Not from template://ubuntu-lts) 
WARN[0000] This form is deprecated. Use `limactl start --name=ubuntu-lts template://default` instead 
? Creating an instance "ubuntu-lts" Proceed with the current configuration
INFO[0017] Attempting to download the image from "https://cloud-images.ubuntu.com/releases/22.10/release-20221201/ubuntu-22.10-server-cloudimg-arm64.img"  digest="sha256:9575dfe9f925ec251a933b88a38c5582a18e9d19495025ac01cb2e217e5f14ca"
47.94 MiB / 664.62 MiB [-->___________________________________] 7.21% 3.52 MiB/s
limactl shell ubuntu-lts
```

connect Lima to your Vscode

```bash
limactl show-ssh --format=config ubuntu-lts
Host lima-ubuntu-lts
  IdentityFile "/Users/sangambiradar/.lima/_config/user"
  StrictHostKeyChecking no
  UserKnownHostsFile /dev/null
  NoHostAuthenticationForLocalhost yes
  GSSAPIAuthentication no
  PreferredAuthentications publickey
  Compression no
  BatchMode yes
  IdentitiesOnly yes
  Ciphers "^aes128-gcm@openssh.com,aes256-gcm@openssh.com"
  User sangambiradar
  ControlMaster auto
  ControlPath "/Users/sangambiradar/.lima/ubuntu-lts/ssh.sock"
  ControlPersist 5m
  Hostname 127.0.0.1
  Port 55305
```

we will see Trace Programs

* Kernel Proble(kprobe)
    
* kernel Tracepoint
    
* User Space Probe ( UProbe)
    
* User Space Tracepoint
    

#### Kernel Probe ( Kprobe)

Linux kernel probes enable you to attach eBPF programs to kernel functions to gather information or modify the function’s behaviour. This section will provide examples of both.

```bash
$ cat /proc/kallsyms
```

There are some 300+ different system calls in the Linux kernel. Applications/workloads running in the user space interact with the kernel using syscalls. e.g. if an application wants to do something like access a file, communicate using a network or even find the time of day, it will have to ask the kernel to do it on the application's behalf via a syscall; hence by attaching these probes to syscalls we're able to judiciously monitor what applications are doing in the user space. A list of all kernel syscall identifiers for a kernel can be found in this file: `/proc/kallsyms`. Here is an excerpt:

```bash
0000000000000000 T vs_create
0000000000000000 T vfs_mkdir
0000000000000000 T vfs_mknod
0000000000000000 T vs link
0000000000000000 T vs unlink
0000000000000000 t path_openat
0000000000000000 T vs_rename
0000000000000000 T getname kernel
0000000000000000 T putname
0000000000000000 t getname_flags.part. O
0000000000000000 T getname flags
0000000000000000 T getname
```

[**System.map**](http://System.map) **file and /proc/kallsyms**

[System.map](http://System.map) file format: address type notation

The type is lowercase for local symbols, and uppercase for global (external).  
Focus on several types:  
T, The symbol is in the text(code) section  
D The symbol is in the initialized data section  
R The symbol is in a read-only data section  
t static  
d static  
R const  
r static const

For example, suppose you have a Rust object file named `hello.o` that contains a function named `hello`. You can use `nm` to list the symbols in this object file by running the following command:

```bash
$ nm hello.o
```

This will print a list of symbols in the `hello.o` object file, which might look something like this:

```bash
0000000000000000 T hello
                 U __libc_start_main
```

#### Block Mount

start of the `open_ctree` function call. The eBPF helper function `bpf_override_return` short circuits the open\_ctree function execution by returning ENOMEM. This prevents the btrfs volume from being mounted.

```bash
#![no_std]
#![no_main]

use aya_bpf::{
    helpers::bpf_override_return, macros::kprobe,
    programs::ProbeContext,
};
use aya_log_ebpf::info;

const ENOMEM: i32 = -12;
#[kprobe(name = "block_mount")]
pub fn block_mount(ctx: ProbeContext) -> u32 {
    match try_block_mount(ctx) {
        Ok(ret) => ret,
        Err(ret) => ret,
    }
}

fn try_block_mount(
    ctx: ProbeContext,
) -> Result<u32, u32> {
    info!(&ctx, "function open_ctree called");
    unsafe {
        bpf_override_return(ctx.regs, ENOMEM as u64)
    };
    Ok(0)
}

#[panic_handler]
fn panic(_info: &core::panic::PanicInfo) -> ! {
    unsafe { core::hint::unreachable_unchecked() }
}
```

### kernel Tracepoint

```bash
cargo generate https://github.com/aya-rs/aya-template
🤷   Project Name: tracepoint-sangam
🔧   Destination: /home/ubuntu/tracepoint-sangam ...
🔧   project-name: tracepoint-sangam ...
🔧   Generating template ...
✔ 🤷   Which type of eBPF program? · tracepoint
🤷   Which tracepoint category? (e.g sched, net etc...): sys_enter_execve
🤷   Which tracepoint name? (e.g sched_switch, net_dev_queue): systemcalls
[ 1/35]   Done: .cargo/config.toml                                                                                    [ 2/35]   Done: .cargo                                                                                                [ 3/35]   Done: .gitignore                                                                                            [ 4/35]   Done: .vim/coc-settings.json                                                                                [ 5/35]   Done: .vim                                                                                                  [ 6/35]   Done: .vscode/settings.json                                                                                 [ 7/35]   Done: .vscode                                                                                               [ 8/35]   Done: Cargo.toml                                                                                            [ 9/35]   Done: README.md                                                                                             [10/35]   Ignored: pre-script.rhai                                                                                    [11/35]   Done: xtask/Cargo.toml                                                                                      [12/35]   Done: xtask/src/build_ebpf.rs                                                                               [13/35]   Done: xtask/src/main.rs                                                                                     [14/35]   Done: xtask/src/run.rs                                                                                      [15/35]   Done: xtask/src                                                                                             [16/35]   Done: xtask                                                                                                 [17/35]   Done: tracepoint-sangam/Cargo.toml                                                                          [18/35]   Done: tracepoint-sangam/src/main.rs                                                                         [19/35]   Done: tracepoint-sangam/src                                                                                 [20/35]   Done: tracepoint-sangam                                                                                     [21/35]   Done: tracepoint-sangam-common/Cargo.toml                                                                   [22/35]   Done: tracepoint-sangam-common/src/lib.rs                                                                   [23/35]   Done: tracepoint-sangam-common/src                                                                          [24/35]   Done: tracepoint-sangam-common                                                                              [25/35]   Done: tracepoint-sangam-ebpf/.cargo/config.toml                                                             [26/35]   Done: tracepoint-sangam-ebpf/.cargo                                                                         [27/35]   Done: tracepoint-sangam-ebpf/.vim/coc-settings.json                                                         [28/35]   Done: tracepoint-sangam-ebpf/.vim                                                                           [29/35]   Done: tracepoint-sangam-ebpf/.vscode/settings.json                                                          [30/35]   Done: tracepoint-sangam-ebpf/.vscode                                                                        [31/35]   Done: tracepoint-sangam-ebpf/Cargo.toml                                                                     [32/35]   Done: tracepoint-sangam-ebpf/rust-toolchain.toml                                                            [33/35]   Done: tracepoint-sangam-ebpf/src/main.rs                                                                    [34/35]   Done: tracepoint-sangam-ebpf/src                                                                            [35/35]   Done: tracepoint-sangam-ebpf                                                                                🔧   Moving generated files into: `/home/ubuntu/tracepoint-sangam`...
💡   Initializing a fresh Git repository
✨   Done! New project created /home/ubuntu/tracepoint-sangam
ubuntu@ip-172-31-56-217:~$
```

its generate template

```bash
.
├── Cargo.toml
├── README.md
├── tracepoint-sangam
│   ├── Cargo.toml
│   └── src
│       └── main.rs
├── tracepoint-sangam-common
│   ├── Cargo.toml
│   └── src
│       └── lib.rs
├── tracepoint-sangam-ebpf
│   ├── Cargo.toml
│   ├── rust-toolchain.toml
│   └── src
│       └── main.rs
└── xtask
    ├── Cargo.toml
    └── src
        ├── build_ebpf.rs
        ├── main.rs
        └── run.rs
```

* tracepoint-sangam - contains the user space program
    
* tracepoint-sangam-ebpf - contains the epbf program
    
* trace-sangam-common contains the code for data structure and data types common to both user space and eBPF programs
    

The user space program can be buit using

```bash
~/tracepoint-sangam$ cargo build
```

the eBPF program can be built using

```bash
~/tracepoint-sangam$ cargo xtask build-ebpf
```

the release version of the eBPF program can be build using

```bash
~/tracepoint-sangam$ cargo xtask build-ebpf --release
```

The userspace program which loads the eBPF program into kernel can be run using

```bash
/tracepoint-sangam$ cargo xtask run
```

above simple ebpf program attached to `sys_enter_exeve` tracepoint in the Linux kenel and is executed for each `sys_execve` syscall.

The eBPF program on execution logs a perf event and this event is returned to the user space for printing via the perf event array map. exporting the logs from the kernel to the user space is abstracted from the developer and handled by the aya-logging library

That's it for this part we will learn more about aya and ebpf .

the eBPF developer experience by allowing Rust programs to easily run within the kernel.

Aya is the first Rust-native eBPF library that is similar in nature to libbpf but entirely written in the Rust programming language, popular for its memory safety and concurrency features, among other reasons this programming language is becoming very popular for systems programming.
