Skip to content

Commit

Permalink
handle sctp and add option all to handle all network ops
Browse files Browse the repository at this point in the history
Signed-off-by: rksharma95 <[email protected]>
  • Loading branch information
rksharma95 authored and daemon1024 committed Nov 25, 2024
1 parent a86f306 commit cd488cd
Show file tree
Hide file tree
Showing 26 changed files with 522 additions and 244 deletions.
78 changes: 59 additions & 19 deletions KubeArmor/BPF/enforcer.bpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -310,8 +310,8 @@ static inline int match_net_rules(int type, int protocol, u32 eventID) {
return 0;

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

Expand All @@ -329,41 +329,80 @@ static inline int match_net_rules(int type, int protocol, u32 eventID) {
if (src_offset == NULL)
fromSourceCheck = false;

void *ptr = &src_buf->buf[*src_offset];

// socket type check
if (type == SOCK_STREAM || type == SOCK_DGRAM || type == SOCK_RAW || type == SOCK_RDM || type == SOCK_SEQPACKET || type == SOCK_DCCP || type == SOCK_PACKET) {
p0_t = sock_type;
p1_t = type;
}

// protocol check
if (type == SOCK_STREAM && (protocol == IPPROTO_TCP || protocol == 0)) {
p0 = sock_proto;
p1 = IPPROTO_TCP;
p0_p = sock_proto;
p1_p = IPPROTO_TCP;
} else if (type == SOCK_DGRAM && (protocol == IPPROTO_UDP || protocol == 0)) {
p0 = sock_proto;
p1 = IPPROTO_UDP;
p0_p = sock_proto;
p1_p = IPPROTO_UDP;
} else if (protocol == IPPROTO_ICMP &&
(type == SOCK_DGRAM || type == SOCK_RAW)) {
p0 = sock_proto;
p1 = IPPROTO_ICMP;
} else if (type == SOCK_RAW && protocol == 0) {
p0 = sock_type;
p1 = SOCK_RAW;
p0_p = sock_proto;
p1_p = IPPROTO_ICMP;
} else if (protocol == IPPROTO_ICMPV6 &&
(type == SOCK_DGRAM || type == SOCK_RAW)) {
p0_p = sock_proto;
p1_p = IPPROTO_ICMPV6;
} else if ((type == SOCK_STREAM || type == SOCK_SEQPACKET) && (protocol == IPPROTO_SCTP || protocol == 0)) {
p0_p = sock_proto;
p1_p = IPPROTO_SCTP;
} else {
p0 = sock_proto;
p1 = protocol;
p0_p = sock_proto;
p1_p = protocol;
}

// socket type fromsource check
if (fromSourceCheck) {
void *ptr = &src_buf->buf[*src_offset];
bpf_probe_read_str(p->source, MAX_STRING_SIZE, ptr);
p->path[0] = p0;
p->path[1] = p1;
p->path[0] = p0_t;
p->path[1] = p1_t;
bpf_probe_read_str(store->source, MAX_STRING_SIZE, p->source);
val = bpf_map_lookup_elem(inner, p);
if (val) {
match = true;
goto decision;
}
}

// protocol fromsource check
if (fromSourceCheck) {
void *ptr = &src_buf->buf[*src_offset];
bpf_probe_read_str(p->source, MAX_STRING_SIZE, ptr);
p->path[0] = p0_p;
p->path[1] = p1_p;
bpf_probe_read_str(store->source, MAX_STRING_SIZE, p->source);
val = bpf_map_lookup_elem(inner, p);
if (val) {
match = true;
goto decision;
}
}
// check for rules without fromSource

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

val = bpf_map_lookup_elem(inner, p);

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

// check for protocol rules without fromSource
bpf_map_update_elem(&bufk, &one, z, BPF_ANY);
p->path[0] = p0_p;
p->path[1] = p1_p;

val = bpf_map_lookup_elem(inner, p);

Expand Down Expand Up @@ -425,6 +464,7 @@ static inline int match_net_rules(int type, int protocol, u32 eventID) {

SEC("lsm/socket_create")
int BPF_PROG(enforce_net_create, int family, int type, int protocol) {
bpf_printk("type: %d protocol: %d", type, protocol);
return match_net_rules(type, protocol, _SOCKET_CREATE);
}

Expand Down
4 changes: 4 additions & 0 deletions KubeArmor/BPF/shared.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ char LICENSE[] SEC("license") = "Dual BSD/GPL";
#define BLOCK_POSTURE 141
#define CAPABLE_KEY 200

enum {
IPPROTO_ICMPV6 = 58
};

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

enum deny_by_default {
Expand Down
17 changes: 13 additions & 4 deletions KubeArmor/enforcer/appArmorProfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -231,14 +231,21 @@ func (ae *AppArmorEnforcer) SetNetworkMatchProtocols(proto tp.NetworkProtocolTyp
//forcing the protocol to lowercase
proto.Protocol = strings.ToLower(proto.Protocol)

// handle icmpv6 protocol same as icmp
if proto.Protocol == "icmpv6" {
proto.Protocol = "icmp"
}

if !deny {
prof.Network = head
}
rule := RuleConfig{}
rule.Deny = deny
rule.Allow = !deny
if len(proto.FromSource) == 0 {
addRuletoMap(rule, proto.Protocol, prof.NetworkRules)
if proto.Protocol != "all" {
addRuletoMap(rule, proto.Protocol, prof.NetworkRules)
}
return
}

Expand All @@ -260,7 +267,9 @@ func (ae *AppArmorEnforcer) SetNetworkMatchProtocols(proto tp.NetworkProtocolTyp
prof.FromSource[source] = val
}
}
addRuletoMap(rule, proto.Protocol, prof.FromSource[source].NetworkRules)
if proto.Protocol != "all" {
addRuletoMap(rule, proto.Protocol, prof.FromSource[source].NetworkRules)
}
}
}

Expand Down Expand Up @@ -382,9 +391,9 @@ func (ae *AppArmorEnforcer) GenerateProfileBody(securityPolicies []tp.SecurityPo
if len(secPolicy.Spec.Network.MatchProtocols) > 0 {
for _, proto := range secPolicy.Spec.Network.MatchProtocols {
if proto.Action == "Allow" {
ae.SetNetworkMatchProtocols(proto, &profile, false, defaultPosture.NetworkAction != "block")
ae.SetNetworkMatchProtocols(proto, &profile, false, defaultPosture.NetworkAction != "block" || proto.Protocol == "all")
} else if proto.Action == "Block" {
ae.SetNetworkMatchProtocols(proto, &profile, true, true)
ae.SetNetworkMatchProtocols(proto, &profile, true, true && proto.Protocol != "all")
}
}
}
Expand Down
10 changes: 7 additions & 3 deletions KubeArmor/enforcer/bpflsm/enforcer.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,12 @@ func NewBPFEnforcer(node tp.Node, pinpath string, logger *fd.Feeder, monitor *mo
PinPath: pinpath,
},
}); err != nil {
var ve *ebpf.VerifierError
if errors.As(err, &ve) {
// Using %+v will print the whole verifier error, not just the last
// few lines.
be.Logger.Errf("Verifier error: %+v", ve)
}
be.Logger.Errf("error loading BPF LSM objects: %v", err)
return be, err
}
Expand Down Expand Up @@ -351,9 +357,7 @@ func (be *BPFEnforcer) TraceEvents() {
sockProtocol = int32(event.Data.Path[1])
log.Operation = "Network"
if event.Data.Path[0] == 2 {
if event.Data.Path[1] == 3 {
log.Resource = fd.GetProtocolFromName("raw")
}
log.Resource = fd.GetProtocolFromType(int32(event.Data.Path[1]))
} else if event.Data.Path[0] == 3 {
log.Resource = fd.GetProtocolFromName(mon.GetProtocol(sockProtocol))
}
Expand Down
12 changes: 11 additions & 1 deletion KubeArmor/enforcer/bpflsm/rulesHandling.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,18 @@ var protocols = map[string]uint8{
"TCP": 6,
"UDP": 17,
"ICMPv6": 58,
"SCTP": 132,
}

// Socket Type Identifiers for Network Rules
var netType = map[string]uint8{
"RAW": 3,
"STREAM": 1,
"DGRAM": 2,
"RAW": 3,
"RDM": 4,
"SEQPACKET": 5,
"DCCP": 6,
"PACKET": 10,
}

// Array Keys for Network Rule Keys
Expand Down Expand Up @@ -251,6 +258,9 @@ func (be *BPFEnforcer) UpdateContainerRules(id string, securityPolicies []tp.Sec
}
}

// handle protocol: all|ALL rules
handleAllNetworkRule(&secPolicy.Spec.Network.MatchProtocols)

for _, net := range secPolicy.Spec.Network.MatchProtocols {
var val [2]uint8
var key = InnerKey{Path: [256]byte{}, Source: [256]byte{}}
Expand Down
90 changes: 90 additions & 0 deletions KubeArmor/enforcer/bpflsm/rulesHelper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2022 Authors of KubeArmor

package bpflsm

import (
"strings"

tp "github.com/kubearmor/KubeArmor/KubeArmor/types"
)

func handleAllNetworkRule(protocols *[]tp.NetworkProtocolType) {
allProtocols := []tp.NetworkProtocolType{}

allWithNoFromSourceAllow := false
allWithNoFromSourceBlock := false

sourcesBlock := map[string]string{}
sourcesAllow := map[string]string{}

for _, net := range *protocols {
if strings.ToUpper(net.Protocol) == "ALL" {
if len(net.FromSource) == 0 {
if net.Action == "Allow" && !allWithNoFromSourceAllow {
for r := range netType {
allProtocols = append(allProtocols, tp.NetworkProtocolType{
Protocol: r,
Action: net.Action,
})
}
allWithNoFromSourceAllow = true
} else if net.Action == "Block" && !allWithNoFromSourceBlock {
for r := range netType {
allProtocols = append(allProtocols, tp.NetworkProtocolType{
Protocol: r,
Action: net.Action,
})
}
allWithNoFromSourceBlock = true
}
} else {
for _, src := range net.FromSource {
if _, ok := sourcesAllow[src.Path]; !ok && net.Action == "Allow" {
sourcesAllow[src.Path] = net.Action
}
if _, ok := sourcesBlock[src.Path]; !ok && net.Action == "Block" {
sourcesBlock[src.Path] = net.Action
}
}
}
}
}

// add all with fromsource rules

if len(sourcesAllow) > 0 {
sources := []tp.MatchSourceType{}
for src := range sourcesAllow {
sources = append(sources, tp.MatchSourceType{
Path: src,
})
}
for r := range netType {
allProtocols = append(allProtocols, tp.NetworkProtocolType{
Protocol: r,
Action: "Allow",
FromSource: sources,
})
}
}

if len(sourcesBlock) > 0 {
sources := []tp.MatchSourceType{}
for src := range sourcesBlock {
sources = append(sources, tp.MatchSourceType{
Path: src,
})
}
for r := range netType {
allProtocols = append(allProtocols, tp.NetworkProtocolType{
Protocol: r,
Action: "Block",
FromSource: sources,
})
}
}

*protocols = append(*protocols, allProtocols...)

}
50 changes: 44 additions & 6 deletions KubeArmor/feeder/policyMatcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,33 @@ func GetProtocolFromName(proto string) string {
return "protocol=UDP,type=SOCK_DGRAM"
case "icmp":
return "protocol=ICMP,type=SOCK_RAW"
case "raw":
case "icmpv6":
return "protocol=ICMPv6,type=SOCK_RAW"
case "sctp":
return "protocol=SCTP,type=SOCK_STREAM|SOCK_SEQPACKET"
default:
return proto
}
}

func GetProtocolFromType(proto int32) string {
switch proto {
case 1:
return "type=SOCK_STREAM"
case 2:
return "type=SOCK_DGRAM"
case 3:
return "type=SOCK_RAW"
case 4:
return "type=SOCK_RDM"
case 5:
return "type=SOCK_SEQPACKET"
case 6:
return "type=SOCK_DCCP"
case 10:
return "type=SOCK_PACKET"
default:
return "unknown"
return string(proto)
}
}

Expand All @@ -44,9 +67,24 @@ func fetchProtocol(resource string) string {
return "icmp"
} else if strings.Contains(resource, "SOCK_RAW") {
return "raw"
} else if strings.Contains(resource, "protocol=ICMPv6") {
return "icmpv6"
} else if strings.Contains(resource, "protocol=SCTP") {
return "sctp"
} else if strings.Contains(resource, "SOCK_STREAM") {
return "stream"
} else if strings.Contains(resource, "SOCK_DGRAM") {
return "dgram"
} else if strings.Contains(resource, "SOCK_RDM") {
return "rdm"
} else if strings.Contains(resource, "SOCK_SEQPACKET") {
return "seqpacket"
} else if strings.Contains(resource, "SOCK_DCCP") {
return "dccp"
} else if strings.Contains(resource, "SOCK_PACKET") {
return "packet"
}

return "unknown"
return resource
}

func getFileProcessUID(path string) string {
Expand Down Expand Up @@ -204,7 +242,7 @@ func (fd *Feeder) newMatchPolicy(policyEnabled int, policyName, src string, mp i
match.Message = npt.Message

match.Operation = "Network"
match.Resource = npt.Protocol
match.Resource = strings.ToLower(npt.Protocol)
match.ResourceType = "Protocol"

// TODO: Handle cases where AppArmor network enforcement is not present
Expand Down Expand Up @@ -1303,7 +1341,7 @@ func (fd *Feeder) UpdateMatchedPolicy(log tp.Log) tp.Log {
matchedFlags := false

protocol := fetchProtocol(log.Resource)
if protocol == secPolicy.Resource {
if protocol == secPolicy.Resource || secPolicy.Resource == "all" {
matchedFlags = true
}

Expand Down
Loading

0 comments on commit cd488cd

Please sign in to comment.