Projects STRLCPY ebpfguard Commits cb26ce12
🤬
Revision indexing in progress... (symbol navigation in revisions will be accurate after indexed)
  • ■ ■ ■ ■ ■ ■
    docker/ubuntu/Dockerfile
     1 +FROM ubuntu:22.04
     2 + 
     3 +RUN apt-get update && apt-get install -y --no-install-recommends \
     4 + build-essential \
     5 + ca-certificates \
     6 + curl \
     7 + libclang-dev \
     8 + linux-tools-$(uname -r) \
     9 + && rm -rf /var/lib/apt/lists/*
     10 + 
     11 +RUN curl https://sh.rustup.rs --proto '=https' --tlsv1.2 -sSf | sh -s -- -y
     12 +RUN $HOME/.cargo/bin/rustup toolchain install nightly --component rust-src
     13 +RUN $HOME/.cargo/bin/rustup component add miri --toolchain nightly
     14 +RUN $HOME/.cargo/bin/cargo install bpf-linker bindgen-cli
     15 + 
  • ■ ■ ■ ■ ■
    docs/gh/development.md
    skipped 40 lines
    41 41  $ cargo clippy --workspace -- --deny warnings
    42 42  ```
    43 43   
    44  -Miri verification.
     44 +Miri verification. Requires optional dependencies from [miri section](prerequisites.md#miri)
    45 45   
    46 46  ```
    47 47  $ cargo +nightly miri test --all-targets
    48 48  ```
    49 49   
    50  -Note that miri verification requires nightly toolchain as well as miri component. To add them execute:
    51  - 
    52  -```
    53  -$ rustup toolchain install nightly --component rust-src
    54  -$ rustup component add miri --toolchain nightly
    55  -```
    56  - 
  • ■ ■ ■ ■ ■ ■
    docs/gh/docker_devel_env.md
     1 +# Docker based development environment
     2 + 
     3 +Reference docker containers with all dependencies needed to develop ebpfguard.
     4 + 
     5 +This instruction assumes that docker is installed. For convenience you can add your user to docker group.
     6 +The following script checks whether current user is in docker group.
     7 + 
     8 +``` bash
     9 +$ groups | grep docker 1>/dev/null 2>&1 || echo "$USER is not in docker group. docker command will require sudo"
     10 +```
     11 + 
     12 +## Ubuntu
     13 + 
     14 +To build ubuntu based development docker image run the following `docker build` command.
     15 + 
     16 +```bash
     17 +$ pwd
     18 +<path to ebpfguard repo>/docker
     19 +$ cd ubuntu
     20 +$ docker build . -t ebpfguard-dev:local
     21 +```
     22 + 
     23 +After building you can start a container with this repository mounted into it and run compilation steps. Proposed `docker run` invocation doesn't copy repository contents. Changes made within container will be present on host machine.
     24 + 
     25 +```bash
     26 +# privileged flag is needed to run ebpfguard applications from within container
     27 +$ docker run -it --privileged -v <path to this repository on local filesystem>:/app ebpfguard-dev:local bash
     28 +# Previous command drops user into bash shell within container
     29 +$ cd app
     30 +$ cargo xtask build-ebpf && cargo build && cargo test
     31 +```
     32 + 
     33 +Lets assume that ebpfguard repository was cloned to `/home/user/ebpfguard`.
     34 + 
     35 +Docker run command would be:
     36 +```bash
     37 +$ docker run -it --privileged -v /home/user/ebpfguard:/app ebpfguard-dev:local bash
     38 +```
     39 + 
  • ■ ■ ■ ■ ■ ■
    docs/gh/prerequisites.md
    1 1  # Prerequisites
    2 2   
     3 +This doc describes characteristics that your system needs to run ebpfguard based applications.
     4 + 
     5 +[Kernel capabilites](#kernel-capabilities) section is required both for compilation and execution. Other sections are needed only for development.
     6 + 
     7 +For development purposes you can either install dependencies from [tools/packages](#toolspackages) and [rust toolchain](#rust-toolchain) sections or use [docker based development environment](docker_devel_env.md).
     8 + 
    3 9  ## kernel capabilities
     10 + 
     11 +Kernel capabilities outlined in this section are required for both execution and development.
    4 12   
    5 13  First, you need to have a Linux kernel:
    6 14  * with BTF support
    skipped 25 lines
    32 40  ```
    33 41   
    34 42  If the output doesn't contain `bpf`, you need to enable BPF LSM by adding
    35  -`lsm=[...],bpf` to your kernel config parameters. That can be achieved by
    36  -executing the [enable-bpf-lsm.py](https://github.com/deepfence/ebpfguard/blob/main/enable-bpf-lsm.py) script.
     43 +`lsm=[...],bpf` to your kernel config parameters.
    37 44   
    38  -This script will print modified contents of `/etc/default/grub` file to stdout.
    39  -Either pipe it back directly to `/etc/default/grub` or save it somewhere
    40  -and compare contents before swapping to a new version.
     45 +Be warned that changes to grub and/or kernel config parameters may result
     46 +in kernel panic at startup. It is strongly encouraged to make backups of
     47 +all files altered in this section.
     48 + 
     49 +Kernel parameter modification can be achieved using [enable-bpf-lsm.py](https://github.com/deepfence/ebpfguard/blob/main/enable-bpf-lsm.py) script.
     50 +This script will read contents of `/etc/default/grub`, add lsm section of kernel
     51 +parameters with `bpf` option appended to `GRUB_CMDLINE_LINUX_DEFAULT` and print
     52 +modified contents to its stdout.
     53 + 
     54 +Either pipe it back directly to `/etc/default/grub` or save it as a separate file
     55 +and compare contents before swapping to a modified version.
     56 + 
     57 +Note that script solution is not bulletproof. If your grub configuration is customized it is encouraged to inspect script contents/output and do changes manually.
    41 58   
    42 59  Whole command with direct pipe:
    43 60   
    44 61  ```bash
    45  -$ ./enable-bpf.lsm.py | sudo tee /etc/default/grub 1>/dev/null
     62 +$ sudo cp /etc/default/grub{,.bak} && \
     63 + ./enable-bpf.lsm.py | sudo tee /etc/default/grub 1>/dev/null
    46 64  ```
    47 65   
    48  -This file is used by grub2 to assemble final `grub.cfg`. To trigger reconfiguration
    49  -use grub's mkconfig command with `-o <path to grub.cfg>` switch.
    50  - 
    51  -Both command name and path to `grub.cfg` are distribution dependent.
     66 +`/etc/default/grub` file is not used directly by grub2. It is used as a parameter source to assemble final configuration file. Path of a final configuration file as well as command which assembles it are distribution dependent.
    52 67   
    53 68  On ubuntu:
    54 69   
    55  -```
    56  -$ sudo grub-mkconfig -o /boot/grub/grub.cfg
     70 +```bash
     71 +$ sudo cp /boot/grub/grub.cfg{,.bak} && sudo grub-mkconfig -o /boot/grub/grub.cfg
    57 72  ```
    58 73   
    59 74  On fedora:
    60 75   
    61  -```
    62  -$ sudo grub2-mkconfig -o /boot/grub2/grub.cfg
     76 +```bash
     77 +$ sudo cp /boot/grub2/grub.cfg{,.bak} && sudo grub2-mkconfig -o /boot/grub2/grub.cfg
    63 78  ```
    64 79   
    65 80  After that's done reboot your system.
    66 81   
    67  -## rust toolchain and packages
     82 +### Reverting script based configuration changes
     83 + 
     84 +Some platforms have additional requirements when `lsm=bpf` is added to kernel parameters.
     85 +This may lead to kernel panic during system boot.
     86 + 
     87 +As an example on thinkpad x1 with ubuntu 22.04 addition of bpf lsm capacity results
     88 +in a kernel panic with a message that another lsm capability - `integrity` - has to be enabled.
     89 + 
     90 +Reboot once again. Wait until grub menu shows up.
     91 + 
     92 +Use up/down arrow keys to select one of entries marked with `(recovery mode)`.
     93 +`GRUB_CMDLINE_LINUX_DEFAULT` modifications are not present in recovery entries.
     94 +On ubuntu those options are available in subsection `Advanced options for Ubuntu`.
    68 95   
    69  -You need the Rust stable and nightly toolchains installed on your system, bpf-linker and bpftool binary.
     96 +Log into the system.
    70 97   
    71  -Install rust from https://rustup.rs. Further commands assume availabilty of rustup command.
     98 +Revert changes by restoring original files. Assumes backup files were created using sample commands from this section.
    72 99   
    73  -Install nightly toolchain:
     100 +On ubuntu the following command may be suitable assuming backup files path
     101 +are equal to original ones with `.bak` suffix appended.
    74 102   
     103 +```bash
     104 +$ sudo mv /boot/grub/grub.cfg.bak /boot/grub/grub.cfg && \
     105 + sudo mv /etc/default/grub.bak /etc/default/grub
    75 106  ```
    76  -$ rustup toolchain install nightly --component rust-src
     107 + 
     108 +## tools/packages
     109 + 
     110 +The following tools have to be available.
     111 +- cc
     112 +- bpftool
     113 +- libclang
     114 + 
     115 +Ways to obtain those tools differ between distributions. Each of them may also be installed from source.
     116 + 
     117 +On ubuntu 22.04 the following command installs all required tools.
     118 + 
     119 +```bash
     120 +$ apt-get update && apt-get install -y --no-install-recommends \
     121 + build-essential \
     122 + libclang-dev \
     123 + linux-tools-$(uname -r)
    77 124  ```
    78 125   
    79  -Optionally add miri:
     126 +## rust toolchain
     127 + 
     128 +You need the Rust stable and nightly toolchains installed on your system, bpf-linker and bpftool binary.
    80 129   
    81  -```
    82  -$ rustup component add miri --toolchain nightly
     130 +Install rust from https://rustup.rs. Further commands assume availability of rustup command.
     131 + 
     132 +Install bindgen-cli:
     133 + 
     134 +```bash
     135 +$ cargo install bindgen-cli
    83 136  ```
    84 137   
    85  -Finally install bpf-linker:
     138 +Install bpf-linker:
    86 139   
    87 140  ```
    88 141  $ cargo install bpf-linker
    89 142  ```
    90 143   
    91  -This bpf-linker installation method works on linux x86_64 systems.
    92  -For others refer to [aya-rs documentation](https://aya-rs.dev/book/start/development/).
     144 +bpf-linker installation on architectures other than x86_64 may be more involved. Refer to [aya-rs documentation](https://aya-rs.dev/book/start/development/) for instructions.
    93 145   
    94  -To install bpftool either use distro provided package or build it from [source](https://github.com/libbpf/bpftool).
     146 +### miri
     147 + 
     148 +As a part of ebpfguard CI pipeline we test for undefined behaviors using [miri](https://github.com/rust-lang/miri).
     149 +To run such tests rust nightly toolchain with miri component is needed.
    95 150   
    96  -On ubuntu it is a part of linux-tools:
     151 +To install nightly toolchain and miri in it run the following command:
    97 152   
    98 153  ```
    99  -$ sudo apt install linux-tools-$(uname -r)
     154 +$ rustup toolchain install nightly --component rust-src miri
    100 155  ```
    101 156   
  • ■ ■ ■ ■ ■ ■
    enable-bpf-lsm.py
    skipped 27 lines
    28 28   bpf_line = None
    29 29   with open("/etc/default/grub") as fd:
    30 30   for i, l in enumerate(fd):
    31  - if l.startswith("GRUB_CMDLINE_LINUX="):
     31 + if l.startswith("GRUB_CMDLINE_LINUX_DEFAULT="):
    32 32   if bpf_line:
    33 33   log.warning(
    34  - "Multiple GRUB_CMDLINE_LINUX. Only last one takes effect. Check your configuration. This script will modify last occurence only."
     34 + "Multiple GRUB_CMDLINE_LINUX_DEFAULT. Only last one takes effect. Check your configuration. This script will modify last occurrence only."
    35 35   )
    36 36   bpf_line = (i, l)
    37 37   else:
    skipped 1 lines
    39 39   idx, effective_grub_cmdline = bpf_line
    40 40   
    41 41   if not effective_grub_cmdline:
    42  - log.error("""No line starting with "GRUB_CMDLINE_LINUX=".""")
     42 + log.error("""No line starting with "GRUB_CMDLINE_LINUX_DEFAULT=".""")
    43 43   sys.exit(-2)
    44 44   
    45 45   if "lsm" in effective_grub_cmdline:
    46 46   log.warning(
    47  - f"""LSMs explicitly declared in /etc/default/grub GRUB_CMDLINE_LINUX. Edit manually and append bpf value.
    48  - Whole line could look like GRUB_CMDLINE_LINUX="lsm={','.join(lsms)}" """
     47 + f"""LSMs explicitly declared in /etc/default/grub GRUB_CMDLINE_LINUX_DEFAULT. Edit manually and append bpf value."""
    49 48   )
    50 49   sys.exit(-3)
    51 50   
    52  - modified_cmdline = effective_grub_cmdline.lstrip('GRUB_CMDLINE_LINUX="').rstrip('"\n')
     51 + modified_cmdline = effective_grub_cmdline.lstrip('GRUB_CMDLINE_LINUX_DEFAULT="').rstrip('"\n')
    53 52   cmdline_lsm = "lsm={}".format(",".join(lsms))
    54 53   if modified_cmdline == "":
    55 54   modified_cmdline = cmdline_lsm
    56 55   else:
    57 56   modified_cmdline += " " + cmdline_lsm
    58  - modified_cmdline = 'GRUB_CMDLINE_LINUX="{}"\n'.format(modified_cmdline)
     57 + modified_cmdline = 'GRUB_CMDLINE_LINUX_DEFAULT="{}"\n'.format(modified_cmdline)
    59 58   
    60 59   content.insert(idx, modified_cmdline)
    61 60   
    skipped 6 lines
  • ■ ■ ■ ■ ■ ■
    examples/demo_socket_listen/Cargo.toml
     1 +[package]
     2 +name = "demo_socket_listen"
     3 +version = "0.1.0"
     4 +edition = "2021"
     5 + 
     6 +[dependencies]
     7 +anyhow = { version = "1", features = ["backtrace"] }
     8 +clap = { version = "4.2", features = ["derive"] }
     9 +ebpfguard = { path = "../../ebpfguard" }
     10 +env_logger = "0.10"
     11 +log = "0.4"
     12 +tokio = { version = "1.25", features = ["macros", "rt", "rt-multi-thread", "net", "signal", "sync"] }
     13 + 
  • ■ ■ ■ ■ ■ ■
    examples/demo_socket_listen/src/main.rs
     1 +use std::{
     2 + fs::{create_dir_all, remove_dir_all},
     3 + path::PathBuf,
     4 +};
     5 + 
     6 +use anyhow::Context;
     7 +use clap::Parser;
     8 +use ebpfguard::{policy::PolicySubject, PolicyManager};
     9 +use log::info;
     10 + 
     11 +#[derive(Debug, Parser)]
     12 +struct Opt {
     13 + #[clap(long, default_value = "/sys/fs/bpf")]
     14 + bpffs_path: PathBuf,
     15 + #[clap(long, default_value = "demo_socket_connect")]
     16 + bpffs_dir: PathBuf,
     17 +}
     18 + 
     19 +#[tokio::main]
     20 +async fn main() -> anyhow::Result<()> {
     21 + let opt = Opt::parse();
     22 + 
     23 + let logger = env_logger::builder()
     24 + .filter_level(log::LevelFilter::Info)
     25 + .build();
     26 + log::set_max_level(logger.filter());
     27 + log::set_boxed_logger(Box::from(logger)).context("Failed to set up logger")?;
     28 + 
     29 + // Create a directory where ebpfguard policy manager can store its BPF
     30 + // objects (maps).
     31 + let bpf_path = opt.bpffs_path.join(opt.bpffs_dir);
     32 + create_dir_all(&bpf_path)?;
     33 + 
     34 + let mut policy_manager =
     35 + PolicyManager::new(&bpf_path).context("couldn't create policy manager")?;
     36 + 
     37 + let mut socket_bind = policy_manager
     38 + .attach_socket_bind()
     39 + .context("couldn't load eBPF bytecode to kernel")?;
     40 + 
     41 + let mut rx = socket_bind
     42 + .alerts()
     43 + .await
     44 + .context("couldn't get notifications channel for bind events")?;
     45 + 
     46 + let policy = ebpfguard::policy::SocketBind {
     47 + subject: PolicySubject::All,
     48 + allow: ebpfguard::policy::Ports::All,
     49 + deny: ebpfguard::policy::Ports::Ports(vec![8000]),
     50 + };
     51 + socket_bind
     52 + .add_policy(policy)
     53 + .await
     54 + .context("failed to install policy")?;
     55 + 
     56 + info!("Will block next 4 attempts to listen on a port 8000");
     57 + 
     58 + for i in 0..4 {
     59 + if let Some(alert) = rx.recv().await {
     60 + info!(
     61 + "socket_bind: pid={} subject={} port={}, count: {}",
     62 + alert.pid, alert.subject, alert.port, i
     63 + );
     64 + }
     65 + }
     66 + 
     67 + info!("Exiting...");
     68 + remove_dir_all(&bpf_path).context("Failed to clean up bpf maps directory")?;
     69 + 
     70 + Ok(())
     71 +}
     72 + 
  • ■ ■ ■ ■
    examples/readme_mount/Cargo.toml
    1 1  [package]
    2  -name = "foo"
     2 +name = "readme_mount"
    3 3  version = "0.1.0"
    4 4  edition = "2021"
    5 5   
    skipped 9 lines
  • ■ ■ ■ ■ ■ ■
    examples/readme_mount/src/main.rs
     1 +use anyhow::Context;
    1 2  use ebpfguard::{
    2 3   policy::{PolicySubject, SbMount},
    3 4   PolicyManager,
    skipped 2 lines
    6 7   
    7 8  #[tokio::main]
    8 9  async fn main() -> anyhow::Result<()> {
    9  - env_logger::init();
    10  - const BPF_MAPS_PATH: &str = "/sys/fs/bpf/example_sb_mount";
     10 + let logger = env_logger::builder()
     11 + .filter_level(log::LevelFilter::Info)
     12 + .build();
     13 + log::set_max_level(logger.filter());
     14 + log::set_boxed_logger(Box::from(logger)).context("Failed to set up logger")?;
    11 15   
    12 16   // Create a directory where ebpfguard policy manager can store its BPF
    13 17   // objects (maps).
     18 + const BPF_MAPS_PATH: &str = "/sys/fs/bpf/example_sb_mount";
    14 19   std::fs::create_dir_all(BPF_MAPS_PATH)?;
    15 20   
    16  - // Create a policy manager.
     21 + // Create a policy manager object.
    17 22   let mut policy_manager = PolicyManager::new(BPF_MAPS_PATH)?;
    18 23   
    19 24   // Attach the policy manager to the mount LSM hook.
     25 + // This instruction loads bytecode into kernel.
    20 26   let mut sb_mount = policy_manager.attach_sb_mount()?;
    21 27   
    22  - // Get the receiver end of the alerts channel (for the `file_open` LSM
    23  - // hook).
     28 + // Get the channel to which eBPF program attached to `file_open` lsm hook
     29 + // will send notifications to.
    24 30   let mut sb_mount_rx = sb_mount.alerts().await?;
    25 31   
    26 32   // Define policies which deny mount operations for all processes (except
    skipped 18 lines
Please wait...
Page is in error, reload to recover