Repository: cilium/ebpf
Pull request #156 (2020-11-09 15:49:52)

Support LSM attach
Based on #147 


Patch:
diff --git a/elf_reader.go b/elf_reader.go
index 6dcd14a..ba5025f 100644
--- a/elf_reader.go
+++ b/elf_reader.go
@@ -638,6 +638,7 @@ func getProgType(sectionName string) (ProgramType, AttachType, string) {
 		"flow_dissector":        {FlowDissector, AttachFlowDissector},
 		"iter/":                 {Tracing, AttachTraceIter},
 		"sk_lookup/":            {SkLookup, AttachSkLookup},
+		"lsm/":                  {LSM, AttachLSMMac},
 
 		"cgroup_skb/ingress": {CGroupSKB, AttachCGroupInetIngress},
 		"cgroup_skb/egress":  {CGroupSKB, AttachCGroupInetEgress},
diff --git a/internal/btf/btf.go b/internal/btf/btf.go
index 5e4a958..efa968a 100644
--- a/internal/btf/btf.go
+++ b/internal/btf/btf.go
@@ -234,7 +234,7 @@ func loadKernelSpec() (*Spec, error) {
 		return loadSpecFromVmlinux(fh)
 	}
 
-	return nil, fmt.Errorf("BTF for kernel version %s: %w", release, ErrNotFound)
+	return nil, fmt.Errorf("no BTF for kernel version %s: %w", release, internal.ErrNotSupported)
 }
 
 func parseBTF(btf io.ReadSeeker, bo binary.ByteOrder) ([]rawType, stringTable, error) {
diff --git a/internal/feature.go b/internal/feature.go
index 7375b21..8f282db 100644
--- a/internal/feature.go
+++ b/internal/feature.go
@@ -20,6 +20,9 @@ type UnsupportedFeatureError struct {
 }
 
 func (ufe *UnsupportedFeatureError) Error() string {
+	if ufe.MinimumVersion.Unspecified() {
+		return fmt.Sprintf("%s not supported", ufe.Name)
+	}
 	return fmt.Sprintf("%s not supported (requires >= %s)", ufe.Name, ufe.MinimumVersion)
 }
 
@@ -120,3 +123,8 @@ func (v Version) Less(other Version) bool {
 	}
 	return false
 }
