Skip to content

KubeArmor BPF LSM Integration

Barun Acharya edited this page Jul 10, 2022 · 2 revisions

High Level Module Changes

Now Proposed

Module Design

Map Design

Outer Map details

struct outer_hash {
  __uint(type, BPF_MAP_TYPE_HASH_OF_MAPS);
  __uint(max_entries, X);
  __uint(key_size, sizeof(struct outer_key));    // 2*u32
  __uint(value_size, sizeof(u32));               // Inner Map File Descriptor
  __uint(pinning, LIBBPF_PIN_BY_NAME);           // Created in Userspace, Identified in Kernel Space using pinned name
};
  • Key
    • Identifier for Containers
struct outer_key {
  u32 pid_ns;
  u32 mnt_ns;
};

Inner Map details

&ebpf.MapSpec{
		Type:       ebpf.Hash,
		KeySize:    4,            // Hash Value of Entity
		ValueSize:  8,            // Decision Values
		MaxEntries: 1024,
    }
  • Value
struct data_t {
  bool owner;        // owner only flag
  bool read;         // read only flag 
  bool dir;          // policy directory flag
  bool recursive;    // directory recursive flag
  bool hint;         // policy directory hint
};

Handling of Events

Deeper Dive with Examples

  1. But what if it's not a match We explore how directory matching works in the next example

  2. Notice How we split the directory policy to a sets of hints in the map. This helps in efficient matching of directory paths in Kernel Space.

    What if we try to access a file in a different directory. Presence of no hint helps break through the iteration hence optimising the process.

Directory Matching

#pragma unroll
  for (int i = 0; i < MAX_STRING_SIZE; i++) {
    if (path[i] == '\0')
      break;

    if (path[i] == '/') {
      __builtin_memset(&dir, 0, sizeof(dir));
      bpf_probe_read_str(&dir, i + 2, path);

      fp = jenkins_hash(dir, i + 1, 0);

      struct data_t *val = bpf_map_lookup_elem(inner, &fp);
      if (val) {
        if (val->dir) {
          matched = true;
          goto decisionmaker;
        }
        if (val->hint == 0) { // If we match a non directory entity somehow
          break;
        }
      } else {
        break;
      }
    }
  }

Hashing

Files and Source Names can be huge. Worst case both add to 8192 bytes. Which is a very large entity for key. So we hash that value to u32 key. We stored hashed values from userspace and lookup up hashed values from kernel space for decision making.

We plan to use a Jenkins hash algorithm modified for use in ebpf land and matching implementation in user land.

Based on Event Auditor Implementation

Inspirations

TODO/ToCheck

  1. List out LSM Hooks to be integrated with
  2. Explore Hashing
  3. Analyse Performance Impact
  4. ...

Miscellaneous Notes

Clone this wiki locally