Skip to content

Commit

Permalink
fix raw packet support check
Browse files Browse the repository at this point in the history
  • Loading branch information
safchain committed Nov 22, 2024
1 parent 230f5fa commit ad94a25
Show file tree
Hide file tree
Showing 8 changed files with 150 additions and 19 deletions.
6 changes: 3 additions & 3 deletions pkg/security/ebpf/probes/all.go
Original file line number Diff line number Diff line change
Expand Up @@ -252,14 +252,14 @@ func AllRingBuffers() []*manager.RingBuffer {
}

// AllTailRoutes returns the list of all the tail call routes
func AllTailRoutes(ERPCDentryResolutionEnabled, networkEnabled, supportMmapableMaps bool) []manager.TailCallRoute {
func AllTailRoutes(eRPCDentryResolutionEnabled, networkEnabled, rawPacketEnabled, supportMmapableMaps bool) []manager.TailCallRoute {
var routes []manager.TailCallRoute

routes = append(routes, getExecTailCallRoutes()...)
routes = append(routes, getDentryResolverTailCallRoutes(ERPCDentryResolutionEnabled, supportMmapableMaps)...)
routes = append(routes, getDentryResolverTailCallRoutes(eRPCDentryResolutionEnabled, supportMmapableMaps)...)
routes = append(routes, getSysExitTailCallRoutes()...)
if networkEnabled {
routes = append(routes, getTCTailCallRoutes()...)
routes = append(routes, getTCTailCallRoutes(rawPacketEnabled)...)
}

return routes
Expand Down
4 changes: 2 additions & 2 deletions pkg/security/ebpf/probes/rawpacket/pcap.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,8 +163,8 @@ func filtersToProgs(filters []Filter, opts ProgOpts, headerInsts, senderInsts as
return progInsts, mErr
}

// TCFiltersToProgramSpecs returns list of program spec from raw packet filters definitions
func TCFiltersToProgramSpecs(rawPacketEventMapFd, clsRouterMapFd int, filters []Filter, opts ProgOpts) ([]*ebpf.ProgramSpec, error) {
// FiltersToProgramSpecs returns list of program spec from raw packet filters definitions
func FiltersToProgramSpecs(rawPacketEventMapFd, clsRouterMapFd int, filters []Filter, opts ProgOpts) ([]*ebpf.ProgramSpec, error) {
var mErr *multierror.Error

const (
Expand Down
4 changes: 2 additions & 2 deletions pkg/security/ebpf/probes/rawpacket/pcap_unsupported.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func BPFFilterToInsts(_ int, _ string, _ ProgOpts) (asm.Instructions, error) {
return asm.Instructions{}, errors.New("not supported")
}

// TCFiltersToProgramSpecs returns list of program spec from raw packet filters definitions
func TCFiltersToProgramSpecs(_, _ int, _ []Filter, _ ProgOpts) ([]*ebpf.ProgramSpec, error) {
// FiltersToProgramSpecs returns list of program spec from raw packet filters definitions
func FiltersToProgramSpecs(_, _ int, _ []Filter, _ ProgOpts) ([]*ebpf.ProgramSpec, error) {
return nil, errors.New("not supported")
}
13 changes: 9 additions & 4 deletions pkg/security/ebpf/probes/tc.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,8 @@ func GetAllTCProgramFunctions() []string {
return output
}

func getTCTailCallRoutes() []manager.TailCallRoute {
return []manager.TailCallRoute{
func getTCTailCallRoutes(withRawPacket bool) []manager.TailCallRoute {
tcr := []manager.TailCallRoute{
{
ProgArrayName: "classifier_router",
Key: TCDNSRequestKey,
Expand All @@ -122,12 +122,17 @@ func getTCTailCallRoutes() []manager.TailCallRoute {
EBPFFuncName: "classifier_imds_request",
},
},
{
}

if withRawPacket {
tcr = append(tcr, manager.TailCallRoute{
ProgArrayName: "classifier_router",
Key: TCRawPacketParserSenderKey,
ProbeIdentificationPair: manager.ProbeIdentificationPair{
EBPFFuncName: "classifier_raw_packet_sender",
},
},
})
}

return tcr
}
2 changes: 1 addition & 1 deletion pkg/security/ebpf/tests/raw_packet_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func testRawPacketFilter(t *testing.T, filters []rawpacket.Filter, expectedRetCo
t.Fatal("map not found")
}

progSpecs, err := rawpacket.TCFiltersToProgramSpecs(rawPacketEventMap.FD(), routerMap.FD(), filters, opts)
progSpecs, err := rawpacket.FiltersToProgramSpecs(rawPacketEventMap.FD(), routerMap.FD(), filters, opts)
if err != nil {
t.Fatal(err)
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/security/probe/model_ebpf.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func NewEBPFModel(probe *EBPFProbe) *model.Model {
return fmt.Errorf("%s is not available on this kernel version", field)
}
case "packet.filter":
if probe.isNetworkNotSupported() {
if probe.isRawPacketNotSupported() {
return fmt.Errorf("%s is not available on this kernel version", field)
}
if _, err := rawpacket.BPFFilterToInsts(0, value.Value.(string), rawpacket.DefaultProgOpts); err != nil {
Expand Down
23 changes: 17 additions & 6 deletions pkg/security/probe/probe_ebpf.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,11 @@ func (p *EBPFProbe) selectFentryMode() {
}

func (p *EBPFProbe) isNetworkNotSupported() bool {
return p.kernelVersion.IsRH7Kernel() || (p.kernelVersion.IsAmazonLinuxKernel() && p.kernelVersion.Code < kernel.Kernel4_15)
return p.kernelVersion.IsRH7Kernel()
}

func (p *EBPFProbe) isRawPacketNotSupported() bool {
return p.isNetworkNotSupported() || (p.kernelVersion.IsAmazonLinuxKernel() && p.kernelVersion.Code < kernel.Kernel4_15)
}

func (p *EBPFProbe) sanityChecks() error {
Expand All @@ -214,10 +218,15 @@ func (p *EBPFProbe) sanityChecks() error {
}

if p.config.Probe.NetworkEnabled && p.isNetworkNotSupported() {
seclog.Warnf("The network feature of CWS isn't supported on Centos7, setting event_monitoring_config.network.enabled to false")
seclog.Warnf("the network feature of CWS isn't supported on this kernel version")
p.config.Probe.NetworkEnabled = false
}

if p.config.Probe.NetworkRawPacketEnabled && p.isRawPacketNotSupported() {
seclog.Warnf("the raw packet feature of CWS isn't supported on this kernel version")
p.config.Probe.NetworkRawPacketEnabled = false
}

return nil
}

Expand Down Expand Up @@ -397,7 +406,7 @@ func (p *EBPFProbe) setupRawPacketProgs(rs *rules.RuleSet) error {
seclog.Debugf("generate rawpacker filter programs with a limit of %d max instructions", opts.MaxProgSize)

// compile the filters
progSpecs, err := rawpacket.TCFiltersToProgramSpecs(rawPacketEventMap.FD(), routerMap.FD(), rawPacketFilters, opts)
progSpecs, err := rawpacket.FiltersToProgramSpecs(rawPacketEventMap.FD(), routerMap.FD(), rawPacketFilters, opts)
if err != nil {
return err
}
Expand Down Expand Up @@ -2042,15 +2051,17 @@ func NewEBPFProbe(probe *Probe, config *config.Config, opts Opts, telemetry tele
}

// tail calls
p.managerOptions.TailCallRouter = probes.AllTailRoutes(config.Probe.ERPCDentryResolutionEnabled, config.Probe.NetworkEnabled, useMmapableMaps)
p.managerOptions.TailCallRouter = probes.AllTailRoutes(config.Probe.ERPCDentryResolutionEnabled, config.Probe.NetworkEnabled, config.Probe.NetworkRawPacketEnabled, useMmapableMaps)
if !config.Probe.ERPCDentryResolutionEnabled || useMmapableMaps {
// exclude the programs that use the bpf_probe_write_user helper
p.managerOptions.ExcludedFunctions = probes.AllBPFProbeWriteUserProgramFunctions()
}

if !config.Probe.NetworkEnabled {
// prevent all TC classifiers from loading
// prevent some TC classifiers from loading
if !p.config.Probe.NetworkEnabled {
p.managerOptions.ExcludedFunctions = append(p.managerOptions.ExcludedFunctions, probes.GetAllTCProgramFunctions()...)
} else if !p.config.Probe.NetworkRawPacketEnabled {
p.managerOptions.ExcludedFunctions = append(p.managerOptions.ExcludedFunctions, probes.GetRawPacketTCProgramFunctions()...)
}

if p.useFentry {
Expand Down
115 changes: 115 additions & 0 deletions pkg/security/tests/network_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@ import (
"strings"
"testing"

"github.com/cilium/ebpf"
"github.com/docker/docker/libnetwork/resolvconf"
"github.com/samber/lo"
"github.com/stretchr/testify/assert"

"github.com/DataDog/datadog-agent/pkg/config/env"
"github.com/DataDog/datadog-agent/pkg/security/ebpf/kernel"
"github.com/DataDog/datadog-agent/pkg/security/ebpf/probes/rawpacket"
"github.com/DataDog/datadog-agent/pkg/security/secl/model"
"github.com/DataDog/datadog-agent/pkg/security/secl/rules"
"github.com/DataDog/datadog-agent/pkg/security/tests/testutils"
Expand Down Expand Up @@ -149,3 +151,116 @@ func TestRawPacket(t *testing.T) {
})
})
}

func TestRawPacketFilter(t *testing.T) {
SkipIfNotAvailable(t)

checkKernelCompatibility(t, "RHEL, SLES, SUSE and Oracle kernels", func(kv *kernel.Version) bool {
// TODO: Oracle because we are missing offsets
// OpenSUSE distributions are missing the dummy kernel module
return kv.IsRH7Kernel() || kv.IsOracleUEKKernel() || kv.IsSLESKernel() || kv.IsOpenSUSELeapKernel() || (kv.IsAmazonLinuxKernel() && kv.Code < kernel.Kernel4_15)
})

colSpecForMaps := ebpf.CollectionSpec{
Maps: map[string]*ebpf.MapSpec{
"raw_packet_event": &ebpf.MapSpec{
Name: "raw_packet_event",
Type: ebpf.Array,
KeySize: 4,
ValueSize: 4096, // to be adapted if the raw_packet_event
MaxEntries: 1,
},
"classifier_router": &ebpf.MapSpec{
Name: "classifier_router",
Type: ebpf.ProgramArray,
KeySize: 4,
ValueSize: 4,
MaxEntries: 1,
},
},
}

mapsCol, err := ebpf.NewCollection(&colSpecForMaps)
assert.Nil(t, err)
defer mapsCol.Close()

rawPacketEventMap := mapsCol.Maps["raw_packet_event"]
assert.NotNil(t, rawPacketEventMap)
assert.Greater(t, rawPacketEventMap.FD(), 0)

clsRouterMapFd := mapsCol.Maps["classifier_router"]
assert.NotNil(t, clsRouterMapFd)
assert.Greater(t, clsRouterMapFd.FD(), 0)

filters := []rawpacket.Filter{
{
BPFFilter: "port 5555",
},
{
BPFFilter: "tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x47455420",
},
{
BPFFilter: "icmp[icmptype] != icmp-echo and icmp[icmptype] != icmp-echoreply",
},
{
BPFFilter: "port ftp or ftp-data",
},
{
BPFFilter: "tcp[tcpflags] & (tcp-syn|tcp-fin) != 0 and not src and dst net 192.168.1.0/24",
},
{
BPFFilter: "tcp port 80 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)",
},
{
BPFFilter: "ether[0] & 1 = 0 and ip[16] >= 224",
},
{
BPFFilter: "udp port 67 and port 68",
},
{
BPFFilter: "((port 67 or port 68) and (udp[38:4] = 0x3e0ccf08))",
},
{
BPFFilter: "portrange 21-23",
},
{
BPFFilter: "tcp[13] & 8!=0",
},
}

runTest := func(t *testing.T, filters []rawpacket.Filter, opts rawpacket.ProgOpts) {
progSpecs, err := rawpacket.FiltersToProgramSpecs(rawPacketEventMap.FD(), clsRouterMapFd.FD(), filters, opts)
assert.Nil(t, err)
assert.NotEmpty(t, progSpecs)

colSpec := ebpf.CollectionSpec{
Programs: make(map[string]*ebpf.ProgramSpec),
}
for _, progSpec := range progSpecs {
colSpec.Programs[progSpec.Name] = progSpec
}

progsCol, err := ebpf.NewCollection(&colSpec)
assert.Nil(t, err)
if err == nil {
progsCol.Close()
}
}

for _, filter := range filters {
t.Run(filter.BPFFilter, func(t *testing.T) {
runTest(t, []rawpacket.Filter{filter}, rawpacket.DefaultProgOpts)
})
}

t.Run("all-without-limit", func(t *testing.T) {
runTest(t, filters, rawpacket.DefaultProgOpts)
})

t.Run("all-with-limit", func(t *testing.T) {
opts := rawpacket.DefaultProgOpts
opts.MaxProgSize = 4000
opts.NopInstLen = 3500
runTest(t, filters, rawpacket.DefaultProgOpts)
})
}

0 comments on commit ad94a25

Please sign in to comment.