Skip to content

Commit

Permalink
test: fix test on old kernels
Browse files Browse the repository at this point in the history
Signed-off-by: Djalal Harouni <[email protected]>
  • Loading branch information
tixxdz committed Jan 22, 2024
1 parent bc910cb commit 3fff5d2
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 9 deletions.
49 changes: 48 additions & 1 deletion pkg/reader/caps/caps.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"path/filepath"
"strconv"
"strings"
"sync"

"github.com/cilium/tetragon/api/v1/tetragon"
"github.com/cilium/tetragon/pkg/api/processapi"
Expand All @@ -18,6 +19,30 @@ import (
"golang.org/x/sys/unix"
)

var (
// Set default last capability based on upstream unix go library
cap_last_cap = int32(unix.CAP_LAST_CAP)
lastCapOnce sync.Once
)

// capLastCap() Returns unix.CAP_LAST_CAP unless the kernel
// defines another last cap which is the case for old kernels.
func capLastCap() int32 {
lastCapOnce.Do(func() {
val := uint64(0)
d, err := os.ReadFile(filepath.Join(option.Config.ProcFS, "/sys/kernel/cap_last_cap"))
if err == nil {
val, err = strconv.ParseUint(string(d), 10, 64)
}
if err != nil {
logger.GetLogger().WithError(err).Warnf("Could not detect cap_last_cap, using default '%d' as cap_last_cap", cap_last_cap)
return
}
cap_last_cap = int32(val)

Check failure

Code scanning / CodeQL

Incorrect conversion between integer types High

Incorrect conversion of an unsigned 64-bit integer from
strconv.ParseUint
to a lower bit size type int32 without an upper bound check.
})
return cap_last_cap
}

