diff --git a/KubeArmor/BPF/common.h b/KubeArmor/BPF/common.h new file mode 100644 index 0000000000..d25155b8fc --- /dev/null +++ b/KubeArmor/BPF/common.h @@ -0,0 +1,37 @@ +/* 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 +#define MAX_STR_ARR_ELEM 20 + +// arguments matching + +// values stored for argument map +struct argVal{ + char argsArray[80]; +}; +struct cmd_args_key { + u64 tgid ; + u64 ind; +}; + +struct { + __uint(type, BPF_MAP_TYPE_LRU_HASH); + __uint(max_entries, MAX_ENTRIES); + __type(key, struct cmd_args_key); + __type(value, struct argVal); + __uint(pinning, LIBBPF_PIN_BY_NAME); +} kubearmor_args_store SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); + __uint(max_entries, 1); // Adjust max_entries based on expected usage + __type(key, u32); + __type(value, struct argVal); // Store the args in this struct +} cmd_args_buf SEC(".maps"); + +#endif /* __COMMON_H */ \ No newline at end of file diff --git a/KubeArmor/BPF/enforcer.bpf.c b/KubeArmor/BPF/enforcer.bpf.c index 97253c5691..7bf608619f 100644 --- a/KubeArmor/BPF/enforcer.bpf.c +++ b/KubeArmor/BPF/enforcer.bpf.c @@ -4,6 +4,7 @@ #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) { @@ -11,11 +12,13 @@ int BPF_PROG(enforce_proc, struct linux_binprm *bprm, int ret) { event *task_info; int retval = ret; - bool match = false; - + // no of arguments + unsigned int num_of_args = BPF_CORE_READ(bprm , argc); + bool argmatch = false; + + bool match = false; struct outer_key okey; get_outer_key(&okey, t); - u32 *inner = bpf_map_lookup_elem(&kubearmor_containers, &okey); if (!inner) { @@ -38,7 +41,7 @@ int BPF_PROG(enforce_proc, struct linux_binprm *bprm, int ret) { bufs_k *pk = bpf_map_lookup_elem(&bufk, &two); if (pk == NULL) return 0; - + bpf_map_update_elem(&bufk, &two, z, BPF_ANY); // Extract full path from file structure provided by LSM Hook bufs_t *path_buf = get_buf(PATH_BUFFER); if (path_buf == NULL) @@ -83,7 +86,9 @@ int BPF_PROG(enforce_proc, struct linux_binprm *bprm, int ret) { if (src_ptr == NULL) fromSourceCheck = false; + if (fromSourceCheck) { + bpf_probe_read_str(store->source, MAX_STRING_SIZE, src_ptr); val = bpf_map_lookup_elem(inner, store); @@ -91,51 +96,49 @@ 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; - goToDecision = true; // to please the holy verifier - break; - } 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; + #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; + goToDecision = true; // to please the holy verifier + break; + } 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 || goToDecision) { match = true; goto decision; @@ -166,6 +169,7 @@ int BPF_PROG(enforce_proc, struct linux_binprm *bprm, int ret) { val = bpf_map_lookup_elem(inner, pk); if (val && (val->processmask & RULE_EXEC)) { + match = true; goto decision; } @@ -210,7 +214,6 @@ int BPF_PROG(enforce_proc, struct linux_binprm *bprm, int ret) { } } } - if (recursivebuthint) { match = true; goto decision; @@ -221,11 +224,21 @@ int BPF_PROG(enforce_proc, struct linux_binprm *bprm, int ret) { } } -decision: - +decision: if (match) { + if (val && (val->processmask & RULE_ARGSET) && get_kubearmor_config(_MATCH_ARGS)){ + argmatch = matchArguments( num_of_args , &okey , store , pk); + if(argmatch){ + // if arguments matches allow the process to be executed + return 0; + } + } + 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 @@ -236,7 +249,6 @@ int BPF_PROG(enforce_proc, struct linux_binprm *bprm, int ret) { retval = -EPERM; } } - if (retval == -EPERM) { goto ringbuf; } diff --git a/KubeArmor/BPF/filelessexec.bpf.c b/KubeArmor/BPF/filelessexec.bpf.c index 919e920965..a378c6dd17 100644 --- a/KubeArmor/BPF/filelessexec.bpf.c +++ b/KubeArmor/BPF/filelessexec.bpf.c @@ -96,10 +96,10 @@ int BPF_PROG(enforce_bprm_check_security, struct linux_binprm *bprm){ // mapping not backed by any file with executable permission, denying mapping if (*present == BLOCK) { - event_data->retval = -13; + event_data->retval = -EPERM; bpf_ringbuf_submit(event_data, 0); - // bpf_printk("[bprm] fileless execution detected with pid %d, denying execution", event_data->pid); - return -13; + + return -EPERM; } else { event_data->retval = 0; bpf_ringbuf_submit(event_data, 0); diff --git a/KubeArmor/BPF/shared.h b/KubeArmor/BPF/shared.h index 03ea3e5f62..11d2366a7f 100644 --- a/KubeArmor/BPF/shared.h +++ b/KubeArmor/BPF/shared.h @@ -11,6 +11,7 @@ #include #include #include "throttling.h" +#include "common.h" char LICENSE[] SEC("license") = "Dual BSD/GPL"; #define EPERM 13 @@ -51,6 +52,7 @@ typedef struct bufkey { char source[MAX_STRING_SIZE]; } bufs_k; + #undef container_of #define container_of(ptr, type, member) \ ({ \ @@ -78,6 +80,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); +} kubearmor_arguments SEC(".maps"); + +//--------------------------------------------// + // ============ // match prefix // ============ @@ -147,14 +176,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 @@ -162,6 +192,7 @@ enum _ALERT_THROTTLING = 3, _MAX_ALERT_PER_SEC = 4, _THROTTLE_SEC = 5, + _MATCH_ARGS = 6, }; struct kaconfig @@ -769,6 +800,59 @@ static inline int match_and_enforce_path_hooks(struct path *f_path, u32 id, bpf_ringbuf_submit(task_info, 0); return retval; } +static inline bool matchArguments( unsigned int num_of_args , struct outer_key *okey , bufs_k *store , bufs_k *pk ) { + + bool argmatch = false; + unsigned int *x ; + + unsigned int argKey; + struct argVal *argval ; + + u32 arg_k = 0; + arg_bufs_k *a_key = bpf_map_lookup_elem(&args_bufk, &arg_k); + if (a_key == NULL) + return 0; + + // 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); + + struct cmd_args_key cmd_args_buf_k; + cmd_args_buf_k.tgid = bpf_get_current_pid_tgid(); + + if (pk->path[0] == '\0') { + // pk->path[0] will be null for fromSource rules + bpf_probe_read_str(&a_key->store.source, sizeof(store->source) , store->source); + } + // block if number of arguments is greater than 16 + if(num_of_args > 16){ + return true; + } + for( u8 i = 0 ; i< num_of_args && i <= 16; i++ ){ + cmd_args_buf_k.ind = i; + argval = bpf_map_lookup_elem(&kubearmor_args_store , &cmd_args_buf_k); + if(argval){ + __builtin_memset(a_key->arg, 0, sizeof(a_key->arg)); + bpf_probe_read_str(&a_key->arg, sizeof(a_key->arg), &argval->argsArray); + x = bpf_map_lookup_elem(&kubearmor_arguments ,a_key); + if (x){ + argmatch = true; + } + else { + argmatch = false; + if (i != 0) { + break; + } + } + } + } + + return argmatch; +} /* How do we check what to deny or not? diff --git a/KubeArmor/BPF/system_monitor.c b/KubeArmor/BPF/system_monitor.c index 3920702465..2f43681493 100644 --- a/KubeArmor/BPF/system_monitor.c +++ b/KubeArmor/BPF/system_monitor.c @@ -48,6 +48,7 @@ #include #include "syscalls.h" #include "throttling.h" +#include "common.h" #ifdef RHEL_RELEASE_CODE @@ -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) @@ -340,6 +343,7 @@ enum _ALERT_THROTTLING = 3, _MAX_ALERT_PER_SEC = 4, _THROTTLE_SEC = 5, + _MATCH_ARGS = 6, }; struct kaconfig @@ -640,7 +644,7 @@ static __always_inline int save_str_to_buffer(bufs_t *bufs_p, void *ptr) { } u32 str_pos = size_pos + sizeof(int); - if (str_pos >= MAX_BUFFER_SIZE -1 || str_pos + MAX_STRING_SIZE > MAX_BUFFER_SIZE -1) { + if (str_pos >= MAX_BUFFER_SIZE -1 || str_pos + MAX_STRING_SIZE > MAX_BUFFER_SIZE -1 ) { return 0; } @@ -1142,6 +1146,37 @@ static __always_inline bool should_drop_alerts_per_container(sys_context_t *cont #endif return false; } + static __always_inline void save_cmd_args_to_buffer(const char __user *const __user *ptr){ + + + struct cmd_args_key key; + key.tgid = bpf_get_current_pid_tgid(); + u32 arg_k = 0; + struct argVal *args_buf = bpf_map_lookup_elem(&cmd_args_buf, &arg_k); + if (args_buf == NULL){ + return ; + } + // add number of args here // pragmaunroll + for ( u8 i = 0; i <= 16; i++) + { + key.ind = i; + const char *const *curr_ptr = (void *)&ptr[i] ; + const char *argp = NULL; + bpf_probe_read(&argp, sizeof(argp), curr_ptr); + if (argp) + { + __builtin_memset(&args_buf->argsArray, 0, sizeof(args_buf->argsArray)); + bpf_probe_read_str(&args_buf->argsArray, sizeof(args_buf->argsArray), argp); + + bpf_map_update_elem(&kubearmor_args_store, &key, args_buf, BPF_ANY); + } + else { + break; + } + } + + + } SEC("kprobe/security_path_mknod") int kprobe__security_path_mknod(struct pt_regs *ctx) @@ -1274,6 +1309,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) && (get_kubearmor_config(_MATCH_ARGS))){ + save_cmd_args_to_buffer((const char *const *)argv); + } init_context(&context); diff --git a/KubeArmor/BPF/throttling.h b/KubeArmor/BPF/throttling.h index 5af306c938..fa808a26fd 100644 --- a/KubeArmor/BPF/throttling.h +++ b/KubeArmor/BPF/throttling.h @@ -4,17 +4,17 @@ #ifndef __THROTTLING_H #define __THROTTLING_H +struct outer_key { + u32 pid_ns; + u32 mnt_ns; +}; +// Throttling struct alert_throttle_state { u64 first_event_timestamp; u64 event_count; u64 throttle; }; -struct outer_key { - u32 pid_ns; - u32 mnt_ns; -}; - struct alert { __uint(type, BPF_MAP_TYPE_HASH); __uint(max_entries, 256); diff --git a/KubeArmor/config/config.go b/KubeArmor/config/config.go index 6fa84248ce..df8945a359 100644 --- a/KubeArmor/config/config.go +++ b/KubeArmor/config/config.go @@ -63,6 +63,7 @@ type KubearmorConfig struct { MaxAlertPerSec int32 // Maximum alerts allowed per second ThrottleSec int32 // Number of seconds for which subsequent alerts will be dropped AnnotateResources bool // enable annotations by kubearmor if kubearmor-controller is not present + MatchArgs bool // enable argument rules for policy ProcFsMount string // path where procfs is hosted } @@ -114,6 +115,7 @@ const ( ConfigThrottleSec string = "throttleSec" ConfigAnnotateResources string = "annotateResources" ConfigProcFsMount string = "procfsMount" + ConfigArgMatching string = "matchArgs" ) func readCmdLineParams() { @@ -175,6 +177,8 @@ func readCmdLineParams() { procFsMount := flag.String(ConfigProcFsMount, "/proc", "Path to the BPF filesystem to use for storing maps") + matchArgs := flag.Bool(ConfigArgMatching, true, "enabling Argument matching") + flags := []string{} flag.VisitAll(func(f *flag.Flag) { kv := fmt.Sprintf("%s:%v", f.Name, f.Value) @@ -240,6 +244,8 @@ func readCmdLineParams() { viper.SetDefault(ConfigAnnotateResources, *annotateResources) + viper.SetDefault(ConfigArgMatching, *matchArgs) + viper.SetDefault(ConfigProcFsMount, *procFsMount) } @@ -359,4 +365,5 @@ func LoadDynamicConfig() { GlobalCfg.AlertThrottling = viper.GetBool(ConfigAlertThrottling) GlobalCfg.MaxAlertPerSec = int32(viper.GetInt(ConfigMaxAlertPerSec)) GlobalCfg.ThrottleSec = int32(viper.GetInt(ConfigThrottleSec)) + GlobalCfg.MatchArgs = viper.GetBool(ConfigArgMatching) } diff --git a/KubeArmor/core/kubeArmor.go b/KubeArmor/core/kubeArmor.go index 70bd5562ad..76b961de46 100644 --- a/KubeArmor/core/kubeArmor.go +++ b/KubeArmor/core/kubeArmor.go @@ -160,13 +160,6 @@ func NewKubeArmorDaemon() *KubeArmorDaemon { func (dm *KubeArmorDaemon) DestroyKubeArmorDaemon() { close(StopChan) - if dm.RuntimeEnforcer != nil { - // close runtime enforcer - if dm.CloseRuntimeEnforcer() { - dm.Logger.Print("Stopped KubeArmor Enforcer") - } - } - if dm.SystemMonitor != nil { // close system monitor if dm.CloseSystemMonitor() { @@ -174,6 +167,13 @@ func (dm *KubeArmorDaemon) DestroyKubeArmorDaemon() { } } + if dm.RuntimeEnforcer != nil { + // close runtime enforcer + if dm.CloseRuntimeEnforcer() { + dm.Logger.Print("Stopped KubeArmor Enforcer") + } + } + if dm.KVMAgent != nil { // close kvm agent if dm.CloseKVMAgent() { diff --git a/KubeArmor/core/kubeUpdate.go b/KubeArmor/core/kubeUpdate.go index a7cfb5e5e9..c609e112d2 100755 --- a/KubeArmor/core/kubeUpdate.go +++ b/KubeArmor/core/kubeUpdate.go @@ -2812,8 +2812,14 @@ func (dm *KubeArmorDaemon) WatchConfigMap() cache.InformerSynced { } cfg.GlobalCfg.ThrottleSec = int32(throttleSec) } + if _, ok := cm.Data[cfg.ConfigArgMatching]; ok { + cfg.GlobalCfg.MatchArgs = (cm.Data[cfg.ConfigArgMatching] == "true") + } + dm.SystemMonitor.UpdateThrottlingConfig() + dm.SystemMonitor.UpdateMatchArgsConfig() + dm.Logger.Printf("Current Global Posture is %v", currentGlobalPosture) dm.UpdateGlobalPosture(globalPosture) diff --git a/KubeArmor/enforcer/bpflsm/enforcer.go b/KubeArmor/enforcer/bpflsm/enforcer.go index 1c2fbd4f31..729e441b2e 100644 --- a/KubeArmor/enforcer/bpflsm/enforcer.go +++ b/KubeArmor/enforcer/bpflsm/enforcer.go @@ -38,6 +38,7 @@ type BPFEnforcer struct { // InnerMapSpec *ebpf.MapSpec BPFContainerMap *ebpf.Map BPFContainerThrottleMap *ebpf.Map + BPFArgumentsMap *ebpf.Map // events Events *ringbuf.Reader @@ -77,7 +78,7 @@ func NewBPFEnforcer(node tp.Node, pinpath string, logger *fd.Feeder, monitor *mo be.InnerMapSpec = &ebpf.MapSpec{ Type: ebpf.Hash, KeySize: 512, - ValueSize: 2, + ValueSize: 4, MaxEntries: 256, } @@ -96,6 +97,20 @@ func NewBPFEnforcer(node tp.Node, pinpath string, logger *fd.Feeder, monitor *mo be.Logger.Errf("error creating kubearmor_containers map: %s", err) return be, err } + be.BPFArgumentsMap, err = ebpf.NewMapWithOptions(&ebpf.MapSpec{ + Type: ebpf.Hash, + KeySize: 776, + ValueSize: 1, + MaxEntries: 100, + Name: "kubearmor_arguments", + Pinning: ebpf.PinByName, + }, ebpf.MapOptions{ + PinPath: pinpath, + }) + if err != nil { + be.Logger.Errf("error creating kubearmor_arguments_map: %s", err) + return be, err + } be.BPFContainerThrottleMap, err = ebpf.NewMapWithOptions(&ebpf.MapSpec{ Type: ebpf.Hash, @@ -449,7 +464,6 @@ func (be *BPFEnforcer) DestroyBPFEnforcer() error { } } - be.ContainerMapLock.Lock() if be.BPFContainerMap != nil { @@ -473,6 +487,16 @@ func (be *BPFEnforcer) DestroyBPFEnforcer() error { errBPFCleanUp = errors.Join(errBPFCleanUp, err) } } + if be.BPFArgumentsMap != nil { + if err := be.BPFArgumentsMap.Unpin(); err != nil { + be.Logger.Err(err.Error()) + errBPFCleanUp = errors.Join(errBPFCleanUp, err) + } + if err := be.BPFArgumentsMap.Close(); err != nil { + be.Logger.Err(err.Error()) + errBPFCleanUp = errors.Join(errBPFCleanUp, err) + } + } be.ContainerMapLock.Unlock() @@ -490,6 +514,16 @@ func (be *BPFEnforcer) DestroyBPFEnforcer() error { errBPFCleanUp = errors.Join(errBPFCleanUp, err) } } + if be.obj.enforcerMaps.KubearmorArgsStore != nil { + if err := be.obj.enforcerMaps.KubearmorArgsStore.Unpin(); err != nil { + be.Logger.Err(err.Error()) + errBPFCleanUp = errors.Join(errBPFCleanUp, err) + } + if err := be.obj.enforcerMaps.KubearmorArgsStore.Close(); err != nil { + be.Logger.Err(err.Error()) + errBPFCleanUp = errors.Join(errBPFCleanUp, err) + } + } be = nil return errBPFCleanUp diff --git a/KubeArmor/enforcer/bpflsm/enforcer_bpfeb.go b/KubeArmor/enforcer/bpflsm/enforcer_bpfeb.go index 75c35bace7..ab570b908f 100644 --- a/KubeArmor/enforcer/bpflsm/enforcer_bpfeb.go +++ b/KubeArmor/enforcer/bpflsm/enforcer_bpfeb.go @@ -12,6 +12,17 @@ import ( "github.com/cilium/ebpf" ) +type enforcerArgBufsK struct { + Okey struct { + PidNs uint32 + MntNs uint32 + } + Store enforcerBufsK + Arg [256]int8 +} + +type enforcerArgVal struct{ ArgsArray [80]int8 } + type enforcerBufsK struct { Path [256]int8 Source [256]int8 @@ -19,6 +30,11 @@ type enforcerBufsK struct { type enforcerBufsT struct{ Buf [32768]int8 } +type enforcerCmdArgsKey struct { + Tgid uint64 + Ind uint64 +} + // loadEnforcer returns the embedded CollectionSpec for enforcer. func loadEnforcer() (*ebpf.CollectionSpec, error) { reader := bytes.NewReader(_EnforcerBytes) @@ -74,10 +90,14 @@ type enforcerProgramSpecs struct { // // It can be passed ebpf.CollectionSpec.Assign. type enforcerMapSpecs struct { + ArgsBufk *ebpf.MapSpec `ebpf:"args_bufk"` Bufk *ebpf.MapSpec `ebpf:"bufk"` Bufs *ebpf.MapSpec `ebpf:"bufs"` BufsOff *ebpf.MapSpec `ebpf:"bufs_off"` + CmdArgsBuf *ebpf.MapSpec `ebpf:"cmd_args_buf"` KubearmorAlertThrottle *ebpf.MapSpec `ebpf:"kubearmor_alert_throttle"` + KubearmorArgsStore *ebpf.MapSpec `ebpf:"kubearmor_args_store"` + KubearmorArguments *ebpf.MapSpec `ebpf:"kubearmor_arguments"` KubearmorConfig *ebpf.MapSpec `ebpf:"kubearmor_config"` KubearmorContainers *ebpf.MapSpec `ebpf:"kubearmor_containers"` KubearmorEvents *ebpf.MapSpec `ebpf:"kubearmor_events"` @@ -109,10 +129,14 @@ func (o *enforcerObjects) Close() error { // // It can be passed to loadEnforcerObjects or ebpf.CollectionSpec.LoadAndAssign. type enforcerMaps struct { + ArgsBufk *ebpf.Map `ebpf:"args_bufk"` Bufk *ebpf.Map `ebpf:"bufk"` Bufs *ebpf.Map `ebpf:"bufs"` BufsOff *ebpf.Map `ebpf:"bufs_off"` + CmdArgsBuf *ebpf.Map `ebpf:"cmd_args_buf"` KubearmorAlertThrottle *ebpf.Map `ebpf:"kubearmor_alert_throttle"` + KubearmorArgsStore *ebpf.Map `ebpf:"kubearmor_args_store"` + KubearmorArguments *ebpf.Map `ebpf:"kubearmor_arguments"` KubearmorConfig *ebpf.Map `ebpf:"kubearmor_config"` KubearmorContainers *ebpf.Map `ebpf:"kubearmor_containers"` KubearmorEvents *ebpf.Map `ebpf:"kubearmor_events"` @@ -120,10 +144,14 @@ type enforcerMaps struct { func (m *enforcerMaps) Close() error { return _EnforcerClose( + m.ArgsBufk, m.Bufk, m.Bufs, m.BufsOff, + m.CmdArgsBuf, m.KubearmorAlertThrottle, + m.KubearmorArgsStore, + m.KubearmorArguments, m.KubearmorConfig, m.KubearmorContainers, m.KubearmorEvents, diff --git a/KubeArmor/enforcer/bpflsm/enforcer_bpfeb.o b/KubeArmor/enforcer/bpflsm/enforcer_bpfeb.o index 9819abe81e..906422d854 100644 Binary files a/KubeArmor/enforcer/bpflsm/enforcer_bpfeb.o and b/KubeArmor/enforcer/bpflsm/enforcer_bpfeb.o differ diff --git a/KubeArmor/enforcer/bpflsm/enforcer_bpfel.go b/KubeArmor/enforcer/bpflsm/enforcer_bpfel.go index 6bd4d8e656..599377cbf7 100644 --- a/KubeArmor/enforcer/bpflsm/enforcer_bpfel.go +++ b/KubeArmor/enforcer/bpflsm/enforcer_bpfel.go @@ -12,6 +12,17 @@ import ( "github.com/cilium/ebpf" ) +type enforcerArgBufsK struct { + Okey struct { + PidNs uint32 + MntNs uint32 + } + Store enforcerBufsK + Arg [256]int8 +} + +type enforcerArgVal struct{ ArgsArray [80]int8 } + type enforcerBufsK struct { Path [256]int8 Source [256]int8 @@ -19,6 +30,11 @@ type enforcerBufsK struct { type enforcerBufsT struct{ Buf [32768]int8 } +type enforcerCmdArgsKey struct { + Tgid uint64 + Ind uint64 +} + // loadEnforcer returns the embedded CollectionSpec for enforcer. func loadEnforcer() (*ebpf.CollectionSpec, error) { reader := bytes.NewReader(_EnforcerBytes) @@ -74,10 +90,14 @@ type enforcerProgramSpecs struct { // // It can be passed ebpf.CollectionSpec.Assign. type enforcerMapSpecs struct { + ArgsBufk *ebpf.MapSpec `ebpf:"args_bufk"` Bufk *ebpf.MapSpec `ebpf:"bufk"` Bufs *ebpf.MapSpec `ebpf:"bufs"` BufsOff *ebpf.MapSpec `ebpf:"bufs_off"` + CmdArgsBuf *ebpf.MapSpec `ebpf:"cmd_args_buf"` KubearmorAlertThrottle *ebpf.MapSpec `ebpf:"kubearmor_alert_throttle"` + KubearmorArgsStore *ebpf.MapSpec `ebpf:"kubearmor_args_store"` + KubearmorArguments *ebpf.MapSpec `ebpf:"kubearmor_arguments"` KubearmorConfig *ebpf.MapSpec `ebpf:"kubearmor_config"` KubearmorContainers *ebpf.MapSpec `ebpf:"kubearmor_containers"` KubearmorEvents *ebpf.MapSpec `ebpf:"kubearmor_events"` @@ -109,10 +129,14 @@ func (o *enforcerObjects) Close() error { // // It can be passed to loadEnforcerObjects or ebpf.CollectionSpec.LoadAndAssign. type enforcerMaps struct { + ArgsBufk *ebpf.Map `ebpf:"args_bufk"` Bufk *ebpf.Map `ebpf:"bufk"` Bufs *ebpf.Map `ebpf:"bufs"` BufsOff *ebpf.Map `ebpf:"bufs_off"` + CmdArgsBuf *ebpf.Map `ebpf:"cmd_args_buf"` KubearmorAlertThrottle *ebpf.Map `ebpf:"kubearmor_alert_throttle"` + KubearmorArgsStore *ebpf.Map `ebpf:"kubearmor_args_store"` + KubearmorArguments *ebpf.Map `ebpf:"kubearmor_arguments"` KubearmorConfig *ebpf.Map `ebpf:"kubearmor_config"` KubearmorContainers *ebpf.Map `ebpf:"kubearmor_containers"` KubearmorEvents *ebpf.Map `ebpf:"kubearmor_events"` @@ -120,10 +144,14 @@ type enforcerMaps struct { func (m *enforcerMaps) Close() error { return _EnforcerClose( + m.ArgsBufk, m.Bufk, m.Bufs, m.BufsOff, + m.CmdArgsBuf, m.KubearmorAlertThrottle, + m.KubearmorArgsStore, + m.KubearmorArguments, m.KubearmorConfig, m.KubearmorContainers, m.KubearmorEvents, diff --git a/KubeArmor/enforcer/bpflsm/enforcer_bpfel.o b/KubeArmor/enforcer/bpflsm/enforcer_bpfel.o index cd9264bee5..8f4dedc134 100644 Binary files a/KubeArmor/enforcer/bpflsm/enforcer_bpfel.o and b/KubeArmor/enforcer/bpflsm/enforcer_bpfel.o differ diff --git a/KubeArmor/enforcer/bpflsm/enforcer_path_bpfeb.go b/KubeArmor/enforcer/bpflsm/enforcer_path_bpfeb.go index fc65fdcd7c..d648eac8eb 100644 --- a/KubeArmor/enforcer/bpflsm/enforcer_path_bpfeb.go +++ b/KubeArmor/enforcer/bpflsm/enforcer_path_bpfeb.go @@ -12,6 +12,17 @@ import ( "github.com/cilium/ebpf" ) +type enforcer_pathArgBufsK struct { + Okey struct { + PidNs uint32 + MntNs uint32 + } + Store enforcer_pathBufsK + Arg [256]int8 +} + +type enforcer_pathArgVal struct{ ArgsArray [80]int8 } + type enforcer_pathBufsK struct { Path [256]int8 Source [256]int8 @@ -19,6 +30,11 @@ type enforcer_pathBufsK struct { type enforcer_pathBufsT struct{ Buf [32768]int8 } +type enforcer_pathCmdArgsKey struct { + Tgid uint64 + Ind uint64 +} + // loadEnforcer_path returns the embedded CollectionSpec for enforcer_path. func loadEnforcer_path() (*ebpf.CollectionSpec, error) { reader := bytes.NewReader(_Enforcer_pathBytes) @@ -78,10 +94,14 @@ type enforcer_pathProgramSpecs struct { // // It can be passed ebpf.CollectionSpec.Assign. type enforcer_pathMapSpecs struct { + ArgsBufk *ebpf.MapSpec `ebpf:"args_bufk"` Bufk *ebpf.MapSpec `ebpf:"bufk"` Bufs *ebpf.MapSpec `ebpf:"bufs"` BufsOff *ebpf.MapSpec `ebpf:"bufs_off"` + CmdArgsBuf *ebpf.MapSpec `ebpf:"cmd_args_buf"` KubearmorAlertThrottle *ebpf.MapSpec `ebpf:"kubearmor_alert_throttle"` + KubearmorArgsStore *ebpf.MapSpec `ebpf:"kubearmor_args_store"` + KubearmorArguments *ebpf.MapSpec `ebpf:"kubearmor_arguments"` KubearmorConfig *ebpf.MapSpec `ebpf:"kubearmor_config"` KubearmorContainers *ebpf.MapSpec `ebpf:"kubearmor_containers"` KubearmorEvents *ebpf.MapSpec `ebpf:"kubearmor_events"` @@ -113,10 +133,14 @@ func (o *enforcer_pathObjects) Close() error { // // It can be passed to loadEnforcer_pathObjects or ebpf.CollectionSpec.LoadAndAssign. type enforcer_pathMaps struct { + ArgsBufk *ebpf.Map `ebpf:"args_bufk"` Bufk *ebpf.Map `ebpf:"bufk"` Bufs *ebpf.Map `ebpf:"bufs"` BufsOff *ebpf.Map `ebpf:"bufs_off"` + CmdArgsBuf *ebpf.Map `ebpf:"cmd_args_buf"` KubearmorAlertThrottle *ebpf.Map `ebpf:"kubearmor_alert_throttle"` + KubearmorArgsStore *ebpf.Map `ebpf:"kubearmor_args_store"` + KubearmorArguments *ebpf.Map `ebpf:"kubearmor_arguments"` KubearmorConfig *ebpf.Map `ebpf:"kubearmor_config"` KubearmorContainers *ebpf.Map `ebpf:"kubearmor_containers"` KubearmorEvents *ebpf.Map `ebpf:"kubearmor_events"` @@ -124,10 +148,14 @@ type enforcer_pathMaps struct { func (m *enforcer_pathMaps) Close() error { return _Enforcer_pathClose( + m.ArgsBufk, m.Bufk, m.Bufs, m.BufsOff, + m.CmdArgsBuf, m.KubearmorAlertThrottle, + m.KubearmorArgsStore, + m.KubearmorArguments, m.KubearmorConfig, m.KubearmorContainers, m.KubearmorEvents, diff --git a/KubeArmor/enforcer/bpflsm/enforcer_path_bpfeb.o b/KubeArmor/enforcer/bpflsm/enforcer_path_bpfeb.o index e259383675..810116d92e 100644 Binary files a/KubeArmor/enforcer/bpflsm/enforcer_path_bpfeb.o and b/KubeArmor/enforcer/bpflsm/enforcer_path_bpfeb.o differ diff --git a/KubeArmor/enforcer/bpflsm/enforcer_path_bpfel.go b/KubeArmor/enforcer/bpflsm/enforcer_path_bpfel.go index ce63b1ffc9..f8b2e76fb9 100644 --- a/KubeArmor/enforcer/bpflsm/enforcer_path_bpfel.go +++ b/KubeArmor/enforcer/bpflsm/enforcer_path_bpfel.go @@ -12,6 +12,17 @@ import ( "github.com/cilium/ebpf" ) +type enforcer_pathArgBufsK struct { + Okey struct { + PidNs uint32 + MntNs uint32 + } + Store enforcer_pathBufsK + Arg [256]int8 +} + +type enforcer_pathArgVal struct{ ArgsArray [80]int8 } + type enforcer_pathBufsK struct { Path [256]int8 Source [256]int8 @@ -19,6 +30,11 @@ type enforcer_pathBufsK struct { type enforcer_pathBufsT struct{ Buf [32768]int8 } +type enforcer_pathCmdArgsKey struct { + Tgid uint64 + Ind uint64 +} + // loadEnforcer_path returns the embedded CollectionSpec for enforcer_path. func loadEnforcer_path() (*ebpf.CollectionSpec, error) { reader := bytes.NewReader(_Enforcer_pathBytes) @@ -78,10 +94,14 @@ type enforcer_pathProgramSpecs struct { // // It can be passed ebpf.CollectionSpec.Assign. type enforcer_pathMapSpecs struct { + ArgsBufk *ebpf.MapSpec `ebpf:"args_bufk"` Bufk *ebpf.MapSpec `ebpf:"bufk"` Bufs *ebpf.MapSpec `ebpf:"bufs"` BufsOff *ebpf.MapSpec `ebpf:"bufs_off"` + CmdArgsBuf *ebpf.MapSpec `ebpf:"cmd_args_buf"` KubearmorAlertThrottle *ebpf.MapSpec `ebpf:"kubearmor_alert_throttle"` + KubearmorArgsStore *ebpf.MapSpec `ebpf:"kubearmor_args_store"` + KubearmorArguments *ebpf.MapSpec `ebpf:"kubearmor_arguments"` KubearmorConfig *ebpf.MapSpec `ebpf:"kubearmor_config"` KubearmorContainers *ebpf.MapSpec `ebpf:"kubearmor_containers"` KubearmorEvents *ebpf.MapSpec `ebpf:"kubearmor_events"` @@ -113,10 +133,14 @@ func (o *enforcer_pathObjects) Close() error { // // It can be passed to loadEnforcer_pathObjects or ebpf.CollectionSpec.LoadAndAssign. type enforcer_pathMaps struct { + ArgsBufk *ebpf.Map `ebpf:"args_bufk"` Bufk *ebpf.Map `ebpf:"bufk"` Bufs *ebpf.Map `ebpf:"bufs"` BufsOff *ebpf.Map `ebpf:"bufs_off"` + CmdArgsBuf *ebpf.Map `ebpf:"cmd_args_buf"` KubearmorAlertThrottle *ebpf.Map `ebpf:"kubearmor_alert_throttle"` + KubearmorArgsStore *ebpf.Map `ebpf:"kubearmor_args_store"` + KubearmorArguments *ebpf.Map `ebpf:"kubearmor_arguments"` KubearmorConfig *ebpf.Map `ebpf:"kubearmor_config"` KubearmorContainers *ebpf.Map `ebpf:"kubearmor_containers"` KubearmorEvents *ebpf.Map `ebpf:"kubearmor_events"` @@ -124,10 +148,14 @@ type enforcer_pathMaps struct { func (m *enforcer_pathMaps) Close() error { return _Enforcer_pathClose( + m.ArgsBufk, m.Bufk, m.Bufs, m.BufsOff, + m.CmdArgsBuf, m.KubearmorAlertThrottle, + m.KubearmorArgsStore, + m.KubearmorArguments, m.KubearmorConfig, m.KubearmorContainers, m.KubearmorEvents, diff --git a/KubeArmor/enforcer/bpflsm/enforcer_path_bpfel.o b/KubeArmor/enforcer/bpflsm/enforcer_path_bpfel.o index 273d0ec48b..934ff0d7db 100644 Binary files a/KubeArmor/enforcer/bpflsm/enforcer_path_bpfel.o and b/KubeArmor/enforcer/bpflsm/enforcer_path_bpfel.o differ diff --git a/KubeArmor/enforcer/bpflsm/mapHelpers.go b/KubeArmor/enforcer/bpflsm/mapHelpers.go index bdb7734f6f..466eb3133e 100644 --- a/KubeArmor/enforcer/bpflsm/mapHelpers.go +++ b/KubeArmor/enforcer/bpflsm/mapHelpers.go @@ -15,6 +15,10 @@ type ContainerKV struct { Key NsKey Map *ebpf.Map Rules RuleList + + // -----------------// + Arg_Key ArgumentsKey + Arg_Map *ebpf.Map } // NsKey Structure acts as an Identifier for containers @@ -28,6 +32,16 @@ type InnerKey struct { Path [256]byte Source [256]byte } +type ArgumentsKey struct { + NsKey + InnerKey + Argument [256]byte +} + +type ArgListKey struct { + NsKey + InnerKey +} // AddContainerIDToMap adds container metadata to Outer eBPF container Map for initialising enforcement tracking and initiates an InnerMap to store the container specific rules func (be *BPFEnforcer) AddContainerIDToMap(containerID string, pidns, mntns uint32) { @@ -83,6 +97,23 @@ func (be *BPFEnforcer) DeleteContainerInnerMap(containerID string) { be.Logger.Errf("error deleting container %s from outer map in kubearmor_alert_throttle map: %s", containerID, err.Error()) } } + + for key, val := range be.ContainerMap[containerID].Rules.ArgumentsList { + + for _, arg := range val { + var bpfArgKey ArgumentsKey + bpfArgKey.InnerKey = key.InnerKey + bpfArgKey.NsKey = key.NsKey + copy(bpfArgKey.Argument[:], []byte(arg)) + if err := be.BPFArgumentsMap.Delete(bpfArgKey); err != nil { + if !errors.Is(err, os.ErrNotExist) { + be.Logger.Errf("error deleting argument from container %s in kubearmor arguments map: %s", containerID, err.Error()) + } + + } + + } + } if err := be.ContainerMap[containerID].Map.Close(); err != nil { be.Logger.Errf("error closing container map for %s: %s", containerID, err) } @@ -90,6 +121,7 @@ func (be *BPFEnforcer) DeleteContainerInnerMap(containerID string) { val.Map = nil val.Rules.Init() be.ContainerMap[containerID] = val + } } diff --git a/KubeArmor/enforcer/bpflsm/rulesHandling.go b/KubeArmor/enforcer/bpflsm/rulesHandling.go index 029174bc9f..807df758bb 100644 --- a/KubeArmor/enforcer/bpflsm/rulesHandling.go +++ b/KubeArmor/enforcer/bpflsm/rulesHandling.go @@ -15,14 +15,15 @@ import ( // Bit Flags for Map Rule Mask const ( - EXEC uint8 = 1 << 0 - WRITE uint8 = 1 << 1 - READ uint8 = 1 << 2 - OWNER uint8 = 1 << 3 - DIR uint8 = 1 << 4 - RECURSIVE uint8 = 1 << 5 - HINT uint8 = 1 << 6 - DENY uint8 = 1 << 7 + EXEC uint16 = 1 << 0 + WRITE uint16 = 1 << 1 + READ uint16 = 1 << 2 + OWNER uint16 = 1 << 3 + DIR uint16 = 1 << 4 + RECURSIVE uint16 = 1 << 5 + HINT uint16 = 1 << 6 + DENY uint16 = 1 << 7 + ARGSET uint16 = 1 << 8 ) // Data Index for rules @@ -48,7 +49,7 @@ var ( ) // Protocol Identifiers for Network Rules -var protocols = map[string]uint8{ +var protocols = map[string]uint16{ "ICMP": 1, "TCP": 6, "UDP": 17, @@ -69,9 +70,9 @@ var netType = map[string]uint8{ // Array Keys for Network Rule Keys const ( - FAMILY uint8 = 1 - TYPE uint8 = 2 - PROTOCOL uint8 = 3 + FAMILY uint16 = 1 + TYPE uint16 = 2 + PROTOCOL uint16 = 3 ) // Key for mapping capabilities in bpf maps @@ -79,29 +80,32 @@ const capableKey = 200 // RuleList Structure contains all the data required to set rules for a particular container type RuleList struct { - ProcessRuleList map[InnerKey][2]uint8 - FileRuleList map[InnerKey][2]uint8 - NetworkRuleList map[InnerKey][2]uint8 - CapabilitiesRuleList map[InnerKey][2]uint8 + ProcessRuleList map[InnerKey][2]uint16 + FileRuleList map[InnerKey][2]uint16 + NetworkRuleList map[InnerKey][2]uint16 + CapabilitiesRuleList map[InnerKey][2]uint16 ProcWhiteListPosture bool FileWhiteListPosture bool NetWhiteListPosture bool CapWhiteListPosture bool + ArgumentsList map[ArgListKey][]string } // Init prepares the RuleList object func (r *RuleList) Init() { - r.ProcessRuleList = make(map[InnerKey][2]uint8) + r.ProcessRuleList = make(map[InnerKey][2]uint16) r.ProcWhiteListPosture = false - r.FileRuleList = make(map[InnerKey][2]uint8) + r.FileRuleList = make(map[InnerKey][2]uint16) r.FileWhiteListPosture = false - r.NetworkRuleList = make(map[InnerKey][2]uint8) + r.NetworkRuleList = make(map[InnerKey][2]uint16) r.NetWhiteListPosture = false - r.CapabilitiesRuleList = make(map[InnerKey][2]uint8) + r.CapabilitiesRuleList = make(map[InnerKey][2]uint16) r.CapWhiteListPosture = false + + r.ArgumentsList = make(map[ArgListKey][]string) } // UpdateContainerRules updates individual container map with new rules and resolves conflicting rules @@ -115,13 +119,17 @@ func (be *BPFEnforcer) UpdateContainerRules(id string, securityPolicies []tp.Sec for _, secPolicy := range securityPolicies { for _, path := range secPolicy.Spec.Process.MatchPaths { - var val [2]uint8 + var argKey ArgListKey + var key InnerKey + var val [2]uint16 val[PROCESS] = val[PROCESS] | EXEC if path.OwnerOnly { val[PROCESS] = val[PROCESS] | OWNER } + if len(path.AllowedArgs) > 0 { + val[PROCESS] = val[PROCESS] | ARGSET + } if len(path.FromSource) == 0 { - var key InnerKey if len(path.ExecName) > 0 { copy(key.Path[:], []byte(path.ExecName)) } else { @@ -136,7 +144,6 @@ func (be *BPFEnforcer) UpdateContainerRules(id string, securityPolicies []tp.Sec } } else { for _, src := range path.FromSource { - var key InnerKey if len(path.ExecName) > 0 { copy(key.Path[:], []byte(path.ExecName)) } else { @@ -152,10 +159,18 @@ func (be *BPFEnforcer) UpdateContainerRules(id string, securityPolicies []tp.Sec } } } + if len(path.AllowedArgs) > 0 { + var argList []string + argKey.InnerKey = key + argKey.MntNS = be.ContainerMap[id].Key.MntNS + argKey.PidNS = be.ContainerMap[id].Key.PidNS + argList = append(argList, path.AllowedArgs...) + newrules.ArgumentsList[argKey] = argList + } } for _, dir := range secPolicy.Spec.Process.MatchDirectories { - var val [2]uint8 + var val [2]uint16 val[PROCESS] = val[PROCESS] | EXEC if dir.OwnerOnly { val[PROCESS] = val[PROCESS] | OWNER @@ -187,7 +202,7 @@ func (be *BPFEnforcer) UpdateContainerRules(id string, securityPolicies []tp.Sec } for _, path := range secPolicy.Spec.File.MatchPaths { - var val [2]uint8 + var val [2]uint16 val[FILE] = val[FILE] | READ if path.OwnerOnly { val[FILE] = val[FILE] | OWNER @@ -224,7 +239,7 @@ func (be *BPFEnforcer) UpdateContainerRules(id string, securityPolicies []tp.Sec } for _, dir := range secPolicy.Spec.File.MatchDirectories { - var val [2]uint8 + var val [2]uint16 val[FILE] = val[FILE] | READ if dir.OwnerOnly { val[FILE] = val[FILE] | OWNER @@ -262,14 +277,14 @@ func (be *BPFEnforcer) UpdateContainerRules(id string, securityPolicies []tp.Sec handleAllNetworkRule(&secPolicy.Spec.Network.MatchProtocols) for _, net := range secPolicy.Spec.Network.MatchProtocols { - var val [2]uint8 + var val [2]uint16 var key = InnerKey{Path: [256]byte{}, Source: [256]byte{}} if val, ok := protocols[strings.ToUpper(net.Protocol)]; ok { - key.Path[0] = PROTOCOL - key.Path[1] = val + key.Path[0] = byte(PROTOCOL) + key.Path[1] = byte(val) } else if val, ok := netType[strings.ToUpper(net.Protocol)]; ok { - key.Path[0] = TYPE - key.Path[1] = val + key.Path[0] = byte(TYPE) // doubt here ( should we increase byte array size?? ) + key.Path[1] = byte(val) } if len(net.FromSource) == 0 { @@ -299,7 +314,7 @@ func (be *BPFEnforcer) UpdateContainerRules(id string, securityPolicies []tp.Sec } } for _, capab := range secPolicy.Spec.Capabilities.MatchCapabilities { - var val [2]uint8 + var val [2]uint16 var key = InnerKey{Path: [256]byte{}, Source: [256]byte{}} key.Path[0] = capableKey @@ -351,6 +366,7 @@ func (be *BPFEnforcer) UpdateContainerRules(id string, securityPolicies []tp.Sec return } + // adding deletion logic for arguments here too if be.ContainerMap[id].Map == nil && !(len(newrules.FileRuleList) == 0 && len(newrules.ProcessRuleList) == 0 && len(newrules.NetworkRuleList) == 0 && len(newrules.CapabilitiesRuleList) == 0) { // We create the inner map only when we have policies specific to that be.Logger.Printf("Creating inner map for %s", id) @@ -362,8 +378,10 @@ func (be *BPFEnforcer) UpdateContainerRules(id string, securityPolicies []tp.Sec return } + // resolving rulesset for arguments + // Check for differences in Fresh Rules Set and Existing Ruleset - be.resolveConflicts(newrules.ProcWhiteListPosture, be.ContainerMap[id].Rules.ProcWhiteListPosture, newrules.ProcessRuleList, be.ContainerMap[id].Rules.ProcessRuleList, be.ContainerMap[id].Map) + be.resolveConflictsProcessRules(newrules.ProcessRuleList, be.ContainerMap[id].Rules.ProcessRuleList, be.ContainerMap[id].Map, id, be.ContainerMap[id].Rules.ArgumentsList) be.resolveConflicts(newrules.FileWhiteListPosture, be.ContainerMap[id].Rules.FileWhiteListPosture, newrules.FileRuleList, be.ContainerMap[id].Rules.FileRuleList, be.ContainerMap[id].Map) be.resolveConflicts(newrules.NetWhiteListPosture, be.ContainerMap[id].Rules.NetWhiteListPosture, newrules.NetworkRuleList, be.ContainerMap[id].Rules.NetworkRuleList, be.ContainerMap[id].Map) be.resolveConflicts(newrules.CapWhiteListPosture, be.ContainerMap[id].Rules.CapWhiteListPosture, newrules.CapabilitiesRuleList, be.ContainerMap[id].Rules.CapabilitiesRuleList, be.ContainerMap[id].Map) @@ -380,11 +398,11 @@ func (be *BPFEnforcer) UpdateContainerRules(id string, securityPolicies []tp.Sec if newrules.ProcWhiteListPosture { if defaultPosture.FileAction == "block" { - if err := be.ContainerMap[id].Map.Put(PROCWHITELIST, [2]uint8{BlockPosture}); err != nil { + if err := be.ContainerMap[id].Map.Put(PROCWHITELIST, [2]uint16{BlockPosture}); err != nil { be.Logger.Errf("error adding proc whitelist key rule to map for container %s: %s", id, err) } } else { - if err := be.ContainerMap[id].Map.Put(PROCWHITELIST, [2]uint8{AuditPosture}); err != nil { + if err := be.ContainerMap[id].Map.Put(PROCWHITELIST, [2]uint16{AuditPosture}); err != nil { be.Logger.Errf("error adding proc whitelist key rule to map for container %s: %s", id, err) } } @@ -402,14 +420,26 @@ func (be *BPFEnforcer) UpdateContainerRules(id string, securityPolicies []tp.Sec be.Logger.Errf("error adding rule to map for container %s: %s", id, err) } } + for key, val := range newrules.ArgumentsList { + be.ContainerMap[id].Rules.ArgumentsList[key] = val + for _, arg := range val { + var argKey ArgumentsKey + argKey.InnerKey = key.InnerKey + argKey.NsKey = key.NsKey + copy(argKey.Argument[:], []byte(arg)) + if err := be.BPFArgumentsMap.Put(argKey, uint8(1)); err != nil { + be.Logger.Errf("error adding allowed args map for container %s: %s", id, err) + } + } + } if newrules.FileWhiteListPosture { if defaultPosture.FileAction == "block" { - if err := be.ContainerMap[id].Map.Put(FILEWHITELIST, [2]uint8{BlockPosture}); err != nil { + if err := be.ContainerMap[id].Map.Put(FILEWHITELIST, [2]uint16{BlockPosture}); err != nil { be.Logger.Errf("error adding file whitelist key rule to map for container %s: %s", id, err) } } else { - if err := be.ContainerMap[id].Map.Put(FILEWHITELIST, [2]uint8{AuditPosture}); err != nil { + if err := be.ContainerMap[id].Map.Put(FILEWHITELIST, [2]uint16{AuditPosture}); err != nil { be.Logger.Errf("error adding file whitelist key rule to map for container %s: %s", id, err) } } @@ -429,11 +459,11 @@ func (be *BPFEnforcer) UpdateContainerRules(id string, securityPolicies []tp.Sec if newrules.NetWhiteListPosture { if defaultPosture.NetworkAction == "block" { - if err := be.ContainerMap[id].Map.Put(NETWHITELIST, [2]uint8{BlockPosture}); err != nil { + if err := be.ContainerMap[id].Map.Put(NETWHITELIST, [2]uint16{BlockPosture}); err != nil { be.Logger.Errf("error adding network key rule to map for container %s: %s", id, err) } } else { - if err := be.ContainerMap[id].Map.Put(NETWHITELIST, [2]uint8{AuditPosture}); err != nil { + if err := be.ContainerMap[id].Map.Put(NETWHITELIST, [2]uint16{AuditPosture}); err != nil { be.Logger.Errf("error adding network key rule to map for container %s: %s", id, err) } } @@ -452,11 +482,11 @@ func (be *BPFEnforcer) UpdateContainerRules(id string, securityPolicies []tp.Sec } if newrules.CapWhiteListPosture { if defaultPosture.CapabilitiesAction == "block" { - if err := be.ContainerMap[id].Map.Put(CAPWHITELIST, [2]uint8{BlockPosture}); err != nil { + if err := be.ContainerMap[id].Map.Put(CAPWHITELIST, [2]uint16{BlockPosture}); err != nil { be.Logger.Errf("error adding network key rule to map for container %s: %s", id, err) } } else { - if err := be.ContainerMap[id].Map.Put(CAPWHITELIST, [2]uint8{AuditPosture}); err != nil { + if err := be.ContainerMap[id].Map.Put(CAPWHITELIST, [2]uint16{AuditPosture}); err != nil { be.Logger.Errf("error adding network key rule to map for container %s: %s", id, err) } } @@ -475,7 +505,7 @@ func (be *BPFEnforcer) UpdateContainerRules(id string, securityPolicies []tp.Sec } } -func fuseProcAndFileRules(procList, fileList map[InnerKey][2]uint8) { +func fuseProcAndFileRules(procList, fileList map[InnerKey][2]uint16) { for k, v := range fileList { if val, ok := procList[k]; ok { v[PROCESS] = val[PROCESS] @@ -484,7 +514,22 @@ func fuseProcAndFileRules(procList, fileList map[InnerKey][2]uint8) { } } -func (be *BPFEnforcer) resolveConflicts(newPosture, oldPosture bool, newRuleList, oldRuleList map[InnerKey][2]uint8, cmap *ebpf.Map) { +func (be *BPFEnforcer) resolveConflicts(newPosture, oldPosture bool, newRuleList, oldRuleList map[InnerKey][2]uint16, cmap *ebpf.Map) { + // We delete existing elements which are not in the fresh rule set + for key := range oldRuleList { + if _, ok := newRuleList[key]; !ok { + // Delete Element from Container Map + if err := cmap.Delete(key); err != nil { + if !errors.Is(err, os.ErrNotExist) { + be.Logger.Err(err.Error()) + } + } + delete(oldRuleList, key) + } + } +} +func (be *BPFEnforcer) resolveConflictsProcessRules(newRuleList, oldRuleList map[InnerKey][2]uint16, cmap *ebpf.Map, id string, argListMap map[ArgListKey][]string) { + // We delete existing elements which are not in the fresh rule set for key := range oldRuleList { if _, ok := newRuleList[key]; !ok { @@ -494,13 +539,33 @@ func (be *BPFEnforcer) resolveConflicts(newPosture, oldPosture bool, newRuleList be.Logger.Err(err.Error()) } } + // Deleting Arguments if exists delete(oldRuleList, key) + // deleting the arguments map valus + if len(argListMap) > 0 { + var argKey ArgListKey + argKey.InnerKey = key + argKey.MntNS = be.ContainerMap[id].Key.MntNS + argKey.PidNS = be.ContainerMap[id].Key.PidNS + for _, arg := range argListMap[argKey] { + var bpfArgKey ArgumentsKey + bpfArgKey.InnerKey = argKey.InnerKey + bpfArgKey.NsKey = argKey.NsKey + copy(bpfArgKey.Argument[:], []byte(arg)) + if err := be.BPFArgumentsMap.Delete(bpfArgKey);err!=nil { + be.Logger.Errf("error deleting arguments rules for container %s: %s", id, err) + } + } + delete(argListMap, argKey) + } + } } + } // dirtoMap extracts parent directories from the Path Key and adds it as hints in the Container Rule Map -func dirtoMap(idx int, p, src string, m map[InnerKey][2]uint8, val [2]uint8) { +func dirtoMap(idx int, p, src string, m map[InnerKey][2]uint16, val [2]uint16) { var key InnerKey if src != "" { copy(key.Source[:], []byte(src)) diff --git a/KubeArmor/monitor/systemMonitor.go b/KubeArmor/monitor/systemMonitor.go index 37a9402e93..9d4be340ca 100644 --- a/KubeArmor/monitor/systemMonitor.go +++ b/KubeArmor/monitor/systemMonitor.go @@ -252,6 +252,7 @@ func (mon *SystemMonitor) initBPFMaps() error { } mon.UpdateThrottlingConfig() + mon.UpdateMatchArgsConfig() return errors.Join(errviz, errconfig) } @@ -302,6 +303,19 @@ func (mon *SystemMonitor) UpdateThrottlingConfig() { cfg.GlobalCfg.MaxAlertPerSec, cfg.GlobalCfg.ThrottleSec) } +func (mon *SystemMonitor) UpdateMatchArgsConfig() { + if cfg.GlobalCfg.MatchArgs { + if err := mon.BpfConfigMap.Update(uint32(6), uint32(1), cle.UpdateAny); err != nil { + mon.Logger.Errf("Error Updating System Monitor Config Map to enable argument matching: %s", err.Error()) + } + } else { + if err := mon.BpfConfigMap.Update(uint32(6), uint32(0), cle.UpdateAny); err != nil { + mon.Logger.Errf("Error Updating System Monitor Config Map to enable argument matching : %s", err.Error()) + } + } + + mon.Logger.Printf("Argument matching configured {matchArgs:%v}", cfg.GlobalCfg.AlertThrottling) +} // UpdateNsKeyMap Function func (mon *SystemMonitor) UpdateNsKeyMap(action string, nsKey NsKey, visibility tp.Visibility) { diff --git a/KubeArmor/presets/anonmapexec/anonmapexec_bpfeb.go b/KubeArmor/presets/anonmapexec/anonmapexec_bpfeb.go index 83344849f7..e0cc599f03 100644 --- a/KubeArmor/presets/anonmapexec/anonmapexec_bpfeb.go +++ b/KubeArmor/presets/anonmapexec/anonmapexec_bpfeb.go @@ -12,6 +12,17 @@ import ( "github.com/cilium/ebpf" ) +type anonmapexecArgBufsK struct { + Okey struct { + PidNs uint32 + MntNs uint32 + } + Store anonmapexecBufsK + Arg [256]int8 +} + +type anonmapexecArgVal struct{ ArgsArray [80]int8 } + type anonmapexecBufsK struct { Path [256]int8 Source [256]int8 @@ -19,6 +30,11 @@ type anonmapexecBufsK struct { type anonmapexecBufsT struct{ Buf [32768]int8 } +type anonmapexecCmdArgsKey struct { + Tgid uint64 + Ind uint64 +} + // loadAnonmapexec returns the embedded CollectionSpec for anonmapexec. func loadAnonmapexec() (*ebpf.CollectionSpec, error) { reader := bytes.NewReader(_AnonmapexecBytes) @@ -69,11 +85,15 @@ type anonmapexecProgramSpecs struct { // It can be passed ebpf.CollectionSpec.Assign. type anonmapexecMapSpecs struct { AnonMapExecPresetContainers *ebpf.MapSpec `ebpf:"anon_map_exec_preset_containers"` + ArgsBufk *ebpf.MapSpec `ebpf:"args_bufk"` Bufk *ebpf.MapSpec `ebpf:"bufk"` Bufs *ebpf.MapSpec `ebpf:"bufs"` BufsOff *ebpf.MapSpec `ebpf:"bufs_off"` + CmdArgsBuf *ebpf.MapSpec `ebpf:"cmd_args_buf"` Events *ebpf.MapSpec `ebpf:"events"` KubearmorAlertThrottle *ebpf.MapSpec `ebpf:"kubearmor_alert_throttle"` + KubearmorArgsStore *ebpf.MapSpec `ebpf:"kubearmor_args_store"` + KubearmorArguments *ebpf.MapSpec `ebpf:"kubearmor_arguments"` KubearmorConfig *ebpf.MapSpec `ebpf:"kubearmor_config"` KubearmorContainers *ebpf.MapSpec `ebpf:"kubearmor_containers"` KubearmorEvents *ebpf.MapSpec `ebpf:"kubearmor_events"` @@ -107,11 +127,15 @@ func (o *anonmapexecObjects) Close() error { // It can be passed to loadAnonmapexecObjects or ebpf.CollectionSpec.LoadAndAssign. type anonmapexecMaps struct { AnonMapExecPresetContainers *ebpf.Map `ebpf:"anon_map_exec_preset_containers"` + ArgsBufk *ebpf.Map `ebpf:"args_bufk"` Bufk *ebpf.Map `ebpf:"bufk"` Bufs *ebpf.Map `ebpf:"bufs"` BufsOff *ebpf.Map `ebpf:"bufs_off"` + CmdArgsBuf *ebpf.Map `ebpf:"cmd_args_buf"` Events *ebpf.Map `ebpf:"events"` KubearmorAlertThrottle *ebpf.Map `ebpf:"kubearmor_alert_throttle"` + KubearmorArgsStore *ebpf.Map `ebpf:"kubearmor_args_store"` + KubearmorArguments *ebpf.Map `ebpf:"kubearmor_arguments"` KubearmorConfig *ebpf.Map `ebpf:"kubearmor_config"` KubearmorContainers *ebpf.Map `ebpf:"kubearmor_containers"` KubearmorEvents *ebpf.Map `ebpf:"kubearmor_events"` @@ -120,11 +144,15 @@ type anonmapexecMaps struct { func (m *anonmapexecMaps) Close() error { return _AnonmapexecClose( m.AnonMapExecPresetContainers, + m.ArgsBufk, m.Bufk, m.Bufs, m.BufsOff, + m.CmdArgsBuf, m.Events, m.KubearmorAlertThrottle, + m.KubearmorArgsStore, + m.KubearmorArguments, m.KubearmorConfig, m.KubearmorContainers, m.KubearmorEvents, diff --git a/KubeArmor/presets/anonmapexec/anonmapexec_bpfeb.o b/KubeArmor/presets/anonmapexec/anonmapexec_bpfeb.o index 48053721f4..fdd1e6e6d1 100644 Binary files a/KubeArmor/presets/anonmapexec/anonmapexec_bpfeb.o and b/KubeArmor/presets/anonmapexec/anonmapexec_bpfeb.o differ diff --git a/KubeArmor/presets/anonmapexec/anonmapexec_bpfel.go b/KubeArmor/presets/anonmapexec/anonmapexec_bpfel.go index fcf055fff1..253d4b46b4 100644 --- a/KubeArmor/presets/anonmapexec/anonmapexec_bpfel.go +++ b/KubeArmor/presets/anonmapexec/anonmapexec_bpfel.go @@ -12,6 +12,17 @@ import ( "github.com/cilium/ebpf" ) +type anonmapexecArgBufsK struct { + Okey struct { + PidNs uint32 + MntNs uint32 + } + Store anonmapexecBufsK + Arg [256]int8 +} + +type anonmapexecArgVal struct{ ArgsArray [80]int8 } + type anonmapexecBufsK struct { Path [256]int8 Source [256]int8 @@ -19,6 +30,11 @@ type anonmapexecBufsK struct { type anonmapexecBufsT struct{ Buf [32768]int8 } +type anonmapexecCmdArgsKey struct { + Tgid uint64 + Ind uint64 +} + // loadAnonmapexec returns the embedded CollectionSpec for anonmapexec. func loadAnonmapexec() (*ebpf.CollectionSpec, error) { reader := bytes.NewReader(_AnonmapexecBytes) @@ -69,11 +85,15 @@ type anonmapexecProgramSpecs struct { // It can be passed ebpf.CollectionSpec.Assign. type anonmapexecMapSpecs struct { AnonMapExecPresetContainers *ebpf.MapSpec `ebpf:"anon_map_exec_preset_containers"` + ArgsBufk *ebpf.MapSpec `ebpf:"args_bufk"` Bufk *ebpf.MapSpec `ebpf:"bufk"` Bufs *ebpf.MapSpec `ebpf:"bufs"` BufsOff *ebpf.MapSpec `ebpf:"bufs_off"` + CmdArgsBuf *ebpf.MapSpec `ebpf:"cmd_args_buf"` Events *ebpf.MapSpec `ebpf:"events"` KubearmorAlertThrottle *ebpf.MapSpec `ebpf:"kubearmor_alert_throttle"` + KubearmorArgsStore *ebpf.MapSpec `ebpf:"kubearmor_args_store"` + KubearmorArguments *ebpf.MapSpec `ebpf:"kubearmor_arguments"` KubearmorConfig *ebpf.MapSpec `ebpf:"kubearmor_config"` KubearmorContainers *ebpf.MapSpec `ebpf:"kubearmor_containers"` KubearmorEvents *ebpf.MapSpec `ebpf:"kubearmor_events"` @@ -107,11 +127,15 @@ func (o *anonmapexecObjects) Close() error { // It can be passed to loadAnonmapexecObjects or ebpf.CollectionSpec.LoadAndAssign. type anonmapexecMaps struct { AnonMapExecPresetContainers *ebpf.Map `ebpf:"anon_map_exec_preset_containers"` + ArgsBufk *ebpf.Map `ebpf:"args_bufk"` Bufk *ebpf.Map `ebpf:"bufk"` Bufs *ebpf.Map `ebpf:"bufs"` BufsOff *ebpf.Map `ebpf:"bufs_off"` + CmdArgsBuf *ebpf.Map `ebpf:"cmd_args_buf"` Events *ebpf.Map `ebpf:"events"` KubearmorAlertThrottle *ebpf.Map `ebpf:"kubearmor_alert_throttle"` + KubearmorArgsStore *ebpf.Map `ebpf:"kubearmor_args_store"` + KubearmorArguments *ebpf.Map `ebpf:"kubearmor_arguments"` KubearmorConfig *ebpf.Map `ebpf:"kubearmor_config"` KubearmorContainers *ebpf.Map `ebpf:"kubearmor_containers"` KubearmorEvents *ebpf.Map `ebpf:"kubearmor_events"` @@ -120,11 +144,15 @@ type anonmapexecMaps struct { func (m *anonmapexecMaps) Close() error { return _AnonmapexecClose( m.AnonMapExecPresetContainers, + m.ArgsBufk, m.Bufk, m.Bufs, m.BufsOff, + m.CmdArgsBuf, m.Events, m.KubearmorAlertThrottle, + m.KubearmorArgsStore, + m.KubearmorArguments, m.KubearmorConfig, m.KubearmorContainers, m.KubearmorEvents, diff --git a/KubeArmor/presets/anonmapexec/anonmapexec_bpfel.o b/KubeArmor/presets/anonmapexec/anonmapexec_bpfel.o index fde6afd4cf..d00c122d8f 100644 Binary files a/KubeArmor/presets/anonmapexec/anonmapexec_bpfel.o and b/KubeArmor/presets/anonmapexec/anonmapexec_bpfel.o differ diff --git a/KubeArmor/presets/filelessexec/filelessexec_bpfeb.go b/KubeArmor/presets/filelessexec/filelessexec_bpfeb.go index a30c0e3d5a..89c1a1f4ed 100644 --- a/KubeArmor/presets/filelessexec/filelessexec_bpfeb.go +++ b/KubeArmor/presets/filelessexec/filelessexec_bpfeb.go @@ -12,6 +12,17 @@ import ( "github.com/cilium/ebpf" ) +type filelessexecArgBufsK struct { + Okey struct { + PidNs uint32 + MntNs uint32 + } + Store filelessexecBufsK + Arg [256]int8 +} + +type filelessexecArgVal struct{ ArgsArray [80]int8 } + type filelessexecBufsK struct { Path [256]int8 Source [256]int8 @@ -19,6 +30,11 @@ type filelessexecBufsK struct { type filelessexecBufsT struct{ Buf [32768]int8 } +type filelessexecCmdArgsKey struct { + Tgid uint64 + Ind uint64 +} + // loadFilelessexec returns the embedded CollectionSpec for filelessexec. func loadFilelessexec() (*ebpf.CollectionSpec, error) { reader := bytes.NewReader(_FilelessexecBytes) @@ -68,12 +84,16 @@ type filelessexecProgramSpecs struct { // // It can be passed ebpf.CollectionSpec.Assign. type filelessexecMapSpecs struct { + ArgsBufk *ebpf.MapSpec `ebpf:"args_bufk"` Bufk *ebpf.MapSpec `ebpf:"bufk"` Bufs *ebpf.MapSpec `ebpf:"bufs"` BufsOff *ebpf.MapSpec `ebpf:"bufs_off"` + CmdArgsBuf *ebpf.MapSpec `ebpf:"cmd_args_buf"` Events *ebpf.MapSpec `ebpf:"events"` FilelessExecPresetContainers *ebpf.MapSpec `ebpf:"fileless_exec_preset_containers"` KubearmorAlertThrottle *ebpf.MapSpec `ebpf:"kubearmor_alert_throttle"` + KubearmorArgsStore *ebpf.MapSpec `ebpf:"kubearmor_args_store"` + KubearmorArguments *ebpf.MapSpec `ebpf:"kubearmor_arguments"` KubearmorConfig *ebpf.MapSpec `ebpf:"kubearmor_config"` KubearmorContainers *ebpf.MapSpec `ebpf:"kubearmor_containers"` KubearmorEvents *ebpf.MapSpec `ebpf:"kubearmor_events"` @@ -106,12 +126,16 @@ func (o *filelessexecObjects) Close() error { // // It can be passed to loadFilelessexecObjects or ebpf.CollectionSpec.LoadAndAssign. type filelessexecMaps struct { + ArgsBufk *ebpf.Map `ebpf:"args_bufk"` Bufk *ebpf.Map `ebpf:"bufk"` Bufs *ebpf.Map `ebpf:"bufs"` BufsOff *ebpf.Map `ebpf:"bufs_off"` + CmdArgsBuf *ebpf.Map `ebpf:"cmd_args_buf"` Events *ebpf.Map `ebpf:"events"` FilelessExecPresetContainers *ebpf.Map `ebpf:"fileless_exec_preset_containers"` KubearmorAlertThrottle *ebpf.Map `ebpf:"kubearmor_alert_throttle"` + KubearmorArgsStore *ebpf.Map `ebpf:"kubearmor_args_store"` + KubearmorArguments *ebpf.Map `ebpf:"kubearmor_arguments"` KubearmorConfig *ebpf.Map `ebpf:"kubearmor_config"` KubearmorContainers *ebpf.Map `ebpf:"kubearmor_containers"` KubearmorEvents *ebpf.Map `ebpf:"kubearmor_events"` @@ -119,12 +143,16 @@ type filelessexecMaps struct { func (m *filelessexecMaps) Close() error { return _FilelessexecClose( + m.ArgsBufk, m.Bufk, m.Bufs, m.BufsOff, + m.CmdArgsBuf, m.Events, m.FilelessExecPresetContainers, m.KubearmorAlertThrottle, + m.KubearmorArgsStore, + m.KubearmorArguments, m.KubearmorConfig, m.KubearmorContainers, m.KubearmorEvents, diff --git a/KubeArmor/presets/filelessexec/filelessexec_bpfeb.o b/KubeArmor/presets/filelessexec/filelessexec_bpfeb.o index c7bf294a04..1fc109cd24 100644 Binary files a/KubeArmor/presets/filelessexec/filelessexec_bpfeb.o and b/KubeArmor/presets/filelessexec/filelessexec_bpfeb.o differ diff --git a/KubeArmor/presets/filelessexec/filelessexec_bpfel.go b/KubeArmor/presets/filelessexec/filelessexec_bpfel.go index 16d4182e89..4a97429585 100644 --- a/KubeArmor/presets/filelessexec/filelessexec_bpfel.go +++ b/KubeArmor/presets/filelessexec/filelessexec_bpfel.go @@ -12,6 +12,17 @@ import ( "github.com/cilium/ebpf" ) +type filelessexecArgBufsK struct { + Okey struct { + PidNs uint32 + MntNs uint32 + } + Store filelessexecBufsK + Arg [256]int8 +} + +type filelessexecArgVal struct{ ArgsArray [80]int8 } + type filelessexecBufsK struct { Path [256]int8 Source [256]int8 @@ -19,6 +30,11 @@ type filelessexecBufsK struct { type filelessexecBufsT struct{ Buf [32768]int8 } +type filelessexecCmdArgsKey struct { + Tgid uint64 + Ind uint64 +} + // loadFilelessexec returns the embedded CollectionSpec for filelessexec. func loadFilelessexec() (*ebpf.CollectionSpec, error) { reader := bytes.NewReader(_FilelessexecBytes) @@ -68,12 +84,16 @@ type filelessexecProgramSpecs struct { // // It can be passed ebpf.CollectionSpec.Assign. type filelessexecMapSpecs struct { + ArgsBufk *ebpf.MapSpec `ebpf:"args_bufk"` Bufk *ebpf.MapSpec `ebpf:"bufk"` Bufs *ebpf.MapSpec `ebpf:"bufs"` BufsOff *ebpf.MapSpec `ebpf:"bufs_off"` + CmdArgsBuf *ebpf.MapSpec `ebpf:"cmd_args_buf"` Events *ebpf.MapSpec `ebpf:"events"` FilelessExecPresetContainers *ebpf.MapSpec `ebpf:"fileless_exec_preset_containers"` KubearmorAlertThrottle *ebpf.MapSpec `ebpf:"kubearmor_alert_throttle"` + KubearmorArgsStore *ebpf.MapSpec `ebpf:"kubearmor_args_store"` + KubearmorArguments *ebpf.MapSpec `ebpf:"kubearmor_arguments"` KubearmorConfig *ebpf.MapSpec `ebpf:"kubearmor_config"` KubearmorContainers *ebpf.MapSpec `ebpf:"kubearmor_containers"` KubearmorEvents *ebpf.MapSpec `ebpf:"kubearmor_events"` @@ -106,12 +126,16 @@ func (o *filelessexecObjects) Close() error { // // It can be passed to loadFilelessexecObjects or ebpf.CollectionSpec.LoadAndAssign. type filelessexecMaps struct { + ArgsBufk *ebpf.Map `ebpf:"args_bufk"` Bufk *ebpf.Map `ebpf:"bufk"` Bufs *ebpf.Map `ebpf:"bufs"` BufsOff *ebpf.Map `ebpf:"bufs_off"` + CmdArgsBuf *ebpf.Map `ebpf:"cmd_args_buf"` Events *ebpf.Map `ebpf:"events"` FilelessExecPresetContainers *ebpf.Map `ebpf:"fileless_exec_preset_containers"` KubearmorAlertThrottle *ebpf.Map `ebpf:"kubearmor_alert_throttle"` + KubearmorArgsStore *ebpf.Map `ebpf:"kubearmor_args_store"` + KubearmorArguments *ebpf.Map `ebpf:"kubearmor_arguments"` KubearmorConfig *ebpf.Map `ebpf:"kubearmor_config"` KubearmorContainers *ebpf.Map `ebpf:"kubearmor_containers"` KubearmorEvents *ebpf.Map `ebpf:"kubearmor_events"` @@ -119,12 +143,16 @@ type filelessexecMaps struct { func (m *filelessexecMaps) Close() error { return _FilelessexecClose( + m.ArgsBufk, m.Bufk, m.Bufs, m.BufsOff, + m.CmdArgsBuf, m.Events, m.FilelessExecPresetContainers, m.KubearmorAlertThrottle, + m.KubearmorArgsStore, + m.KubearmorArguments, m.KubearmorConfig, m.KubearmorContainers, m.KubearmorEvents, diff --git a/KubeArmor/presets/filelessexec/filelessexec_bpfel.o b/KubeArmor/presets/filelessexec/filelessexec_bpfel.o index b4b52be773..8aac485b18 100644 Binary files a/KubeArmor/presets/filelessexec/filelessexec_bpfel.o and b/KubeArmor/presets/filelessexec/filelessexec_bpfel.o differ diff --git a/KubeArmor/presets/protectEnv/protectenv_bpfeb.go b/KubeArmor/presets/protectEnv/protectenv_bpfeb.go index e4ef08e6fc..4ef81108e4 100644 --- a/KubeArmor/presets/protectEnv/protectenv_bpfeb.go +++ b/KubeArmor/presets/protectEnv/protectenv_bpfeb.go @@ -12,6 +12,17 @@ import ( "github.com/cilium/ebpf" ) +type protectenvArgBufsK struct { + Okey struct { + PidNs uint32 + MntNs uint32 + } + Store protectenvBufsK + Arg [256]int8 +} + +type protectenvArgVal struct{ ArgsArray [80]int8 } + type protectenvBufsK struct { Path [256]int8 Source [256]int8 @@ -19,6 +30,11 @@ type protectenvBufsK struct { type protectenvBufsT struct{ Buf [32768]int8 } +type protectenvCmdArgsKey struct { + Tgid uint64 + Ind uint64 +} + // loadProtectenv returns the embedded CollectionSpec for protectenv. func loadProtectenv() (*ebpf.CollectionSpec, error) { reader := bytes.NewReader(_ProtectenvBytes) @@ -68,11 +84,15 @@ type protectenvProgramSpecs struct { // // It can be passed ebpf.CollectionSpec.Assign. type protectenvMapSpecs struct { + ArgsBufk *ebpf.MapSpec `ebpf:"args_bufk"` Bufk *ebpf.MapSpec `ebpf:"bufk"` Bufs *ebpf.MapSpec `ebpf:"bufs"` BufsOff *ebpf.MapSpec `ebpf:"bufs_off"` + CmdArgsBuf *ebpf.MapSpec `ebpf:"cmd_args_buf"` Events *ebpf.MapSpec `ebpf:"events"` KubearmorAlertThrottle *ebpf.MapSpec `ebpf:"kubearmor_alert_throttle"` + KubearmorArgsStore *ebpf.MapSpec `ebpf:"kubearmor_args_store"` + KubearmorArguments *ebpf.MapSpec `ebpf:"kubearmor_arguments"` KubearmorConfig *ebpf.MapSpec `ebpf:"kubearmor_config"` KubearmorContainers *ebpf.MapSpec `ebpf:"kubearmor_containers"` KubearmorEvents *ebpf.MapSpec `ebpf:"kubearmor_events"` @@ -106,11 +126,15 @@ func (o *protectenvObjects) Close() error { // // It can be passed to loadProtectenvObjects or ebpf.CollectionSpec.LoadAndAssign. type protectenvMaps struct { + ArgsBufk *ebpf.Map `ebpf:"args_bufk"` Bufk *ebpf.Map `ebpf:"bufk"` Bufs *ebpf.Map `ebpf:"bufs"` BufsOff *ebpf.Map `ebpf:"bufs_off"` + CmdArgsBuf *ebpf.Map `ebpf:"cmd_args_buf"` Events *ebpf.Map `ebpf:"events"` KubearmorAlertThrottle *ebpf.Map `ebpf:"kubearmor_alert_throttle"` + KubearmorArgsStore *ebpf.Map `ebpf:"kubearmor_args_store"` + KubearmorArguments *ebpf.Map `ebpf:"kubearmor_arguments"` KubearmorConfig *ebpf.Map `ebpf:"kubearmor_config"` KubearmorContainers *ebpf.Map `ebpf:"kubearmor_containers"` KubearmorEvents *ebpf.Map `ebpf:"kubearmor_events"` @@ -119,11 +143,15 @@ type protectenvMaps struct { func (m *protectenvMaps) Close() error { return _ProtectenvClose( + m.ArgsBufk, m.Bufk, m.Bufs, m.BufsOff, + m.CmdArgsBuf, m.Events, m.KubearmorAlertThrottle, + m.KubearmorArgsStore, + m.KubearmorArguments, m.KubearmorConfig, m.KubearmorContainers, m.KubearmorEvents, diff --git a/KubeArmor/presets/protectEnv/protectenv_bpfeb.o b/KubeArmor/presets/protectEnv/protectenv_bpfeb.o index 962250e6c8..53a77c509d 100644 Binary files a/KubeArmor/presets/protectEnv/protectenv_bpfeb.o and b/KubeArmor/presets/protectEnv/protectenv_bpfeb.o differ diff --git a/KubeArmor/presets/protectEnv/protectenv_bpfel.go b/KubeArmor/presets/protectEnv/protectenv_bpfel.go index f6d7bc6b7b..c240afb0c2 100644 --- a/KubeArmor/presets/protectEnv/protectenv_bpfel.go +++ b/KubeArmor/presets/protectEnv/protectenv_bpfel.go @@ -12,6 +12,17 @@ import ( "github.com/cilium/ebpf" ) +type protectenvArgBufsK struct { + Okey struct { + PidNs uint32 + MntNs uint32 + } + Store protectenvBufsK + Arg [256]int8 +} + +type protectenvArgVal struct{ ArgsArray [80]int8 } + type protectenvBufsK struct { Path [256]int8 Source [256]int8 @@ -19,6 +30,11 @@ type protectenvBufsK struct { type protectenvBufsT struct{ Buf [32768]int8 } +type protectenvCmdArgsKey struct { + Tgid uint64 + Ind uint64 +} + // loadProtectenv returns the embedded CollectionSpec for protectenv. func loadProtectenv() (*ebpf.CollectionSpec, error) { reader := bytes.NewReader(_ProtectenvBytes) @@ -68,11 +84,15 @@ type protectenvProgramSpecs struct { // // It can be passed ebpf.CollectionSpec.Assign. type protectenvMapSpecs struct { + ArgsBufk *ebpf.MapSpec `ebpf:"args_bufk"` Bufk *ebpf.MapSpec `ebpf:"bufk"` Bufs *ebpf.MapSpec `ebpf:"bufs"` BufsOff *ebpf.MapSpec `ebpf:"bufs_off"` + CmdArgsBuf *ebpf.MapSpec `ebpf:"cmd_args_buf"` Events *ebpf.MapSpec `ebpf:"events"` KubearmorAlertThrottle *ebpf.MapSpec `ebpf:"kubearmor_alert_throttle"` + KubearmorArgsStore *ebpf.MapSpec `ebpf:"kubearmor_args_store"` + KubearmorArguments *ebpf.MapSpec `ebpf:"kubearmor_arguments"` KubearmorConfig *ebpf.MapSpec `ebpf:"kubearmor_config"` KubearmorContainers *ebpf.MapSpec `ebpf:"kubearmor_containers"` KubearmorEvents *ebpf.MapSpec `ebpf:"kubearmor_events"` @@ -106,11 +126,15 @@ func (o *protectenvObjects) Close() error { // // It can be passed to loadProtectenvObjects or ebpf.CollectionSpec.LoadAndAssign. type protectenvMaps struct { + ArgsBufk *ebpf.Map `ebpf:"args_bufk"` Bufk *ebpf.Map `ebpf:"bufk"` Bufs *ebpf.Map `ebpf:"bufs"` BufsOff *ebpf.Map `ebpf:"bufs_off"` + CmdArgsBuf *ebpf.Map `ebpf:"cmd_args_buf"` Events *ebpf.Map `ebpf:"events"` KubearmorAlertThrottle *ebpf.Map `ebpf:"kubearmor_alert_throttle"` + KubearmorArgsStore *ebpf.Map `ebpf:"kubearmor_args_store"` + KubearmorArguments *ebpf.Map `ebpf:"kubearmor_arguments"` KubearmorConfig *ebpf.Map `ebpf:"kubearmor_config"` KubearmorContainers *ebpf.Map `ebpf:"kubearmor_containers"` KubearmorEvents *ebpf.Map `ebpf:"kubearmor_events"` @@ -119,11 +143,15 @@ type protectenvMaps struct { func (m *protectenvMaps) Close() error { return _ProtectenvClose( + m.ArgsBufk, m.Bufk, m.Bufs, m.BufsOff, + m.CmdArgsBuf, m.Events, m.KubearmorAlertThrottle, + m.KubearmorArgsStore, + m.KubearmorArguments, m.KubearmorConfig, m.KubearmorContainers, m.KubearmorEvents, diff --git a/KubeArmor/presets/protectEnv/protectenv_bpfel.o b/KubeArmor/presets/protectEnv/protectenv_bpfel.o index 4eab7ff3d8..83e8fb7b6e 100644 Binary files a/KubeArmor/presets/protectEnv/protectenv_bpfel.o and b/KubeArmor/presets/protectEnv/protectenv_bpfel.o differ diff --git a/KubeArmor/types/types.go b/KubeArmor/types/types.go index 9e66182af1..20f4799f78 100644 --- a/KubeArmor/types/types.go +++ b/KubeArmor/types/types.go @@ -348,10 +348,11 @@ type MatchSourceType struct { // ProcessPathType Structure type ProcessPathType struct { - Path string `json:"path,omitempty"` - ExecName string `json:"execname,omitempty"` - OwnerOnly bool `json:"ownerOnly,omitempty"` - FromSource []MatchSourceType `json:"fromSource,omitempty"` + Path string `json:"path,omitempty"` + ExecName string `json:"execname,omitempty"` + OwnerOnly bool `json:"ownerOnly,omitempty"` + FromSource []MatchSourceType `json:"fromSource,omitempty"` + AllowedArgs []string `json:"allowedArgs,omitempty"` Severity int `json:"severity,omitempty"` Tags []string `json:"tags,omitempty"` diff --git a/README.md b/README.md index 2dbf693261..6817f4231d 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ ![](.gitbook/assets/logo.png) -[![Build Status](https://github.com/kubearmor/KubeArmor/actions/workflows/ci-go.yml/badge.svg)](https://github.com/kubearmor/KubeArmor/actions/workflows/ci-go.yml/) +[![Build Status](https://github.com/kubearmor/KubeArmor/actions/workflows/ci-test-go.yml/badge.svg)](https://github.com/kubearmor/KubeArmor/actions/workflows/ci-test-go.yml/) [![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/5401/badge)](https://bestpractices.coreinfrastructure.org/projects/5401) [![CLOMonitor](https://img.shields.io/endpoint?url=https://clomonitor.io/api/projects/cncf/kubearmor/badge)](https://clomonitor.io/projects/cncf/kubearmor) [![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/kubearmor/kubearmor/badge)](https://securityscorecards.dev/viewer/?uri=github.com/kubearmor/KubeArmor) diff --git a/deployments/CRD/KubeArmorClusterPolicy.yaml b/deployments/CRD/KubeArmorClusterPolicy.yaml index e29ad014cc..f02bfda01e 100644 --- a/deployments/CRD/KubeArmorClusterPolicy.yaml +++ b/deployments/CRD/KubeArmorClusterPolicy.yaml @@ -369,6 +369,11 @@ spec: path: pattern: ^\/+.*[^\/]$ type: string + allowedArgs: + items: + type: string + type: array + maxItems: 16 severity: maximum: 10 minimum: 1 diff --git a/deployments/CRD/KubeArmorHostPolicy.yaml b/deployments/CRD/KubeArmorHostPolicy.yaml index faca51f4da..db79621736 100644 --- a/deployments/CRD/KubeArmorHostPolicy.yaml +++ b/deployments/CRD/KubeArmorHostPolicy.yaml @@ -378,6 +378,11 @@ spec: path: pattern: ^\/+.*[^\/]$ type: string + allowedArgs: + items: + type: string + type: array + maxItems: 16 severity: maximum: 10 minimum: 1 diff --git a/deployments/CRD/KubeArmorPolicy.yaml b/deployments/CRD/KubeArmorPolicy.yaml index 708c7112b8..71966ac74b 100644 --- a/deployments/CRD/KubeArmorPolicy.yaml +++ b/deployments/CRD/KubeArmorPolicy.yaml @@ -372,6 +372,11 @@ spec: path: pattern: ^\/+.*[^\/]$ type: string + allowedArgs: + items: + type: string + type: array + maxItems: 16 severity: maximum: 10 minimum: 1 diff --git a/deployments/get/objects.go b/deployments/get/objects.go index b0068f1381..57a411abc6 100644 --- a/deployments/get/objects.go +++ b/deployments/get/objects.go @@ -829,6 +829,7 @@ func GetKubearmorConfigMap(namespace, name string) *corev1.ConfigMap { data[cfg.ConfigAlertThrottling] = "true" data[cfg.ConfigMaxAlertPerSec] = "10" data[cfg.ConfigThrottleSec] = "30" + data[cfg.ConfigArgMatching] = "true" return &corev1.ConfigMap{ TypeMeta: metav1.TypeMeta{ diff --git a/deployments/helm/KubeArmor/templates/configmap.yaml b/deployments/helm/KubeArmor/templates/configmap.yaml index f4c3b82826..496615a2f5 100644 --- a/deployments/helm/KubeArmor/templates/configmap.yaml +++ b/deployments/helm/KubeArmor/templates/configmap.yaml @@ -7,6 +7,9 @@ data: alertThrottling: {{ .Values.kubearmorConfigMap.alertThrottling | quote }} maxAlertPerSec: {{ .Values.kubearmorConfigMap.maxAlertPerSec | quote }} throttleSec: {{ .Values.kubearmorConfigMap.throttleSec | quote }} + matchArgs: {{ .Values.kubearmorConfigMap.matchArgs | quote }} + + kind: ConfigMap metadata: labels: diff --git a/deployments/helm/KubeArmor/values.yaml b/deployments/helm/KubeArmor/values.yaml index b708306600..29c05c9613 100644 --- a/deployments/helm/KubeArmor/values.yaml +++ b/deployments/helm/KubeArmor/values.yaml @@ -108,6 +108,7 @@ kubearmorConfigMap: alertThrottling: true maxAlertPerSec: 10 throttleSec: 30 + matchArgs: true #volume mounts and volumes kubearmor: diff --git a/deployments/helm/KubeArmorOperator/crds/operator.kubearmor.com_kubearmorconfigs.yaml b/deployments/helm/KubeArmorOperator/crds/operator.kubearmor.com_kubearmorconfigs.yaml index b2622cbbce..d17790d871 100644 --- a/deployments/helm/KubeArmorOperator/crds/operator.kubearmor.com_kubearmorconfigs.yaml +++ b/deployments/helm/KubeArmorOperator/crds/operator.kubearmor.com_kubearmorconfigs.yaml @@ -72,6 +72,8 @@ spec: type: object alertThrottling: type: boolean + matchArgs: + type: boolean defaultCapabilitiesPosture: enum: - audit diff --git a/deployments/helm/KubeArmorOperator/values.yaml b/deployments/helm/KubeArmorOperator/values.yaml index 66aa8afe89..9be9b6e283 100644 --- a/deployments/helm/KubeArmorOperator/values.yaml +++ b/deployments/helm/KubeArmorOperator/values.yaml @@ -58,6 +58,7 @@ kubearmorConfig: alertThrottling: true maxAlertPerSec: 10 throttleSec: 30 + matchArgs: true # DO NOT CHANGE THIS VALUES # changing these values will require code changes with the operator diff --git a/deployments/operator/operator.yaml b/deployments/operator/operator.yaml index 6f37b3d9b7..34c7cc26d9 100644 --- a/deployments/operator/operator.yaml +++ b/deployments/operator/operator.yaml @@ -71,6 +71,8 @@ spec: type: object alertThrottling: type: boolean + matchArgs: + type: boolean defaultCapabilitiesPosture: enum: - audit diff --git a/pkg/KubeArmorController/api/security.kubearmor.com/v1/common.go b/pkg/KubeArmorController/api/security.kubearmor.com/v1/common.go index df8b328cfa..d633ee2118 100644 --- a/pkg/KubeArmorController/api/security.kubearmor.com/v1/common.go +++ b/pkg/KubeArmorController/api/security.kubearmor.com/v1/common.go @@ -31,6 +31,10 @@ type ProcessPathType struct { // +kubebuilder:validation:Optional Path MatchPathType `json:"path,omitempty"` + // +kubebuilder:validation:Optional + // +kubebuilder:validation:MaxItems=16 + AllowedArgs []string `json:"allowedArgs,omitempty"` + // +kubebuilder:validation:Optional ExecName MatchBinType `json:"execname,omitempty"` diff --git a/pkg/KubeArmorController/api/security.kubearmor.com/v1/zz_generated.deepcopy.go b/pkg/KubeArmorController/api/security.kubearmor.com/v1/zz_generated.deepcopy.go index 9e8f336820..b1c25a32a2 100644 --- a/pkg/KubeArmorController/api/security.kubearmor.com/v1/zz_generated.deepcopy.go +++ b/pkg/KubeArmorController/api/security.kubearmor.com/v1/zz_generated.deepcopy.go @@ -762,6 +762,11 @@ func (in *ProcessDirectoryType) DeepCopy() *ProcessDirectoryType { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ProcessPathType) DeepCopyInto(out *ProcessPathType) { *out = *in + if in.AllowedArgs != nil { + in, out := &in.AllowedArgs, &out.AllowedArgs + *out = make([]string, len(*in)) + copy(*out, *in) + } if in.FromSource != nil { in, out := &in.FromSource, &out.FromSource *out = make([]MatchSourceType, len(*in)) diff --git a/pkg/KubeArmorOperator/api/operator.kubearmor.com/v1/kubearmorconfig_types.go b/pkg/KubeArmorOperator/api/operator.kubearmor.com/v1/kubearmorconfig_types.go index 0f5f5b4b64..1509ee17f0 100644 --- a/pkg/KubeArmorOperator/api/operator.kubearmor.com/v1/kubearmorconfig_types.go +++ b/pkg/KubeArmorOperator/api/operator.kubearmor.com/v1/kubearmorconfig_types.go @@ -116,6 +116,8 @@ type KubeArmorConfigSpec struct { Adapters Adapters `json:"adapters,omitempty"` EnableNRI bool `json:"enableNRI,omitempty"` + + MatchArgs bool `json:"matchArgs,omitempty"` } // KubeArmorConfigStatus defines the observed state of KubeArmorConfig diff --git a/pkg/KubeArmorOperator/common/defaults.go b/pkg/KubeArmorOperator/common/defaults.go index 7d0a0d6cb6..a613ddc8bc 100644 --- a/pkg/KubeArmorOperator/common/defaults.go +++ b/pkg/KubeArmorOperator/common/defaults.go @@ -87,6 +87,7 @@ var ( ConfigMaxAlertPerSec string = "maxAlertPerSec" ConfigThrottleSec string = "throttleSec" ConfigEnableNRI string = "enableNRI" + ConfigArgMatching string = "matchArgs" GlobalImagePullSecrets []corev1.LocalObjectReference = []corev1.LocalObjectReference{} GlobalTolerations []corev1.Toleration = []corev1.Toleration{} @@ -152,6 +153,7 @@ var ( AlertThrottling bool = true DefaultMaxAlertPerSec string = "10" DefaultThrottleSec string = "30" + MatchArgs bool = true // recommend policies RecommendedPolicies opv1.RecommendedPolicies = opv1.RecommendedPolicies{ @@ -198,6 +200,7 @@ var ConfigMapData = map[string]string{ ConfigAlertThrottling: "true", ConfigMaxAlertPerSec: "10", ConfigThrottleSec: "30", + ConfigArgMatching: "true", } var ConfigDefaultSeccompEnabled = "false" diff --git a/pkg/KubeArmorOperator/config/crd/bases/operator.kubearmor.com_kubearmorconfigs.yaml b/pkg/KubeArmorOperator/config/crd/bases/operator.kubearmor.com_kubearmorconfigs.yaml index b2622cbbce..d17790d871 100644 --- a/pkg/KubeArmorOperator/config/crd/bases/operator.kubearmor.com_kubearmorconfigs.yaml +++ b/pkg/KubeArmorOperator/config/crd/bases/operator.kubearmor.com_kubearmorconfigs.yaml @@ -72,6 +72,8 @@ spec: type: object alertThrottling: type: boolean + matchArgs: + type: boolean defaultCapabilitiesPosture: enum: - audit diff --git a/pkg/KubeArmorOperator/config/samples/kubearmor-coverage.yaml b/pkg/KubeArmorOperator/config/samples/kubearmor-coverage.yaml index ec67b6b964..30274115d0 100644 --- a/pkg/KubeArmorOperator/config/samples/kubearmor-coverage.yaml +++ b/pkg/KubeArmorOperator/config/samples/kubearmor-coverage.yaml @@ -18,6 +18,7 @@ spec: alertThrottling: false maxAlertPerSec: 10 throttleSec: 30 + matchArgs: true kubearmorImage: image: kubearmor/kubearmor-test:latest imagePullPolicy: Never diff --git a/pkg/KubeArmorOperator/config/samples/kubearmor-test.yaml b/pkg/KubeArmorOperator/config/samples/kubearmor-test.yaml index 22038c4c5c..55ca5545df 100644 --- a/pkg/KubeArmorOperator/config/samples/kubearmor-test.yaml +++ b/pkg/KubeArmorOperator/config/samples/kubearmor-test.yaml @@ -18,6 +18,7 @@ spec: alertThrottling: false maxAlertPerSec: 10 throttleSec: 30 + matchArgs: true kubearmorImage: image: kubearmor/kubearmor:latest imagePullPolicy: Never diff --git a/pkg/KubeArmorOperator/config/samples/sample-config.yml b/pkg/KubeArmorOperator/config/samples/sample-config.yml index 0276db3b69..f9d160dfca 100644 --- a/pkg/KubeArmorOperator/config/samples/sample-config.yml +++ b/pkg/KubeArmorOperator/config/samples/sample-config.yml @@ -21,6 +21,7 @@ spec: alertThrottling: true maxAlertPerSec: 10 throttleSec: 30 + matchArgs: true kubearmorImage: image: kubearmor/kubearmor:stable imagePullPolicy: Always diff --git a/pkg/KubeArmorOperator/internal/controller/cluster.go b/pkg/KubeArmorOperator/internal/controller/cluster.go index e83be03d48..483d7cfc8b 100755 --- a/pkg/KubeArmorOperator/internal/controller/cluster.go +++ b/pkg/KubeArmorOperator/internal/controller/cluster.go @@ -1298,6 +1298,11 @@ func UpdateConfigMapData(config *opv1.KubeArmorConfigSpec) bool { if config.ThrottleSec == 0 { ThrottleSec = common.DefaultThrottleSec } + MatchArgsEnabled := strconv.FormatBool(config.MatchArgs) + if common.ConfigMapData[common.ConfigArgMatching] != MatchArgsEnabled { + common.ConfigMapData[common.ConfigArgMatching] = MatchArgsEnabled + updated = true + } if common.ConfigMapData[common.ConfigThrottleSec] != ThrottleSec { common.ConfigMapData[common.ConfigThrottleSec] = ThrottleSec updated = true diff --git a/tests/k8s_env/ksp/ksp_test.go b/tests/k8s_env/ksp/ksp_test.go index 0673fb5d94..d5b96a01b8 100644 --- a/tests/k8s_env/ksp/ksp_test.go +++ b/tests/k8s_env/ksp/ksp_test.go @@ -691,6 +691,33 @@ var _ = Describe("Ksp", func() { Expect(err).To(BeNil()) Expect(res.Found).To(BeTrue()) }) + It("it can allow certain arguments in process execution", func() { + if strings.Contains(K8sRuntimeEnforcer(), "apparmor") { + Skip("Skipping due to args rule only supported by BPFLSM") + } + err := K8sApplyFile("multiubuntu/ksp-ubuntu-1-allow-proc-args.yaml") + Expect(err).To(BeNil()) + + // Start KubeArmor Logs + err = KarmorLogStart("policy", "multiubuntu", "Process", ub1) + Expect(err).To(BeNil()) + + AssertCommand(ub1, "multiubuntu", []string{"bash", "-c", "python3 -m pydoc"}, + MatchRegexp(".*Permission denied"), true, + ) + + expect := protobuf.Alert{ + PolicyName: "ksp-ubuntu-1-allow-proc-args", + Action: "Block", + Result: "Permission denied", + } + + res, err := KarmorGetTargetAlert(5*time.Second, &expect) + Expect(err).To(BeNil()) + Expect(res.Found).To(BeTrue()) + + //ksp-group-1-allow-proc-args + }) }) diff --git a/tests/k8s_env/ksp/multiubuntu/ksp-ubuntu-1-allow-proc-args.yaml b/tests/k8s_env/ksp/multiubuntu/ksp-ubuntu-1-allow-proc-args.yaml new file mode 100644 index 0000000000..4779f0f88d --- /dev/null +++ b/tests/k8s_env/ksp/multiubuntu/ksp-ubuntu-1-allow-proc-args.yaml @@ -0,0 +1,30 @@ +apiVersion: security.kubearmor.com/v1 +kind: KubeArmorPolicy +metadata: + name: ksp-ubuntu-1-allow-proc-args + namespace: multiubuntu +spec: + severity: 5 + message: "block all arguments except allowedArgs" + selector: + matchLabels: + container: ubuntu-1 + process: + matchPaths: + - path: /usr/bin/python3.6 + allowedArgs: + - -m + - random + action: + Block + +# multiubuntu_test_12 + +# test +# python -m random +# allowed +# python -m pydoc +# permission denied +# python +# permission denied +