Skip to content

Commit

Permalink
apparmor recorder: require bpf lsm
Browse files Browse the repository at this point in the history
see kubernetes-sigs#2260 for details
  • Loading branch information
mhils committed May 14, 2024
1 parent e0f88cc commit c5ac7a2
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 9 deletions.
12 changes: 12 additions & 0 deletions internal/pkg/daemon/bpfrecorder/bpfrecorder.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
"fmt"
"os"
"path/filepath"
"regexp"
"runtime"
"strconv"
"strings"
Expand Down Expand Up @@ -859,3 +860,14 @@ func (b *BpfRecorder) WaitForPidExit(ctx context.Context, pid uint32) error {
b.eventWorkers.Release(maxEventWorkers)
return nil
}

func BPFLSMEnabled() bool {
if enabled := os.Getenv("E2E_TEST_BPF_LSM_ENABLED"); enabled != "" {
return enabled == "1"
}
contents, err := os.ReadFile("/sys/kernel/security/lsm")
if err != nil {
return false
}
return regexp.MustCompile(`(^|,)bpf(,|$)`).Match(contents)
}
4 changes: 4 additions & 0 deletions internal/pkg/daemon/bpfrecorder/bpfrecorder_apparmor.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ limitations under the License.
package bpfrecorder

import (
"errors"
"fmt"
"log"
"path/filepath"
Expand Down Expand Up @@ -108,6 +109,9 @@ func newAppArmorRecorder(logger logr.Logger, programName string) *AppArmorRecord
}

func (*AppArmorRecorder) Load(b *BpfRecorder) error {
if !BPFLSMEnabled() {
return errors.New("BPF LSM is not enabled for this kernel")
}
for _, hook := range appArmorHooks {
if err := b.attachBpfProgram(hook); err != nil {
return err
Expand Down
8 changes: 4 additions & 4 deletions internal/pkg/daemon/bpfrecorder/bpfrecorder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -408,7 +408,7 @@ func TestRun(t *testing.T) {
} {
mock := &bpfrecorderfakes.FakeImpl{}
tc.prepare(mock)
sut := New("test", logr.Discard(), true, true)
sut := New("test", logr.Discard(), true, false)
sut.impl = mock

err := sut.Run()
Expand Down Expand Up @@ -457,7 +457,7 @@ func TestStart(t *testing.T) {
mock := &bpfrecorderfakes.FakeImpl{}
tc.prepare(mock)

sut := New("", logr.Discard(), true, true)
sut := New("", logr.Discard(), true, false)
sut.impl = mock

_, err := sut.Start(context.Background(), &api.EmptyRequest{})
Expand Down Expand Up @@ -504,7 +504,7 @@ func TestStop(t *testing.T) {
},
},
} {
sut := New("", logr.Discard(), true, true)
sut := New("", logr.Discard(), true, false)

mock := &bpfrecorderfakes.FakeImpl{}
sut.impl = mock
Expand Down Expand Up @@ -626,7 +626,7 @@ func TestSyscallsForProfile(t *testing.T) {
},
},
} {
sut := New("", logr.Discard(), true, true)
sut := New("", logr.Discard(), true, false)

mock := &bpfrecorderfakes.FakeImpl{}
sut.impl = mock
Expand Down
34 changes: 29 additions & 5 deletions test/spoc/e2e_spoc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import (
apparmorprofileapi "sigs.k8s.io/security-profiles-operator/api/apparmorprofile/v1alpha1"
seccompprofileapi "sigs.k8s.io/security-profiles-operator/api/seccompprofile/v1beta1"
"sigs.k8s.io/security-profiles-operator/internal/pkg/cli/recorder"
"sigs.k8s.io/security-profiles-operator/internal/pkg/daemon/bpfrecorder"
)

const spocPath = "../../build/spoc"
Expand All @@ -61,7 +62,22 @@ func recordTest(t *testing.T) {
}

func recordAppArmorTest(t *testing.T) {
t.Run("unsupported", func(t *testing.T) {
out, err := exec.Command(
"sudo",
"E2E_TEST_BPF_LSM_ENABLED=0",
spocPath,
"record",
"-t", "apparmor",
"./demobinary",
).CombinedOutput()
require.NotNil(t, err)
require.Contains(t, string(out), "BPF LSM is not enabled")
})
t.Run("files", func(t *testing.T) {
if !bpfrecorder.BPFLSMEnabled() {
t.Skip("BPF LSM disabled")
}
profile := recordAppArmor(t, "--file-read", "../../README.md", "--file-write", "/dev/null")
readme, err := filepath.Abs("../../README.md")
require.Nil(t, err)
Expand All @@ -84,6 +100,9 @@ func recordAppArmorTest(t *testing.T) {
})

t.Run("subprocess", func(t *testing.T) {
if !bpfrecorder.BPFLSMEnabled() {
t.Skip("BPF LSM disabled")
}
profile := recordAppArmor(t, "./demobinary-child", "--file-read", "/dev/null")
require.Contains(t, (*profile.Executable.AllowedExecutables)[0], "/demobinary-child")
require.Contains(t, *profile.Filesystem.ReadOnlyPaths, "/dev/null")
Expand All @@ -102,7 +121,9 @@ func recordAppArmorTest(t *testing.T) {
require.Nil(t, err)

cmd := exec.Command(
"sudo", spocPath,
"sudo",
"E2E_TEST_BPF_LSM_ENABLED=1",
spocPath,
"record",
"--no-proc-start",
"-t", "apparmor",
Expand All @@ -128,7 +149,7 @@ func recordAppArmorTest(t *testing.T) {
}

// Run binary...
cmd2 := exec.Command(demobinary, "--file-read", "/dev/null")
cmd2 := exec.Command(demobinary, "--net-tcp")
err = cmd2.Run()
require.Nil(t, err)

Expand Down Expand Up @@ -156,7 +177,7 @@ func recordAppArmorTest(t *testing.T) {
err = cmd.Wait()
require.Nil(t, err)

require.Contains(t, stdout.String(), "/dev/null", "did not find file read in profile")
require.Contains(t, stdout.String(), "allowTcp", "did not find TCP permission in profile")
})
}

Expand All @@ -167,8 +188,11 @@ func recordSeccompTest(t *testing.T) {

func runSpoc(t *testing.T, args ...string) []byte {
t.Helper()
args = append([]string{spocPath}, args...)
cmd := exec.Command("sudo", args...)
args = append([]string{"E2E_TEST_BPF_LSM_ENABLED=1", spocPath}, args...)
cmd := exec.Command(
"sudo",
args...,
)
cmd.Stderr = os.Stderr
out, err := cmd.Output()
require.Nil(t, err, "failed to run spoc")
Expand Down

0 comments on commit c5ac7a2

Please sign in to comment.