Skip to content

Commit

Permalink
Merge pull request #1543 from Aryan-sharma11/enforc_cap
Browse files Browse the repository at this point in the history
feat: Add capabilities support for BPFLSM
  • Loading branch information
daemon1024 authored Feb 13, 2024
2 parents 69bb4a1 + 042783d commit d12c30f
Show file tree
Hide file tree
Showing 18 changed files with 555 additions and 13 deletions.
127 changes: 127 additions & 0 deletions KubeArmor/BPF/enforcer.bpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -435,4 +435,131 @@ int BPF_PROG(enforce_file_perm, struct file *file, int mask) {

struct path f_path = BPF_CORE_READ(file, f_path);
return match_and_enforce_path_hooks(&f_path, dfilewrite, _FILE_PERMISSION);
}
SEC("lsm/capable")
int BPF_PROG(enforce_cap, const struct cred *cred, struct user_namespace *ns ,int cap, int ret){

event *task_info;
int retval = 0;

struct task_struct *t = (struct task_struct *)bpf_get_current_task();

bool match = false;

struct outer_key okey;
get_outer_key(&okey, t);

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

if (!inner) {
return 0;
}

u32 zero = 0;
bufs_k *z = bpf_map_lookup_elem(&bufk, &zero);
if (z == NULL)
return 0;

u32 one = 1;
bufs_k *p = bpf_map_lookup_elem(&bufk, &one);
if (p == NULL)
return 0;

u32 two = 2;
bufs_k *store = bpf_map_lookup_elem(&bufk, &two);
if (store == NULL)
return 0;

bpf_map_update_elem(&bufk, &one, z, BPF_ANY);
int p0;
int p1;
struct data_t *val = bpf_map_lookup_elem(inner, p);
bool fromSourceCheck = true;

struct file *file_p = get_task_file(t);
if (file_p == NULL)
fromSourceCheck = false;
bufs_t *src_buf = get_buf(PATH_BUFFER);
if (src_buf == NULL)
fromSourceCheck = false;
struct path f_src = BPF_CORE_READ(file_p, f_path);
if (!prepend_path(&f_src, src_buf))
fromSourceCheck = false;

u32 *src_offset = get_buf_off(PATH_BUFFER);
if (src_offset == NULL)
fromSourceCheck = false;

void *ptr = &src_buf->buf[*src_offset];
p0 = CAPABLE_KEY;
p1 = cap;

if (fromSourceCheck) {
bpf_probe_read_str(p->source, MAX_STRING_SIZE, ptr);
bpf_probe_read_str(store->source, MAX_STRING_SIZE, p->source);
p->path[0] = p0 ;
p->path[1] = p1 ;
val = bpf_map_lookup_elem(inner, p);

if (val) {
match = true;
goto decision;
}
}

bpf_map_update_elem(&bufk, &one, z, BPF_ANY);
// check for rules without fromsource
p->path[0] = p0;
p->path[1] = p1;

val = bpf_map_lookup_elem(inner, p);

if (val) {
match = true;
goto decision;
}

decision:
bpf_probe_read_str(store->path, MAX_STRING_SIZE, p->path);
if (match) {
if (val && (val->processmask & RULE_DENY)) {
retval = -EPERM;
goto ringbuf;
}
}

bpf_map_update_elem(&bufk, &one, z, BPF_ANY);
p->path[0] = dcap;
struct data_t *allow = bpf_map_lookup_elem(inner, p);

if (allow) {
if (!match) {
if (allow->processmask == BLOCK_POSTURE) {
retval = -EPERM;
}
goto ringbuf;
}
}

return 0;

ringbuf:
task_info = bpf_ringbuf_reserve(&kubearmor_events, sizeof(event), 0);
if (!task_info) {
return retval;
}
// Clearing arrays to avoid garbage values to be parsed
__builtin_memset(task_info->data.path, 0, sizeof(task_info->data.path));
__builtin_memset(task_info->data.source, 0, sizeof(task_info->data.source));

init_context(task_info);
bpf_probe_read_str(&task_info->data.path, MAX_STRING_SIZE, store->path);
bpf_probe_read_str(&task_info->data.source, MAX_STRING_SIZE, store->source);

task_info->event_id = _CAPABLE;

task_info->retval = retval;
bpf_ringbuf_submit(task_info, 0);
return retval;

}
4 changes: 3 additions & 1 deletion KubeArmor/BPF/shared.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,15 @@ char LICENSE[] SEC("license") = "Dual BSD/GPL";
#define TASK_COMM_LEN 80
#define AUDIT_POSTURE 140
#define BLOCK_POSTURE 141
#define CAPABLE_KEY 200

