Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions elf_reader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,44 +118,44 @@ func TestLoadCollectionSpec(t *testing.T) {
MaxEntries: 1,
},
".bss": {
Name: SanitizeName(".bss", -1),
Name: ".bss",
Type: Array,
KeySize: 4,
ValueSize: 4,
MaxEntries: 1,
},
".data": {
Name: SanitizeName(".data", -1),
Name: ".data",
Type: Array,
KeySize: 4,
ValueSize: 4,
MaxEntries: 1,
},
".data.test": {
Name: SanitizeName(".data.test", -1),
Name: ".data.test",
Type: Array,
KeySize: 4,
ValueSize: 4,
MaxEntries: 1,
},
".rodata": {
Name: SanitizeName(".rodata", -1),
Name: ".rodata",
Type: Array,
KeySize: 4,
ValueSize: 24,
MaxEntries: 1,
Flags: sys.BPF_F_RDONLY_PROG,
},
".rodata.test": {
Name: SanitizeName(".rodata.test", -1),
Name: ".rodata.test",
Type: Array,
KeySize: 4,
ValueSize: 4,
MaxEntries: 1,
Flags: sys.BPF_F_RDONLY_PROG,
},
".rodata.cst32": {
Name: SanitizeName(".rodata.cst32", -1),
Name: ".rodata.cst32",
Type: Array,
KeySize: 4,
ValueSize: 32,
Expand Down
5 changes: 1 addition & 4 deletions map.go
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,7 @@ func (spec *MapSpec) createMap(inner *sys.FD) (_ *Map, err error) {
}

attr := sys.MapCreateAttr{
MapName: maybeFillObjName(spec.Name),
MapType: sys.MapType(sysMapType),
KeySize: spec.KeySize,
ValueSize: spec.ValueSize,
Expand All @@ -498,10 +499,6 @@ func (spec *MapSpec) createMap(inner *sys.FD) (_ *Map, err error) {
attr.InnerMapFd = inner.Uint()
}

if haveObjName() == nil {
attr.MapName = sys.NewObjName(spec.Name)
}

if spec.Key != nil || spec.Value != nil {
handle, keyTypeID, valueTypeID, err := btf.MarshalMapKV(spec.Key, spec.Value)
if err != nil && !errors.Is(err, btf.ErrNotSupported) {
Expand Down
22 changes: 1 addition & 21 deletions prog.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"math"
"path/filepath"
"runtime"
"strings"
"time"

"github.com/cilium/ebpf/asm"
Expand Down Expand Up @@ -286,17 +285,14 @@ func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions) (*Program, er
}

attr := &sys.ProgLoadAttr{
ProgName: maybeFillObjName(spec.Name),
ProgType: sys.ProgType(progType),
ProgFlags: spec.Flags,
ExpectedAttachType: sys.AttachType(spec.AttachType),
License: sys.NewStringPointer(spec.License),
KernVersion: kv,
}

if haveObjName() == nil {
attr.ProgName = sys.NewObjName(spec.Name)
}

insns := make(asm.Instructions, len(spec.Instructions))
copy(insns, spec.Instructions)

Expand Down Expand Up @@ -969,22 +965,6 @@ func LoadPinnedProgram(fileName string, opts *LoadPinOptions) (*Program, error)
return &Program{"", fd, progName, fileName, info.Type}, nil
}

// SanitizeName replaces all invalid characters in name with replacement.
// Passing a negative value for replacement will delete characters instead
// of replacing them. Use this to automatically generate valid names for maps
// and programs at runtime.
//
// The set of allowed characters depends on the running kernel version.
// Dots are only allowed as of kernel 5.2.
func SanitizeName(name string, replacement rune) string {
return strings.Map(func(char rune) rune {
if invalidBPFObjNameChar(char) {
return replacement
}
return char
}, name)
}

// ProgramGetNextID returns the ID of the next eBPF program.
//
// Returns ErrNotExist, if there is no next eBPF program.
Expand Down
13 changes: 0 additions & 13 deletions prog_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -406,19 +406,6 @@ func TestProgramName(t *testing.T) {
}
}

func TestSanitizeName(t *testing.T) {
for input, want := range map[string]string{
"test": "test",
"t-est": "test",
"t_est": "t_est",
"hörnchen": "hrnchen",
} {
if have := SanitizeName(input, -1); have != want {
t.Errorf("Wanted '%s' got '%s'", want, have)
}
}
}

func TestProgramCloneNil(t *testing.T) {
p, err := (*Program)(nil).Clone()
if err != nil {
Expand Down
73 changes: 36 additions & 37 deletions syscalls.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"math"
"os"
"runtime"
"strings"

"github.com/cilium/ebpf/asm"
"github.com/cilium/ebpf/internal"
Expand All @@ -26,25 +27,40 @@ var (
sysErrNotSupported = sys.Error(ErrNotSupported, sys.ENOTSUPP)
)

// invalidBPFObjNameChar returns true if char may not appear in
// a BPF object name.
func invalidBPFObjNameChar(char rune) bool {
dotAllowed := objNameAllowsDot() == nil

switch {
case char >= 'A' && char <= 'Z':
return false
case char >= 'a' && char <= 'z':
return false
case char >= '0' && char <= '9':
return false
case dotAllowed && char == '.':
return false
case char == '_':
return false
default:
return true
// SanitizeName replaces all invalid characters in name with replacement.
// Passing a negative value for replacement will delete characters instead
// of replacing them.
//
// The set of allowed characters may change over time.
func SanitizeName(name string, replacement rune) string {
return strings.Map(func(char rune) rune {
switch {
case char >= 'A' && char <= 'Z':
return char
case char >= 'a' && char <= 'z':
return char
case char >= '0' && char <= '9':
return char
case char == '.':
return char
case char == '_':
return char
default:
return replacement
}
}, name)
}

func maybeFillObjName(name string) sys.ObjName {
if errors.Is(haveObjName(), ErrNotSupported) {
return sys.ObjName{}
}

if errors.Is(objNameAllowsDot(), ErrNotSupported) {
name = strings.ReplaceAll(name, ".", "")
}

return sys.NewObjName(name)
}

func progLoad(insns asm.Instructions, typ ProgramType, license string) (*sys.FD, error) {
Expand Down Expand Up @@ -190,17 +206,9 @@ var haveObjName = internal.NewFeatureTest("object names", func() error {
MapName: sys.NewObjName("feature_test"),
}

// Tolerate EPERM as this runs during ELF loading which is potentially
// unprivileged. Only EINVAL is conclusive, thrown from CHECK_ATTR.
fd, err := sys.MapCreate(&attr)
if errors.Is(err, unix.EPERM) {
return nil
}
if errors.Is(err, unix.EINVAL) {
return internal.ErrNotSupported
}
if err != nil {
return err
return internal.ErrNotSupported
}

_ = fd.Close()
Expand All @@ -225,18 +233,9 @@ var objNameAllowsDot = internal.NewFeatureTest("dot in object names", func() err
MapName: sys.NewObjName(".test"),
}

// Tolerate EPERM, otherwise MapSpec.Name has its dots removed when run by
// unprivileged tools. (bpf2go, other code gen). Only EINVAL is conclusive,
// thrown from bpf_obj_name_cpy().
fd, err := sys.MapCreate(&attr)
if errors.Is(err, unix.EPERM) {
return nil
}
if errors.Is(err, unix.EINVAL) {
return internal.ErrNotSupported
}
if err != nil {
return err
return internal.ErrNotSupported
}

_ = fd.Close()
Expand Down
26 changes: 13 additions & 13 deletions syscalls_test.go
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
package ebpf

import (
"strings"
"testing"

"github.com/go-quicktest/qt"

"github.com/cilium/ebpf/internal/testutils"
)

func TestObjNameCharacters(t *testing.T) {
for in, valid := range map[string]bool{
"test": true,
"": true,
"a-b": false,
"yeah so": false,
"dot.": objNameAllowsDot() == nil,
"Capital": true,
func TestSanitizeName(t *testing.T) {
for input, want := range map[string]string{
"test": "test",
"": "",
"a-b": "ab",
"yeah so": "yeahso",
"dot.": "dot.",
"Capital": "Capital",
"t_est": "t_est",
"hörnchen": "hrnchen",
} {
result := strings.IndexFunc(in, invalidBPFObjNameChar) == -1
if result != valid {
t.Errorf("Name '%s' classified incorrectly", in)
}
qt.Assert(t, qt.Equals(SanitizeName(input, -1), want), qt.Commentf("input: %s", input))
}
}

Expand Down