Skip to content
Open
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
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,8 @@ all: format testdata update-external-deps
$(MAKE) generate

generate:
go generate -run "stringer" ./...
go generate -run "gentypes" ./...
go generate -run "stringer" ./...
go generate -skip "(gentypes|stringer)" ./...

testdata: $(addsuffix -el.elf,$(TARGETS)) $(addsuffix -eb.elf,$(TARGETS)) $(addsuffix -el.elf,$(TARGETS_EL))
Expand Down
17 changes: 15 additions & 2 deletions btf/feature.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ package btf

import (
"errors"
"fmt"
"math"

"github.com/cilium/ebpf/internal"
"github.com/cilium/ebpf/internal/sys"
"github.com/cilium/ebpf/internal/token"
"github.com/cilium/ebpf/internal/unix"
)

Expand Down Expand Up @@ -145,10 +147,21 @@ func probeBTF(typ Type) error {
return err
}

fd, err := sys.BtfLoad(&sys.BtfLoadAttr{
attr := &sys.BtfLoadAttr{
Btf: sys.SlicePointer(buf),
BtfSize: uint32(len(buf)),
})
}

tok, err := token.Get()
if err != nil && !errors.Is(err, token.ErrTokenNotAvailable) {
return fmt.Errorf("get BPF token: %w", err)
}
if tok != nil {
attr.BtfTokenFd = int32(tok.FD())
attr.BtfFlags |= sys.BPF_F_TOKEN_FD
}

fd, err := sys.BtfLoad(attr)

if err == nil {
fd.Close()
Expand Down
21 changes: 17 additions & 4 deletions btf/handle.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/cilium/ebpf/internal"
"github.com/cilium/ebpf/internal/platform"
"github.com/cilium/ebpf/internal/sys"
"github.com/cilium/ebpf/internal/token"
"github.com/cilium/ebpf/internal/unix"
)

Expand Down Expand Up @@ -56,10 +57,16 @@ func NewHandleFromRawBTF(btf []byte) (*Handle, error) {
BtfSize: uint32(len(btf)),
}

var (
logBuf []byte
err error
)
tok, err := token.Get()
if err != nil && !errors.Is(err, token.ErrTokenNotAvailable) {
return nil, fmt.Errorf("get BPF token: %w", err)
}
if tok != nil {
attr.BtfTokenFd = int32(tok.FD())
attr.BtfFlags |= sys.BPF_F_TOKEN_FD
}