+
+// Unspecified returns true if the version is all zero.
+func (v Version) Unspecified() bool {
+	return v[0] == 0 && v[1] == 0 && v[2] == 0
+}
diff --git a/prog.go b/prog.go
index bb38f21..95ee2c5 100644
--- a/prog.go
+++ b/prog.go
@@ -626,10 +626,30 @@ func resolveBTFType(name string, progType ProgramType, attachType AttachType) (b
 
 	target := match{progType, attachType}
 	switch target {
+	case match{LSM, AttachLSMMac}:
+		var target btf.Func
+		err := findKernelType("bpf_lsm_"+name, &target)
+		if errors.Is(err, btf.ErrNotFound) {
+			return nil, &internal.UnsupportedFeatureError{
+				Name: name + " LSM hook",
+			}
+		}
+		if err != nil {
+			return nil, fmt.Errorf("resolve BTF for LSM hook %s: %w", name, err)
+		}
+
+		return &target, nil
+
 	case match{Tracing, AttachTraceIter}:
 		var target btf.Func
-		if err := findKernelType("bpf_iter_"+name, &target); err != nil {
-			return nil, fmt.Errorf("can't resolve BTF for iterator %s: %w", name, err)
+		err := findKernelType("bpf_iter_"+name, &target)
+		if errors.Is(err, btf.ErrNotFound) {
+			return nil, &internal.UnsupportedFeatureError{
+				Name: name + " iterator",
+			}
+		}
+		if err != nil {
+			return nil, fmt.Errorf("resolve BTF for iterator %s: %w", name, err)
 		}
 
 		return &target, nil


Test patch:
diff --git a/internal/btf/btf_test.go b/internal/btf/btf_test.go
index de8e022..32b2890 100644
--- a/internal/btf/btf_test.go
+++ b/internal/btf/btf_test.go
@@ -68,9 +68,7 @@ func TestParseVmlinux(t *testing.T) {
 
 func TestParseCurrentKernelBTF(t *testing.T) {
 	spec, err := loadKernelSpec()
-	if errors.Is(err, ErrNotFound) {
-		t.Skip("BTF is not available:", err)
-	}
+	testutils.SkipIfNotSupported(t, err)
 	if err != nil {
 		t.Fatal("Can't load BTF:", err)
 	}
diff --git a/internal/testutils/feature.go b/internal/testutils/feature.go
index 7ab8541..e319086 100644
--- a/internal/testutils/feature.go
+++ b/internal/testutils/feature.go
@@ -63,6 +63,10 @@ func SkipIfNotSupported(tb testing.TB, err error) {
 }
 
 func checkKernelVersion(tb testing.TB, ufe *internal.UnsupportedFeatureError) {
+	if ufe.MinimumVersion.Unspecified() {
+		return
+	}
+
 	kernelVersion := mustKernelVersion()
 	if ufe.MinimumVersion.Less(kernelVersion) {
 		tb.Helper()
diff --git a/link/iter_test.go b/link/iter_test.go
index 3db91e3..1a7e75d 100644
--- a/link/iter_test.go
+++ b/link/iter_test.go
@@ -1,13 +1,12 @@
 package link
 
 import (
-	"errors"
 	"io/ioutil"
 	"testing"
 
 	"github.com/cilium/ebpf"
 	"github.com/cilium/ebpf/asm"
-	"github.com/cilium/ebpf/internal/btf"
+	"github.com/cilium/ebpf/internal/testutils"
 )
 
 func TestIter(t *testing.T) {
@@ -21,9 +20,7 @@ func TestIter(t *testing.T) {
 		},
 		License: "MIT",
 	})
-	if errors.Is(err, btf.ErrNotFound) {
-		t.Skip("Kernel doesn't support iter:", err)
-	}
+	testutils.SkipIfNotSupported(t, err)
 	if err != nil {
 		t.Fatal("Can't load program:", err)
 	}
diff --git a/prog_test.go b/prog_test.go
index 433b6a0..e2dd65a 100644
--- a/prog_test.go
+++ b/prog_test.go
@@ -473,6 +473,24 @@ func TestProgramRejectIncorrectByteOrder(t *testing.T) {
 	}
 }
 
+func TestProgramTypeLSM(t *testing.T) {
+	prog, err := NewProgram(&ProgramSpec{
+		AttachTo:   "task_getpgid",
+		AttachType: AttachLSMMac,
+		Instructions: asm.Instructions{
+			asm.LoadImm(asm.R0, 0, asm.DWord),
+			asm.Return(),
+		},
+		License: "GPL",
+		Type:    LSM,
+	})
+	testutils.SkipIfNotSupported(t, err)
+	if err != nil {
+		t.Fatal(err)
+	}
+	prog.Close()
+}
+
 func createProgramArray(t *testing.T) *Map {
 	t.Helper()
 
diff --git a/run-tests.sh b/run-tests.sh
index 3a27594..0e85c63 100755
--- a/run-tests.sh
+++ b/run-tests.sh
@@ -22,8 +22,8 @@ if [[ "${1:-}" = "--in-vm" ]]; then
 
   echo Running tests...
   # TestLibBPFCompat runs separately to pass the "-elfs" flag only for it: https://github.com/cilium/ebpf/pull/119
-  go test -v -run TestLibBPFCompat -elfs "$elfs"
-  go test -v ./...
+  go test -v -count 1 -run TestLibBPFCompat -elfs "$elfs"
+  go test -v -count 1 ./...
   touch "$1/success"
   exit 0
 fi