enum file_hook_type { dpath = 0, dfileread, dfilewrite };

enum deny_by_default {
dproc = 101,
dfile,
dnet
dnet,
dcap
}; // check if the list is whitelist/blacklist
enum network_check_type {
sock_type = 2,
Expand Down
3 changes: 3 additions & 0 deletions KubeArmor/BPF/syscalls.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ enum
//process
_SECURITY_BPRM_CHECK = 352,

// capabilities
_CAPABLE = 464,


};
#endif /* __SYSCALLS_H */
10 changes: 10 additions & 0 deletions KubeArmor/enforcer/bpflsm/enforcer.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,11 @@ func NewBPFEnforcer(node tp.Node, pinpath string, logger *fd.Feeder, monitor *mo
be.Logger.Errf("opening lsm %s: %s", be.obj.EnforceNetAccept.String(), err)
return be, err
}
be.Probes[be.obj.EnforceCap.String()], err = link.AttachLSM(link.LSMOptions{Program: be.obj.EnforceCap})
if err != nil {
be.Logger.Errf("opening lsm %s: %s", be.obj.EnforceCap.String(), err)
return be, err
}

/*
Path Hooks
Expand Down Expand Up @@ -338,6 +343,11 @@ func (be *BPFEnforcer) TraceEvents() {
log.Source = string(bytes.Trim(event.Data.Source[:], "\x00"))
log.Resource = string(bytes.Trim(event.Data.Path[:], "\x00"))
log.Data = "lsm=" + mon.GetSyscallName(int32(event.EventID))

case mon.Capable:
log.Operation = "Capabilities"
log.Resource = mon.Capabilities[int32(event.Data.Path[1])]
log.Data = "lsm=" + mon.GetSyscallName(int32(event.EventID)) + " " + log.Resource
}
// fallback logic if we don't receive source from BuildLogBase()
if len(log.Source) == 0 {
Expand Down
3 changes: 3 additions & 0 deletions KubeArmor/enforcer/bpflsm/enforcer_bpfeb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file modified KubeArmor/enforcer/bpflsm/enforcer_bpfeb.o
Binary file not shown.
3 changes: 3 additions & 0 deletions KubeArmor/enforcer/bpflsm/enforcer_bpfel.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file modified KubeArmor/enforcer/bpflsm/enforcer_bpfel.o
Binary file not shown.
Binary file modified KubeArmor/enforcer/bpflsm/enforcer_path_bpfeb.o
Binary file not shown.
Binary file modified KubeArmor/enforcer/bpflsm/enforcer_path_bpfel.o
Binary file not shown.
85 changes: 80 additions & 5 deletions KubeArmor/enforcer/bpflsm/rulesHandling.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"strings"

"github.com/cilium/ebpf"
mon "github.com/kubearmor/KubeArmor/KubeArmor/monitor"
tp "github.com/kubearmor/KubeArmor/KubeArmor/types"
)

Expand All @@ -26,9 +27,10 @@ const (

// Data Index for rules
const (
PROCESS = 0
FILE = 1
NETWORK = 0
PROCESS = 0
FILE = 1
NETWORK = 0
CAPABILITIES = 0
)

// values for posture and retval
Expand All @@ -42,6 +44,7 @@ var (
PROCWHITELIST = InnerKey{Path: [256]byte{101}}
FILEWHITELIST = InnerKey{Path: [256]byte{102}}
NETWHITELIST = InnerKey{Path: [256]byte{103}}
CAPWHITELIST = InnerKey{Path: [256]byte{104}}
)

// Protocol Identifiers for Network Rules
Expand All @@ -64,14 +67,19 @@ const (
PROTOCOL uint8 = 3
)

// Key for mapping capabilities in bpf maps
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
ProcWhiteListPosture bool
FileWhiteListPosture bool
NetWhiteListPosture bool
CapWhiteListPosture bool
}

// Init prepares the RuleList object
Expand All @@ -84,6 +92,9 @@ func (r *RuleList) Init() {

r.NetworkRuleList = make(map[InnerKey][2]uint8)
r.NetWhiteListPosture = false

r.CapabilitiesRuleList = make(map[InnerKey][2]uint8)
r.CapWhiteListPosture = false
}

// UpdateContainerRules updates individual container map with new rules and resolves conflicting rules
Expand Down Expand Up @@ -272,6 +283,45 @@ func (be *BPFEnforcer) UpdateContainerRules(id string, securityPolicies []tp.Sec
}
}
}
for _, capab := range secPolicy.Spec.Capabilities.MatchCapabilities {
var val [2]uint8
var key = InnerKey{Path: [256]byte{}, Source: [256]byte{}}

key.Path[0] = capableKey

// this will support both ( CAP_NET_RAW and NET_RAW ) format type
if !strings.Contains(capab.Capability, "cap_") {
key.Path[1] = mon.CapToCode["CAP_"+strings.ToUpper(capab.Capability)]
} else {
key.Path[1] = mon.CapToCode[strings.ToUpper(capab.Capability)]
}

if len(capab.FromSource) == 0 {
if capab.Action == "Allow" {
newrules.CapWhiteListPosture = true
newrules.CapabilitiesRuleList[key] = val

} else if capab.Action == "Block" {
val[CAPABILITIES] = val[CAPABILITIES] | DENY
newrules.CapabilitiesRuleList[key] = val
}
} else {
for _, src := range capab.FromSource {
var source [256]byte
copy(source[:], []byte(src.Path))
key.Source = source
if capab.Action == "Allow" {
newrules.CapWhiteListPosture = true
newrules.CapabilitiesRuleList[key] = val

} else if capab.Action == "Block" {
val[CAPABILITIES] = val[CAPABILITIES] | DENY
newrules.CapabilitiesRuleList[key] = val
}

}
}
}
}

fuseProcAndFileRules(newrules.ProcessRuleList, newrules.FileRuleList)
Expand All @@ -286,11 +336,11 @@ func (be *BPFEnforcer) UpdateContainerRules(id string, securityPolicies []tp.Sec
return
}

if be.ContainerMap[id].Map == nil && !(len(newrules.FileRuleList) == 0 && len(newrules.ProcessRuleList) == 0 && len(newrules.NetworkRuleList) == 0) {
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)
be.CreateContainerInnerMap(id)
} else if len(newrules.FileRuleList) == 0 && len(newrules.ProcessRuleList) == 0 && len(newrules.NetworkRuleList) == 0 {
} else if len(newrules.FileRuleList) == 0 && len(newrules.ProcessRuleList) == 0 && len(newrules.NetworkRuleList) == 0 && len(newrules.CapabilitiesRuleList) == 0 {
// All Policies removed for the container
be.Logger.Printf("Deleting inner map for %s", id)
be.DeleteContainerInnerMap(id)
Expand All @@ -301,12 +351,14 @@ func (be *BPFEnforcer) UpdateContainerRules(id string, securityPolicies []tp.Sec
be.resolveConflicts(newrules.ProcWhiteListPosture, be.ContainerMap[id].Rules.ProcWhiteListPosture, newrules.ProcessRuleList, be.ContainerMap[id].Rules.ProcessRuleList, be.ContainerMap[id].Map)
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)

// Update Posture
if list, ok := be.ContainerMap[id]; ok {
list.Rules.ProcWhiteListPosture = newrules.ProcWhiteListPosture
list.Rules.FileWhiteListPosture = newrules.FileWhiteListPosture
list.Rules.NetWhiteListPosture = newrules.NetWhiteListPosture
list.Rules.CapWhiteListPosture = newrules.CapWhiteListPosture

be.ContainerMap[id] = list
}
Expand Down Expand Up @@ -383,6 +435,29 @@ func (be *BPFEnforcer) UpdateContainerRules(id string, securityPolicies []tp.Sec
be.Logger.Errf("error adding rule to map for container %s: %s", id, err)
}
}
if newrules.CapWhiteListPosture {
if defaultPosture.CapabilitiesAction == "block" {
if err := be.ContainerMap[id].Map.Put(CAPWHITELIST, [2]uint8{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 {
be.Logger.Errf("error adding network key rule to map for container %s: %s", id, err)
}
}
} else {
if err := be.ContainerMap[id].Map.Delete(CAPWHITELIST); err != nil {
if !errors.Is(err, os.ErrNotExist) {
be.Logger.Err(err.Error())
}
}
}
for key, val := range newrules.CapabilitiesRuleList {
be.ContainerMap[id].Rules.CapabilitiesRuleList[key] = val
if err := be.ContainerMap[id].Map.Put(key, val); err != nil {
be.Logger.Errf("error adding rule to map for container %s: %s", id, err)
}
}
}

func fuseProcAndFileRules(procList, fileList map[InnerKey][2]uint8) {
Expand Down
Loading

0 comments on commit d12c30f

Please sign in to comment.