var logBuf []byte
for {
var fd *sys.FD
fd, err = sys.BtfLoad(attr)
Expand Down Expand Up @@ -99,6 +106,12 @@ func NewHandleFromRawBTF(btf []byte) (*Handle, error) {
attr.BtfLogLevel = 1
}

if errors.Is(err, unix.EPERM) {
if terr := tok.CmdAllowed(sys.BPF_BTF_LOAD); terr != nil {
return nil, fmt.Errorf("%w: %w", terr, err)
}
}

if err := haveBTF(); err != nil {
return nil, err
}
Expand Down
34 changes: 34 additions & 0 deletions btf/handle_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,12 @@ import (
"fmt"
"testing"

"github.com/go-quicktest/qt"

"github.com/cilium/ebpf/btf"
"github.com/cilium/ebpf/internal/sys"
"github.com/cilium/ebpf/internal/testutils"
"github.com/cilium/ebpf/internal/unix"
)

func TestHandleIterator(t *testing.T) {
Expand Down Expand Up @@ -83,6 +87,36 @@ func TestParseModuleSplitSpec(t *testing.T) {
}
}

func TestNewHandleFromBTFWithToken(t *testing.T) {
b, err := btf.NewBuilder([]btf.Type{
&btf.Int{Name: "example", Size: 4, Encoding: btf.Unsigned},
}, nil)
qt.Assert(t, qt.IsNil(err))
buf, err := b.Marshal(nil, nil)
qt.Assert(t, qt.IsNil(err))

testutils.RunWithToken(t, "no-cmd", testutils.Delegated{
Cmds: []sys.Cmd{},
// We need to delegate at least one permission, so picking a random map type that we don't use in this test.
Maps: []sys.MapType{sys.BPF_MAP_TYPE_ARRAY},
}, func(t *testing.T) {
h, err := btf.NewHandleFromRawBTF(buf)
testutils.SkipIfNotSupported(t, err)
qt.Assert(t, qt.ErrorIs(err, unix.EPERM))
h.Close()
})

testutils.RunWithToken(t, "success", testutils.Delegated{
Cmds: []sys.Cmd{sys.BPF_BTF_LOAD},
Maps: []sys.MapType{},
}, func(t *testing.T) {
h, err := btf.NewHandleFromRawBTF(buf)
testutils.SkipIfNotSupported(t, err)
qt.Assert(t, qt.IsNil(err))
h.Close()
})
}

func ExampleHandleIterator() {
it := new(btf.HandleIterator)
defer it.Handle.Close()
Expand Down
19 changes: 19 additions & 0 deletions features/map.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/cilium/ebpf"
"github.com/cilium/ebpf/internal"
"github.com/cilium/ebpf/internal/sys"
"github.com/cilium/ebpf/internal/token"
"github.com/cilium/ebpf/internal/unix"
)

Expand Down Expand Up @@ -77,6 +78,15 @@ func probeMap(attr *sys.MapCreateAttr) error {
}

func createMap(attr *sys.MapCreateAttr) error {
tok, err := token.Get()
if err != nil && !errors.Is(err, token.ErrTokenNotAvailable) {
return fmt.Errorf("get BPF token: %w", err)
}
if tok != nil {
attr.MapTokenFd = int32(tok.FD())
attr.MapFlags |= sys.BPF_F_TOKEN_FD
}

fd, err := sys.MapCreate(attr)
if err == nil {
fd.Close()
Expand Down Expand Up @@ -300,6 +310,15 @@ func probeMapFlag(attr *sys.MapCreateAttr) error {
attr.ValueSize = 4
attr.MaxEntries = 1

tok, err := token.Get()
if err != nil && !errors.Is(err, token.ErrTokenNotAvailable) {
return fmt.Errorf("get BPF token: %w", err)
}
if tok != nil {
attr.MapTokenFd = int32(tok.FD())
attr.MapFlags |= sys.BPF_F_TOKEN_FD
}

fd, err := sys.MapCreate(attr)
if err == nil {
fd.Close()
Expand Down
15 changes: 15 additions & 0 deletions internal/cmd/gentypes/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,8 @@ import (

`)

w.WriteString("//go:generate go tool stringer -output types_string.go -type=Cmd,MapType,ProgType,AttachType\n\n")

// Constants (aka unnamed enums)
var consts []btf.EnumValue
for typ, err := range spec.All() {
Expand Down Expand Up @@ -233,6 +235,13 @@ import (
enumTypes := make(map[string]btf.Type)

outputEnum := func(goType string, t *btf.Enum) error {
for i, value := range t.Values {
// The BPF enum values have a __MAX value, which is really useful for bound checking and iterating over
// all valid values. In Go, identifier starting with _ are unexported, so remove the underscores so
// we can use the MAX values.
t.Values[i].Name = strings.Replace(value.Name, "__MAX", "MAX", 1)
}

// Add the enum as a predeclared type so that generated structs
// refer to the Go types.
if name := gf.Names[t]; name != "" {
Expand Down Expand Up @@ -359,6 +368,7 @@ import (
replaceWithBytes("remote_ip4", "remote_ip6", "local_ip4", "local_ip6"),
},
},
{"TokenInfo", "bpf_token_info", nil},
}

sort.Slice(structs, func(i, j int) bool {
Expand Down Expand Up @@ -682,6 +692,10 @@ import (
rename("target_fd", "target_fd_or_ifindex"),
},
},
{
"TokenCreate", retFd, "token_create", "BPF_TOKEN_CREATE",
nil,
},
}

sort.Slice(attrs, func(i, j int) bool {
Expand Down Expand Up @@ -712,6 +726,7 @@ import (
{"enable_stats", "enable_stats"},
{"iter_create", "iter_create"},
{"prog_bind_map", "prog_bind_map"},
{"token_create", "token_create"},
})
if err != nil {
return nil, fmt.Errorf("split bpf_attr: %w", err)
Expand Down
9 changes: 8 additions & 1 deletion internal/sys/syscall.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const ENOTSUPP = unix.Errno(524)
// ProgInfo
// LinkInfo
// BtfInfo
// TokenInfo
type Info interface {
info() (unsafe.Pointer, uint32)
}
Expand Down Expand Up @@ -106,9 +107,15 @@ func (i *PerfEventLinkInfo) info() (unsafe.Pointer, uint32) {
return unsafe.Pointer(i), uint32(unsafe.Sizeof(*i))
}

var _ Info = (*TokenInfo)(nil)

func (i *TokenInfo) info() (unsafe.Pointer, uint32) {
return unsafe.Pointer(i), uint32(unsafe.Sizeof(*i))
}

// ObjInfo retrieves information about a BPF Fd.
//
// info may be one of MapInfo, ProgInfo, LinkInfo and BtfInfo.
// info may be one of MapInfo, ProgInfo, LinkInfo, BtfInfo, and TokenInfo.
func ObjInfo(fd *FD, info Info) error {
ptr, len := info.info()
err := ObjGetInfoByFd(&ObjGetInfoByFdAttr{
Expand Down
34 changes: 29 additions & 5 deletions internal/sys/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import (
"unsafe"
)

//go:generate go tool stringer -output types_string.go -type=Cmd,MapType,ProgType,AttachType

const (
BPF_ADJ_ROOM_ENCAP_L2_MASK = 255
BPF_ADJ_ROOM_ENCAP_L2_SHIFT = 56
Expand Down Expand Up @@ -253,7 +255,7 @@ const (
BPF_NETKIT_PEER AttachType = 55
BPF_TRACE_KPROBE_SESSION AttachType = 56
BPF_TRACE_UPROBE_SESSION AttachType = 57
__MAX_BPF_ATTACH_TYPE AttachType = 58
MAX_BPF_ATTACH_TYPE AttachType = 58
)

type Cmd uint32
Expand Down Expand Up @@ -298,7 +300,7 @@ const (
BPF_PROG_BIND_MAP Cmd = 35
BPF_TOKEN_CREATE Cmd = 36
BPF_PROG_STREAM_READ_BY_FD Cmd = 37
__MAX_BPF_CMD Cmd = 38
MAX_BPF_CMD Cmd = 38
)

type FunctionId uint32
Expand Down Expand Up @@ -544,7 +546,7 @@ const (
BPF_LINK_TYPE_UPROBE_MULTI LinkType = 12
BPF_LINK_TYPE_NETKIT LinkType = 13
BPF_LINK_TYPE_SOCKMAP LinkType = 14
__MAX_BPF_LINK_TYPE LinkType = 15
MAX_BPF_LINK_TYPE LinkType = 15
)

type MapType uint32
Expand Down Expand Up @@ -586,7 +588,7 @@ const (
BPF_MAP_TYPE_USER_RINGBUF MapType = 31
BPF_MAP_TYPE_CGRP_STORAGE MapType = 32
BPF_MAP_TYPE_ARENA MapType = 33
__MAX_BPF_MAP_TYPE MapType = 34
MAX_BPF_MAP_TYPE MapType = 34
)

type NetfilterInetHook uint32
Expand Down Expand Up @@ -658,7 +660,7 @@ const (
BPF_PROG_TYPE_SK_LOOKUP ProgType = 30
BPF_PROG_TYPE_SYSCALL ProgType = 31
BPF_PROG_TYPE_NETFILTER ProgType = 32
__MAX_BPF_PROG_TYPE ProgType = 33
MAX_BPF_PROG_TYPE ProgType = 33
)

type RetCode uint32
Expand Down Expand Up @@ -839,6 +841,14 @@ type SkLookup struct {
_ [4]byte
}

type TokenInfo struct {
_ structs.HostLayout
AllowedCmds uint64
AllowedMaps uint64
AllowedProgs uint64
AllowedAttachs uint64
}

type XdpMd struct {
_ structs.HostLayout
Data uint32
Expand Down Expand Up @@ -1566,6 +1576,20 @@ func RawTracepointOpen(attr *RawTracepointOpenAttr) (*FD, error) {
return NewFD(int(fd))
}

type TokenCreateAttr struct {
_ structs.HostLayout
Flags uint32
BpffsFd uint32
}

func TokenCreate(attr *TokenCreateAttr) (*FD, error) {
fd, err := BPF(BPF_TOKEN_CREATE, unsafe.Pointer(attr), unsafe.Sizeof(*attr))
if err != nil {
return nil, err
}
return NewFD(int(fd))
}

type CgroupLinkInfo struct {
_ structs.HostLayout
Type LinkType
Expand Down
Loading