func isCapValid(capInt int32) bool {
if capInt >= 0 && capInt <= unix.CAP_LAST_CAP {
return true
Expand All @@ -26,6 +51,29 @@ func isCapValid(capInt int32) bool {
return false
}

// AreSubset() Checks if "a" is a subset of "set"
// Rerturns true if all "a" capabilities are also in "set", otherwise
// false.
func AreSubset(a uint64, set uint64) bool {
return (!((a & ^uint64(set)) != 0))
}

// capToMask() returns the mask of the corresponding u32
func capToMask(cap int32) uint32 {
return uint32(1 << ((cap) & 31))
}

// GetCapsFullSet() Returns up to date (go unix library) full set.
func GetCapsFullSet() uint64 {
// Get last u32 bits
caps := uint64(capToMask(capLastCap()+1)-1) << 32
// Get first u32 bits
caps |= uint64(^uint32(0))

return caps
}

/* uapi/linux/capability.h */
func GetCapability(capInt int32) (string, error) {
if !isCapValid(capInt) {
return "", fmt.Errorf("invalid capability value %d", capInt)
Expand Down Expand Up @@ -53,7 +101,6 @@ func GetCapabilitiesHex(capInt uint64) string {
return fmt.Sprintf("%016x", capInt)
}

/* uapi/linux/capability.h */
var capabilitiesString = map[uint64]string{
/* In a system with the [_POSIX_CHOWN_RESTRICTED] option defined, this
overrides the restriction of changing file ownership and group
Expand Down
7 changes: 7 additions & 0 deletions pkg/reader/caps/caps_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,10 @@ func TestGetCapability(t *testing.T) {
assert.Error(t, err)
assert.Empty(t, str)
}

func TestCapsAreSubset(t *testing.T) {
assert.Equal(t, true, AreSubset(0x000001ffffffffff, 0x000001ffffffffff))
assert.Equal(t, true, AreSubset(0x000001fffffffffe, 0x000001ffffffffff))
assert.Equal(t, false, AreSubset(0x000001ffffffffff, 0x000001fffffffffe))
assert.Equal(t, true, AreSubset(0x0, 0x0))
}
30 changes: 22 additions & 8 deletions pkg/sensors/tracing/kprobe_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6104,6 +6104,24 @@ spec:

createCrdFile(t, tracingPolicy)

fullSet := caps.GetCapsFullSet()
firstChange := fullSet&0xffffffff00000000 | uint64(0xffdfffff) // Removes CAP_SYS_ADMIN
secondChange := fullSet&0xffffffff00000000 | uint64(0xffdffffe) // removes CAP_SYS_ADMIN and CAP_CHOWN

_, currentPermitted, currentEffective, _ := caps.GetPIDCaps(filepath.Join(option.Config.ProcFS, fmt.Sprint(os.Getpid()), "status"))

if currentPermitted == 0 || currentPermitted != currentEffective {
t.Skip("Skipping test since current Permitted or Effective capabilities are zero or do not match")
}

// Now we ensure at least that we have the fullset active

Check failure on line 6117 in pkg/sensors/tracing/kprobe_test.go

View workflow job for this annotation

GitHub Actions / golangci-lint

`fullset` is a misspelling of `fullest` (misspell)
if caps.AreSubset(fullSet, currentPermitted) == false ||
caps.AreSubset(fullSet, currentEffective) == false {
// fullSet is not set in currentPermitted let's check the old fullset of old kernels

Check failure on line 6120 in pkg/sensors/tracing/kprobe_test.go

View workflow job for this annotation

GitHub Actions / golangci-lint

`fullset` is a misspelling of `fullest` (misspell)
t.Skipf("Skipping test since current Permitted or Effective capabilities are not a full capabilities set %s - %s",
caps.GetCapabilitiesHex(currentPermitted), caps.GetCapabilitiesHex(currentEffective))
}

obs, err := observertesthelper.GetDefaultObserverWithFile(t, ctx, testConfigFile, tus.Conf().TetragonLib, observertesthelper.WithMyPid())
if err != nil {
t.Fatalf("GetDefaultObserverWithFile error: %s", err)
Expand All @@ -6113,21 +6131,17 @@ spec:

testSetCaps := testutils.RepoRootPath("contrib/tester-progs/change-capabilities")

fullSet := "000001ffffffffff"
firstChange := "000001ffffdfffff" // removes CAP_SYS_ADMIN
secondChange := "000001ffffdffffe" // removes CAP_SYS_ADMIN and CAP_CHOWN

kpCheckers1 := ec.NewProcessKprobeChecker("").
WithMessage(sm.Full("Process changed its capabilities with capset system call")).
WithFunctionName(sm.Full("security_capset")).
WithArgs(ec.NewKprobeArgumentListMatcher().
WithValues(
// effective caps
ec.NewKprobeArgumentChecker().WithCapEffectiveArg(sm.Full(firstChange)),
ec.NewKprobeArgumentChecker().WithCapEffectiveArg(sm.Full(caps.GetCapabilitiesHex(firstChange))),
// inheritable
ec.NewKprobeArgumentChecker().WithCapInheritableArg(sm.Full(fmt.Sprintf("%016x", 0))),
// permitted
ec.NewKprobeArgumentChecker().WithCapPermittedArg(sm.Full(fullSet)),
ec.NewKprobeArgumentChecker().WithCapPermittedArg(sm.Full(caps.GetCapabilitiesHex(fullSet))),
))

kpCheckers2 := ec.NewProcessKprobeChecker("").
Expand All @@ -6136,11 +6150,11 @@ spec:
WithArgs(ec.NewKprobeArgumentListMatcher().
WithValues(
// effective caps
ec.NewKprobeArgumentChecker().WithCapEffectiveArg(sm.Full(secondChange)),
ec.NewKprobeArgumentChecker().WithCapEffectiveArg(sm.Full(caps.GetCapabilitiesHex(secondChange))),
// inheritable
ec.NewKprobeArgumentChecker().WithCapInheritableArg(sm.Full(fmt.Sprintf("%016x", 0))),
// permitted
ec.NewKprobeArgumentChecker().WithCapPermittedArg(sm.Full(fullSet)),
ec.NewKprobeArgumentChecker().WithCapPermittedArg(sm.Full(caps.GetCapabilitiesHex(fullSet))),
))

testCmd := exec.CommandContext(ctx, testSetCaps)
Expand Down

0 comments on commit 3fff5d2

Please sign in to comment.