Skip to content

Commit

Permalink
feat : process arguments matching
Browse files Browse the repository at this point in the history
Signed-off-by: Aryan-sharma11 <[email protected]>
  • Loading branch information
Aryan-sharma11 committed Oct 3, 2024
1 parent ae5f57c commit 9ec1e42
Show file tree
Hide file tree
Showing 22 changed files with 469 additions and 101 deletions.
32 changes: 32 additions & 0 deletions KubeArmor/BPF/common.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright 2024 Authors of KubeArmor */
/* This module contains the common structures shared by lsm and system monitor*/
# include "throttling.h"
#ifndef __COMMON_H
#define __COMMON_H
#define MAX_ENTRIES 10240
#define MAX_ARGUMENT_SIZE 256

// arguments matching

// values stored for argument map
struct argVal{
char argsArray[10][20];
};

struct {
__uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, 1); // Only one entry to store the count
__type(key, int);
__type(value, int);
} count_map SEC(".maps");

struct {
__uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, MAX_ENTRIES);
__type(key, unsigned int);
__type(value, struct argVal);
__uint(pinning, LIBBPF_PIN_BY_NAME);
} cmd_args SEC(".maps");

#endif /* __COMMON_H */
148 changes: 102 additions & 46 deletions KubeArmor/BPF/enforcer.bpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,28 @@

#include "shared.h"
#include "syscalls.h"
#include "common.h"

