Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix arm64 testsuite failures #745

Merged
merged 7 commits into from Jul 27, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions features/map.go
Expand Up @@ -108,7 +108,7 @@ func HaveMapType(mt ebpf.MapType) error {

func validateMaptype(mt ebpf.MapType) error {
if mt > mt.Max() {
return os.ErrInvalid
return fmt.Errorf("%w", os.ErrInvalid)
}

if mt == ebpf.StructOpsMap {
Expand Down Expand Up @@ -143,7 +143,7 @@ func haveMapType(mt ebpf.MapType) error {
// of the struct known by the running kernel, meaning the kernel is too old
// to support the given map type.
case errors.Is(err, unix.EINVAL), errors.Is(err, unix.E2BIG):
err = ebpf.ErrNotSupported
err = fmt.Errorf("%w", ebpf.ErrNotSupported)

// EPERM is kept as-is and is not converted or wrapped.
case errors.Is(err, unix.EPERM):
Expand Down
5 changes: 3 additions & 2 deletions features/map_test.go
@@ -1,6 +1,7 @@
package features

import (
"errors"
"fmt"
"math"
"os"
Expand Down Expand Up @@ -70,13 +71,13 @@ func TestHaveMapType(t *testing.T) {
}

func TestHaveMapTypeUnsupported(t *testing.T) {
if err := haveMapType(ebpf.MapType(math.MaxUint32)); err != ebpf.ErrNotSupported {
if err := haveMapType(ebpf.MapType(math.MaxUint32)); !errors.Is(err, ebpf.ErrNotSupported) {
t.Fatalf("Expected ebpf.ErrNotSupported but was: %v", err)
}
}

func TestHaveMapTypeInvalid(t *testing.T) {
if err := HaveMapType(ebpf.MapType(math.MaxUint32)); err != os.ErrInvalid {
if err := HaveMapType(ebpf.MapType(math.MaxUint32)); !errors.Is(err, os.ErrInvalid) {
t.Fatalf("Expected os.ErrInvalid but was: %v", err)
}

Expand Down
2 changes: 1 addition & 1 deletion features/misc.go
Expand Up @@ -99,7 +99,7 @@ func probeMisc(mt miscType) error {
// of the struct known by the running kernel, meaning the kernel is too old
// to support the given map type.
case errors.Is(err, unix.EINVAL), errors.Is(err, unix.E2BIG):
err = ebpf.ErrNotSupported
err = fmt.Errorf("%w", ebpf.ErrNotSupported)

// EPERM is kept as-is and is not converted or wrapped.
case errors.Is(err, unix.EPERM):
Expand Down
8 changes: 4 additions & 4 deletions features/prog.go
Expand Up @@ -112,7 +112,7 @@ func HaveProgramType(pt ebpf.ProgramType) error {

func validateProgramType(pt ebpf.ProgramType) error {
if pt > pt.Max() {
return os.ErrInvalid
return fmt.Errorf("%w", os.ErrInvalid)
}

if progLoadProbeNotImplemented(pt) {
Expand Down Expand Up @@ -145,7 +145,7 @@ func haveProgramType(pt ebpf.ProgramType) error {
// of the struct known by the running kernel, meaning the kernel is too old
// to support the given prog type.
case errors.Is(err, unix.EINVAL), errors.Is(err, unix.E2BIG):
err = ebpf.ErrNotSupported
err = fmt.Errorf("%w", ebpf.ErrNotSupported)

// EPERM is kept as-is and is not converted or wrapped.
case errors.Is(err, unix.EPERM):
Expand Down Expand Up @@ -191,7 +191,7 @@ func HaveProgramHelper(pt ebpf.ProgramType, helper asm.BuiltinFunc) error {

func validateProgramHelper(helper asm.BuiltinFunc) error {
if helper > helper.Max() {
return os.ErrInvalid
return fmt.Errorf("%w", os.ErrInvalid)
}

return nil
Expand Down Expand Up @@ -230,7 +230,7 @@ func haveProgramHelper(pt ebpf.ProgramType, helper asm.BuiltinFunc) error {
// to support the given prog type.
case errors.Is(err, unix.EINVAL), errors.Is(err, unix.E2BIG):
// TODO: possibly we need to check verifier output here to be sure
err = ebpf.ErrNotSupported
err = fmt.Errorf("%w", ebpf.ErrNotSupported)

// EPERM is kept as-is and is not converted or wrapped.
case errors.Is(err, unix.EPERM):
Expand Down
6 changes: 3 additions & 3 deletions features/prog_test.go
Expand Up @@ -85,13 +85,13 @@ func TestHaveProgramType(t *testing.T) {
}

func TestHaveProgramTypeUnsupported(t *testing.T) {
if err := haveProgramType(ebpf.ProgramType(math.MaxUint32)); err != ebpf.ErrNotSupported {
if err := haveProgramType(ebpf.ProgramType(math.MaxUint32)); !errors.Is(err, ebpf.ErrNotSupported) {
t.Fatalf("Expected ebpf.ErrNotSupported but was: %v", err)
}
}

func TestHaveProgramTypeInvalid(t *testing.T) {
if err := HaveProgramType(ebpf.ProgramType(math.MaxUint32)); err != os.ErrInvalid {
if err := HaveProgramType(ebpf.ProgramType(math.MaxUint32)); !errors.Is(err, os.ErrInvalid) {
t.Fatalf("Expected os.ErrInvalid but was: %v", err)
}
}
Expand Down Expand Up @@ -174,7 +174,7 @@ func TestHaveProgramHelperUnsupported(t *testing.T) {

testutils.SkipOnOldKernel(t, minVersion, feature)

if err := haveProgramHelper(pt, asm.BuiltinFunc(math.MaxInt32)); err != ebpf.ErrNotSupported {
if err := haveProgramHelper(pt, asm.BuiltinFunc(math.MaxInt32)); !errors.Is(err, ebpf.ErrNotSupported) {
t.Fatalf("Expected ebpf.ErrNotSupported but was: %v", err)
}
}
12 changes: 12 additions & 0 deletions internal/sys/syscall.go
Expand Up @@ -8,6 +8,11 @@ import (
"github.com/cilium/ebpf/internal/unix"
)

// ENOTSUPP is a Linux internal error code that has leaked into UAPI.
//
// It is not the same as ENOTSUP or EOPNOTSUPP.
var ENOTSUPP = syscall.Errno(524)

// BPF wraps SYS_BPF.
//
// Any pointers contained in attr must use the Pointer type from this package.
Expand Down Expand Up @@ -108,6 +113,13 @@ func (we wrappedErrno) Unwrap() error {
return we.Errno
}

func (we wrappedErrno) Error() string {
if we.Errno == ENOTSUPP {
return "operation not supported"
}
return we.Errno.Error()
}

type syscallError struct {
error
errno syscall.Errno
Expand Down
5 changes: 5 additions & 0 deletions internal/sys/syscall_test.go
Expand Up @@ -5,6 +5,8 @@ import (
"testing"

"github.com/cilium/ebpf/internal/unix"

qt "github.com/frankban/quicktest"
)

func TestObjName(t *testing.T) {
Expand Down Expand Up @@ -32,6 +34,9 @@ func TestWrappedErrno(t *testing.T) {
if errors.Is(a, unix.EAGAIN) {
t.Error("errors.Is(wrappedErrno, EAGAIN) returns true")
}

notsupp := wrappedErrno{ENOTSUPP}
qt.Assert(t, notsupp.Error(), qt.Contains, "operation not supported")
}

func TestSyscallError(t *testing.T) {
Expand Down
3 changes: 1 addition & 2 deletions internal/unix/types_linux.go
Expand Up @@ -24,8 +24,7 @@ const (
E2BIG = linux.E2BIG
EFAULT = linux.EFAULT
EACCES = linux.EACCES
// ENOTSUPP is not the same as ENOTSUP or EOPNOTSUP
ENOTSUPP = syscall.Errno(0x20c)
EILSEQ = linux.EILSEQ

BPF_F_NO_PREALLOC = linux.BPF_F_NO_PREALLOC
BPF_F_NUMA_NODE = linux.BPF_F_NUMA_NODE
Expand Down
3 changes: 1 addition & 2 deletions internal/unix/types_other.go
Expand Up @@ -25,8 +25,7 @@ const (
E2BIG = syscall.Errno(0)
EFAULT = syscall.EFAULT
EACCES = syscall.Errno(0)
// ENOTSUPP is not the same as ENOTSUP or EOPNOTSUP
ENOTSUPP = syscall.Errno(0x20c)
EILSEQ = syscall.Errno(0)

BPF_F_NO_PREALLOC = 0
BPF_F_NUMA_NODE = 0
Expand Down
9 changes: 5 additions & 4 deletions link/kprobe.go
Expand Up @@ -307,14 +307,15 @@ func pmuProbe(typ probeType, args probeArgs) (*perfEvent, error) {
if errors.Is(err, os.ErrNotExist) || errors.Is(err, unix.EINVAL) {
return nil, fmt.Errorf("symbol '%s+%#x' not found: %w", args.symbol, args.offset, os.ErrNotExist)
}
// Since commit ab105a4fb894, -EILSEQ is returned when a kprobe sym+offset is resolved
// to an invalid insn boundary.
if errors.Is(err, syscall.EILSEQ) {
// Since commit ab105a4fb894, EILSEQ is returned when a kprobe sym+offset is resolved
// to an invalid insn boundary. The exact conditions that trigger this error are
// arch specific however.
if errors.Is(err, unix.EILSEQ) {
return nil, fmt.Errorf("symbol '%s+%#x' not found (bad insn boundary): %w", args.symbol, args.offset, os.ErrNotExist)
}
// Since at least commit cb9a19fe4aa51, ENOTSUPP is returned
// when attempting to set a uprobe on a trap instruction.
if errors.Is(err, unix.ENOTSUPP) {
if errors.Is(err, sys.ENOTSUPP) {
return nil, fmt.Errorf("failed setting uprobe on offset %#x (possible trap insn): %w", args.offset, err)
}
if err != nil {
Expand Down
32 changes: 0 additions & 32 deletions link/kprobe_amd64_test.go

This file was deleted.

20 changes: 18 additions & 2 deletions link/kprobe_test.go
Expand Up @@ -20,9 +20,8 @@ var ksym = "vprintk"
// Collection of various symbols present in all tested kernels.
// Compiler optimizations result in different names for these symbols.
var symTests = []string{
"async_resume.cold", // marked with 'cold' gcc attribute, unlikely to be executed
"echo_char.isra.0", // function optimized by -fipa-sra
"get_buffer.constprop.0", // optimized function with constant operands
"proc_get_long.constprop.0", // optimized function with constant operands
"unregister_kprobes.part.0", // function body that was split and partially inlined
}

Expand Down Expand Up @@ -54,6 +53,23 @@ func TestKprobe(t *testing.T) {
testLink(t, k, prog)
}

func TestKprobeOffset(t *testing.T) {
prog := mustLoadProgram(t, ebpf.Kprobe, 0, "")

// The layout of a function is compiler and arch dependent, so we try to
// find a valid attach target in the first few bytes of the function.
for i := uint64(1); i < 16; i++ {
k, err := Kprobe("inet6_release", prog, &KprobeOptions{Offset: i})
if err != nil {
continue
}
k.Close()
return
}

t.Fatal("Can't attach with non-zero offset")
}

func TestKretprobe(t *testing.T) {
prog := mustLoadProgram(t, ebpf.Kprobe, 0, "")

Expand Down
2 changes: 1 addition & 1 deletion link/link.go
Expand Up @@ -177,7 +177,7 @@ func AttachRawLink(opts RawLinkOptions) (*RawLink, error) {
}
fd, err := sys.LinkCreate(&attr)
if err != nil {
return nil, fmt.Errorf("can't create link: %s", err)
return nil, fmt.Errorf("create link: %w", err)
}

return &RawLink{fd, ""}, nil
Expand Down
3 changes: 1 addition & 2 deletions link/perf_event_test.go
Expand Up @@ -27,8 +27,7 @@ func TestTraceEventTypePMU(t *testing.T) {
func TestTraceEventID(t *testing.T) {
c := qt.New(t)

// using sys_enter_mkdir here as it exist in old kernel (< 4.9) as well
eid, err := getTraceEventID("syscalls", "sys_enter_mkdir")
eid, err := getTraceEventID("syscalls", "sys_enter_mmap")
c.Assert(err, qt.IsNil)
c.Assert(eid, qt.Not(qt.Equals), 0)
}
Expand Down
11 changes: 10 additions & 1 deletion link/tracing.go
@@ -1,6 +1,7 @@
package link

import (
"errors"
"fmt"

"github.com/cilium/ebpf"
Expand Down Expand Up @@ -70,6 +71,10 @@ func AttachFreplace(targetProg *ebpf.Program, name string, prog *ebpf.Program) (
Attach: ebpf.AttachNone,
BTF: typeID,
})
if errors.Is(err, sys.ENOTSUPP) {
// This may be returned by bpf_tracing_prog_attach via bpf_arch_text_poke.
return nil, fmt.Errorf("create raw tracepoint: %w", ErrNotSupported)
}
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -99,8 +104,12 @@ func attachBTFID(program *ebpf.Program) (Link, error) {
fd, err := sys.RawTracepointOpen(&sys.RawTracepointOpenAttr{
ProgFd: uint32(program.FD()),
})
if errors.Is(err, sys.ENOTSUPP) {
// This may be returned by bpf_tracing_prog_attach via bpf_arch_text_poke.
return nil, fmt.Errorf("create raw tracepoint: %w", ErrNotSupported)
}
if err != nil {
return nil, err
return nil, fmt.Errorf("create raw tracepoint: %w", err)
}

raw := RawLink{fd: fd}
Expand Down
4 changes: 4 additions & 0 deletions link/tracing_test.go
Expand Up @@ -38,6 +38,7 @@ func TestFreplace(t *testing.T) {
defer replacement.Close()

freplace, err := AttachFreplace(nil, "", replacement)
testutils.SkipIfNotSupported(t, err)
if err != nil {
t.Fatal("Can't create freplace:", err)
}
Expand All @@ -48,6 +49,7 @@ func TestFreplace(t *testing.T) {

func TestTracing(t *testing.T) {
testutils.SkipOnOldKernel(t, "5.11", "BPF_LINK_TYPE_TRACING")

tests := []struct {
name string
attachTo string
Expand Down Expand Up @@ -85,6 +87,7 @@ func TestTracing(t *testing.T) {
prog := mustLoadProgram(t, tt.programType, tt.attachType, tt.attachTo)

link, err := AttachTracing(TracingOptions{Program: prog})
testutils.SkipIfNotSupported(t, err)
if err != nil {
t.Fatal(err)
}
Expand All @@ -100,6 +103,7 @@ func TestLSM(t *testing.T) {
prog := mustLoadProgram(t, ebpf.LSM, ebpf.AttachLSMMac, "file_mprotect")

link, err := AttachLSM(LSMOptions{Program: prog})
testutils.SkipIfNotSupported(t, err)
if err != nil {
t.Fatal(err)
}
Expand Down
10 changes: 7 additions & 3 deletions link/uprobe_test.go
Expand Up @@ -94,9 +94,13 @@ func TestUprobeExtNotFound(t *testing.T) {
func TestUprobeExtWithOpts(t *testing.T) {
prog := mustLoadProgram(t, ebpf.Kprobe, 0, "")

// This Uprobe is broken and will not work because the offset is not
// correct. This is expected since the offset is provided by the user.
up, err := bashEx.Uprobe("open", prog, &UprobeOptions{Address: 0x1})
// NB: It's not possible to invoke the uprobe since we use an arbitrary
// address.
up, err := bashEx.Uprobe("open", prog, &UprobeOptions{
// arm64 doesn't seem to allow addresses on the first page. Use
// the first byte of the second page.
Address: uint64(os.Getpagesize()),
})
if err != nil {
t.Fatal(err)
}
Expand Down