SEC("lsm/bprm_check_security")
int BPF_PROG(enforce_proc, struct linux_binprm *bprm, int ret) {
struct task_struct *t = (struct task_struct *)bpf_get_current_task();
event *task_info;
int retval = ret;
// variables required for argument matching---------|
struct argVal *argval ;
unsigned int num = BPF_CORE_READ(bprm , argc);
unsigned int argKey;
unsigned int *x ;
u32 arg_k = 0;
arg_bufs_k *a_key = bpf_map_lookup_elem(&args_bufk, &arg_k);
if (a_key == NULL)
return 0;
bool argmatch = false;
// -------------------------------------------------|

bool match = false;

bool match = false;
struct outer_key okey;
get_outer_key(&okey, t);

u32 *inner = bpf_map_lookup_elem(&kubearmor_containers, &okey);

if (!inner) {
Expand Down Expand Up @@ -87,49 +97,50 @@ int BPF_PROG(enforce_proc, struct linux_binprm *bprm, int ret) {
match = true;
goto decision;
}

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

if (store->path[i] == '/') {
bpf_map_update_elem(&bufk, &two, z, BPF_ANY);

match = false;

bpf_probe_read_str(pk->path, i + 2, store->path);
// Check Subdir with From Source
bpf_probe_read_str(pk->source, MAX_STRING_SIZE, store->source);
dirval = bpf_map_lookup_elem(inner, pk);
if (dirval) {
if ((dirval->processmask & RULE_DIR) &&
(dirval->processmask & RULE_EXEC)) {
match = true;
if ((dirval->processmask & RULE_RECURSIVE) &&
(~dirval->processmask &
RULE_HINT)) { // true directory match and not a hint suggests
// there are no possibility of child dir
val = dirval;
goto decision;
} else if (dirval->processmask &
RULE_RECURSIVE) { // It's a directory match but also a
// hint, it's possible that a
// subdirectory exists that can also
// match so we continue the loop to look
// for a true match in subdirectories
recursivebuthint = true;
val = dirval;
// bpf_printk(" source = %s path= %s " , store->source , store->path);

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

if (store->path[i] == '/') {
bpf_map_update_elem(&bufk, &two, z, BPF_ANY);

match = false;

bpf_probe_read_str(pk->path, i + 2, store->path);
// Check Subdir with From Source
bpf_probe_read_str(pk->source, MAX_STRING_SIZE, store->source);
dirval = bpf_map_lookup_elem(inner, pk);
if (dirval) {
if ((dirval->processmask & RULE_DIR) &&
(dirval->processmask & RULE_EXEC)) {
match = true;
if ((dirval->processmask & RULE_RECURSIVE) &&
(~dirval->processmask &
RULE_HINT)) { // true directory match and not a hint suggests
// there are no possibility of child dir
val = dirval;
goto decision;
} else if (dirval->processmask &
RULE_RECURSIVE) { // It's a directory match but also a
// hint, it's possible that a
// subdirectory exists that can also
// match so we continue the loop to look
// for a true match in subdirectories
recursivebuthint = true;
val = dirval;
} else {
continue; // We continue the loop to see if we have more nested
// directories and set match to false
}
}
} else {
continue; // We continue the loop to see if we have more nested
// directories and set match to false
break;
}
}
} else {
break;
}
}
}

if (recursivebuthint) {
match = true;
Expand Down Expand Up @@ -167,6 +178,7 @@ int BPF_PROG(enforce_proc, struct linux_binprm *bprm, int ret) {
}

recursivebuthint = false;
// bpf_printk(" source = %s path= %s " , store->source , store->path);

#pragma unroll
for (int i = 0; i < 64; i++) {
Expand Down Expand Up @@ -206,7 +218,6 @@ int BPF_PROG(enforce_proc, struct linux_binprm *bprm, int ret) {
}
}
}

if (recursivebuthint) {
match = true;
goto decision;
Expand All @@ -217,22 +228,59 @@ int BPF_PROG(enforce_proc, struct linux_binprm *bprm, int ret) {
}
}

decision:

decision:
if (match) {
if (val && (val->processmask & RULE_ARGSET)) {
argKey = bpf_get_current_pid_tgid();
argval = bpf_map_lookup_elem(&cmd_args, &argKey);

// clearing to avoid processing garbage values
__builtin_memset(&a_key->okey, 0, sizeof(a_key->okey));
__builtin_memset(&a_key->store, 0, sizeof(a_key->store));

bpf_probe_read(&a_key->okey.mnt_ns, sizeof(okey.mnt_ns) , &okey.mnt_ns);
bpf_probe_read(&a_key->okey.pid_ns, sizeof(okey.pid_ns) , &okey.pid_ns);
bpf_probe_read_str(&a_key->store.path, sizeof(store->path) , store->path);
// bpf_probe_read_str(&a_key->store.source, sizeof(store->source) , store->source);
if (argval) {
for( int i = 1 ; i< num && i<10; i++ ){
bpf_printk("Argurment %d : %s\n", i, argval->argsArray[i]);
__builtin_memset(a_key->arg, 0, sizeof(a_key->arg));
bpf_probe_read_str(&a_key->arg, sizeof(a_key->arg), argval->argsArray[i]);
x = bpf_map_lookup_elem(&a_map ,a_key);
bpf_printk("a_key->path %s , a_key->source - %s ", a_key->store.path , a_key->store.source);

if(x){
bpf_printk("argument matched");
argmatch = true;
} else {
bpf_printk("argument not matched");
argmatch = false;
break;
}
}
}
}

if (val && (val->processmask & RULE_OWNER)) {
if (!is_owner(bprm->file)) {
if((val->processmask & RULE_ARGSET) && argmatch){
return 0;
}
retval = -EPERM;
} else {
// Owner Only Rule Match, No need to enforce
return ret;
}
}
if (val && (val->processmask & RULE_DENY)) {
// Allow if argset matches
if((val->processmask & RULE_ARGSET) && argmatch){
return 0;
}
retval = -EPERM;
}
}

if (retval == -EPERM) {
goto ringbuf;
}
Expand All @@ -247,6 +295,14 @@ int BPF_PROG(enforce_proc, struct linux_binprm *bprm, int ret) {
retval = -EPERM;
}
goto ringbuf;
} else {
// allow policy + match + !argmatch = action based on default posture
if((val->processmask & RULE_ARGSET) && !argmatch){
if (allow->processmask == BLOCK_POSTURE) {
retval = -EPERM;
}
goto ringbuf;
}
}
}

Expand Down
33 changes: 31 additions & 2 deletions KubeArmor/BPF/shared.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ typedef struct bufkey {
char source[MAX_STRING_SIZE];
} bufs_k;


#undef container_of
#define container_of(ptr, type, member) \
({ \
Expand Down Expand Up @@ -74,6 +75,33 @@ struct {
__uint(max_entries, 3);
} bufk SEC(".maps");

typedef struct argskey{
struct outer_key okey;
bufs_k store;
char arg[MAX_STRING_SIZE];
} arg_bufs_k;

//-- Maps and structs for argument matching--//
// argument matching

// Key for argument map => okey+bufkey+argname

struct {
__uint(type,BPF_MAP_TYPE_PERCPU_ARRAY);
__type(key, u32);
__type(value, arg_bufs_k);
__uint(max_entries, 1);
} args_bufk SEC(".maps");
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, 100);
__type(key, arg_bufs_k); // Composite key of okey+bufkey+argname
__type(value, u8); // Value is a u8 integer
__uint(pinning, LIBBPF_PIN_BY_NAME);
} a_map SEC(".maps");

//--------------------------------------------//

typedef struct {
u64 ts;

Expand Down Expand Up @@ -109,14 +137,15 @@ struct {
#define RULE_RECURSIVE 1 << 5
#define RULE_HINT 1 << 6
#define RULE_DENY 1 << 7
#define RULE_ARGSET 1 << 8

#define MASK_WRITE 0x00000002
#define MASK_READ 0x00000004
#define MASK_APPEND 0x00000008

struct data_t {
u8 processmask;
u8 filemask;
u16 processmask;
u16 filemask;
};

enum
Expand Down
40 changes: 40 additions & 0 deletions KubeArmor/BPF/system_monitor.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
#include <bpf_tracing.h>
#include "syscalls.h"
#include "throttling.h"
#include "common.h"


#ifdef RHEL_RELEASE_CODE
Expand Down Expand Up @@ -260,6 +261,8 @@ typedef struct __attribute__((__packed__)) sys_context

BPF_LRU_HASH(pid_ns_map, u32, u32);



#ifdef BTF_SUPPORTED
#define GET_FIELD_ADDR(field) __builtin_preserve_access_index(&field)

Expand Down Expand Up @@ -1114,6 +1117,39 @@ static __always_inline bool should_drop_alerts_per_container(sys_context_t *cont
bpf_map_update_elem(&kubearmor_alert_throttle, &key, state, BPF_ANY);
return false;
}
static __always_inline void save_cmd_args_to_buffer(const char __user *const __user *ptr){
unsigned int key_tgid = bpf_get_current_pid_tgid();
int *j;
int z = 0 ;
bpf_map_update_elem(&count_map, &z , &z , BPF_ANY);
struct argVal val;
__builtin_memset(&val, 0, sizeof(val));
// add number of args here
#pragma unroll
for (int i = 0; i < 5; i++)
{
j = bpf_map_lookup_elem(&count_map, &z);
if (!j){
bpf_printk("Failed to loarray \n");
break;
}
const char *const *curr_ptr = (void *)&ptr[i] ;
const char *argp = NULL;
bpf_probe_read(&argp, sizeof(argp), curr_ptr);
int k = *j;
if (*j < 0 || *j >= 4)
break;
if (argp)
{
// bpf_printk("in execve arg - %s , key %u ",argp , key_tgid);
bpf_probe_read_str(val.argsArray[k], sizeof(val.argsArray[0]), argp);
k++ ; // Increment the index
}
*j = k;
bpf_map_update_elem(&count_map, &z, j, BPF_ANY);
}
bpf_map_update_elem(&cmd_args, &key_tgid, &val, BPF_ANY);
}

SEC("kprobe/security_path_mknod")
int kprobe__security_path_mknod(struct pt_regs *ctx)
Expand Down Expand Up @@ -1246,6 +1282,10 @@ int kprobe__execve(struct pt_regs *ctx)
char *filename = (char *)READ_KERN(PT_REGS_PARM1(ctx2));
unsigned long argv = READ_KERN(PT_REGS_PARM2(ctx2));
#endif

if(get_kubearmor_config(_ENFORCER_BPFLSM)){
save_cmd_args_to_buffer((const char *const *)argv);
}

init_context(&context);

Expand Down
Loading

0 comments on commit 9ec1e42

Please sign in to comment.