diff --git a/pkg/containerd/opts/spec_unix.go b/pkg/containerd/opts/spec_unix.go index 6c1eefa22..97c819446 100644 --- a/pkg/containerd/opts/spec_unix.go +++ b/pkg/containerd/opts/spec_unix.go @@ -324,7 +324,7 @@ func WithDevices(osi osinterface.OS, config *runtime.ContainerConfig) oci.SpecOp Type: string(dev.Type), Major: &dev.Major, Minor: &dev.Minor, - Access: dev.Permissions, + Access: string(dev.Permissions), }) } return nil diff --git a/pkg/server/container_create_unix_test.go b/pkg/server/container_create_unix_test.go index 479c0849b..d55dea715 100644 --- a/pkg/server/container_create_unix_test.go +++ b/pkg/server/container_create_unix_test.go @@ -33,6 +33,7 @@ import ( "github.com/containerd/containerd/mount" "github.com/containerd/containerd/oci" imagespec "github.com/opencontainers/image-spec/specs-go/v1" + libcontainerconfigs "github.com/opencontainers/runc/libcontainer/configs" "github.com/opencontainers/runc/libcontainer/devices" runtimespec "github.com/opencontainers/runtime-spec/specs-go" "github.com/opencontainers/selinux/go-selinux" @@ -1193,8 +1194,15 @@ func TestPrivilegedDevices(t *testing.T) { spec, err := c.containerSpec(t.Name(), testSandboxID, testPid, "", testContainerName, containerConfig, sandboxConfig, imageConfig, nil, ociRuntime) assert.NoError(t, err) - hostDevices, err := devices.HostDevices() + hostDevicesRaw, err := devices.HostDevices() assert.NoError(t, err) + var hostDevices []*libcontainerconfigs.Device + for _, dev := range hostDevicesRaw { + // https://github.com/containerd/cri/pull/1521#issuecomment-652807951 + if dev.DeviceRule.Major != 0 { + hostDevices = append(hostDevices, dev) + } + } if test.expectHostDevices { assert.Len(t, spec.Linux.Devices, len(hostDevices)) diff --git a/vendor.conf b/vendor.conf index 5b21e5aa5..81955b62f 100644 --- a/vendor.conf +++ b/vendor.conf @@ -1,13 +1,13 @@ # cri dependencies github.com/docker/docker 4634ce647cf2ce2c6031129ccd109e557244986f -github.com/opencontainers/selinux bb88c45a3863dc4c38320d71b890bb30ef9feba4 +github.com/opencontainers/selinux v1.5.1 github.com/tchap/go-patricia v2.2.6 # containerd dependencies github.com/beorn7/perks v1.0.1 github.com/BurntSushi/toml v0.3.1 github.com/cespare/xxhash/v2 v2.1.1 -github.com/containerd/cgroups b4448137398923af7f4918b8b2ad8249172ca7a6 +github.com/containerd/cgroups e9676da73eddf8ed2433f77aaf3b9cf8f0f75b8c github.com/containerd/console v1.0.0 github.com/containerd/containerd v1.4.0-beta.0 github.com/containerd/continuity d3ef23f19fbb106bb73ffde425d07a9187e30745 @@ -16,14 +16,14 @@ github.com/containerd/go-runc 7016d3ce2328dd2cb1192b2076eb github.com/containerd/ttrpc v1.0.1 github.com/containerd/typeurl v1.0.1 github.com/coreos/go-systemd/v22 v22.0.0 -github.com/cpuguy83/go-md2man v1.0.10 +github.com/cpuguy83/go-md2man/v2 v2.0.0 github.com/docker/go-events e31b211e4f1cd09aa76fe4ac244571fab96ae47f github.com/docker/go-metrics v0.0.1 github.com/docker/go-units v0.4.0 github.com/godbus/dbus/v5 v5.0.3 github.com/gogo/googleapis v1.3.2 github.com/gogo/protobuf v1.3.1 -github.com/golang/protobuf v1.3.3 +github.com/golang/protobuf v1.3.5 github.com/google/uuid v1.1.1 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 github.com/hashicorp/errwrap v1.0.0 @@ -36,28 +36,29 @@ github.com/Microsoft/go-winio v0.4.14 github.com/Microsoft/hcsshim v0.8.9 github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/image-spec v1.0.1 -github.com/opencontainers/runc v1.0.0-rc10 -github.com/opencontainers/runtime-spec v1.0.2 +github.com/opencontainers/runc v1.0.0-rc91 +github.com/opencontainers/runtime-spec 237cc4f519e2e8f9b235bacccfa8ef5a84df2875 # v1.0.2-14-g8e2f17c github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.6.0 github.com/prometheus/client_model v0.2.0 github.com/prometheus/common v0.9.1 github.com/prometheus/procfs v0.0.11 -github.com/russross/blackfriday v1.5.2 +github.com/russross/blackfriday/v2 v2.0.1 +github.com/shurcooL/sanitized_anchor_name v1.0.0 github.com/sirupsen/logrus v1.6.0 github.com/syndtr/gocapability d98352740cb2c55f81556b63d4a1ec64c5a319c2 -github.com/urfave/cli v1.22.0 +github.com/urfave/cli v1.22.1 # NOTE: urfave/cli must be <= v1.22.1 due to a regression: https://github.com/urfave/cli/issues/1092 go.etcd.io/bbolt v1.3.3 go.opencensus.io v0.22.0 golang.org/x/net f3200d17e092c607f615320ecaad13d87ad9a2b3 golang.org/x/sync 42b317875d0fa942474b76e1b46a6060d720ae6e -golang.org/x/sys 5c8b2ff67527cb88b770f693cebf3799036d8bc0 +golang.org/x/sys 9dae0f8f577553e0f21298e18926efc9644c281d golang.org/x/text 19e51611da83d6be54ddafce4a4af510cb3e9ea4 google.golang.org/genproto e50cd9704f63023d62cd06a1994b98227fc4d21a google.golang.org/grpc v1.27.1 # cgroups dependencies -github.com/cilium/ebpf 4032b1d8aae306b7bb94a2a11002932caf88c644 +github.com/cilium/ebpf 1c8d4c9ef7759622653a1d319284a44652333b28 # kubernetes dependencies github.com/davecgh/go-spew v1.1.1 diff --git a/vendor/github.com/cilium/ebpf/abi.go b/vendor/github.com/cilium/ebpf/abi.go index 77227ffda..d432eb46f 100644 --- a/vendor/github.com/cilium/ebpf/abi.go +++ b/vendor/github.com/cilium/ebpf/abi.go @@ -3,14 +3,13 @@ package ebpf import ( "bufio" "bytes" + "errors" "fmt" "io" "os" "syscall" "github.com/cilium/ebpf/internal" - - "github.com/pkg/errors" ) // MapABI are the attributes of a Map which are available across all supported kernels. @@ -35,7 +34,7 @@ func newMapABIFromSpec(spec *MapSpec) *MapABI { func newMapABIFromFd(fd *internal.FD) (string, *MapABI, error) { info, err := bpfGetMapInfoByFD(fd) if err != nil { - if errors.Cause(err) == syscall.EINVAL { + if errors.Is(err, syscall.EINVAL) { abi, err := newMapABIFromProc(fd) return "", abi, err } @@ -98,7 +97,7 @@ func newProgramABIFromSpec(spec *ProgramSpec) *ProgramABI { func newProgramABIFromFd(fd *internal.FD) (string, *ProgramABI, error) { info, err := bpfGetProgInfoByFD(fd) if err != nil { - if errors.Cause(err) == syscall.EINVAL { + if errors.Is(err, syscall.EINVAL) { return newProgramABIFromProc(fd) } @@ -127,7 +126,7 @@ func newProgramABIFromProc(fd *internal.FD) (string, *ProgramABI, error) { "prog_type": &abi.Type, "prog_tag": &name, }) - if errors.Cause(err) == errMissingFields { + if errors.Is(err, errMissingFields) { return "", nil, &internal.UnsupportedFeatureError{ Name: "reading ABI from /proc/self/fdinfo", MinimumVersion: internal.Version{4, 11, 0}, @@ -152,7 +151,10 @@ func scanFdInfo(fd *internal.FD, fields map[string]interface{}) error { } defer fh.Close() - return errors.Wrap(scanFdInfoReader(fh, fields), fh.Name()) + if err := scanFdInfoReader(fh, fields); err != nil { + return fmt.Errorf("%s: %w", fh.Name(), err) + } + return nil } var errMissingFields = errors.New("missing fields") @@ -176,7 +178,7 @@ func scanFdInfoReader(r io.Reader, fields map[string]interface{}) error { } if n, err := fmt.Fscanln(bytes.NewReader(parts[1]), field); err != nil || n != 1 { - return errors.Wrapf(err, "can't parse field %s", name) + return fmt.Errorf("can't parse field %s: %v", name, err) } scanned++ diff --git a/vendor/github.com/cilium/ebpf/asm/instruction.go b/vendor/github.com/cilium/ebpf/asm/instruction.go index c8ed6cfb4..8fbcf5664 100644 --- a/vendor/github.com/cilium/ebpf/asm/instruction.go +++ b/vendor/github.com/cilium/ebpf/asm/instruction.go @@ -2,12 +2,11 @@ package asm import ( "encoding/binary" + "errors" "fmt" "io" "math" "strings" - - "github.com/pkg/errors" ) // InstructionSize is the size of a BPF instruction in bytes @@ -39,10 +38,12 @@ func (ins *Instruction) Unmarshal(r io.Reader, bo binary.ByteOrder) (uint64, err } ins.OpCode = bi.OpCode - ins.Dst = bi.Registers.Dst() - ins.Src = bi.Registers.Src() ins.Offset = bi.Offset ins.Constant = int64(bi.Constant) + ins.Dst, ins.Src, err = bi.Registers.Unmarshal(bo) + if err != nil { + return 0, fmt.Errorf("can't unmarshal registers: %s", err) + } if !bi.OpCode.isDWordLoad() { return InstructionSize, nil @@ -75,9 +76,14 @@ func (ins Instruction) Marshal(w io.Writer, bo binary.ByteOrder) (uint64, error) cons = int32(uint32(ins.Constant)) } + regs, err := newBPFRegisters(ins.Dst, ins.Src, bo) + if err != nil { + return 0, fmt.Errorf("can't marshal registers: %s", err) + } + bpfi := bpfInstruction{ ins.OpCode, - newBPFRegisters(ins.Dst, ins.Src), + regs, ins.Offset, cons, } @@ -103,22 +109,52 @@ func (ins Instruction) Marshal(w io.Writer, bo binary.ByteOrder) (uint64, error) // RewriteMapPtr changes an instruction to use a new map fd. // -// Returns an error if the fd is invalid, or the instruction -// is incorrect. +// Returns an error if the instruction doesn't load a map. func (ins *Instruction) RewriteMapPtr(fd int) error { if !ins.OpCode.isDWordLoad() { - return errors.Errorf("%s is not a 64 bit load", ins.OpCode) + return fmt.Errorf("%s is not a 64 bit load", ins.OpCode) } - if fd < 0 { - return errors.New("invalid fd") + if ins.Src != PseudoMapFD && ins.Src != PseudoMapValue { + return errors.New("not a load from a map") } - ins.Src = R1 - ins.Constant = int64(fd) + // Preserve the offset value for direct map loads. + offset := uint64(ins.Constant) & (math.MaxUint32 << 32) + rawFd := uint64(uint32(fd)) + ins.Constant = int64(offset | rawFd) return nil } +func (ins *Instruction) mapPtr() uint32 { + return uint32(uint64(ins.Constant) & math.MaxUint32) +} + +// RewriteMapOffset changes the offset of a direct load from a map. +// +// Returns an error if the instruction is not a direct load. +func (ins *Instruction) RewriteMapOffset(offset uint32) error { + if !ins.OpCode.isDWordLoad() { + return fmt.Errorf("%s is not a 64 bit load", ins.OpCode) + } + + if ins.Src != PseudoMapValue { + return errors.New("not a direct load from a map") + } + + fd := uint64(ins.Constant) & math.MaxUint32 + ins.Constant = int64(uint64(offset)<<32 | fd) + return nil +} + +func (ins *Instruction) mapOffset() uint32 { + return uint32(uint64(ins.Constant) >> 32) +} + +func (ins *Instruction) isLoadFromMap() bool { + return ins.OpCode == LoadImmOp(DWord) && (ins.Src == PseudoMapFD || ins.Src == PseudoMapValue) +} + // Format implements fmt.Formatter. func (ins Instruction) Format(f fmt.State, c rune) { if c != 'v' { @@ -139,6 +175,19 @@ func (ins Instruction) Format(f fmt.State, c rune) { return } + if ins.isLoadFromMap() { + fd := int32(ins.mapPtr()) + switch ins.Src { + case PseudoMapFD: + fmt.Fprintf(f, "LoadMapPtr dst: %s fd: %d", ins.Dst, fd) + + case PseudoMapValue: + fmt.Fprintf(f, "LoadMapValue dst: %s, fd: %d off: %d", ins.Dst, fd, ins.mapOffset()) + } + + goto ref + } + fmt.Fprintf(f, "%v ", op) switch cls := op.Class(); cls { case LdClass, LdXClass, StClass, StXClass: @@ -166,7 +215,7 @@ func (ins Instruction) Format(f fmt.State, c rune) { case JumpClass: switch jop := op.JumpOp(); jop { case Call: - if ins.Src == R1 { + if ins.Src == PseudoCall { // bpf-to-bpf call fmt.Fprint(f, ins.Constant) } else { @@ -183,6 +232,7 @@ func (ins Instruction) Format(f fmt.State, c rune) { } } +ref: if ins.Reference != "" { fmt.Fprintf(f, " <%s>", ins.Reference) } @@ -235,7 +285,7 @@ func (insns Instructions) SymbolOffsets() (map[string]int, error) { } if _, ok := offsets[ins.Symbol]; ok { - return nil, errors.Errorf("duplicate symbol %s", ins.Symbol) + return nil, fmt.Errorf("duplicate symbol %s", ins.Symbol) } offsets[ins.Symbol] = i @@ -273,7 +323,7 @@ func (insns Instructions) marshalledOffsets() (map[string]int, error) { } if _, ok := symbols[ins.Symbol]; ok { - return nil, errors.Errorf("duplicate symbol %s", ins.Symbol) + return nil, fmt.Errorf("duplicate symbol %s", ins.Symbol) } symbols[ins.Symbol] = currentPos @@ -350,11 +400,11 @@ func (insns Instructions) Marshal(w io.Writer, bo binary.ByteOrder) error { num := 0 for i, ins := range insns { switch { - case ins.OpCode.JumpOp() == Call && ins.Constant == -1: + case ins.OpCode.JumpOp() == Call && ins.Src == PseudoCall && ins.Constant == -1: // Rewrite bpf to bpf call offset, ok := absoluteOffsets[ins.Reference] if !ok { - return errors.Errorf("instruction %d: reference to missing symbol %s", i, ins.Reference) + return fmt.Errorf("instruction %d: reference to missing symbol %s", i, ins.Reference) } ins.Constant = int64(offset - num - 1) @@ -363,7 +413,7 @@ func (insns Instructions) Marshal(w io.Writer, bo binary.ByteOrder) error { // Rewrite jump to label offset, ok := absoluteOffsets[ins.Reference] if !ok { - return errors.Errorf("instruction %d: reference to missing symbol %s", i, ins.Reference) + return fmt.Errorf("instruction %d: reference to missing symbol %s", i, ins.Reference) } ins.Offset = int16(offset - num - 1) @@ -371,7 +421,7 @@ func (insns Instructions) Marshal(w io.Writer, bo binary.ByteOrder) error { n, err := ins.Marshal(w, bo) if err != nil { - return errors.Wrapf(err, "instruction %d", i) + return fmt.Errorf("instruction %d: %w", i, err) } num += int(n / InstructionSize) @@ -388,16 +438,26 @@ type bpfInstruction struct { type bpfRegisters uint8 -func newBPFRegisters(dst, src Register) bpfRegisters { - return bpfRegisters((src << 4) | (dst & 0xF)) +func newBPFRegisters(dst, src Register, bo binary.ByteOrder) (bpfRegisters, error) { + switch bo { + case binary.LittleEndian: + return bpfRegisters((src << 4) | (dst & 0xF)), nil + case binary.BigEndian: + return bpfRegisters((dst << 4) | (src & 0xF)), nil + default: + return 0, fmt.Errorf("unrecognized ByteOrder %T", bo) + } } -func (r bpfRegisters) Dst() Register { - return Register(r & 0xF) -} - -func (r bpfRegisters) Src() Register { - return Register(r >> 4) +func (r bpfRegisters) Unmarshal(bo binary.ByteOrder) (dst, src Register, err error) { + switch bo { + case binary.LittleEndian: + return Register(r & 0xF), Register(r >> 4), nil + case binary.BigEndian: + return Register(r >> 4), Register(r & 0xf), nil + default: + return 0, 0, fmt.Errorf("unrecognized ByteOrder %T", bo) + } } type unreferencedSymbolError struct { diff --git a/vendor/github.com/cilium/ebpf/asm/jump.go b/vendor/github.com/cilium/ebpf/asm/jump.go index 33c9b5656..7757179de 100644 --- a/vendor/github.com/cilium/ebpf/asm/jump.go +++ b/vendor/github.com/cilium/ebpf/asm/jump.go @@ -95,7 +95,7 @@ func (op JumpOp) Label(label string) Instruction { if op == Call { return Instruction{ OpCode: OpCode(JumpClass).SetJumpOp(Call), - Src: R1, + Src: PseudoCall, Constant: -1, Reference: label, } diff --git a/vendor/github.com/cilium/ebpf/asm/load_store.go b/vendor/github.com/cilium/ebpf/asm/load_store.go index ab0e92fc3..2d0ec648e 100644 --- a/vendor/github.com/cilium/ebpf/asm/load_store.go +++ b/vendor/github.com/cilium/ebpf/asm/load_store.go @@ -110,11 +110,26 @@ func LoadMapPtr(dst Register, fd int) Instruction { return Instruction{ OpCode: LoadImmOp(DWord), Dst: dst, - Src: R1, + Src: PseudoMapFD, Constant: int64(fd), } } +// LoadMapValue stores a pointer to the value at a certain offset of a map. +func LoadMapValue(dst Register, fd int, offset uint32) Instruction { + if fd < 0 { + return Instruction{OpCode: InvalidOpCode} + } + + fdAndOffset := (uint64(offset) << 32) | uint64(uint32(fd)) + return Instruction{ + OpCode: LoadImmOp(DWord), + Dst: dst, + Src: PseudoMapValue, + Constant: int64(fdAndOffset), + } +} + // LoadIndOp returns the OpCode for loading a value of given size from an sk_buff. func LoadIndOp(size Size) OpCode { return OpCode(LdClass).SetMode(IndMode).SetSize(size) diff --git a/vendor/github.com/cilium/ebpf/asm/opcode.go b/vendor/github.com/cilium/ebpf/asm/opcode.go index d796de3fe..c99b6595a 100644 --- a/vendor/github.com/cilium/ebpf/asm/opcode.go +++ b/vendor/github.com/cilium/ebpf/asm/opcode.go @@ -225,7 +225,7 @@ func (op OpCode) String() string { } default: - fmt.Fprintf(&f, "%#x", op) + fmt.Fprintf(&f, "OpCode(%#x)", uint8(op)) } return f.String() diff --git a/vendor/github.com/cilium/ebpf/asm/register.go b/vendor/github.com/cilium/ebpf/asm/register.go index 4f284fbe7..76cb44bff 100644 --- a/vendor/github.com/cilium/ebpf/asm/register.go +++ b/vendor/github.com/cilium/ebpf/asm/register.go @@ -33,6 +33,13 @@ const ( RFP = R10 ) +// Pseudo registers used by 64bit loads and jumps +const ( + PseudoMapFD = R1 // BPF_PSEUDO_MAP_FD + PseudoMapValue = R2 // BPF_PSEUDO_MAP_VALUE + PseudoCall = R1 // BPF_PSEUDO_CALL +) + func (r Register) String() string { v := uint8(r) if v == 10 { diff --git a/vendor/github.com/cilium/ebpf/collection.go b/vendor/github.com/cilium/ebpf/collection.go index bf6a96d4a..0c8b65d94 100644 --- a/vendor/github.com/cilium/ebpf/collection.go +++ b/vendor/github.com/cilium/ebpf/collection.go @@ -1,9 +1,13 @@ package ebpf import ( + "errors" + "fmt" + "math" + "github.com/cilium/ebpf/asm" + "github.com/cilium/ebpf/internal" "github.com/cilium/ebpf/internal/btf" - "github.com/pkg/errors" ) // CollectionOptions control loading a collection into the kernel. @@ -39,6 +43,89 @@ func (cs *CollectionSpec) Copy() *CollectionSpec { return &cpy } +// RewriteMaps replaces all references to specific maps. +// +// Use this function to use pre-existing maps instead of creating new ones +// when calling NewCollection. Any named maps are removed from CollectionSpec.Maps. +// +// Returns an error if a named map isn't used in at least one program. +func (cs *CollectionSpec) RewriteMaps(maps map[string]*Map) error { + for symbol, m := range maps { + // have we seen a program that uses this symbol / map + seen := false + fd := m.FD() + for progName, progSpec := range cs.Programs { + err := progSpec.Instructions.RewriteMapPtr(symbol, fd) + + switch { + case err == nil: + seen = true + + case asm.IsUnreferencedSymbol(err): + // Not all programs need to use the map + + default: + return fmt.Errorf("program %s: %w", progName, err) + } + } + + if !seen { + return fmt.Errorf("map %s not referenced by any programs", symbol) + } + + // Prevent NewCollection from creating rewritten maps + delete(cs.Maps, symbol) + } + + return nil +} + +// RewriteConstants replaces the value of multiple constants. +// +// The constant must be defined like so in the C program: +// +// static volatile const type foobar; +// static volatile const type foobar = default; +// +// Replacement values must be of the same length as the C sizeof(type). +// If necessary, they are marshalled according to the same rules as +// map values. +// +// From Linux 5.5 the verifier will use constants to eliminate dead code. +// +// Returns an error if a constant doesn't exist. +func (cs *CollectionSpec) RewriteConstants(consts map[string]interface{}) error { + rodata := cs.Maps[".rodata"] + if rodata == nil { + return errors.New("missing .rodata section") + } + + if rodata.BTF == nil { + return errors.New(".rodata section has no BTF") + } + + if n := len(rodata.Contents); n != 1 { + return fmt.Errorf("expected one key in .rodata, found %d", n) + } + + kv := rodata.Contents[0] + value, ok := kv.Value.([]byte) + if !ok { + return fmt.Errorf("first value in .rodata is %T not []byte", kv.Value) + } + + buf := make([]byte, len(value)) + copy(buf, value) + + err := patchValue(buf, btf.MapValue(rodata.BTF), consts) + if err != nil { + return err + } + + rodata.Contents[0] = MapKV{kv.Key, buf} + return nil +} + // Collection is a collection of Programs and Maps associated // with their symbols type Collection struct { @@ -99,14 +186,14 @@ func NewCollectionWithOptions(spec *CollectionSpec, opts CollectionOptions) (col var handle *btf.Handle if mapSpec.BTF != nil { handle, err = loadBTF(btf.MapSpec(mapSpec.BTF)) - if err != nil && !btf.IsNotSupported(err) { + if err != nil && !errors.Is(err, btf.ErrNotSupported) { return nil, err } } m, err := newMapWithBTF(mapSpec, handle) if err != nil { - return nil, errors.Wrapf(err, "map %s", mapName) + return nil, fmt.Errorf("map %s: %w", mapName, err) } maps[mapName] = m } @@ -116,37 +203,43 @@ func NewCollectionWithOptions(spec *CollectionSpec, opts CollectionOptions) (col // Rewrite any reference to a valid map. for i := range progSpec.Instructions { - var ( - ins = &progSpec.Instructions[i] - m = maps[ins.Reference] - ) + ins := &progSpec.Instructions[i] - if ins.Reference == "" || m == nil { + if ins.OpCode != asm.LoadImmOp(asm.DWord) || ins.Reference == "" { continue } - if ins.Src == asm.R1 { + if uint32(ins.Constant) != math.MaxUint32 { // Don't overwrite maps already rewritten, users can // rewrite programs in the spec themselves continue } + m := maps[ins.Reference] + if m == nil { + return nil, fmt.Errorf("program %s: missing map %s", progName, ins.Reference) + } + + fd := m.FD() + if fd < 0 { + return nil, fmt.Errorf("map %s: %w", ins.Reference, internal.ErrClosedFd) + } if err := ins.RewriteMapPtr(m.FD()); err != nil { - return nil, errors.Wrapf(err, "progam %s: map %s", progName, ins.Reference) + return nil, fmt.Errorf("progam %s: map %s: %w", progName, ins.Reference, err) } } var handle *btf.Handle if progSpec.BTF != nil { handle, err = loadBTF(btf.ProgramSpec(progSpec.BTF)) - if err != nil && !btf.IsNotSupported(err) { + if err != nil && !errors.Is(err, btf.ErrNotSupported) { return nil, err } } prog, err := newProgramWithBTF(progSpec, handle, opts.Programs) if err != nil { - return nil, errors.Wrapf(err, "program %s", progName) + return nil, fmt.Errorf("program %s: %w", progName, err) } progs[progName] = prog } diff --git a/vendor/github.com/cilium/ebpf/elf_reader.go b/vendor/github.com/cilium/ebpf/elf_reader.go index c33b744f8..77acaed8d 100644 --- a/vendor/github.com/cilium/ebpf/elf_reader.go +++ b/vendor/github.com/cilium/ebpf/elf_reader.go @@ -4,21 +4,23 @@ import ( "bytes" "debug/elf" "encoding/binary" + "errors" + "fmt" "io" + "math" "os" "strings" "github.com/cilium/ebpf/asm" "github.com/cilium/ebpf/internal" "github.com/cilium/ebpf/internal/btf" - - "github.com/pkg/errors" + "github.com/cilium/ebpf/internal/unix" ) type elfCode struct { *elf.File symbols []elf.Symbol - symbolsPerSection map[elf.SectionIndex]map[uint64]string + symbolsPerSection map[elf.SectionIndex]map[uint64]elf.Symbol license string version uint32 } @@ -32,7 +34,10 @@ func LoadCollectionSpec(file string) (*CollectionSpec, error) { defer f.Close() spec, err := LoadCollectionSpecFromReader(f) - return spec, errors.Wrapf(err, "file %s", file) + if err != nil { + return nil, fmt.Errorf("file %s: %w", file, err) + } + return spec, nil } // LoadCollectionSpecFromReader parses an ELF file into a CollectionSpec. @@ -45,7 +50,7 @@ func LoadCollectionSpecFromReader(rd io.ReaderAt) (*CollectionSpec, error) { symbols, err := f.Symbols() if err != nil { - return nil, errors.Wrap(err, "load symbols") + return nil, fmt.Errorf("load symbols: %v", err) } ec := &elfCode{f, symbols, symbolsPerSection(symbols), "", 0} @@ -57,6 +62,7 @@ func LoadCollectionSpecFromReader(rd io.ReaderAt) (*CollectionSpec, error) { progSections = make(map[elf.SectionIndex]*elf.Section) relSections = make(map[elf.SectionIndex]*elf.Section) mapSections = make(map[elf.SectionIndex]*elf.Section) + dataSections = make(map[elf.SectionIndex]*elf.Section) ) for i, sec := range ec.Sections { @@ -69,15 +75,17 @@ func LoadCollectionSpecFromReader(rd io.ReaderAt) (*CollectionSpec, error) { mapSections[elf.SectionIndex(i)] = sec case sec.Name == ".maps": btfMaps[elf.SectionIndex(i)] = sec + case sec.Name == ".bss" || sec.Name == ".rodata" || sec.Name == ".data": + dataSections[elf.SectionIndex(i)] = sec case sec.Type == elf.SHT_REL: if int(sec.Info) >= len(ec.Sections) { - return nil, errors.Errorf("found relocation section %v for missing section %v", i, sec.Info) + return nil, fmt.Errorf("found relocation section %v for missing section %v", i, sec.Info) } // Store relocations under the section index of the target idx := elf.SectionIndex(sec.Info) if relSections[idx] != nil { - return nil, errors.Errorf("section %d has multiple relocation sections", sec.Info) + return nil, fmt.Errorf("section %d has multiple relocation sections", sec.Info) } relSections[idx] = sec case sec.Type == elf.SHT_PROGBITS && (sec.Flags&elf.SHF_EXECINSTR) != 0 && sec.Size > 0: @@ -87,34 +95,52 @@ func LoadCollectionSpecFromReader(rd io.ReaderAt) (*CollectionSpec, error) { ec.license, err = loadLicense(licenseSection) if err != nil { - return nil, errors.Wrap(err, "load license") + return nil, fmt.Errorf("load license: %w", err) } ec.version, err = loadVersion(versionSection, ec.ByteOrder) if err != nil { - return nil, errors.Wrap(err, "load version") + return nil, fmt.Errorf("load version: %w", err) } - btf, err := btf.LoadSpecFromReader(rd) + btfSpec, err := btf.LoadSpecFromReader(rd) if err != nil { - return nil, errors.Wrap(err, "load BTF") + return nil, fmt.Errorf("load BTF: %w", err) + } + + relocations, referencedSections, err := ec.loadRelocations(relSections) + if err != nil { + return nil, fmt.Errorf("load relocations: %w", err) } maps := make(map[string]*MapSpec) - if err := ec.loadMaps(maps, mapSections); err != nil { - return nil, errors.Wrap(err, "load maps") + return nil, fmt.Errorf("load maps: %w", err) } if len(btfMaps) > 0 { - if err := ec.loadBTFMaps(maps, btfMaps, btf); err != nil { - return nil, errors.Wrap(err, "load BTF maps") + if err := ec.loadBTFMaps(maps, btfMaps, btfSpec); err != nil { + return nil, fmt.Errorf("load BTF maps: %w", err) } } - progs, err := ec.loadPrograms(progSections, relSections, btf) + if len(dataSections) > 0 { + for idx := range dataSections { + if !referencedSections[idx] { + // Prune data sections which are not referenced by any + // instructions. + delete(dataSections, idx) + } + } + + if err := ec.loadDataSections(maps, dataSections, btfSpec); err != nil { + return nil, fmt.Errorf("load data sections: %w", err) + } + } + + progs, err := ec.loadPrograms(progSections, relocations, btfSpec) if err != nil { - return nil, errors.Wrap(err, "load programs") + return nil, fmt.Errorf("load programs: %w", err) } return &CollectionSpec{maps, progs}, nil @@ -122,11 +148,12 @@ func LoadCollectionSpecFromReader(rd io.ReaderAt) (*CollectionSpec, error) { func loadLicense(sec *elf.Section) (string, error) { if sec == nil { - return "", errors.Errorf("missing license section") + return "", nil } + data, err := sec.Data() if err != nil { - return "", errors.Wrapf(err, "section %s", sec.Name) + return "", fmt.Errorf("section %s: %v", sec.Name, err) } return string(bytes.TrimRight(data, "\000")), nil } @@ -137,52 +164,51 @@ func loadVersion(sec *elf.Section, bo binary.ByteOrder) (uint32, error) { } var version uint32 - err := binary.Read(sec.Open(), bo, &version) - return version, errors.Wrapf(err, "section %s", sec.Name) + if err := binary.Read(sec.Open(), bo, &version); err != nil { + return 0, fmt.Errorf("section %s: %v", sec.Name, err) + } + return version, nil } -func (ec *elfCode) loadPrograms(progSections, relSections map[elf.SectionIndex]*elf.Section, btf *btf.Spec) (map[string]*ProgramSpec, error) { +func (ec *elfCode) loadPrograms(progSections map[elf.SectionIndex]*elf.Section, relocations map[elf.SectionIndex]map[uint64]elf.Symbol, btfSpec *btf.Spec) (map[string]*ProgramSpec, error) { var ( progs []*ProgramSpec libs []*ProgramSpec ) - for idx, prog := range progSections { + for idx, sec := range progSections { syms := ec.symbolsPerSection[idx] if len(syms) == 0 { - return nil, errors.Errorf("section %v: missing symbols", prog.Name) + return nil, fmt.Errorf("section %v: missing symbols", sec.Name) } - funcSym := syms[0] - if funcSym == "" { - return nil, errors.Errorf("section %v: no label at start", prog.Name) + funcSym, ok := syms[0] + if !ok { + return nil, fmt.Errorf("section %v: no label at start", sec.Name) } - rels, err := ec.loadRelocations(relSections[idx]) + insns, length, err := ec.loadInstructions(sec, syms, relocations[idx]) if err != nil { - return nil, errors.Wrapf(err, "program %s: can't load relocations", funcSym) + return nil, fmt.Errorf("program %s: can't unmarshal instructions: %w", funcSym.Name, err) } - insns, length, err := ec.loadInstructions(prog, syms, rels) - if err != nil { - return nil, errors.Wrapf(err, "program %s: can't unmarshal instructions", funcSym) - } - - progType, attachType := getProgType(prog.Name) + progType, attachType, attachTo := getProgType(sec.Name) spec := &ProgramSpec{ - Name: funcSym, + Name: funcSym.Name, Type: progType, AttachType: attachType, + AttachTo: attachTo, License: ec.license, KernelVersion: ec.version, Instructions: insns, + ByteOrder: ec.ByteOrder, } - if btf != nil { - spec.BTF, err = btf.Program(prog.Name, length) - if err != nil { - return nil, errors.Wrapf(err, "BTF for section %s (program %s)", prog.Name, funcSym) + if btfSpec != nil { + spec.BTF, err = btfSpec.Program(sec.Name, length) + if err != nil && !errors.Is(err, btf.ErrNoExtendedInfo) { + return nil, fmt.Errorf("program %s: %w", funcSym.Name, err) } } @@ -200,7 +226,7 @@ func (ec *elfCode) loadPrograms(progSections, relSections map[elf.SectionIndex]* for _, prog := range progs { err := link(prog, libs) if err != nil { - return nil, errors.Wrapf(err, "program %s", prog.Name) + return nil, fmt.Errorf("program %s: %w", prog.Name, err) } res[prog.Name] = prog } @@ -208,39 +234,158 @@ func (ec *elfCode) loadPrograms(progSections, relSections map[elf.SectionIndex]* return res, nil } -func (ec *elfCode) loadInstructions(section *elf.Section, symbols, relocations map[uint64]string) (asm.Instructions, uint64, error) { +func (ec *elfCode) loadInstructions(section *elf.Section, symbols, relocations map[uint64]elf.Symbol) (asm.Instructions, uint64, error) { var ( r = section.Open() insns asm.Instructions - ins asm.Instruction offset uint64 ) for { + var ins asm.Instruction n, err := ins.Unmarshal(r, ec.ByteOrder) if err == io.EOF { return insns, offset, nil } if err != nil { - return nil, 0, errors.Wrapf(err, "offset %d", offset) + return nil, 0, fmt.Errorf("offset %d: %w", offset, err) } - ins.Symbol = symbols[offset] - ins.Reference = relocations[offset] + ins.Symbol = symbols[offset].Name + + if rel, ok := relocations[offset]; ok { + if err = ec.relocateInstruction(&ins, rel); err != nil { + return nil, 0, fmt.Errorf("offset %d: can't relocate instruction: %w", offset, err) + } + } insns = append(insns, ins) offset += n } } +func (ec *elfCode) relocateInstruction(ins *asm.Instruction, rel elf.Symbol) error { + var ( + typ = elf.ST_TYPE(rel.Info) + bind = elf.ST_BIND(rel.Info) + name = rel.Name + ) + + if typ == elf.STT_SECTION { + // Symbols with section type do not have a name set. Get it + // from the section itself. + idx := int(rel.Section) + if idx > len(ec.Sections) { + return errors.New("out-of-bounds section index") + } + + name = ec.Sections[idx].Name + } + +outer: + switch { + case ins.OpCode == asm.LoadImmOp(asm.DWord): + // There are two distinct types of a load from a map: + // a direct one, where the value is extracted without + // a call to map_lookup_elem in eBPF, and an indirect one + // that goes via the helper. They are distinguished by + // different relocations. + switch typ { + case elf.STT_SECTION: + // This is a direct load since the referenced symbol is a + // section. Weirdly, the offset of the real symbol in the + // section is encoded in the instruction stream. + if bind != elf.STB_LOCAL { + return fmt.Errorf("direct load: %s: unsupported relocation %s", name, bind) + } + + // For some reason, clang encodes the offset of the symbol its + // section in the first basic BPF instruction, while the kernel + // expects it in the second one. + ins.Constant <<= 32 + ins.Src = asm.PseudoMapValue + + case elf.STT_NOTYPE: + if bind == elf.STB_GLOBAL && rel.Section == elf.SHN_UNDEF { + // This is a relocation generated by inline assembly. + // We can't do more than assigning ins.Reference. + break outer + } + + // This is an ELF generated on clang < 8, which doesn't tag + // relocations appropriately. + fallthrough + + case elf.STT_OBJECT: + if bind != elf.STB_GLOBAL { + return fmt.Errorf("load: %s: unsupported binding: %s", name, bind) + } + + ins.Src = asm.PseudoMapFD + + default: + return fmt.Errorf("load: %s: unsupported relocation: %s", name, typ) + } + + // Mark the instruction as needing an update when creating the + // collection. + if err := ins.RewriteMapPtr(-1); err != nil { + return err + } + + case ins.OpCode.JumpOp() == asm.Call: + if ins.Src != asm.PseudoCall { + return fmt.Errorf("call: %s: incorrect source register", name) + } + + switch typ { + case elf.STT_NOTYPE, elf.STT_FUNC: + if bind != elf.STB_GLOBAL { + return fmt.Errorf("call: %s: unsupported binding: %s", name, bind) + } + + case elf.STT_SECTION: + if bind != elf.STB_LOCAL { + return fmt.Errorf("call: %s: unsupported binding: %s", name, bind) + } + + // The function we want to call is in the indicated section, + // at the offset encoded in the instruction itself. Reverse + // the calculation to find the real function we're looking for. + // A value of -1 references the first instruction in the section. + offset := int64(int32(ins.Constant)+1) * asm.InstructionSize + if offset < 0 { + return fmt.Errorf("call: %s: invalid offset %d", name, offset) + } + + sym, ok := ec.symbolsPerSection[rel.Section][uint64(offset)] + if !ok { + return fmt.Errorf("call: %s: no symbol at offset %d", name, offset) + } + + ins.Constant = -1 + name = sym.Name + + default: + return fmt.Errorf("call: %s: invalid symbol type %s", name, typ) + } + + default: + return fmt.Errorf("relocation for unsupported instruction: %s", ins.OpCode) + } + + ins.Reference = name + return nil +} + func (ec *elfCode) loadMaps(maps map[string]*MapSpec, mapSections map[elf.SectionIndex]*elf.Section) error { for idx, sec := range mapSections { syms := ec.symbolsPerSection[idx] if len(syms) == 0 { - return errors.Errorf("section %v: no symbols", sec.Name) + return fmt.Errorf("section %v: no symbols", sec.Name) } if sec.Size%uint64(len(syms)) != 0 { - return errors.Errorf("section %v: map descriptors are not of equal size", sec.Name) + return fmt.Errorf("section %v: map descriptors are not of equal size", sec.Name) } var ( @@ -248,36 +393,38 @@ func (ec *elfCode) loadMaps(maps map[string]*MapSpec, mapSections map[elf.Sectio size = sec.Size / uint64(len(syms)) ) for i, offset := 0, uint64(0); i < len(syms); i, offset = i+1, offset+size { - mapSym := syms[offset] - if mapSym == "" { - return errors.Errorf("section %s: missing symbol for map at offset %d", sec.Name, offset) + mapSym, ok := syms[offset] + if !ok { + return fmt.Errorf("section %s: missing symbol for map at offset %d", sec.Name, offset) } - if maps[mapSym] != nil { - return errors.Errorf("section %v: map %v already exists", sec.Name, mapSym) + if maps[mapSym.Name] != nil { + return fmt.Errorf("section %v: map %v already exists", sec.Name, mapSym) } lr := io.LimitReader(r, int64(size)) - var spec MapSpec + spec := MapSpec{ + Name: SanitizeName(mapSym.Name, -1), + } switch { case binary.Read(lr, ec.ByteOrder, &spec.Type) != nil: - return errors.Errorf("map %v: missing type", mapSym) + return fmt.Errorf("map %v: missing type", mapSym) case binary.Read(lr, ec.ByteOrder, &spec.KeySize) != nil: - return errors.Errorf("map %v: missing key size", mapSym) + return fmt.Errorf("map %v: missing key size", mapSym) case binary.Read(lr, ec.ByteOrder, &spec.ValueSize) != nil: - return errors.Errorf("map %v: missing value size", mapSym) + return fmt.Errorf("map %v: missing value size", mapSym) case binary.Read(lr, ec.ByteOrder, &spec.MaxEntries) != nil: - return errors.Errorf("map %v: missing max entries", mapSym) + return fmt.Errorf("map %v: missing max entries", mapSym) case binary.Read(lr, ec.ByteOrder, &spec.Flags) != nil: - return errors.Errorf("map %v: missing flags", mapSym) + return fmt.Errorf("map %v: missing flags", mapSym) } if _, err := io.Copy(internal.DiscardZeroes{}, lr); err != nil { - return errors.Errorf("map %v: unknown and non-zero fields in definition", mapSym) + return fmt.Errorf("map %v: unknown and non-zero fields in definition", mapSym) } - maps[mapSym] = &spec + maps[mapSym.Name] = &spec } } @@ -285,85 +432,117 @@ func (ec *elfCode) loadMaps(maps map[string]*MapSpec, mapSections map[elf.Sectio } func (ec *elfCode) loadBTFMaps(maps map[string]*MapSpec, mapSections map[elf.SectionIndex]*elf.Section, spec *btf.Spec) error { - if spec == nil { - return errors.Errorf("missing BTF") + return fmt.Errorf("missing BTF") } for idx, sec := range mapSections { syms := ec.symbolsPerSection[idx] if len(syms) == 0 { - return errors.Errorf("section %v: no symbols", sec.Name) + return fmt.Errorf("section %v: no symbols", sec.Name) } for _, sym := range syms { - if maps[sym] != nil { - return errors.Errorf("section %v: map %v already exists", sec.Name, sym) + name := sym.Name + if maps[name] != nil { + return fmt.Errorf("section %v: map %v already exists", sec.Name, sym) } - btfMap, err := spec.Map(sym) + mapSpec, err := mapSpecFromBTF(spec, name) if err != nil { - return errors.Wrapf(err, "map %v: can't get BTF", sym) + return fmt.Errorf("map %v: %w", name, err) } - spec, err := mapSpecFromBTF(btfMap) - if err != nil { - return errors.Wrapf(err, "map %v", sym) - } - - maps[sym] = spec + maps[name] = mapSpec } } return nil } -func mapSpecFromBTF(btfMap *btf.Map) (*MapSpec, error) { +func mapSpecFromBTF(spec *btf.Spec, name string) (*MapSpec, error) { + btfMap, btfMapMembers, err := spec.Map(name) + if err != nil { + return nil, fmt.Errorf("can't get BTF: %w", err) + } + + keyType := btf.MapKey(btfMap) + size, err := btf.Sizeof(keyType) + if err != nil { + return nil, fmt.Errorf("can't get size of BTF key: %w", err) + } + keySize := uint32(size) + + valueType := btf.MapValue(btfMap) + size, err = btf.Sizeof(valueType) + if err != nil { + return nil, fmt.Errorf("can't get size of BTF value: %w", err) + } + valueSize := uint32(size) + var ( mapType, flags, maxEntries uint32 - err error ) - for _, member := range btf.MapType(btfMap).Members { + for _, member := range btfMapMembers { switch member.Name { case "type": mapType, err = uintFromBTF(member.Type) if err != nil { - return nil, errors.Wrap(err, "can't get type") + return nil, fmt.Errorf("can't get type: %w", err) } case "map_flags": flags, err = uintFromBTF(member.Type) if err != nil { - return nil, errors.Wrap(err, "can't get BTF map flags") + return nil, fmt.Errorf("can't get BTF map flags: %w", err) } case "max_entries": maxEntries, err = uintFromBTF(member.Type) if err != nil { - return nil, errors.Wrap(err, "can't get BTF map max entries") + return nil, fmt.Errorf("can't get BTF map max entries: %w", err) } - case "key": - case "value": + case "key_size": + if _, isVoid := keyType.(*btf.Void); !isVoid { + return nil, errors.New("both key and key_size given") + } + + keySize, err = uintFromBTF(member.Type) + if err != nil { + return nil, fmt.Errorf("can't get BTF key size: %w", err) + } + + case "value_size": + if _, isVoid := valueType.(*btf.Void); !isVoid { + return nil, errors.New("both value and value_size given") + } + + valueSize, err = uintFromBTF(member.Type) + if err != nil { + return nil, fmt.Errorf("can't get BTF value size: %w", err) + } + + case "pinning": + pinning, err := uintFromBTF(member.Type) + if err != nil { + return nil, fmt.Errorf("can't get pinning: %w", err) + } + + if pinning != 0 { + return nil, fmt.Errorf("'pinning' attribute not supported: %w", ErrNotSupported) + } + + case "key", "value": default: - return nil, errors.Errorf("unrecognized field %s in BTF map definition", member.Name) + return nil, fmt.Errorf("unrecognized field %s in BTF map definition", member.Name) } } - keySize, err := btf.Sizeof(btf.MapKey(btfMap)) - if err != nil { - return nil, errors.Wrap(err, "can't get size of BTF key") - } - - valueSize, err := btf.Sizeof(btf.MapValue(btfMap)) - if err != nil { - return nil, errors.Wrap(err, "can't get size of BTF value") - } - return &MapSpec{ Type: MapType(mapType), - KeySize: uint32(keySize), - ValueSize: uint32(valueSize), + KeySize: keySize, + ValueSize: valueSize, MaxEntries: maxEntries, Flags: flags, BTF: btfMap, @@ -375,127 +554,163 @@ func mapSpecFromBTF(btfMap *btf.Map) (*MapSpec, error) { func uintFromBTF(typ btf.Type) (uint32, error) { ptr, ok := typ.(*btf.Pointer) if !ok { - return 0, errors.Errorf("not a pointer: %v", typ) + return 0, fmt.Errorf("not a pointer: %v", typ) } arr, ok := ptr.Target.(*btf.Array) if !ok { - return 0, errors.Errorf("not a pointer to array: %v", typ) + return 0, fmt.Errorf("not a pointer to array: %v", typ) } return arr.Nelems, nil } -func getProgType(v string) (ProgramType, AttachType) { - types := map[string]ProgramType{ - // From https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/tools/lib/bpf/libbpf.c#n3568 - "socket": SocketFilter, - "seccomp": SocketFilter, - "kprobe/": Kprobe, - "uprobe/": Kprobe, - "kretprobe/": Kprobe, - "uretprobe/": Kprobe, - "tracepoint/": TracePoint, - "raw_tracepoint/": RawTracepoint, - "xdp": XDP, - "perf_event": PerfEvent, - "lwt_in": LWTIn, - "lwt_out": LWTOut, - "lwt_xmit": LWTXmit, - "lwt_seg6local": LWTSeg6Local, - "sockops": SockOps, - "sk_skb": SkSKB, - "sk_msg": SkMsg, - "lirc_mode2": LircMode2, - "flow_dissector": FlowDissector, - - "cgroup_skb/": CGroupSKB, - "cgroup/dev": CGroupDevice, - "cgroup/skb": CGroupSKB, - "cgroup/sock": CGroupSock, - "cgroup/post_bind": CGroupSock, - "cgroup/bind": CGroupSockAddr, - "cgroup/connect": CGroupSockAddr, - "cgroup/sendmsg": CGroupSockAddr, - "cgroup/recvmsg": CGroupSockAddr, - "cgroup/sysctl": CGroupSysctl, - "cgroup/getsockopt": CGroupSockopt, - "cgroup/setsockopt": CGroupSockopt, - "classifier": SchedCLS, - "action": SchedACT, - } - attachTypes := map[string]AttachType{ - "cgroup_skb/ingress": AttachCGroupInetIngress, - "cgroup_skb/egress": AttachCGroupInetEgress, - "cgroup/sock": AttachCGroupInetSockCreate, - "cgroup/post_bind4": AttachCGroupInet4PostBind, - "cgroup/post_bind6": AttachCGroupInet6PostBind, - "cgroup/dev": AttachCGroupDevice, - "sockops": AttachCGroupSockOps, - "sk_skb/stream_parser": AttachSkSKBStreamParser, - "sk_skb/stream_verdict": AttachSkSKBStreamVerdict, - "sk_msg": AttachSkSKBStreamVerdict, - "lirc_mode2": AttachLircMode2, - "flow_dissector": AttachFlowDissector, - "cgroup/bind4": AttachCGroupInet4Bind, - "cgroup/bind6": AttachCGroupInet6Bind, - "cgroup/connect4": AttachCGroupInet4Connect, - "cgroup/connect6": AttachCGroupInet6Connect, - "cgroup/sendmsg4": AttachCGroupUDP4Sendmsg, - "cgroup/sendmsg6": AttachCGroupUDP6Sendmsg, - "cgroup/recvmsg4": AttachCGroupUDP4Recvmsg, - "cgroup/recvmsg6": AttachCGroupUDP6Recvmsg, - "cgroup/sysctl": AttachCGroupSysctl, - "cgroup/getsockopt": AttachCGroupGetsockopt, - "cgroup/setsockopt": AttachCGroupSetsockopt, - } - attachType := AttachNone - for k, t := range attachTypes { - if strings.HasPrefix(v, k) { - attachType = t - } +func (ec *elfCode) loadDataSections(maps map[string]*MapSpec, dataSections map[elf.SectionIndex]*elf.Section, spec *btf.Spec) error { + if spec == nil { + return errors.New("data sections require BTF, make sure all consts are marked as static") } - for k, t := range types { - if strings.HasPrefix(v, k) { - return t, attachType + for _, sec := range dataSections { + btfMap, err := spec.Datasec(sec.Name) + if err != nil { + return err } + + data, err := sec.Data() + if err != nil { + return fmt.Errorf("data section %s: can't get contents: %w", sec.Name, err) + } + + if uint64(len(data)) > math.MaxUint32 { + return fmt.Errorf("data section %s: contents exceed maximum size", sec.Name) + } + + mapSpec := &MapSpec{ + Name: SanitizeName(sec.Name, -1), + Type: Array, + KeySize: 4, + ValueSize: uint32(len(data)), + MaxEntries: 1, + Contents: []MapKV{{uint32(0), data}}, + BTF: btfMap, + } + + switch sec.Name { + case ".rodata": + mapSpec.Flags = unix.BPF_F_RDONLY_PROG + mapSpec.Freeze = true + case ".bss": + // The kernel already zero-initializes the map + mapSpec.Contents = nil + } + + maps[sec.Name] = mapSpec } - return UnspecifiedProgram, AttachNone + return nil } -func (ec *elfCode) loadRelocations(sec *elf.Section) (map[uint64]string, error) { - rels := make(map[uint64]string) - if sec == nil { - return rels, nil +func getProgType(sectionName string) (ProgramType, AttachType, string) { + types := map[string]struct { + progType ProgramType + attachType AttachType + }{ + // From https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/tools/lib/bpf/libbpf.c + "socket": {SocketFilter, AttachNone}, + "seccomp": {SocketFilter, AttachNone}, + "kprobe/": {Kprobe, AttachNone}, + "uprobe/": {Kprobe, AttachNone}, + "kretprobe/": {Kprobe, AttachNone}, + "uretprobe/": {Kprobe, AttachNone}, + "tracepoint/": {TracePoint, AttachNone}, + "raw_tracepoint/": {RawTracepoint, AttachNone}, + "xdp": {XDP, AttachNone}, + "perf_event": {PerfEvent, AttachNone}, + "lwt_in": {LWTIn, AttachNone}, + "lwt_out": {LWTOut, AttachNone}, + "lwt_xmit": {LWTXmit, AttachNone}, + "lwt_seg6local": {LWTSeg6Local, AttachNone}, + "sockops": {SockOps, AttachCGroupSockOps}, + "sk_skb/stream_parser": {SkSKB, AttachSkSKBStreamParser}, + "sk_skb/stream_verdict": {SkSKB, AttachSkSKBStreamParser}, + "sk_msg": {SkMsg, AttachSkSKBStreamVerdict}, + "lirc_mode2": {LircMode2, AttachLircMode2}, + "flow_dissector": {FlowDissector, AttachFlowDissector}, + "iter/": {Tracing, AttachTraceIter}, + + "cgroup_skb/ingress": {CGroupSKB, AttachCGroupInetIngress}, + "cgroup_skb/egress": {CGroupSKB, AttachCGroupInetEgress}, + "cgroup/dev": {CGroupDevice, AttachCGroupDevice}, + "cgroup/skb": {CGroupSKB, AttachNone}, + "cgroup/sock": {CGroupSock, AttachCGroupInetSockCreate}, + "cgroup/post_bind4": {CGroupSock, AttachCGroupInet4PostBind}, + "cgroup/post_bind6": {CGroupSock, AttachCGroupInet6PostBind}, + "cgroup/bind4": {CGroupSockAddr, AttachCGroupInet4Bind}, + "cgroup/bind6": {CGroupSockAddr, AttachCGroupInet6Bind}, + "cgroup/connect4": {CGroupSockAddr, AttachCGroupInet4Connect}, + "cgroup/connect6": {CGroupSockAddr, AttachCGroupInet6Connect}, + "cgroup/sendmsg4": {CGroupSockAddr, AttachCGroupUDP4Sendmsg}, + "cgroup/sendmsg6": {CGroupSockAddr, AttachCGroupUDP6Sendmsg}, + "cgroup/recvmsg4": {CGroupSockAddr, AttachCGroupUDP4Recvmsg}, + "cgroup/recvmsg6": {CGroupSockAddr, AttachCGroupUDP6Recvmsg}, + "cgroup/sysctl": {CGroupSysctl, AttachCGroupSysctl}, + "cgroup/getsockopt": {CGroupSockopt, AttachCGroupGetsockopt}, + "cgroup/setsockopt": {CGroupSockopt, AttachCGroupSetsockopt}, + "classifier": {SchedCLS, AttachNone}, + "action": {SchedACT, AttachNone}, } - if sec.Entsize < 16 { - return nil, errors.New("rels are less than 16 bytes") - } - - r := sec.Open() - for off := uint64(0); off < sec.Size; off += sec.Entsize { - ent := io.LimitReader(r, int64(sec.Entsize)) - - var rel elf.Rel64 - if binary.Read(ent, ec.ByteOrder, &rel) != nil { - return nil, errors.Errorf("can't parse relocation at offset %v", off) + for prefix, t := range types { + if !strings.HasPrefix(sectionName, prefix) { + continue } - symNo := int(elf.R_SYM64(rel.Info) - 1) - if symNo >= len(ec.symbols) { - return nil, errors.Errorf("relocation at offset %d: symbol %v doesnt exist", off, symNo) + if !strings.HasSuffix(prefix, "/") { + return t.progType, t.attachType, "" } - rels[rel.Off] = ec.symbols[symNo].Name + return t.progType, t.attachType, sectionName[len(prefix):] } - return rels, nil + + return UnspecifiedProgram, AttachNone, "" } -func symbolsPerSection(symbols []elf.Symbol) map[elf.SectionIndex]map[uint64]string { - result := make(map[elf.SectionIndex]map[uint64]string) - for i, sym := range symbols { +func (ec *elfCode) loadRelocations(sections map[elf.SectionIndex]*elf.Section) (map[elf.SectionIndex]map[uint64]elf.Symbol, map[elf.SectionIndex]bool, error) { + result := make(map[elf.SectionIndex]map[uint64]elf.Symbol) + targets := make(map[elf.SectionIndex]bool) + for idx, sec := range sections { + rels := make(map[uint64]elf.Symbol) + + if sec.Entsize < 16 { + return nil, nil, fmt.Errorf("section %s: relocations are less than 16 bytes", sec.Name) + } + + r := sec.Open() + for off := uint64(0); off < sec.Size; off += sec.Entsize { + ent := io.LimitReader(r, int64(sec.Entsize)) + + var rel elf.Rel64 + if binary.Read(ent, ec.ByteOrder, &rel) != nil { + return nil, nil, fmt.Errorf("can't parse relocation at offset %v", off) + } + + symNo := int(elf.R_SYM64(rel.Info) - 1) + if symNo >= len(ec.symbols) { + return nil, nil, fmt.Errorf("relocation at offset %d: symbol %v doesnt exist", off, symNo) + } + + symbol := ec.symbols[symNo] + targets[symbol.Section] = true + rels[rel.Off] = ec.symbols[symNo] + } + + result[idx] = rels + } + return result, targets, nil +} + +func symbolsPerSection(symbols []elf.Symbol) map[elf.SectionIndex]map[uint64]elf.Symbol { + result := make(map[elf.SectionIndex]map[uint64]elf.Symbol) + for _, sym := range symbols { switch elf.ST_TYPE(sym.Info) { case elf.STT_NOTYPE: // Older versions of LLVM doesn't tag @@ -509,15 +724,19 @@ func symbolsPerSection(symbols []elf.Symbol) map[elf.SectionIndex]map[uint64]str continue } + if sym.Section == elf.SHN_UNDEF || sym.Section >= elf.SHN_LORESERVE { + continue + } + if sym.Name == "" { continue } idx := sym.Section if _, ok := result[idx]; !ok { - result[idx] = make(map[uint64]string) + result[idx] = make(map[uint64]elf.Symbol) } - result[idx][sym.Value] = symbols[i].Name + result[idx][sym.Value] = sym } return result } diff --git a/vendor/github.com/cilium/ebpf/go.mod b/vendor/github.com/cilium/ebpf/go.mod index 687bdec9f..a05cf85ed 100644 --- a/vendor/github.com/cilium/ebpf/go.mod +++ b/vendor/github.com/cilium/ebpf/go.mod @@ -1,8 +1,5 @@ module github.com/cilium/ebpf -go 1.12 +go 1.13 -require ( - github.com/pkg/errors v0.8.1 - golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7 -) +require golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9 diff --git a/vendor/github.com/cilium/ebpf/internal/btf/btf.go b/vendor/github.com/cilium/ebpf/internal/btf/btf.go index b2122f37e..3dd000a28 100644 --- a/vendor/github.com/cilium/ebpf/internal/btf/btf.go +++ b/vendor/github.com/cilium/ebpf/internal/btf/btf.go @@ -4,20 +4,29 @@ import ( "bytes" "debug/elf" "encoding/binary" + "errors" + "fmt" "io" "io/ioutil" "math" + "os" "reflect" + "sync" "unsafe" "github.com/cilium/ebpf/internal" "github.com/cilium/ebpf/internal/unix" - - "github.com/pkg/errors" ) const btfMagic = 0xeB9F +// Errors returned by BTF functions. +var ( + ErrNotSupported = internal.ErrNotSupported + ErrNotFound = errors.New("not found") + ErrNoExtendedInfo = errors.New("no extended info") +) + // Spec represents decoded BTF. type Spec struct { rawTypes []rawType @@ -25,6 +34,7 @@ type Spec struct { types map[string][]Type funcInfos map[string]extInfo lineInfos map[string]extInfo + byteOrder binary.ByteOrder } type btfHeader struct { @@ -52,6 +62,7 @@ func LoadSpecFromReader(rd io.ReaderAt) (*Spec, error) { var ( btfSection *elf.Section btfExtSection *elf.Section + sectionSizes = make(map[string]uint32) ) for _, sec := range file.Sections { @@ -60,6 +71,16 @@ func LoadSpecFromReader(rd io.ReaderAt) (*Spec, error) { btfSection = sec case ".BTF.ext": btfExtSection = sec + default: + if sec.Type != elf.SHT_PROGBITS && sec.Type != elf.SHT_NOBITS { + break + } + + if sec.Size > math.MaxUint32 { + return nil, fmt.Errorf("section %s exceeds maximum size", sec.Name) + } + + sectionSizes[sec.Name] = uint32(sec.Size) } } @@ -67,74 +88,59 @@ func LoadSpecFromReader(rd io.ReaderAt) (*Spec, error) { return nil, nil } - spec, err := parseBTF(btfSection.Open(), file.ByteOrder) + symbols, err := file.Symbols() + if err != nil { + return nil, fmt.Errorf("can't read symbols: %v", err) + } + + variableOffsets := make(map[variable]uint32) + for _, symbol := range symbols { + if idx := symbol.Section; idx >= elf.SHN_LORESERVE && idx <= elf.SHN_HIRESERVE { + // Ignore things like SHN_ABS + continue + } + + secName := file.Sections[symbol.Section].Name + if _, ok := sectionSizes[secName]; !ok { + continue + } + + if symbol.Value > math.MaxUint32 { + return nil, fmt.Errorf("section %s: symbol %s: size exceeds maximum", secName, symbol.Name) + } + + variableOffsets[variable{secName, symbol.Name}] = uint32(symbol.Value) + } + + spec, err := loadNakedSpec(btfSection.Open(), file.ByteOrder, sectionSizes, variableOffsets) if err != nil { return nil, err } - if btfExtSection != nil { - spec.funcInfos, spec.lineInfos, err = parseExtInfos(btfExtSection.Open(), file.ByteOrder, spec.strings) - if err != nil { - return nil, errors.Wrap(err, "can't read ext info") - } + if btfExtSection == nil { + return spec, nil + } + + spec.funcInfos, spec.lineInfos, err = parseExtInfos(btfExtSection.Open(), file.ByteOrder, spec.strings) + if err != nil { + return nil, fmt.Errorf("can't read ext info: %w", err) } return spec, nil } -func parseBTF(btf io.ReadSeeker, bo binary.ByteOrder) (*Spec, error) { - rawBTF, err := ioutil.ReadAll(btf) +func loadNakedSpec(btf io.ReadSeeker, bo binary.ByteOrder, sectionSizes map[string]uint32, variableOffsets map[variable]uint32) (*Spec, error) { + rawTypes, rawStrings, err := parseBTF(btf, bo) if err != nil { - return nil, errors.Wrap(err, "can't read BTF") + return nil, err } - rd := bytes.NewReader(rawBTF) - - var header btfHeader - if err := binary.Read(rd, bo, &header); err != nil { - return nil, errors.Wrap(err, "can't read header") - } - - if header.Magic != btfMagic { - return nil, errors.Errorf("incorrect magic value %v", header.Magic) - } - - if header.Version != 1 { - return nil, errors.Errorf("unexpected version %v", header.Version) - } - - if header.Flags != 0 { - return nil, errors.Errorf("unsupported flags %v", header.Flags) - } - - remainder := int64(header.HdrLen) - int64(binary.Size(&header)) - if remainder < 0 { - return nil, errors.New("header is too short") - } - - if _, err := io.CopyN(internal.DiscardZeroes{}, rd, remainder); err != nil { - return nil, errors.Wrap(err, "header padding") - } - - if _, err := rd.Seek(int64(header.HdrLen+header.StringOff), io.SeekStart); err != nil { - return nil, errors.Wrap(err, "can't seek to start of string section") - } - - strings, err := readStringTable(io.LimitReader(rd, int64(header.StringLen))) + err = fixupDatasec(rawTypes, rawStrings, sectionSizes, variableOffsets) if err != nil { - return nil, errors.Wrap(err, "can't read type names") + return nil, err } - if _, err := rd.Seek(int64(header.HdrLen+header.TypeOff), io.SeekStart); err != nil { - return nil, errors.Wrap(err, "can't seek to start of type section") - } - - rawTypes, err := readTypes(io.LimitReader(rd, int64(header.TypeLen)), bo) - if err != nil { - return nil, errors.Wrap(err, "can't read types") - } - - types, err := inflateRawTypes(rawTypes, strings) + types, err := inflateRawTypes(rawTypes, rawStrings) if err != nil { return nil, err } @@ -142,13 +148,158 @@ func parseBTF(btf io.ReadSeeker, bo binary.ByteOrder) (*Spec, error) { return &Spec{ rawTypes: rawTypes, types: types, - strings: strings, - funcInfos: make(map[string]extInfo), - lineInfos: make(map[string]extInfo), + strings: rawStrings, + byteOrder: bo, }, nil } -func (s *Spec) marshal(bo binary.ByteOrder) ([]byte, error) { +var kernelBTF struct { + sync.Mutex + *Spec +} + +// LoadKernelSpec returns the current kernel's BTF information. +// +// Requires a >= 5.5 kernel with CONFIG_DEBUG_INFO_BTF enabled. Returns +// ErrNotSupported if BTF is not enabled. +func LoadKernelSpec() (*Spec, error) { + kernelBTF.Lock() + defer kernelBTF.Unlock() + + if kernelBTF.Spec != nil { + return kernelBTF.Spec, nil + } + + var err error + kernelBTF.Spec, err = loadKernelSpec() + return kernelBTF.Spec, err +} + +func loadKernelSpec() (*Spec, error) { + fh, err := os.Open("/sys/kernel/btf/vmlinux") + if os.IsNotExist(err) { + return nil, fmt.Errorf("can't open kernel BTF at /sys/kernel/btf/vmlinux: %w", ErrNotFound) + } + if err != nil { + return nil, fmt.Errorf("can't read kernel BTF: %s", err) + } + defer fh.Close() + + return loadNakedSpec(fh, internal.NativeEndian, nil, nil) +} + +func parseBTF(btf io.ReadSeeker, bo binary.ByteOrder) ([]rawType, stringTable, error) { + rawBTF, err := ioutil.ReadAll(btf) + if err != nil { + return nil, nil, fmt.Errorf("can't read BTF: %v", err) + } + + rd := bytes.NewReader(rawBTF) + + var header btfHeader + if err := binary.Read(rd, bo, &header); err != nil { + return nil, nil, fmt.Errorf("can't read header: %v", err) + } + + if header.Magic != btfMagic { + return nil, nil, fmt.Errorf("incorrect magic value %v", header.Magic) + } + + if header.Version != 1 { + return nil, nil, fmt.Errorf("unexpected version %v", header.Version) + } + + if header.Flags != 0 { + return nil, nil, fmt.Errorf("unsupported flags %v", header.Flags) + } + + remainder := int64(header.HdrLen) - int64(binary.Size(&header)) + if remainder < 0 { + return nil, nil, errors.New("header is too short") + } + + if _, err := io.CopyN(internal.DiscardZeroes{}, rd, remainder); err != nil { + return nil, nil, fmt.Errorf("header padding: %v", err) + } + + if _, err := rd.Seek(int64(header.HdrLen+header.StringOff), io.SeekStart); err != nil { + return nil, nil, fmt.Errorf("can't seek to start of string section: %v", err) + } + + rawStrings, err := readStringTable(io.LimitReader(rd, int64(header.StringLen))) + if err != nil { + return nil, nil, fmt.Errorf("can't read type names: %w", err) + } + + if _, err := rd.Seek(int64(header.HdrLen+header.TypeOff), io.SeekStart); err != nil { + return nil, nil, fmt.Errorf("can't seek to start of type section: %v", err) + } + + rawTypes, err := readTypes(io.LimitReader(rd, int64(header.TypeLen)), bo) + if err != nil { + return nil, nil, fmt.Errorf("can't read types: %w", err) + } + + return rawTypes, rawStrings, nil +} + +type variable struct { + section string + name string +} + +func fixupDatasec(rawTypes []rawType, rawStrings stringTable, sectionSizes map[string]uint32, variableOffsets map[variable]uint32) error { + for i, rawType := range rawTypes { + if rawType.Kind() != kindDatasec { + continue + } + + name, err := rawStrings.Lookup(rawType.NameOff) + if err != nil { + return err + } + + if name == ".kconfig" || name == ".ksym" { + return fmt.Errorf("reference to %s: %w", name, ErrNotSupported) + } + + size, ok := sectionSizes[name] + if !ok { + return fmt.Errorf("data section %s: missing size", name) + } + + rawTypes[i].SizeType = size + + secinfos := rawType.data.([]btfVarSecinfo) + for j, secInfo := range secinfos { + id := int(secInfo.Type - 1) + if id >= len(rawTypes) { + return fmt.Errorf("data section %s: invalid type id %d for variable %d", name, id, j) + } + + varName, err := rawStrings.Lookup(rawTypes[id].NameOff) + if err != nil { + return fmt.Errorf("data section %s: can't get name for type %d: %w", name, id, err) + } + + offset, ok := variableOffsets[variable{name, varName}] + if !ok { + return fmt.Errorf("data section %s: missing offset for variable %s", name, varName) + } + + secinfos[j].Offset = offset + } + } + + return nil +} + +type marshalOpts struct { + ByteOrder binary.ByteOrder + StripFuncLinkage bool +} + +func (s *Spec) marshal(opts marshalOpts) ([]byte, error) { var ( buf bytes.Buffer header = new(btfHeader) @@ -160,17 +311,14 @@ func (s *Spec) marshal(bo binary.ByteOrder) ([]byte, error) { _, _ = buf.Write(make([]byte, headerLen)) // Write type section, just after the header. - for _, typ := range s.rawTypes { - if typ.Kind() == kindDatasec { - // Datasec requires patching with information from the ELF - // file. We don't support this at the moment, so patch - // out any Datasec by turning it into a void*. - typ = rawType{} - typ.SetKind(kindPointer) + for _, raw := range s.rawTypes { + switch { + case opts.StripFuncLinkage && raw.Kind() == kindFunc: + raw.SetLinkage(linkageStatic) } - if err := typ.Marshal(&buf, bo); err != nil { - return nil, errors.Wrap(err, "can't marshal BTF") + if err := raw.Marshal(&buf, opts.ByteOrder); err != nil { + return nil, fmt.Errorf("can't marshal BTF: %w", err) } } @@ -192,9 +340,9 @@ func (s *Spec) marshal(bo binary.ByteOrder) ([]byte, error) { } raw := buf.Bytes() - err := binary.Write(sliceWriter(raw[:headerLen]), bo, header) + err := binary.Write(sliceWriter(raw[:headerLen]), opts.ByteOrder, header) if err != nil { - return nil, errors.Wrap(err, "can't write header") + return nil, fmt.Errorf("can't write header: %v", err) } return raw, nil @@ -214,17 +362,22 @@ func (sw sliceWriter) Write(p []byte) (int, error) { // // Length is the number of bytes in the raw BPF instruction stream. // -// Returns an error if there is no BTF. +// Returns an error which may wrap ErrNoExtendedInfo if the Spec doesn't +// contain extended BTF info. func (s *Spec) Program(name string, length uint64) (*Program, error) { if length == 0 { return nil, errors.New("length musn't be zero") } + if s.funcInfos == nil && s.lineInfos == nil { + return nil, fmt.Errorf("BTF for section %s: %w", name, ErrNoExtendedInfo) + } + funcInfos, funcOK := s.funcInfos[name] lineInfos, lineOK := s.lineInfos[name] if !funcOK && !lineOK { - return nil, errors.Errorf("no BTF for program %s", name) + return nil, fmt.Errorf("no extended BTF info for section %s", name) } return &Program{s, length, funcInfos, lineInfos}, nil @@ -233,15 +386,15 @@ func (s *Spec) Program(name string, length uint64) (*Program, error) { // Map finds the BTF for a map. // // Returns an error if there is no BTF for the given name. -func (s *Spec) Map(name string) (*Map, error) { +func (s *Spec) Map(name string) (*Map, []Member, error) { var mapVar Var if err := s.FindType(name, &mapVar); err != nil { - return nil, err + return nil, nil, err } mapStruct, ok := mapVar.Type.(*Struct) if !ok { - return nil, errors.Errorf("expected struct, have %s", mapVar.Type) + return nil, nil, fmt.Errorf("expected struct, have %s", mapVar.Type) } var key, value Type @@ -256,23 +409,32 @@ func (s *Spec) Map(name string) (*Map, error) { } if key == nil { - return nil, errors.Errorf("map %s: missing 'key' in type", name) + key = (*Void)(nil) } if value == nil { - return nil, errors.Errorf("map %s: missing 'value' in type", name) + value = (*Void)(nil) } - return &Map{mapStruct, s, key, value}, nil + return &Map{s, key, value}, mapStruct.Members, nil } -var errNotFound = errors.New("not found") +// Datasec returns the BTF required to create maps which represent data sections. +func (s *Spec) Datasec(name string) (*Map, error) { + var datasec Datasec + if err := s.FindType(name, &datasec); err != nil { + return nil, fmt.Errorf("data section %s: can't get BTF: %w", name, err) + } + + return &Map{s, &Void{}, &datasec}, nil +} // FindType searches for a type with a specific name. // // hint determines the type of the returned Type. // -// Returns an error if there is no or multiple matches. +// Returns an error wrapping ErrNotFound if no matching +// type exists in spec. func (s *Spec) FindType(name string, typ Type) error { var ( wanted = reflect.TypeOf(typ) @@ -285,14 +447,14 @@ func (s *Spec) FindType(name string, typ Type) error { } if candidate != nil { - return errors.Errorf("type %s: multiple candidates for %T", name, typ) + return fmt.Errorf("type %s: multiple candidates for %T", name, typ) } candidate = typ } if candidate == nil { - return errors.WithMessagef(errNotFound, "type %s", name) + return fmt.Errorf("type %s: %w", name, ErrNotFound) } value := reflect.Indirect(reflect.ValueOf(copyType(candidate))) @@ -307,16 +469,22 @@ type Handle struct { // NewHandle loads BTF into the kernel. // -// Returns an error if BTF is not supported, which can -// be checked by IsNotSupported. +// Returns ErrNotSupported if BTF is not supported. func NewHandle(spec *Spec) (*Handle, error) { if err := haveBTF(); err != nil { return nil, err } - btf, err := spec.marshal(internal.NativeEndian) + if spec.byteOrder != internal.NativeEndian { + return nil, fmt.Errorf("can't load %s BTF on %s", spec.byteOrder, internal.NativeEndian) + } + + btf, err := spec.marshal(marshalOpts{ + ByteOrder: internal.NativeEndian, + StripFuncLinkage: haveFuncLinkage() != nil, + }) if err != nil { - return nil, errors.Wrap(err, "can't marshal BTF") + return nil, fmt.Errorf("can't marshal BTF: %w", err) } if uint64(len(btf)) > math.MaxUint32 { @@ -360,7 +528,6 @@ func (h *Handle) FD() int { // Map is the BTF for a map. type Map struct { - definition *Struct spec *Spec key, value Type } @@ -371,12 +538,6 @@ func MapSpec(m *Map) *Spec { return m.spec } -// MapType should be a method on Map, but is a free function -// to hide it from users of the ebpf package. -func MapType(m *Map) *Struct { - return m.definition -} - // MapKey should be a method on Map, but is a free function // to hide it from users of the ebpf package. func MapKey(m *Map) Type { @@ -411,12 +572,12 @@ func ProgramSpec(s *Program) *Spec { func ProgramAppend(s, other *Program) error { funcInfos, err := s.funcInfos.append(other.funcInfos, s.length) if err != nil { - return errors.Wrap(err, "func infos") + return fmt.Errorf("func infos: %w", err) } lineInfos, err := s.lineInfos.append(other.lineInfos, s.length) if err != nil { - return errors.Wrap(err, "line infos") + return fmt.Errorf("line infos: %w", err) } s.length += other.length @@ -451,13 +612,6 @@ func ProgramLineInfos(s *Program) (recordSize uint32, bytes []byte, err error) { return s.lineInfos.recordSize, bytes, nil } -// IsNotSupported returns true if the error indicates that the kernel -// doesn't support BTF. -func IsNotSupported(err error) bool { - ufe, ok := errors.Cause(err).(*internal.UnsupportedFeatureError) - return ok && ufe.Name == "BTF" -} - type bpfLoadBTFAttr struct { btf internal.Pointer logBuf internal.Pointer @@ -477,26 +631,36 @@ func bpfLoadBTF(attr *bpfLoadBTFAttr) (*internal.FD, error) { return internal.NewFD(uint32(fd)), nil } -func minimalBTF(bo binary.ByteOrder) []byte { +func marshalBTF(types interface{}, strings []byte, bo binary.ByteOrder) []byte { const minHeaderLength = 24 + typesLen := uint32(binary.Size(types)) + header := btfHeader{ + Magic: btfMagic, + Version: 1, + HdrLen: minHeaderLength, + TypeOff: 0, + TypeLen: typesLen, + StringOff: typesLen, + StringLen: uint32(len(strings)), + } + + buf := new(bytes.Buffer) + _ = binary.Write(buf, bo, &header) + _ = binary.Write(buf, bo, types) + buf.Write(strings) + + return buf.Bytes() +} + +var haveBTF = internal.FeatureTest("BTF", "5.1", func() (bool, error) { var ( types struct { Integer btfType Var btfType btfVar struct{ Linkage uint32 } } - typLen = uint32(binary.Size(&types)) strings = []byte{0, 'a', 0} - header = btfHeader{ - Magic: btfMagic, - Version: 1, - HdrLen: minHeaderLength, - TypeOff: 0, - TypeLen: typLen, - StringOff: typLen, - StringLen: uint32(len(strings)), - } ) // We use a BTF_KIND_VAR here, to make sure that @@ -507,16 +671,8 @@ func minimalBTF(bo binary.ByteOrder) []byte { types.Var.SetKind(kindVar) types.Var.SizeType = 1 - buf := new(bytes.Buffer) - _ = binary.Write(buf, bo, &header) - _ = binary.Write(buf, bo, &types) - buf.Write(strings) + btf := marshalBTF(&types, strings, internal.NativeEndian) - return buf.Bytes() -} - -var haveBTF = internal.FeatureTest("BTF", "5.1", func() bool { - btf := minimalBTF(internal.NativeEndian) fd, err := bpfLoadBTF(&bpfLoadBTFAttr{ btf: internal.NewSlicePointer(btf), btfSize: uint32(len(btf)), @@ -526,5 +682,35 @@ var haveBTF = internal.FeatureTest("BTF", "5.1", func() bool { } // Check for EINVAL specifically, rather than err != nil since we // otherwise misdetect due to insufficient permissions. - return errors.Cause(err) != unix.EINVAL + return !errors.Is(err, unix.EINVAL), nil +}) + +var haveFuncLinkage = internal.FeatureTest("BTF func linkage", "5.6", func() (bool, error) { + var ( + types struct { + FuncProto btfType + Func btfType + } + strings = []byte{0, 'a', 0} + ) + + types.FuncProto.SetKind(kindFuncProto) + types.Func.SetKind(kindFunc) + types.Func.SizeType = 1 // aka FuncProto + types.Func.NameOff = 1 + types.Func.SetLinkage(linkageGlobal) + + btf := marshalBTF(&types, strings, internal.NativeEndian) + + fd, err := bpfLoadBTF(&bpfLoadBTFAttr{ + btf: internal.NewSlicePointer(btf), + btfSize: uint32(len(btf)), + }) + if err == nil { + fd.Close() + } + + // Check for EINVAL specifically, rather than err != nil since we + // otherwise misdetect due to insufficient permissions. + return !errors.Is(err, unix.EINVAL), nil }) diff --git a/vendor/github.com/cilium/ebpf/internal/btf/btf_types.go b/vendor/github.com/cilium/ebpf/internal/btf/btf_types.go index 6570fedff..e34a87ecb 100644 --- a/vendor/github.com/cilium/ebpf/internal/btf/btf_types.go +++ b/vendor/github.com/cilium/ebpf/internal/btf/btf_types.go @@ -2,9 +2,8 @@ package btf import ( "encoding/binary" + "fmt" "io" - - "github.com/pkg/errors" ) // btfKind describes a Type. @@ -32,6 +31,14 @@ const ( kindDatasec ) +type btfFuncLinkage uint8 + +const ( + linkageStatic btfFuncLinkage = iota + linkageGlobal + linkageExtern +) + const ( btfTypeKindShift = 24 btfTypeKindLen = 4 @@ -43,7 +50,7 @@ const ( type btfType struct { NameOff uint32 /* "info" bits arrangement - * bits 0-15: vlen (e.g. # of struct's members) + * bits 0-15: vlen (e.g. # of struct's members), linkage * bits 16-23: unused * bits 24-27: kind (e.g. int, ptr, array...etc) * bits 28-30: unused @@ -61,6 +68,45 @@ type btfType struct { SizeType uint32 } +func (k btfKind) String() string { + switch k { + case kindUnknown: + return "Unknown" + case kindInt: + return "Integer" + case kindPointer: + return "Pointer" + case kindArray: + return "Array" + case kindStruct: + return "Struct" + case kindUnion: + return "Union" + case kindEnum: + return "Enumeration" + case kindForward: + return "Forward" + case kindTypedef: + return "Typedef" + case kindVolatile: + return "Volatile" + case kindConst: + return "Const" + case kindRestrict: + return "Restrict" + case kindFunc: + return "Function" + case kindFuncProto: + return "Function Proto" + case kindVar: + return "Variable" + case kindDatasec: + return "Section" + default: + return fmt.Sprintf("Unknown (%d)", k) + } +} + func mask(len uint32) uint32 { return (1 << len) - 1 } @@ -90,6 +136,14 @@ func (bt *btfType) SetVlen(vlen int) { bt.setInfo(uint32(vlen), btfTypeVlenMask, btfTypeVlenShift) } +func (bt *btfType) Linkage() btfFuncLinkage { + return btfFuncLinkage(bt.info(btfTypeVlenMask, btfTypeVlenShift)) +} + +func (bt *btfType) SetLinkage(linkage btfFuncLinkage) { + bt.setInfo(uint32(linkage), btfTypeVlenMask, btfTypeVlenShift) +} + func (bt *btfType) Type() TypeID { // TODO: Panic here if wrong kind? return TypeID(bt.SizeType) @@ -129,6 +183,26 @@ type btfMember struct { Offset uint32 } +type btfVarSecinfo struct { + Type TypeID + Offset uint32 + Size uint32 +} + +type btfVariable struct { + Linkage uint32 +} + +type btfEnum struct { + NameOff uint32 + Val int32 +} + +type btfParam struct { + NameOff uint32 + Type TypeID +} + func readTypes(r io.Reader, bo binary.ByteOrder) ([]rawType, error) { var ( header btfType @@ -139,14 +213,13 @@ func readTypes(r io.Reader, bo binary.ByteOrder) ([]rawType, error) { if err := binary.Read(r, bo, &header); err == io.EOF { return types, nil } else if err != nil { - return nil, errors.Wrapf(err, "can't read type info for id %v", id) + return nil, fmt.Errorf("can't read type info for id %v: %v", id, err) } var data interface{} switch header.Kind() { case kindInt: - // sizeof(uint32) - data = make([]byte, 4) + data = new(uint32) case kindPointer: case kindArray: data = new(btfArray) @@ -155,8 +228,7 @@ func readTypes(r io.Reader, bo binary.ByteOrder) ([]rawType, error) { case kindUnion: data = make([]btfMember, header.Vlen()) case kindEnum: - // sizeof(struct btf_enum) - data = make([]byte, header.Vlen()*4*2) + data = make([]btfEnum, header.Vlen()) case kindForward: case kindTypedef: case kindVolatile: @@ -164,16 +236,13 @@ func readTypes(r io.Reader, bo binary.ByteOrder) ([]rawType, error) { case kindRestrict: case kindFunc: case kindFuncProto: - // sizeof(struct btf_param) - data = make([]byte, header.Vlen()*4*2) + data = make([]btfParam, header.Vlen()) case kindVar: - // sizeof(struct btf_variable) - data = make([]byte, 4) + data = new(btfVariable) case kindDatasec: - // sizeof(struct btf_var_secinfo) - data = make([]byte, header.Vlen()*4*3) + data = make([]btfVarSecinfo, header.Vlen()) default: - return nil, errors.Errorf("type id %v: unknown kind: %v", id, header.Kind()) + return nil, fmt.Errorf("type id %v: unknown kind: %v", id, header.Kind()) } if data == nil { @@ -182,7 +251,7 @@ func readTypes(r io.Reader, bo binary.ByteOrder) ([]rawType, error) { } if err := binary.Read(r, bo, data); err != nil { - return nil, errors.Wrapf(err, "type id %d: kind %v: can't read %T", id, header.Kind(), data) + return nil, fmt.Errorf("type id %d: kind %v: can't read %T: %v", id, header.Kind(), data, err) } types = append(types, rawType{header, data}) diff --git a/vendor/github.com/cilium/ebpf/internal/btf/ext_info.go b/vendor/github.com/cilium/ebpf/internal/btf/ext_info.go index ab019cac7..28918ae9e 100644 --- a/vendor/github.com/cilium/ebpf/internal/btf/ext_info.go +++ b/vendor/github.com/cilium/ebpf/internal/btf/ext_info.go @@ -3,13 +3,13 @@ package btf import ( "bytes" "encoding/binary" + "errors" + "fmt" "io" "io/ioutil" "github.com/cilium/ebpf/asm" "github.com/cilium/ebpf/internal" - - "github.com/pkg/errors" ) type btfExtHeader struct { @@ -25,23 +25,21 @@ type btfExtHeader struct { } func parseExtInfos(r io.ReadSeeker, bo binary.ByteOrder, strings stringTable) (funcInfo, lineInfo map[string]extInfo, err error) { - const expectedMagic = 0xeB9F - var header btfExtHeader if err := binary.Read(r, bo, &header); err != nil { - return nil, nil, errors.Wrap(err, "can't read header") + return nil, nil, fmt.Errorf("can't read header: %v", err) } - if header.Magic != expectedMagic { - return nil, nil, errors.Errorf("incorrect magic value %v", header.Magic) + if header.Magic != btfMagic { + return nil, nil, fmt.Errorf("incorrect magic value %v", header.Magic) } if header.Version != 1 { - return nil, nil, errors.Errorf("unexpected version %v", header.Version) + return nil, nil, fmt.Errorf("unexpected version %v", header.Version) } if header.Flags != 0 { - return nil, nil, errors.Errorf("unsupported flags %v", header.Flags) + return nil, nil, fmt.Errorf("unsupported flags %v", header.Flags) } remainder := int64(header.HdrLen) - int64(binary.Size(&header)) @@ -53,25 +51,25 @@ func parseExtInfos(r io.ReadSeeker, bo binary.ByteOrder, strings stringTable) (f // .BTF ext header. We need to ignore non-null values. _, err = io.CopyN(ioutil.Discard, r, remainder) if err != nil { - return nil, nil, errors.Wrap(err, "header padding") + return nil, nil, fmt.Errorf("header padding: %v", err) } if _, err := r.Seek(int64(header.HdrLen+header.FuncInfoOff), io.SeekStart); err != nil { - return nil, nil, errors.Wrap(err, "can't seek to function info section") + return nil, nil, fmt.Errorf("can't seek to function info section: %v", err) } funcInfo, err = parseExtInfo(io.LimitReader(r, int64(header.FuncInfoLen)), bo, strings) if err != nil { - return nil, nil, errors.Wrap(err, "function info") + return nil, nil, fmt.Errorf("function info: %w", err) } if _, err := r.Seek(int64(header.HdrLen+header.LineInfoOff), io.SeekStart); err != nil { - return nil, nil, errors.Wrap(err, "can't seek to line info section") + return nil, nil, fmt.Errorf("can't seek to line info section: %v", err) } lineInfo, err = parseExtInfo(io.LimitReader(r, int64(header.LineInfoLen)), bo, strings) if err != nil { - return nil, nil, errors.Wrap(err, "line info") + return nil, nil, fmt.Errorf("line info: %w", err) } return funcInfo, lineInfo, nil @@ -94,7 +92,7 @@ type extInfo struct { func (ei extInfo) append(other extInfo, offset uint64) (extInfo, error) { if other.recordSize != ei.recordSize { - return extInfo{}, errors.Errorf("ext_info record size mismatch, want %d (got %d)", ei.recordSize, other.recordSize) + return extInfo{}, fmt.Errorf("ext_info record size mismatch, want %d (got %d)", ei.recordSize, other.recordSize) } records := make([]extInfoRecord, 0, len(ei.records)+len(other.records)) @@ -119,7 +117,7 @@ func (ei extInfo) MarshalBinary() ([]byte, error) { // while the ELF tracks it in bytes. insnOff := uint32(info.InsnOff / asm.InstructionSize) if err := binary.Write(buf, internal.NativeEndian, insnOff); err != nil { - return nil, errors.Wrap(err, "can't write instruction offset") + return nil, fmt.Errorf("can't write instruction offset: %v", err) } buf.Write(info.Opaque) @@ -131,7 +129,7 @@ func (ei extInfo) MarshalBinary() ([]byte, error) { func parseExtInfo(r io.Reader, bo binary.ByteOrder, strings stringTable) (map[string]extInfo, error) { var recordSize uint32 if err := binary.Read(r, bo, &recordSize); err != nil { - return nil, errors.Wrap(err, "can't read record size") + return nil, fmt.Errorf("can't read record size: %v", err) } if recordSize < 4 { @@ -145,32 +143,32 @@ func parseExtInfo(r io.Reader, bo binary.ByteOrder, strings stringTable) (map[st if err := binary.Read(r, bo, &infoHeader); err == io.EOF { return result, nil } else if err != nil { - return nil, errors.Wrap(err, "can't read ext info header") + return nil, fmt.Errorf("can't read ext info header: %v", err) } secName, err := strings.Lookup(infoHeader.SecNameOff) if err != nil { - return nil, errors.Wrap(err, "can't get section name") + return nil, fmt.Errorf("can't get section name: %w", err) } if infoHeader.NumInfo == 0 { - return nil, errors.Errorf("section %s has invalid number of records", secName) + return nil, fmt.Errorf("section %s has invalid number of records", secName) } var records []extInfoRecord for i := uint32(0); i < infoHeader.NumInfo; i++ { var byteOff uint32 if err := binary.Read(r, bo, &byteOff); err != nil { - return nil, errors.Wrapf(err, "section %v: can't read extended info offset", secName) + return nil, fmt.Errorf("section %v: can't read extended info offset: %v", secName, err) } buf := make([]byte, int(recordSize-4)) if _, err := io.ReadFull(r, buf); err != nil { - return nil, errors.Wrapf(err, "section %v: can't read record", secName) + return nil, fmt.Errorf("section %v: can't read record: %v", secName, err) } if byteOff%asm.InstructionSize != 0 { - return nil, errors.Errorf("section %v: offset %v is not aligned with instruction size", secName, byteOff) + return nil, fmt.Errorf("section %v: offset %v is not aligned with instruction size", secName, byteOff) } records = append(records, extInfoRecord{uint64(byteOff), buf}) diff --git a/vendor/github.com/cilium/ebpf/internal/btf/strings.go b/vendor/github.com/cilium/ebpf/internal/btf/strings.go index c0337649e..8782643a0 100644 --- a/vendor/github.com/cilium/ebpf/internal/btf/strings.go +++ b/vendor/github.com/cilium/ebpf/internal/btf/strings.go @@ -2,10 +2,10 @@ package btf import ( "bytes" + "errors" + "fmt" "io" "io/ioutil" - - "github.com/pkg/errors" ) type stringTable []byte @@ -13,7 +13,7 @@ type stringTable []byte func readStringTable(r io.Reader) (stringTable, error) { contents, err := ioutil.ReadAll(r) if err != nil { - return nil, errors.Wrap(err, "can't read string table") + return nil, fmt.Errorf("can't read string table: %v", err) } if len(contents) < 1 { @@ -33,22 +33,22 @@ func readStringTable(r io.Reader) (stringTable, error) { func (st stringTable) Lookup(offset uint32) (string, error) { if int64(offset) > int64(^uint(0)>>1) { - return "", errors.Errorf("offset %d overflows int", offset) + return "", fmt.Errorf("offset %d overflows int", offset) } pos := int(offset) if pos >= len(st) { - return "", errors.Errorf("offset %d is out of bounds", offset) + return "", fmt.Errorf("offset %d is out of bounds", offset) } if pos > 0 && st[pos-1] != '\x00' { - return "", errors.Errorf("offset %d isn't start of a string", offset) + return "", fmt.Errorf("offset %d isn't start of a string", offset) } str := st[pos:] end := bytes.IndexByte(str, '\x00') if end == -1 { - return "", errors.Errorf("offset %d isn't null terminated", offset) + return "", fmt.Errorf("offset %d isn't null terminated", offset) } return string(str[:end]), nil diff --git a/vendor/github.com/cilium/ebpf/internal/btf/types.go b/vendor/github.com/cilium/ebpf/internal/btf/types.go index c49cb8621..264142abc 100644 --- a/vendor/github.com/cilium/ebpf/internal/btf/types.go +++ b/vendor/github.com/cilium/ebpf/internal/btf/types.go @@ -1,9 +1,9 @@ package btf import ( + "errors" + "fmt" "math" - - "github.com/pkg/errors" ) const maxTypeDepth = 32 @@ -38,9 +38,10 @@ func (n Name) name() string { // Void is the unit type of BTF. type Void struct{} -func (v Void) ID() TypeID { return 0 } -func (v Void) copy() Type { return Void{} } -func (v Void) walk(*copyStack) {} +func (v *Void) ID() TypeID { return 0 } +func (v *Void) size() uint32 { return 0 } +func (v *Void) copy() Type { return (*Void)(nil) } +func (v *Void) walk(*copyStack) {} // Int is an integer of a given length. type Int struct { @@ -103,7 +104,8 @@ func (s *Struct) walk(cs *copyStack) { func (s *Struct) copy() Type { cpy := *s - cpy.Members = copyMembers(cpy.Members) + cpy.Members = make([]Member, len(s.Members)) + copy(cpy.Members, s.Members) return &cpy } @@ -126,7 +128,8 @@ func (u *Union) walk(cs *copyStack) { func (u *Union) copy() Type { cpy := *u - cpy.Members = copyMembers(cpy.Members) + cpy.Members = make([]Member, len(u.Members)) + copy(cpy.Members, u.Members) return &cpy } @@ -139,14 +142,6 @@ type Member struct { Offset uint32 } -func copyMembers(in []Member) []Member { - cpy := make([]Member, 0, len(in)) - for _, member := range in { - cpy = append(cpy, member) - } - return cpy -} - // Enum lists possible values. type Enum struct { TypeID @@ -265,15 +260,31 @@ type Datasec struct { TypeID Name Size uint32 + Vars []VarSecinfo +} + +func (ds *Datasec) size() uint32 { return ds.Size } + +func (ds *Datasec) walk(cs *copyStack) { + for i := range ds.Vars { + cs.push(&ds.Vars[i].Type) + } } -func (ds *Datasec) size() uint32 { return ds.Size } -func (ds *Datasec) walk(*copyStack) {} func (ds *Datasec) copy() Type { cpy := *ds + cpy.Vars = make([]VarSecinfo, len(ds.Vars)) + copy(cpy.Vars, ds.Vars) return &cpy } +// VarSecinfo describes variable in a Datasec +type VarSecinfo struct { + Type Type + Offset uint32 + Size uint32 +} + type sizer interface { size() uint32 } @@ -326,7 +337,7 @@ func Sizeof(typ Type) (int, error) { continue default: - return 0, errors.Errorf("unrecognized type %T", typ) + return 0, fmt.Errorf("unrecognized type %T", typ) } if n > 0 && elem > math.MaxInt64/n { @@ -405,12 +416,17 @@ var _ namer = Name("") // compilation units, multiple types may share the same name. A Type may form a // cyclic graph by pointing at itself. func inflateRawTypes(rawTypes []rawType, rawStrings stringTable) (namedTypes map[string][]Type, err error) { - type fixup struct { - id TypeID - typ *Type + type fixupDef struct { + id TypeID + expectedKind btfKind + typ *Type + } + + var fixups []fixupDef + fixup := func(id TypeID, expectedKind btfKind, typ *Type) { + fixups = append(fixups, fixupDef{id, expectedKind, typ}) } - var fixups []fixup convertMembers := func(raw []btfMember) ([]Member, error) { // NB: The fixup below relies on pre-allocating this array to // work, since otherwise append might re-allocate members. @@ -418,7 +434,7 @@ func inflateRawTypes(rawTypes []rawType, rawStrings stringTable) (namedTypes map for i, btfMember := range raw { name, err := rawStrings.LookupName(btfMember.NameOff) if err != nil { - return nil, errors.Wrapf(err, "can't get name for member %d", i) + return nil, fmt.Errorf("can't get name for member %d: %w", i, err) } members = append(members, Member{ Name: name, @@ -426,13 +442,13 @@ func inflateRawTypes(rawTypes []rawType, rawStrings stringTable) (namedTypes map }) } for i := range members { - fixups = append(fixups, fixup{raw[i].Type, &members[i].Type}) + fixup(raw[i].Type, kindUnknown, &members[i].Type) } return members, nil } types := make([]Type, 0, len(rawTypes)) - types = append(types, Void{}) + types = append(types, (*Void)(nil)) namedTypes = make(map[string][]Type) for i, raw := range rawTypes { @@ -445,7 +461,7 @@ func inflateRawTypes(rawTypes []rawType, rawStrings stringTable) (namedTypes map name, err := rawStrings.LookupName(raw.NameOff) if err != nil { - return nil, errors.Wrapf(err, "can't get name for type id %d", id) + return nil, fmt.Errorf("can't get name for type id %d: %w", id, err) } switch raw.Kind() { @@ -454,7 +470,7 @@ func inflateRawTypes(rawTypes []rawType, rawStrings stringTable) (namedTypes map case kindPointer: ptr := &Pointer{id, nil} - fixups = append(fixups, fixup{raw.Type(), &ptr.Target}) + fixup(raw.Type(), kindUnknown, &ptr.Target) typ = ptr case kindArray: @@ -463,20 +479,20 @@ func inflateRawTypes(rawTypes []rawType, rawStrings stringTable) (namedTypes map // IndexType is unused according to btf.rst. // Don't make it available right now. arr := &Array{id, nil, btfArr.Nelems} - fixups = append(fixups, fixup{btfArr.Type, &arr.Type}) + fixup(btfArr.Type, kindUnknown, &arr.Type) typ = arr case kindStruct: members, err := convertMembers(raw.data.([]btfMember)) if err != nil { - return nil, errors.Wrapf(err, "struct %s (id %d)", name, id) + return nil, fmt.Errorf("struct %s (id %d): %w", name, id, err) } typ = &Struct{id, name, raw.Size(), members} case kindUnion: members, err := convertMembers(raw.data.([]btfMember)) if err != nil { - return nil, errors.Wrapf(err, "union %s (id %d)", name, id) + return nil, fmt.Errorf("union %s (id %d): %w", name, id, err) } typ = &Union{id, name, raw.Size(), members} @@ -488,44 +504,55 @@ func inflateRawTypes(rawTypes []rawType, rawStrings stringTable) (namedTypes map case kindTypedef: typedef := &Typedef{id, name, nil} - fixups = append(fixups, fixup{raw.Type(), &typedef.Type}) + fixup(raw.Type(), kindUnknown, &typedef.Type) typ = typedef case kindVolatile: volatile := &Volatile{id, nil} - fixups = append(fixups, fixup{raw.Type(), &volatile.Type}) + fixup(raw.Type(), kindUnknown, &volatile.Type) typ = volatile case kindConst: cnst := &Const{id, nil} - fixups = append(fixups, fixup{raw.Type(), &cnst.Type}) + fixup(raw.Type(), kindUnknown, &cnst.Type) typ = cnst case kindRestrict: restrict := &Restrict{id, nil} - fixups = append(fixups, fixup{raw.Type(), &restrict.Type}) + fixup(raw.Type(), kindUnknown, &restrict.Type) typ = restrict case kindFunc: fn := &Func{id, name, nil} - fixups = append(fixups, fixup{raw.Type(), &fn.Type}) + fixup(raw.Type(), kindFuncProto, &fn.Type) typ = fn case kindFuncProto: fp := &FuncProto{id, nil} - fixups = append(fixups, fixup{raw.Type(), &fp.Return}) + fixup(raw.Type(), kindUnknown, &fp.Return) typ = fp case kindVar: v := &Var{id, name, nil} - fixups = append(fixups, fixup{raw.Type(), &v.Type}) + fixup(raw.Type(), kindUnknown, &v.Type) typ = v case kindDatasec: - typ = &Datasec{id, name, raw.SizeType} + btfVars := raw.data.([]btfVarSecinfo) + vars := make([]VarSecinfo, 0, len(btfVars)) + for _, btfVar := range btfVars { + vars = append(vars, VarSecinfo{ + Offset: btfVar.Offset, + Size: btfVar.Size, + }) + } + for i := range vars { + fixup(btfVars[i].Type, kindVar, &vars[i].Type) + } + typ = &Datasec{id, name, raw.SizeType, vars} default: - return nil, errors.Errorf("type id %d: unknown kind: %v", id, raw.Kind()) + return nil, fmt.Errorf("type id %d: unknown kind: %v", id, raw.Kind()) } types = append(types, typ) @@ -540,7 +567,17 @@ func inflateRawTypes(rawTypes []rawType, rawStrings stringTable) (namedTypes map for _, fixup := range fixups { i := int(fixup.id) if i >= len(types) { - return nil, errors.Errorf("reference to invalid type id: %d", fixup.id) + return nil, fmt.Errorf("reference to invalid type id: %d", fixup.id) + } + + // Default void (id 0) to unknown + rawKind := kindUnknown + if i > 0 { + rawKind = rawTypes[i-1].Kind() + } + + if expected := fixup.expectedKind; expected != kindUnknown && rawKind != expected { + return nil, fmt.Errorf("expected type id %d to have kind %s, found %s", fixup.id, expected, rawKind) } *fixup.typ = types[i] diff --git a/vendor/github.com/cilium/ebpf/internal/cpu.go b/vendor/github.com/cilium/ebpf/internal/cpu.go index ce3cab730..d3424ba43 100644 --- a/vendor/github.com/cilium/ebpf/internal/cpu.go +++ b/vendor/github.com/cilium/ebpf/internal/cpu.go @@ -2,10 +2,9 @@ package internal import ( "fmt" - "os" + "io/ioutil" + "strings" "sync" - - "github.com/pkg/errors" ) var sysCPU struct { @@ -18,45 +17,44 @@ var sysCPU struct { // Logical CPU numbers must be of the form 0-n func PossibleCPUs() (int, error) { sysCPU.once.Do(func() { - sysCPU.num, sysCPU.err = parseCPUs("/sys/devices/system/cpu/possible") + sysCPU.num, sysCPU.err = parseCPUsFromFile("/sys/devices/system/cpu/possible") }) return sysCPU.num, sysCPU.err } -var onlineCPU struct { - once sync.Once - err error - num int -} - -// OnlineCPUs returns the number of currently online CPUs -// Logical CPU numbers must be of the form 0-n -func OnlineCPUs() (int, error) { - onlineCPU.once.Do(func() { - onlineCPU.num, onlineCPU.err = parseCPUs("/sys/devices/system/cpu/online") - }) - - return onlineCPU.num, onlineCPU.err -} - -// parseCPUs parses the number of cpus from sysfs, -// in the format of "/sys/devices/system/cpu/{possible,online,..}. -// Logical CPU numbers must be of the form 0-n -func parseCPUs(path string) (int, error) { - file, err := os.Open(path) +func parseCPUsFromFile(path string) (int, error) { + spec, err := ioutil.ReadFile(path) if err != nil { return 0, err } - defer file.Close() + + n, err := parseCPUs(string(spec)) + if err != nil { + return 0, fmt.Errorf("can't parse %s: %v", path, err) + } + + return n, nil +} + +// parseCPUs parses the number of cpus from a string produced +// by bitmap_list_string() in the Linux kernel. +// Multiple ranges are rejected, since they can't be unified +// into a single number. +// This is the format of /sys/devices/system/cpu/possible, it +// is not suitable for /sys/devices/system/cpu/online, etc. +func parseCPUs(spec string) (int, error) { + if strings.Trim(spec, "\n") == "0" { + return 1, nil + } var low, high int - n, _ := fmt.Fscanf(file, "%d-%d", &low, &high) - if n < 1 || low != 0 { - return 0, errors.Wrapf(err, "%s has unknown format", path) + n, err := fmt.Sscanf(spec, "%d-%d\n", &low, &high) + if n != 2 || err != nil { + return 0, fmt.Errorf("invalid format: %s", spec) } - if n == 1 { - high = low + if low != 0 { + return 0, fmt.Errorf("CPU spec doesn't start at zero: %s", spec) } // cpus is 0 indexed diff --git a/vendor/github.com/cilium/ebpf/internal/errors.go b/vendor/github.com/cilium/ebpf/internal/errors.go index 9590fe84e..b6aee81f7 100644 --- a/vendor/github.com/cilium/ebpf/internal/errors.go +++ b/vendor/github.com/cilium/ebpf/internal/errors.go @@ -2,11 +2,11 @@ package internal import ( "bytes" + "errors" "fmt" "strings" "github.com/cilium/ebpf/internal/unix" - "github.com/pkg/errors" ) // ErrorWithLog returns an error that includes logs from the @@ -16,19 +16,20 @@ import ( // the log. It is used to check for truncation of the output. func ErrorWithLog(err error, log []byte, logErr error) error { logStr := strings.Trim(CString(log), "\t\r\n ") - if errors.Cause(logErr) == unix.ENOSPC { + if errors.Is(logErr, unix.ENOSPC) { logStr += " (truncated...)" } - return &loadError{err, logStr} + return &VerifierError{err, logStr} } -type loadError struct { +// VerifierError includes information from the eBPF verifier. +type VerifierError struct { cause error log string } -func (le *loadError) Error() string { +func (le *VerifierError) Error() string { if le.log == "" { return le.cause.Error() } @@ -36,10 +37,6 @@ func (le *loadError) Error() string { return fmt.Sprintf("%s: %s", le.cause, le.log) } -func (le *loadError) Cause() error { - return le.cause -} - // CString turns a NUL / zero terminated byte buffer into a string. func CString(in []byte) string { inLen := bytes.IndexByte(in, 0) diff --git a/vendor/github.com/cilium/ebpf/internal/fd.go b/vendor/github.com/cilium/ebpf/internal/fd.go index 6800c84aa..af04955bd 100644 --- a/vendor/github.com/cilium/ebpf/internal/fd.go +++ b/vendor/github.com/cilium/ebpf/internal/fd.go @@ -1,12 +1,13 @@ package internal import ( + "errors" + "fmt" + "os" "runtime" "strconv" "github.com/cilium/ebpf/internal/unix" - - "github.com/pkg/errors" ) var ErrClosedFd = errors.New("use of closed file descriptor") @@ -56,8 +57,13 @@ func (fd *FD) Dup() (*FD, error) { dup, err := unix.FcntlInt(uintptr(fd.raw), unix.F_DUPFD_CLOEXEC, 0) if err != nil { - return nil, errors.Wrap(err, "can't dup fd") + return nil, fmt.Errorf("can't dup fd: %v", err) } return NewFD(uint32(dup)), nil } + +func (fd *FD) File(name string) *os.File { + fd.Forget() + return os.NewFile(uintptr(fd.raw), name) +} diff --git a/vendor/github.com/cilium/ebpf/internal/feature.go b/vendor/github.com/cilium/ebpf/internal/feature.go index f7497d37f..7375b21ef 100644 --- a/vendor/github.com/cilium/ebpf/internal/feature.go +++ b/vendor/github.com/cilium/ebpf/internal/feature.go @@ -1,12 +1,14 @@ package internal import ( + "errors" "fmt" "sync" - - "github.com/pkg/errors" ) +// ErrNotSupported indicates that a feature is not supported by the current kernel. +var ErrNotSupported = errors.New("not supported") + // UnsupportedFeatureError is returned by FeatureTest() functions. type UnsupportedFeatureError struct { // The minimum Linux mainline version required for this feature. @@ -21,33 +23,68 @@ func (ufe *UnsupportedFeatureError) Error() string { return fmt.Sprintf("%s not supported (requires >= %s)", ufe.Name, ufe.MinimumVersion) } +// Is indicates that UnsupportedFeatureError is ErrNotSupported. +func (ufe *UnsupportedFeatureError) Is(target error) bool { + return target == ErrNotSupported +} + +type featureTest struct { + sync.Mutex + successful bool + result error +} + +// FeatureTestFn is used to determine whether the kernel supports +// a certain feature. +// +// The return values have the following semantics: +// +// err != nil: the test couldn't be executed +// err == nil && available: the feature is available +// err == nil && !available: the feature isn't available +type FeatureTestFn func() (available bool, err error) + // FeatureTest wraps a function so that it is run at most once. // // name should identify the tested feature, while version must be in the // form Major.Minor[.Patch]. // -// Returns a descriptive UnsupportedFeatureError if the feature is not available. -func FeatureTest(name, version string, fn func() bool) func() error { +// Returns an error wrapping ErrNotSupported if the feature is not supported. +func FeatureTest(name, version string, fn FeatureTestFn) func() error { v, err := NewVersion(version) if err != nil { return func() error { return err } } - var ( - once sync.Once - result error - ) - + ft := new(featureTest) return func() error { - once.Do(func() { - if !fn() { - result = &UnsupportedFeatureError{ - MinimumVersion: v, - Name: name, - } + ft.Lock() + defer ft.Unlock() + + if ft.successful { + return ft.result + } + + available, err := fn() + if errors.Is(err, ErrNotSupported) { + // The feature test aborted because a dependent feature + // is missing, which we should cache. + available = false + } else if err != nil { + // We couldn't execute the feature test to a point + // where it could make a determination. + // Don't cache the result, just return it. + return fmt.Errorf("can't detect support for %s: %w", name, err) + } + + ft.successful = true + if !available { + ft.result = &UnsupportedFeatureError{ + MinimumVersion: v, + Name: name, } - }) - return result + } + return ft.result } } @@ -61,7 +98,7 @@ func NewVersion(ver string) (Version, error) { var major, minor, patch uint16 n, _ := fmt.Sscanf(ver, "%d.%d.%d", &major, &minor, &patch) if n < 2 { - return Version{}, errors.Errorf("invalid version: %s", ver) + return Version{}, fmt.Errorf("invalid version: %s", ver) } return Version{major, minor, patch}, nil } diff --git a/vendor/github.com/cilium/ebpf/internal/io.go b/vendor/github.com/cilium/ebpf/internal/io.go index 756e86119..fa7402782 100644 --- a/vendor/github.com/cilium/ebpf/internal/io.go +++ b/vendor/github.com/cilium/ebpf/internal/io.go @@ -1,6 +1,6 @@ package internal -import "github.com/pkg/errors" +import "errors" // DiscardZeroes makes sure that all written bytes are zero // before discarding them. diff --git a/vendor/github.com/cilium/ebpf/internal/ptr.go b/vendor/github.com/cilium/ebpf/internal/ptr.go index e79b5aa00..a7f12b2db 100644 --- a/vendor/github.com/cilium/ebpf/internal/ptr.go +++ b/vendor/github.com/cilium/ebpf/internal/ptr.go @@ -22,5 +22,9 @@ func NewStringPointer(str string) Pointer { return Pointer{} } - return Pointer{ptr: unsafe.Pointer(&[]byte(str)[0])} + // The kernel expects strings to be zero terminated + buf := make([]byte, len(str)+1) + copy(buf, str) + + return Pointer{ptr: unsafe.Pointer(&buf[0])} } diff --git a/vendor/github.com/cilium/ebpf/internal/syscall.go b/vendor/github.com/cilium/ebpf/internal/syscall.go index b32cf3bce..efbf40327 100644 --- a/vendor/github.com/cilium/ebpf/internal/syscall.go +++ b/vendor/github.com/cilium/ebpf/internal/syscall.go @@ -1,16 +1,61 @@ package internal import ( + "fmt" + "path/filepath" "runtime" "unsafe" "github.com/cilium/ebpf/internal/unix" ) +//go:generate stringer -output syscall_string.go -type=BPFCmd + +// BPFCmd identifies a subcommand of the bpf syscall. +type BPFCmd int + +// Well known BPF commands. +const ( + BPF_MAP_CREATE BPFCmd = iota + BPF_MAP_LOOKUP_ELEM + BPF_MAP_UPDATE_ELEM + BPF_MAP_DELETE_ELEM + BPF_MAP_GET_NEXT_KEY + BPF_PROG_LOAD + BPF_OBJ_PIN + BPF_OBJ_GET + BPF_PROG_ATTACH + BPF_PROG_DETACH + BPF_PROG_TEST_RUN + BPF_PROG_GET_NEXT_ID + BPF_MAP_GET_NEXT_ID + BPF_PROG_GET_FD_BY_ID + BPF_MAP_GET_FD_BY_ID + BPF_OBJ_GET_INFO_BY_FD + BPF_PROG_QUERY + BPF_RAW_TRACEPOINT_OPEN + BPF_BTF_LOAD + BPF_BTF_GET_FD_BY_ID + BPF_TASK_FD_QUERY + BPF_MAP_LOOKUP_AND_DELETE_ELEM + BPF_MAP_FREEZE + BPF_BTF_GET_NEXT_ID + BPF_MAP_LOOKUP_BATCH + BPF_MAP_LOOKUP_AND_DELETE_BATCH + BPF_MAP_UPDATE_BATCH + BPF_MAP_DELETE_BATCH + BPF_LINK_CREATE + BPF_LINK_UPDATE + BPF_LINK_GET_FD_BY_ID + BPF_LINK_GET_NEXT_ID + BPF_ENABLE_STATS + BPF_ITER_CREATE +) + // BPF wraps SYS_BPF. // // Any pointers contained in attr must use the Pointer type from this package. -func BPF(cmd int, attr unsafe.Pointer, size uintptr) (uintptr, error) { +func BPF(cmd BPFCmd, attr unsafe.Pointer, size uintptr) (uintptr, error) { r1, _, errNo := unix.Syscall(unix.SYS_BPF, uintptr(cmd), uintptr(attr), size) runtime.KeepAlive(attr) @@ -21,3 +66,74 @@ func BPF(cmd int, attr unsafe.Pointer, size uintptr) (uintptr, error) { return r1, err } + +type BPFProgAttachAttr struct { + TargetFd uint32 + AttachBpfFd uint32 + AttachType uint32 + AttachFlags uint32 + ReplaceBpfFd uint32 +} + +func BPFProgAttach(attr *BPFProgAttachAttr) error { + _, err := BPF(BPF_PROG_ATTACH, unsafe.Pointer(attr), unsafe.Sizeof(*attr)) + return err +} + +type BPFProgDetachAttr struct { + TargetFd uint32 + AttachBpfFd uint32 + AttachType uint32 +} + +func BPFProgDetach(attr *BPFProgDetachAttr) error { + _, err := BPF(BPF_PROG_DETACH, unsafe.Pointer(attr), unsafe.Sizeof(*attr)) + return err +} + +type bpfObjAttr struct { + fileName Pointer + fd uint32 + fileFlags uint32 +} + +const bpfFSType = 0xcafe4a11 + +// BPFObjPin wraps BPF_OBJ_PIN. +func BPFObjPin(fileName string, fd *FD) error { + dirName := filepath.Dir(fileName) + var statfs unix.Statfs_t + if err := unix.Statfs(dirName, &statfs); err != nil { + return err + } + if uint64(statfs.Type) != bpfFSType { + return fmt.Errorf("%s is not on a bpf filesystem", fileName) + } + + value, err := fd.Value() + if err != nil { + return err + } + + attr := bpfObjAttr{ + fileName: NewStringPointer(fileName), + fd: value, + } + _, err = BPF(BPF_OBJ_PIN, unsafe.Pointer(&attr), unsafe.Sizeof(attr)) + if err != nil { + return fmt.Errorf("pin object %s: %w", fileName, err) + } + return nil +} + +// BPFObjGet wraps BPF_OBJ_GET. +func BPFObjGet(fileName string) (*FD, error) { + attr := bpfObjAttr{ + fileName: NewStringPointer(fileName), + } + ptr, err := BPF(BPF_OBJ_GET, unsafe.Pointer(&attr), unsafe.Sizeof(attr)) + if err != nil { + return nil, fmt.Errorf("get object %s: %w", fileName, err) + } + return NewFD(uint32(ptr)), nil +} diff --git a/vendor/github.com/cilium/ebpf/internal/syscall_string.go b/vendor/github.com/cilium/ebpf/internal/syscall_string.go new file mode 100644 index 000000000..85df04779 --- /dev/null +++ b/vendor/github.com/cilium/ebpf/internal/syscall_string.go @@ -0,0 +1,56 @@ +// Code generated by "stringer -output syscall_string.go -type=BPFCmd"; DO NOT EDIT. + +package internal + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[BPF_MAP_CREATE-0] + _ = x[BPF_MAP_LOOKUP_ELEM-1] + _ = x[BPF_MAP_UPDATE_ELEM-2] + _ = x[BPF_MAP_DELETE_ELEM-3] + _ = x[BPF_MAP_GET_NEXT_KEY-4] + _ = x[BPF_PROG_LOAD-5] + _ = x[BPF_OBJ_PIN-6] + _ = x[BPF_OBJ_GET-7] + _ = x[BPF_PROG_ATTACH-8] + _ = x[BPF_PROG_DETACH-9] + _ = x[BPF_PROG_TEST_RUN-10] + _ = x[BPF_PROG_GET_NEXT_ID-11] + _ = x[BPF_MAP_GET_NEXT_ID-12] + _ = x[BPF_PROG_GET_FD_BY_ID-13] + _ = x[BPF_MAP_GET_FD_BY_ID-14] + _ = x[BPF_OBJ_GET_INFO_BY_FD-15] + _ = x[BPF_PROG_QUERY-16] + _ = x[BPF_RAW_TRACEPOINT_OPEN-17] + _ = x[BPF_BTF_LOAD-18] + _ = x[BPF_BTF_GET_FD_BY_ID-19] + _ = x[BPF_TASK_FD_QUERY-20] + _ = x[BPF_MAP_LOOKUP_AND_DELETE_ELEM-21] + _ = x[BPF_MAP_FREEZE-22] + _ = x[BPF_BTF_GET_NEXT_ID-23] + _ = x[BPF_MAP_LOOKUP_BATCH-24] + _ = x[BPF_MAP_LOOKUP_AND_DELETE_BATCH-25] + _ = x[BPF_MAP_UPDATE_BATCH-26] + _ = x[BPF_MAP_DELETE_BATCH-27] + _ = x[BPF_LINK_CREATE-28] + _ = x[BPF_LINK_UPDATE-29] + _ = x[BPF_LINK_GET_FD_BY_ID-30] + _ = x[BPF_LINK_GET_NEXT_ID-31] + _ = x[BPF_ENABLE_STATS-32] + _ = x[BPF_ITER_CREATE-33] +} + +const _BPFCmd_name = "BPF_MAP_CREATEBPF_MAP_LOOKUP_ELEMBPF_MAP_UPDATE_ELEMBPF_MAP_DELETE_ELEMBPF_MAP_GET_NEXT_KEYBPF_PROG_LOADBPF_OBJ_PINBPF_OBJ_GETBPF_PROG_ATTACHBPF_PROG_DETACHBPF_PROG_TEST_RUNBPF_PROG_GET_NEXT_IDBPF_MAP_GET_NEXT_IDBPF_PROG_GET_FD_BY_IDBPF_MAP_GET_FD_BY_IDBPF_OBJ_GET_INFO_BY_FDBPF_PROG_QUERYBPF_RAW_TRACEPOINT_OPENBPF_BTF_LOADBPF_BTF_GET_FD_BY_IDBPF_TASK_FD_QUERYBPF_MAP_LOOKUP_AND_DELETE_ELEMBPF_MAP_FREEZEBPF_BTF_GET_NEXT_IDBPF_MAP_LOOKUP_BATCHBPF_MAP_LOOKUP_AND_DELETE_BATCHBPF_MAP_UPDATE_BATCHBPF_MAP_DELETE_BATCHBPF_LINK_CREATEBPF_LINK_UPDATEBPF_LINK_GET_FD_BY_IDBPF_LINK_GET_NEXT_IDBPF_ENABLE_STATSBPF_ITER_CREATE" + +var _BPFCmd_index = [...]uint16{0, 14, 33, 52, 71, 91, 104, 115, 126, 141, 156, 173, 193, 212, 233, 253, 275, 289, 312, 324, 344, 361, 391, 405, 424, 444, 475, 495, 515, 530, 545, 566, 586, 602, 617} + +func (i BPFCmd) String() string { + if i < 0 || i >= BPFCmd(len(_BPFCmd_index)-1) { + return "BPFCmd(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _BPFCmd_name[_BPFCmd_index[i]:_BPFCmd_index[i+1]] +} diff --git a/vendor/github.com/cilium/ebpf/internal/unix/types_linux.go b/vendor/github.com/cilium/ebpf/internal/unix/types_linux.go index 169309667..9363d0be8 100644 --- a/vendor/github.com/cilium/ebpf/internal/unix/types_linux.go +++ b/vendor/github.com/cilium/ebpf/internal/unix/types_linux.go @@ -10,10 +10,17 @@ import ( const ( ENOENT = linux.ENOENT + EEXIST = linux.EEXIST EAGAIN = linux.EAGAIN ENOSPC = linux.ENOSPC EINVAL = linux.EINVAL EPOLLIN = linux.EPOLLIN + EINTR = linux.EINTR + EPERM = linux.EPERM + ESRCH = linux.ESRCH + ENODEV = linux.ENODEV + BPF_F_RDONLY_PROG = linux.BPF_F_RDONLY_PROG + BPF_F_WRONLY_PROG = linux.BPF_F_WRONLY_PROG BPF_OBJ_NAME_LEN = linux.BPF_OBJ_NAME_LEN BPF_TAG_SIZE = linux.BPF_TAG_SIZE SYS_BPF = linux.SYS_BPF @@ -31,6 +38,7 @@ const ( PERF_SAMPLE_RAW = linux.PERF_SAMPLE_RAW PERF_FLAG_FD_CLOEXEC = linux.PERF_FLAG_FD_CLOEXEC RLIM_INFINITY = linux.RLIM_INFINITY + RLIMIT_MEMLOCK = linux.RLIMIT_MEMLOCK ) // Statfs_t is a wrapper @@ -125,3 +133,18 @@ type Utsname = linux.Utsname func Uname(buf *Utsname) (err error) { return linux.Uname(buf) } + +// Getpid is a wrapper +func Getpid() int { + return linux.Getpid() +} + +// Gettid is a wrapper +func Gettid() int { + return linux.Gettid() +} + +// Tgkill is a wrapper +func Tgkill(tgid int, tid int, sig syscall.Signal) (err error) { + return linux.Tgkill(tgid, tid, sig) +} diff --git a/vendor/github.com/cilium/ebpf/internal/unix/types_other.go b/vendor/github.com/cilium/ebpf/internal/unix/types_other.go index 57a514da7..2dea950f8 100644 --- a/vendor/github.com/cilium/ebpf/internal/unix/types_other.go +++ b/vendor/github.com/cilium/ebpf/internal/unix/types_other.go @@ -12,9 +12,16 @@ var errNonLinux = fmt.Errorf("unsupported platform %s/%s", runtime.GOOS, runtime const ( ENOENT = syscall.ENOENT + EEXIST = syscall.EEXIST EAGAIN = syscall.EAGAIN ENOSPC = syscall.ENOSPC EINVAL = syscall.EINVAL + EINTR = syscall.EINTR + EPERM = syscall.EPERM + ESRCH = syscall.ESRCH + ENODEV = syscall.ENODEV + BPF_F_RDONLY_PROG = 0 + BPF_F_WRONLY_PROG = 0 BPF_OBJ_NAME_LEN = 0x10 BPF_TAG_SIZE = 0x8 SYS_BPF = 321 @@ -32,6 +39,8 @@ const ( PerfBitWatermark = 0x4000 PERF_SAMPLE_RAW = 0x400 PERF_FLAG_FD_CLOEXEC = 0x8 + RLIM_INFINITY = 0x7fffffffffffffff + RLIMIT_MEMLOCK = 8 ) // Statfs_t is a wrapper @@ -184,10 +193,25 @@ func PerfEventOpen(attr *PerfEventAttr, pid int, cpu int, groupFd int, flags int // Utsname is a wrapper type Utsname struct { - Release [65]byte + Release [65]byte } // Uname is a wrapper func Uname(buf *Utsname) (err error) { return errNonLinux } + +// Getpid is a wrapper +func Getpid() int { + return -1 +} + +// Gettid is a wrapper +func Gettid() int { + return -1 +} + +// Tgkill is a wrapper +func Tgkill(tgid int, tid int, sig syscall.Signal) (err error) { + return errNonLinux +} diff --git a/vendor/github.com/cilium/ebpf/linker.go b/vendor/github.com/cilium/ebpf/linker.go index 25f2ab947..1bb8f61c2 100644 --- a/vendor/github.com/cilium/ebpf/linker.go +++ b/vendor/github.com/cilium/ebpf/linker.go @@ -1,43 +1,60 @@ package ebpf import ( + "fmt" + "github.com/cilium/ebpf/asm" "github.com/cilium/ebpf/internal/btf" - "github.com/pkg/errors" ) // link resolves bpf-to-bpf calls. // // Each library may contain multiple functions / labels, and is only linked -// if the program being edited references one of these functions. +// if prog references one of these functions. // -// Libraries must not require linking themselves. +// Libraries also linked. func link(prog *ProgramSpec, libs []*ProgramSpec) error { - for _, lib := range libs { - insns, err := linkSection(prog.Instructions, lib.Instructions) - if err != nil { - return errors.Wrapf(err, "linking %s", lib.Name) - } + var ( + linked = make(map[*ProgramSpec]bool) + pending = []asm.Instructions{prog.Instructions} + insns asm.Instructions + ) + for len(pending) > 0 { + insns, pending = pending[0], pending[1:] + for _, lib := range libs { + if linked[lib] { + continue + } - if len(insns) == len(prog.Instructions) { - continue - } + needed, err := needSection(insns, lib.Instructions) + if err != nil { + return fmt.Errorf("linking %s: %w", lib.Name, err) + } - prog.Instructions = insns - if prog.BTF != nil && lib.BTF != nil { - if err := btf.ProgramAppend(prog.BTF, lib.BTF); err != nil { - return errors.Wrapf(err, "linking BTF of %s", lib.Name) + if !needed { + continue + } + + linked[lib] = true + prog.Instructions = append(prog.Instructions, lib.Instructions...) + pending = append(pending, lib.Instructions) + + if prog.BTF != nil && lib.BTF != nil { + if err := btf.ProgramAppend(prog.BTF, lib.BTF); err != nil { + return fmt.Errorf("linking BTF of %s: %w", lib.Name, err) + } } } } + return nil } -func linkSection(insns, section asm.Instructions) (asm.Instructions, error) { +func needSection(insns, section asm.Instructions) (bool, error) { // A map of symbols to the libraries which contain them. symbols, err := section.SymbolOffsets() if err != nil { - return nil, err + return false, err } for _, ins := range insns { @@ -45,7 +62,7 @@ func linkSection(insns, section asm.Instructions) (asm.Instructions, error) { continue } - if ins.OpCode.JumpOp() != asm.Call || ins.Src != asm.R1 { + if ins.OpCode.JumpOp() != asm.Call || ins.Src != asm.PseudoCall { continue } @@ -60,11 +77,10 @@ func linkSection(insns, section asm.Instructions) (asm.Instructions, error) { } // At this point we know that at least one function in the - // library is called from insns. Merge the two sections. - // The rewrite of ins.Constant happens in asm.Instruction.Marshal. - return append(insns, section...), nil + // library is called from insns, so we have to link it. + return true, nil } - // None of the functions in the section are called. Do nothing. - return insns, nil + // None of the functions in the section are called. + return false, nil } diff --git a/vendor/github.com/cilium/ebpf/map.go b/vendor/github.com/cilium/ebpf/map.go index 86eff1aef..461b995a5 100644 --- a/vendor/github.com/cilium/ebpf/map.go +++ b/vendor/github.com/cilium/ebpf/map.go @@ -1,15 +1,25 @@ package ebpf import ( + "errors" "fmt" + "strings" "github.com/cilium/ebpf/internal" "github.com/cilium/ebpf/internal/btf" "github.com/cilium/ebpf/internal/unix" - - "github.com/pkg/errors" ) +// Errors returned by Map and MapIterator methods. +var ( + ErrKeyNotExist = errors.New("key does not exist") + ErrKeyExist = errors.New("key already exists") + ErrIterationAborted = errors.New("iteration aborted") +) + +// MapID represents the unique ID of an eBPF map +type MapID uint32 + // MapSpec defines a Map. type MapSpec struct { // Name is passed to the kernel as a debug aid. Must only contain @@ -21,6 +31,12 @@ type MapSpec struct { MaxEntries uint32 Flags uint32 + // The initial contents of the map. May be nil. + Contents []MapKV + + // Whether to freeze a map after setting its initial contents. + Freeze bool + // InnerMap is used as a template for ArrayOfMaps and HashOfMaps InnerMap *MapSpec @@ -33,16 +49,26 @@ func (ms *MapSpec) String() string { } // Copy returns a copy of the spec. +// +// MapSpec.Contents is a shallow copy. func (ms *MapSpec) Copy() *MapSpec { if ms == nil { return nil } cpy := *ms + cpy.Contents = make([]MapKV, len(ms.Contents)) + copy(cpy.Contents, ms.Contents) cpy.InnerMap = ms.InnerMap.Copy() return &cpy } +// MapKV is used to initialize the contents of a Map. +type MapKV struct { + Key interface{} + Value interface{} +} + // Map represents a Map file descriptor. // // It is not safe to close a map which is used by other goroutines. @@ -81,14 +107,18 @@ func NewMapFromFD(fd int) (*Map, error) { // // Creating a map for the first time will perform feature detection // by creating small, temporary maps. +// +// The caller is responsible for ensuring the process' rlimit is set +// sufficiently high for locking memory during map creation. This can be done +// by calling unix.Setrlimit with unix.RLIMIT_MEMLOCK prior to calling NewMap. func NewMap(spec *MapSpec) (*Map, error) { if spec.BTF == nil { return newMapWithBTF(spec, nil) } handle, err := btf.NewHandle(btf.MapSpec(spec.BTF)) - if err != nil && !btf.IsNotSupported(err) { - return nil, errors.Wrap(err, "can't load BTF") + if err != nil && !errors.Is(err, btf.ErrNotSupported) { + return nil, fmt.Errorf("can't load BTF: %w", err) } return newMapWithBTF(spec, handle) @@ -100,7 +130,7 @@ func newMapWithBTF(spec *MapSpec, handle *btf.Handle) (*Map, error) { } if spec.InnerMap == nil { - return nil, errors.Errorf("%s requires InnerMap", spec.Type) + return nil, fmt.Errorf("%s requires InnerMap", spec.Type) } template, err := createMap(spec.InnerMap, nil, handle) @@ -113,7 +143,7 @@ func newMapWithBTF(spec *MapSpec, handle *btf.Handle) (*Map, error) { } func createMap(spec *MapSpec, inner *internal.FD, handle *btf.Handle) (*Map, error) { - spec = spec.Copy() + abi := newMapABIFromSpec(spec) switch spec.Type { case ArrayOfMaps: @@ -123,43 +153,50 @@ func createMap(spec *MapSpec, inner *internal.FD, handle *btf.Handle) (*Map, err return nil, err } - if spec.ValueSize != 0 && spec.ValueSize != 4 { - return nil, errors.Errorf("ValueSize must be zero or four for map of map") + if abi.ValueSize != 0 && abi.ValueSize != 4 { + return nil, errors.New("ValueSize must be zero or four for map of map") } - spec.ValueSize = 4 + abi.ValueSize = 4 case PerfEventArray: - if spec.KeySize != 0 { - return nil, errors.Errorf("KeySize must be zero for perf event array") - } - if spec.ValueSize != 0 { - return nil, errors.Errorf("ValueSize must be zero for perf event array") - } - if spec.MaxEntries == 0 { - n, err := internal.OnlineCPUs() - if err != nil { - return nil, errors.Wrap(err, "perf event array") - } - spec.MaxEntries = uint32(n) + if abi.KeySize != 0 && abi.KeySize != 4 { + return nil, errors.New("KeySize must be zero or four for perf event array") } + abi.KeySize = 4 - spec.KeySize = 4 - spec.ValueSize = 4 + if abi.ValueSize != 0 && abi.ValueSize != 4 { + return nil, errors.New("ValueSize must be zero or four for perf event array") + } + abi.ValueSize = 4 + + if abi.MaxEntries == 0 { + n, err := internal.PossibleCPUs() + if err != nil { + return nil, fmt.Errorf("perf event array: %w", err) + } + abi.MaxEntries = uint32(n) + } + } + + if abi.Flags&(unix.BPF_F_RDONLY_PROG|unix.BPF_F_WRONLY_PROG) > 0 || spec.Freeze { + if err := haveMapMutabilityModifiers(); err != nil { + return nil, fmt.Errorf("map create: %w", err) + } } attr := bpfMapCreateAttr{ - mapType: spec.Type, - keySize: spec.KeySize, - valueSize: spec.ValueSize, - maxEntries: spec.MaxEntries, - flags: spec.Flags, + mapType: abi.Type, + keySize: abi.KeySize, + valueSize: abi.ValueSize, + maxEntries: abi.MaxEntries, + flags: abi.Flags, } if inner != nil { var err error attr.innerMapFd, err = inner.Value() if err != nil { - return nil, errors.Wrap(err, "map create") + return nil, fmt.Errorf("map create: %w", err) } } @@ -169,21 +206,33 @@ func createMap(spec *MapSpec, inner *internal.FD, handle *btf.Handle) (*Map, err attr.btfValueTypeID = btf.MapValue(spec.BTF).ID() } - name, err := newBPFObjName(spec.Name) - if err != nil { - return nil, errors.Wrap(err, "map create") - } - if haveObjName() == nil { - attr.mapName = name + attr.mapName = newBPFObjName(spec.Name) } fd, err := bpfMapCreate(&attr) if err != nil { - return nil, errors.Wrap(err, "map create") + return nil, fmt.Errorf("map create: %w", err) } - return newMap(fd, spec.Name, newMapABIFromSpec(spec)) + m, err := newMap(fd, spec.Name, abi) + if err != nil { + return nil, err + } + + if err := m.populate(spec.Contents); err != nil { + m.Close() + return nil, fmt.Errorf("map create: can't set initial contents: %w", err) + } + + if spec.Freeze { + if err := m.Freeze(); err != nil { + m.Close() + return nil, fmt.Errorf("can't freeze map: %w", err) + } + } + + return m, nil } func newMap(fd *internal.FD, name string, abi *MapABI) (*Map, error) { @@ -251,9 +300,9 @@ func (m *Map) Lookup(key, valueOut interface{}) error { *value = m return nil case *Map: - return errors.Errorf("can't unmarshal into %T, need %T", value, (**Map)(nil)) + return fmt.Errorf("can't unmarshal into %T, need %T", value, (**Map)(nil)) case Map: - return errors.Errorf("can't unmarshal into %T, need %T", value, (**Map)(nil)) + return fmt.Errorf("can't unmarshal into %T, need %T", value, (**Map)(nil)) case **Program: p, err := unmarshalProgram(valueBytes) @@ -265,9 +314,9 @@ func (m *Map) Lookup(key, valueOut interface{}) error { *value = p return nil case *Program: - return errors.Errorf("can't unmarshal into %T, need %T", value, (**Program)(nil)) + return fmt.Errorf("can't unmarshal into %T, need %T", value, (**Program)(nil)) case Program: - return errors.Errorf("can't unmarshal into %T, need %T", value, (**Program)(nil)) + return fmt.Errorf("can't unmarshal into %T, need %T", value, (**Program)(nil)) default: return unmarshalBytes(valueOut, valueBytes) @@ -275,16 +324,18 @@ func (m *Map) Lookup(key, valueOut interface{}) error { } // LookupAndDelete retrieves and deletes a value from a Map. +// +// Returns ErrKeyNotExist if the key doesn't exist. func (m *Map) LookupAndDelete(key, valueOut interface{}) error { valuePtr, valueBytes := makeBuffer(valueOut, m.fullValueSize) keyPtr, err := marshalPtr(key, int(m.abi.KeySize)) if err != nil { - return errors.WithMessage(err, "can't marshal key") + return fmt.Errorf("can't marshal key: %w", err) } if err := bpfMapLookupAndDelete(m.fd, keyPtr, valuePtr); err != nil { - return errors.WithMessage(err, "lookup and delete and delete failed") + return fmt.Errorf("lookup and delete failed: %w", err) } return unmarshalBytes(valueOut, valueBytes) @@ -298,7 +349,7 @@ func (m *Map) LookupBytes(key interface{}) ([]byte, error) { valuePtr := internal.NewSlicePointer(valueBytes) err := m.lookup(key, valuePtr) - if IsNotExist(err) { + if errors.Is(err, ErrKeyNotExist) { return nil, nil } @@ -308,11 +359,13 @@ func (m *Map) LookupBytes(key interface{}) ([]byte, error) { func (m *Map) lookup(key interface{}, valueOut internal.Pointer) error { keyPtr, err := marshalPtr(key, int(m.abi.KeySize)) if err != nil { - return errors.WithMessage(err, "can't marshal key") + return fmt.Errorf("can't marshal key: %w", err) } - err = bpfMapLookupElem(m.fd, keyPtr, valueOut) - return errors.WithMessage(err, "lookup failed") + if err = bpfMapLookupElem(m.fd, keyPtr, valueOut); err != nil { + return fmt.Errorf("lookup failed: %w", err) + } + return nil } // MapUpdateFlags controls the behaviour of the Map.Update call. @@ -340,7 +393,7 @@ func (m *Map) Put(key, value interface{}) error { func (m *Map) Update(key, value interface{}, flags MapUpdateFlags) error { keyPtr, err := marshalPtr(key, int(m.abi.KeySize)) if err != nil { - return errors.WithMessage(err, "can't marshal key") + return fmt.Errorf("can't marshal key: %w", err) } var valuePtr internal.Pointer @@ -350,28 +403,36 @@ func (m *Map) Update(key, value interface{}, flags MapUpdateFlags) error { valuePtr, err = marshalPtr(value, int(m.abi.ValueSize)) } if err != nil { - return errors.WithMessage(err, "can't marshal value") + return fmt.Errorf("can't marshal value: %w", err) } - return bpfMapUpdateElem(m.fd, keyPtr, valuePtr, uint64(flags)) + if err = bpfMapUpdateElem(m.fd, keyPtr, valuePtr, uint64(flags)); err != nil { + return fmt.Errorf("update failed: %w", err) + } + + return nil } // Delete removes a value. // -// Returns an error if the key does not exist, see IsNotExist. +// Returns ErrKeyNotExist if the key does not exist. func (m *Map) Delete(key interface{}) error { keyPtr, err := marshalPtr(key, int(m.abi.KeySize)) if err != nil { - return errors.WithMessage(err, "can't marshal key") + return fmt.Errorf("can't marshal key: %w", err) } - err = bpfMapDeleteElem(m.fd, keyPtr) - return errors.WithMessage(err, "can't delete key") + if err = bpfMapDeleteElem(m.fd, keyPtr); err != nil { + return fmt.Errorf("delete failed: %w", err) + } + return nil } // NextKey finds the key following an initial key. // // See NextKeyBytes for details. +// +// Returns ErrKeyNotExist if there is no next key. func (m *Map) NextKey(key, nextKeyOut interface{}) error { nextKeyPtr, nextKeyBytes := makeBuffer(nextKeyOut, int(m.abi.KeySize)) @@ -383,8 +444,10 @@ func (m *Map) NextKey(key, nextKeyOut interface{}) error { return nil } - err := unmarshalBytes(nextKeyOut, nextKeyBytes) - return errors.WithMessage(err, "can't unmarshal next key") + if err := unmarshalBytes(nextKeyOut, nextKeyBytes); err != nil { + return fmt.Errorf("can't unmarshal next key: %w", err) + } + return nil } // NextKeyBytes returns the key following an initial key as a byte slice. @@ -392,12 +455,14 @@ func (m *Map) NextKey(key, nextKeyOut interface{}) error { // Passing nil will return the first key. // // Use Iterate if you want to traverse all entries in the map. +// +// Returns nil if there are no more keys. func (m *Map) NextKeyBytes(key interface{}) ([]byte, error) { nextKey := make([]byte, m.abi.KeySize) nextKeyPtr := internal.NewSlicePointer(nextKey) err := m.nextKey(key, nextKeyPtr) - if IsNotExist(err) { + if errors.Is(err, ErrKeyNotExist) { return nil, nil } @@ -413,12 +478,14 @@ func (m *Map) nextKey(key interface{}, nextKeyOut internal.Pointer) error { if key != nil { keyPtr, err = marshalPtr(key, int(m.abi.KeySize)) if err != nil { - return errors.WithMessage(err, "can't marshal key") + return fmt.Errorf("can't marshal key: %w", err) } } - err = bpfMapGetNextKey(m.fd, keyPtr, nextKeyOut) - return errors.WithMessage(err, "can't get next key") + if err = bpfMapGetNextKey(m.fd, keyPtr, nextKeyOut); err != nil { + return fmt.Errorf("next key failed: %w", err) + } + return nil } // Iterate traverses a map. @@ -469,7 +536,7 @@ func (m *Map) Clone() (*Map, error) { dup, err := m.fd.Dup() if err != nil { - return nil, errors.Wrap(err, "can't clone map") + return nil, fmt.Errorf("can't clone map: %w", err) } return newMap(dup, m.name, &m.abi) @@ -479,7 +546,30 @@ func (m *Map) Clone() (*Map, error) { // // This requires bpffs to be mounted above fileName. See http://cilium.readthedocs.io/en/doc-1.0/kubernetes/install/#mounting-the-bpf-fs-optional func (m *Map) Pin(fileName string) error { - return bpfPinObject(fileName, m.fd) + return internal.BPFObjPin(fileName, m.fd) +} + +// Freeze prevents a map to be modified from user space. +// +// It makes no changes to kernel-side restrictions. +func (m *Map) Freeze() error { + if err := haveMapMutabilityModifiers(); err != nil { + return fmt.Errorf("can't freeze map: %w", err) + } + + if err := bpfMapFreeze(m.fd); err != nil { + return fmt.Errorf("can't freeze map: %w", err) + } + return nil +} + +func (m *Map) populate(contents []MapKV) error { + for _, kv := range contents { + if err := m.Put(kv.Key, kv.Value); err != nil { + return fmt.Errorf("key %v: %w", kv.Key, err) + } + } + return nil } // LoadPinnedMap load a Map from a BPF file. @@ -487,7 +577,7 @@ func (m *Map) Pin(fileName string) error { // The function is not compatible with nested maps. // Use LoadPinnedMapExplicit in these situations. func LoadPinnedMap(fileName string) (*Map, error) { - fd, err := bpfGetObject(fileName) + fd, err := internal.BPFObjGet(fileName) if err != nil { return nil, err } @@ -501,7 +591,7 @@ func LoadPinnedMap(fileName string) (*Map, error) { // LoadPinnedMapExplicit loads a map with explicit parameters. func LoadPinnedMapExplicit(fileName string, abi *MapABI) (*Map, error) { - fd, err := bpfGetObject(fileName) + fd, err := internal.BPFObjGet(fileName) if err != nil { return nil, err } @@ -516,18 +606,7 @@ func unmarshalMap(buf []byte) (*Map, error) { // Looking up an entry in a nested map or prog array returns an id, // not an fd. id := internal.NativeEndian.Uint32(buf) - fd, err := bpfGetMapFDByID(id) - if err != nil { - return nil, err - } - - name, abi, err := newMapABIFromFd(fd) - if err != nil { - _ = fd.Close() - return nil, err - } - - return newMap(fd, name, abi) + return NewMapFromID(MapID(id)) } // MarshalBinary implements BinaryMarshaler. @@ -542,6 +621,60 @@ func (m *Map) MarshalBinary() ([]byte, error) { return buf, nil } +func patchValue(value []byte, typ btf.Type, replacements map[string]interface{}) error { + replaced := make(map[string]bool) + replace := func(name string, offset, size int, replacement interface{}) error { + if offset+size > len(value) { + return fmt.Errorf("%s: offset %d(+%d) is out of bounds", name, offset, size) + } + + buf, err := marshalBytes(replacement, size) + if err != nil { + return fmt.Errorf("marshal %s: %w", name, err) + } + + copy(value[offset:offset+size], buf) + replaced[name] = true + return nil + } + + switch parent := typ.(type) { + case *btf.Datasec: + for _, secinfo := range parent.Vars { + name := string(secinfo.Type.(*btf.Var).Name) + replacement, ok := replacements[name] + if !ok { + continue + } + + err := replace(name, int(secinfo.Offset), int(secinfo.Size), replacement) + if err != nil { + return err + } + } + + default: + return fmt.Errorf("patching %T is not supported", typ) + } + + if len(replaced) == len(replacements) { + return nil + } + + var missing []string + for name := range replacements { + if !replaced[name] { + missing = append(missing, name) + } + } + + if len(missing) == 1 { + return fmt.Errorf("unknown field: %s", missing[0]) + } + + return fmt.Errorf("unknown fields: %s", strings.Join(missing, ",")) +} + // MapIterator iterates a Map. // // See Map.Iterate. @@ -562,8 +695,6 @@ func newMapIterator(target *Map) *MapIterator { } } -var errIterationAborted = errors.New("iteration aborted") - // Next decodes the next key and value. // // Iterating a hash map from which keys are being deleted is not @@ -599,7 +730,7 @@ func (mi *MapIterator) Next(keyOut, valueOut interface{}) bool { mi.prevKey = mi.prevBytes mi.err = mi.target.Lookup(nextBytes, valueOut) - if IsNotExist(mi.err) { + if errors.Is(mi.err, ErrKeyNotExist) { // Even though the key should be valid, we couldn't look up // its value. If we're iterating a hash map this is probably // because a concurrent delete removed the value before we @@ -618,26 +749,50 @@ func (mi *MapIterator) Next(keyOut, valueOut interface{}) bool { return mi.err == nil } - mi.err = errIterationAborted + mi.err = fmt.Errorf("%w", ErrIterationAborted) return false } // Err returns any encountered error. // // The method must be called after Next returns nil. +// +// Returns ErrIterationAborted if it wasn't possible to do a full iteration. func (mi *MapIterator) Err() error { return mi.err } -// IsNotExist returns true if the error indicates that a -// key doesn't exist. -func IsNotExist(err error) bool { - return errors.Cause(err) == unix.ENOENT +// MapGetNextID returns the ID of the next eBPF map. +// +// Returns ErrNotExist, if there is no next eBPF map. +func MapGetNextID(startID MapID) (MapID, error) { + id, err := objGetNextID(internal.BPF_MAP_GET_NEXT_ID, uint32(startID)) + return MapID(id), err } -// IsIterationAborted returns true if the iteration was aborted. +// NewMapFromID returns the map for a given id. // -// This occurs when keys are deleted from a hash map during iteration. -func IsIterationAborted(err error) bool { - return errors.Cause(err) == errIterationAborted +// Returns ErrNotExist, if there is no eBPF map with the given id. +func NewMapFromID(id MapID) (*Map, error) { + fd, err := bpfObjGetFDByID(internal.BPF_MAP_GET_FD_BY_ID, uint32(id)) + if err != nil { + return nil, err + } + + name, abi, err := newMapABIFromFd(fd) + if err != nil { + _ = fd.Close() + return nil, err + } + + return newMap(fd, name, abi) +} + +// ID returns the systemwide unique ID of the map. +func (m *Map) ID() (MapID, error) { + info, err := bpfGetMapInfoByFD(m.fd) + if err != nil { + return MapID(0), err + } + return MapID(info.id), nil } diff --git a/vendor/github.com/cilium/ebpf/marshalers.go b/vendor/github.com/cilium/ebpf/marshalers.go index 64b7d4de7..c0db2f6b0 100644 --- a/vendor/github.com/cilium/ebpf/marshalers.go +++ b/vendor/github.com/cilium/ebpf/marshalers.go @@ -4,13 +4,13 @@ import ( "bytes" "encoding" "encoding/binary" + "errors" + "fmt" "reflect" "runtime" "unsafe" "github.com/cilium/ebpf/internal" - - "github.com/pkg/errors" ) func marshalPtr(data interface{}, length int) (internal.Pointer, error) { @@ -46,7 +46,9 @@ func marshalBytes(data interface{}, length int) (buf []byte, err error) { default: var wr bytes.Buffer err = binary.Write(&wr, internal.NativeEndian, value) - err = errors.Wrapf(err, "encoding %T", value) + if err != nil { + err = fmt.Errorf("encoding %T: %v", value, err) + } buf = wr.Bytes() } if err != nil { @@ -54,7 +56,7 @@ func marshalBytes(data interface{}, length int) (buf []byte, err error) { } if len(buf) != length { - return nil, errors.Errorf("%T doesn't marshal to %d bytes", data, length) + return nil, fmt.Errorf("%T doesn't marshal to %d bytes", data, length) } return buf, nil } @@ -95,8 +97,10 @@ func unmarshalBytes(data interface{}, buf []byte) error { return errors.New("require pointer to []byte") default: rd := bytes.NewReader(buf) - err := binary.Read(rd, internal.NativeEndian, value) - return errors.Wrapf(err, "decoding %T", value) + if err := binary.Read(rd, internal.NativeEndian, value); err != nil { + return fmt.Errorf("decoding %T: %v", value, err) + } + return nil } } @@ -120,7 +124,7 @@ func marshalPerCPUValue(slice interface{}, elemLength int) (internal.Pointer, er sliceValue := reflect.ValueOf(slice) sliceLen := sliceValue.Len() if sliceLen > possibleCPUs { - return internal.Pointer{}, errors.Errorf("per-CPU value exceeds number of CPUs") + return internal.Pointer{}, fmt.Errorf("per-CPU value exceeds number of CPUs") } alignedElemLength := align(elemLength, 8) @@ -147,7 +151,7 @@ func marshalPerCPUValue(slice interface{}, elemLength int) (internal.Pointer, er func unmarshalPerCPUValue(slicePtr interface{}, elemLength int, buf []byte) error { slicePtrType := reflect.TypeOf(slicePtr) if slicePtrType.Kind() != reflect.Ptr || slicePtrType.Elem().Kind() != reflect.Slice { - return errors.Errorf("per-cpu value requires pointer to slice") + return fmt.Errorf("per-cpu value requires pointer to slice") } possibleCPUs, err := internal.PossibleCPUs() @@ -166,7 +170,7 @@ func unmarshalPerCPUValue(slicePtr interface{}, elemLength int, buf []byte) erro step := len(buf) / possibleCPUs if step < elemLength { - return errors.Errorf("per-cpu element length is larger than available data") + return fmt.Errorf("per-cpu element length is larger than available data") } for i := 0; i < possibleCPUs; i++ { var elem interface{} @@ -184,7 +188,7 @@ func unmarshalPerCPUValue(slicePtr interface{}, elemLength int, buf []byte) erro err := unmarshalBytes(elem, elemBytes) if err != nil { - return errors.Wrapf(err, "cpu %d", i) + return fmt.Errorf("cpu %d: %w", i, err) } buf = buf[step:] diff --git a/vendor/github.com/cilium/ebpf/prog.go b/vendor/github.com/cilium/ebpf/prog.go index 08ef4fa46..429203f07 100644 --- a/vendor/github.com/cilium/ebpf/prog.go +++ b/vendor/github.com/cilium/ebpf/prog.go @@ -2,20 +2,25 @@ package ebpf import ( "bytes" + "encoding/binary" + "errors" "fmt" "math" "strings" "time" - "unsafe" "github.com/cilium/ebpf/asm" "github.com/cilium/ebpf/internal" "github.com/cilium/ebpf/internal/btf" "github.com/cilium/ebpf/internal/unix" - - "github.com/pkg/errors" ) +// ErrNotSupported is returned whenever the kernel doesn't support a feature. +var ErrNotSupported = internal.ErrNotSupported + +// ProgramID represents the unique ID of an eBPF program +type ProgramID uint32 + const ( // Number of bytes to pad the output buffer for BPF_PROG_TEST_RUN. // This is currently the maximum of spare space allocated for SKB @@ -41,17 +46,33 @@ type ProgramOptions struct { type ProgramSpec struct { // Name is passed to the kernel as a debug aid. Must only contain // alpha numeric and '_' characters. - Name string - Type ProgramType - AttachType AttachType - Instructions asm.Instructions - License string + Name string + // Type determines at which hook in the kernel a program will run. + Type ProgramType + AttachType AttachType + // Name of a kernel data structure to attach to. It's interpretation + // depends on Type and AttachType. + AttachTo string + Instructions asm.Instructions + + // License of the program. Some helpers are only available if + // the license is deemed compatible with the GPL. + // + // See https://www.kernel.org/doc/html/latest/process/license-rules.html#id1 + License string + + // Version used by tracing programs. + // + // Deprecated: superseded by BTF. KernelVersion uint32 // The BTF associated with this program. Changing Instructions // will most likely invalidate the contained data, and may // result in errors when attempting to load it into the kernel. BTF *btf.Program + + // The byte order this program was compiled for, may be nil. + ByteOrder binary.ByteOrder } // Copy returns a copy of the spec. @@ -74,9 +95,10 @@ type Program struct { // otherwise it is empty. VerifierLog string - fd *internal.FD - name string - abi ProgramABI + fd *internal.FD + name string + abi ProgramABI + attachType AttachType } // NewProgram creates a new Program. @@ -97,8 +119,8 @@ func NewProgramWithOptions(spec *ProgramSpec, opts ProgramOptions) (*Program, er } handle, err := btf.NewHandle(btf.ProgramSpec(spec.BTF)) - if err != nil && !btf.IsNotSupported(err) { - return nil, errors.Wrap(err, "can't load BTF") + if err != nil && !errors.Is(err, btf.ErrNotSupported) { + return nil, fmt.Errorf("can't load BTF: %w", err) } return newProgramWithBTF(spec, handle, opts) @@ -130,6 +152,7 @@ func newProgramWithBTF(spec *ProgramSpec, btf *btf.Handle, opts ProgramOptions) return prog, nil } + logErr := err if opts.LogLevel == 0 { // Re-run with the verifier enabled to get better error messages. logBuf = make([]byte, logSize) @@ -137,11 +160,11 @@ func newProgramWithBTF(spec *ProgramSpec, btf *btf.Handle, opts ProgramOptions) attr.logSize = uint32(len(logBuf)) attr.logBuf = internal.NewSlicePointer(logBuf) - _, logErr := bpfProgLoad(attr) - err = internal.ErrorWithLog(err, logBuf, logErr) + _, logErr = bpfProgLoad(attr) } - return nil, errors.Wrap(err, "can't load program") + err = internal.ErrorWithLog(err, logBuf, logErr) + return nil, fmt.Errorf("can't load program: %w", err) } // NewProgramFromFD creates a program from a raw fd. @@ -181,6 +204,10 @@ func convertProgramSpec(spec *ProgramSpec, handle *btf.Handle) (*bpfProgLoadAttr return nil, errors.New("License cannot be empty") } + if spec.ByteOrder != nil && spec.ByteOrder != internal.NativeEndian { + return nil, fmt.Errorf("can't load %s program on %s", spec.ByteOrder, internal.NativeEndian) + } + buf := bytes.NewBuffer(make([]byte, 0, len(spec.Instructions)*asm.InstructionSize)) err := spec.Instructions.Marshal(buf, internal.NativeEndian) if err != nil { @@ -195,15 +222,11 @@ func convertProgramSpec(spec *ProgramSpec, handle *btf.Handle) (*bpfProgLoadAttr insCount: insCount, instructions: internal.NewSlicePointer(bytecode), license: internal.NewStringPointer(spec.License), - } - - name, err := newBPFObjName(spec.Name) - if err != nil { - return nil, err + kernelVersion: spec.KernelVersion, } if haveObjName() == nil { - attr.progName = name + attr.progName = newBPFObjName(spec.Name) } if handle != nil && spec.BTF != nil { @@ -211,7 +234,7 @@ func convertProgramSpec(spec *ProgramSpec, handle *btf.Handle) (*bpfProgLoadAttr recSize, bytes, err := btf.ProgramLineInfos(spec.BTF) if err != nil { - return nil, errors.Wrap(err, "can't get BTF line infos") + return nil, fmt.Errorf("can't get BTF line infos: %w", err) } attr.lineInfoRecSize = recSize attr.lineInfoCnt = uint32(uint64(len(bytes)) / uint64(recSize)) @@ -219,13 +242,23 @@ func convertProgramSpec(spec *ProgramSpec, handle *btf.Handle) (*bpfProgLoadAttr recSize, bytes, err = btf.ProgramFuncInfos(spec.BTF) if err != nil { - return nil, errors.Wrap(err, "can't get BTF function infos") + return nil, fmt.Errorf("can't get BTF function infos: %w", err) } attr.funcInfoRecSize = recSize attr.funcInfoCnt = uint32(uint64(len(bytes)) / uint64(recSize)) attr.funcInfo = internal.NewSlicePointer(bytes) } + if spec.AttachTo != "" { + target, err := resolveBTFType(spec.AttachTo, spec.Type, spec.AttachType) + if err != nil { + return nil, err + } + if target != nil { + attr.attachBTFID = target.ID() + } + } + return attr, nil } @@ -267,7 +300,7 @@ func (p *Program) Clone() (*Program, error) { dup, err := p.fd.Dup() if err != nil { - return nil, errors.Wrap(err, "can't clone program") + return nil, fmt.Errorf("can't clone program: %w", err) } return newProgram(dup, p.name, &p.abi), nil @@ -277,7 +310,10 @@ func (p *Program) Clone() (*Program, error) { // // This requires bpffs to be mounted above fileName. See http://cilium.readthedocs.io/en/doc-1.0/kubernetes/install/#mounting-the-bpf-fs-optional func (p *Program) Pin(fileName string) error { - return errors.Wrap(bpfPinObject(fileName, p.fd), "can't pin program") + if err := internal.BPFObjPin(fileName, p.fd); err != nil { + return fmt.Errorf("can't pin program: %w", err) + } + return nil } // Close unloads the program from the kernel. @@ -297,23 +333,33 @@ func (p *Program) Close() error { // // This function requires at least Linux 4.12. func (p *Program) Test(in []byte) (uint32, []byte, error) { - ret, out, _, err := p.testRun(in, 1) - return ret, out, errors.Wrap(err, "can't test program") + ret, out, _, err := p.testRun(in, 1, nil) + if err != nil { + return ret, nil, fmt.Errorf("can't test program: %w", err) + } + return ret, out, nil } // Benchmark runs the Program with the given input for a number of times // and returns the time taken per iteration. // -// The returned value is the return value of the last execution of -// the program. +// Returns the result of the last execution of the program and the time per +// run or an error. reset is called whenever the benchmark syscall is +// interrupted, and should be set to testing.B.ResetTimer or similar. +// +// Note: profiling a call to this function will skew it's results, see +// https://github.com/cilium/ebpf/issues/24 // // This function requires at least Linux 4.12. -func (p *Program) Benchmark(in []byte, repeat int) (uint32, time.Duration, error) { - ret, _, total, err := p.testRun(in, repeat) - return ret, total, errors.Wrap(err, "can't benchmark program") +func (p *Program) Benchmark(in []byte, repeat int, reset func()) (uint32, time.Duration, error) { + ret, _, total, err := p.testRun(in, repeat, reset) + if err != nil { + return ret, total, fmt.Errorf("can't benchmark program: %w", err) + } + return ret, total, nil } -var haveProgTestRun = internal.FeatureTest("BPF_PROG_TEST_RUN", "4.12", func() bool { +var haveProgTestRun = internal.FeatureTest("BPF_PROG_TEST_RUN", "4.12", func() (bool, error) { prog, err := NewProgram(&ProgramSpec{ Type: SocketFilter, Instructions: asm.Instructions{ @@ -324,31 +370,26 @@ var haveProgTestRun = internal.FeatureTest("BPF_PROG_TEST_RUN", "4.12", func() b }) if err != nil { // This may be because we lack sufficient permissions, etc. - return false + return false, err } defer prog.Close() - fd, err := prog.fd.Value() - if err != nil { - return false - } - // Programs require at least 14 bytes input in := make([]byte, 14) attr := bpfProgTestRunAttr{ - fd: fd, + fd: uint32(prog.FD()), dataSizeIn: uint32(len(in)), dataIn: internal.NewSlicePointer(in), } - _, err = internal.BPF(_ProgTestRun, unsafe.Pointer(&attr), unsafe.Sizeof(attr)) + err = bpfProgTestRun(&attr) // Check for EINVAL specifically, rather than err != nil since we // otherwise misdetect due to insufficient permissions. - return errors.Cause(err) != unix.EINVAL + return !errors.Is(err, unix.EINVAL), nil }) -func (p *Program) testRun(in []byte, repeat int) (uint32, []byte, time.Duration, error) { +func (p *Program) testRun(in []byte, repeat int, reset func()) (uint32, []byte, time.Duration, error) { if uint(repeat) > math.MaxUint32 { return 0, nil, 0, fmt.Errorf("repeat is too high") } @@ -386,9 +427,20 @@ func (p *Program) testRun(in []byte, repeat int) (uint32, []byte, time.Duration, repeat: uint32(repeat), } - _, err = internal.BPF(_ProgTestRun, unsafe.Pointer(&attr), unsafe.Sizeof(attr)) - if err != nil { - return 0, nil, 0, errors.Wrap(err, "can't run test") + for { + err = bpfProgTestRun(&attr) + if err == nil { + break + } + + if errors.Is(err, unix.EINTR) { + if reset != nil { + reset() + } + continue + } + + return 0, nil, 0, fmt.Errorf("can't run test: %w", err) } if int(attr.dataSizeOut) > cap(out) { @@ -410,18 +462,7 @@ func unmarshalProgram(buf []byte) (*Program, error) { // Looking up an entry in a nested map or prog array returns an id, // not an fd. id := internal.NativeEndian.Uint32(buf) - fd, err := bpfGetProgramFDByID(id) - if err != nil { - return nil, err - } - - name, abi, err := newProgramABIFromFd(fd) - if err != nil { - _ = fd.Close() - return nil, err - } - - return newProgram(fd, name, abi), nil + return NewProgramFromID(ProgramID(id)) } // MarshalBinary implements BinaryMarshaler. @@ -436,7 +477,9 @@ func (p *Program) MarshalBinary() ([]byte, error) { return buf, nil } -// Attach a Program to a container object fd +// Attach a Program. +// +// Deprecated: use link.RawAttachProgram instead. func (p *Program) Attach(fd int, typ AttachType, flags AttachFlags) error { if fd < 0 { return errors.New("invalid fd") @@ -447,42 +490,47 @@ func (p *Program) Attach(fd int, typ AttachType, flags AttachFlags) error { return err } - attr := bpfProgAlterAttr{ - targetFd: uint32(fd), - attachBpfFd: pfd, - attachType: uint32(typ), - attachFlags: uint32(flags), + attr := internal.BPFProgAttachAttr{ + TargetFd: uint32(fd), + AttachBpfFd: pfd, + AttachType: uint32(typ), + AttachFlags: uint32(flags), } - return bpfProgAlter(_ProgAttach, &attr) + return internal.BPFProgAttach(&attr) } -// Detach a Program from a container object fd +// Detach a Program. +// +// Deprecated: use link.RawDetachProgram instead. func (p *Program) Detach(fd int, typ AttachType, flags AttachFlags) error { if fd < 0 { return errors.New("invalid fd") } + if flags != 0 { + return errors.New("flags must be zero") + } + pfd, err := p.fd.Value() if err != nil { return err } - attr := bpfProgAlterAttr{ - targetFd: uint32(fd), - attachBpfFd: pfd, - attachType: uint32(typ), - attachFlags: uint32(flags), + attr := internal.BPFProgDetachAttr{ + TargetFd: uint32(fd), + AttachBpfFd: pfd, + AttachType: uint32(typ), } - return bpfProgAlter(_ProgDetach, &attr) + return internal.BPFProgDetach(&attr) } // LoadPinnedProgram loads a Program from a BPF file. // // Requires at least Linux 4.11. func LoadPinnedProgram(fileName string) (*Program, error) { - fd, err := bpfGetObject(fileName) + fd, err := internal.BPFObjGet(fileName) if err != nil { return nil, err } @@ -490,7 +538,7 @@ func LoadPinnedProgram(fileName string) (*Program, error) { name, abi, err := newProgramABIFromFd(fd) if err != nil { _ = fd.Close() - return nil, errors.Wrapf(err, "can't get ABI for %s", fileName) + return nil, fmt.Errorf("can't get ABI for %s: %w", fileName, err) } return newProgram(fd, name, abi), nil @@ -512,9 +560,63 @@ func SanitizeName(name string, replacement rune) string { }, name) } -// IsNotSupported returns true if an error occurred because -// the kernel does not have support for a specific feature. -func IsNotSupported(err error) bool { - _, notSupported := errors.Cause(err).(*internal.UnsupportedFeatureError) - return notSupported +// ProgramGetNextID returns the ID of the next eBPF program. +// +// Returns ErrNotExist, if there is no next eBPF program. +func ProgramGetNextID(startID ProgramID) (ProgramID, error) { + id, err := objGetNextID(internal.BPF_PROG_GET_NEXT_ID, uint32(startID)) + return ProgramID(id), err +} + +// NewProgramFromID returns the program for a given id. +// +// Returns ErrNotExist, if there is no eBPF program with the given id. +func NewProgramFromID(id ProgramID) (*Program, error) { + fd, err := bpfObjGetFDByID(internal.BPF_PROG_GET_FD_BY_ID, uint32(id)) + if err != nil { + return nil, err + } + + name, abi, err := newProgramABIFromFd(fd) + if err != nil { + _ = fd.Close() + return nil, err + } + + return newProgram(fd, name, abi), nil +} + +// ID returns the systemwide unique ID of the program. +func (p *Program) ID() (ProgramID, error) { + info, err := bpfGetProgInfoByFD(p.fd) + if err != nil { + return ProgramID(0), err + } + return ProgramID(info.id), nil +} + +func resolveBTFType(name string, progType ProgramType, attachType AttachType) (btf.Type, error) { + kernel, err := btf.LoadKernelSpec() + if err != nil { + return nil, fmt.Errorf("can't resolve BTF type %s: %w", name, err) + } + + type match struct { + p ProgramType + a AttachType + } + + target := match{progType, attachType} + switch target { + case match{Tracing, AttachTraceIter}: + var target btf.Func + if err := kernel.FindType("bpf_iter_"+name, &target); err != nil { + return nil, fmt.Errorf("can't resolve BTF for iterator %s: %w", name, err) + } + + return &target, nil + + default: + return nil, nil + } } diff --git a/vendor/github.com/cilium/ebpf/readme.md b/vendor/github.com/cilium/ebpf/readme.md index 26ab2b904..cc8e89c75 100644 --- a/vendor/github.com/cilium/ebpf/readme.md +++ b/vendor/github.com/cilium/ebpf/readme.md @@ -13,6 +13,11 @@ The library is maintained by [Cloudflare](https://www.cloudflare.com) and [Ciliu The package is production ready, but **the API is explicitly unstable right now**. Expect to update your code if you want to follow along. +## Requirements + +* A version of Go that is [supported by upstream](https://golang.org/doc/devel/release.html#policy) +* Linux 4.9, 4.19 or 5.4 (versions in-between should work, but are not tested) + ## Useful resources * [Cilium eBPF documentation](https://cilium.readthedocs.io/en/latest/bpf/#bpf-guide) (recommended) diff --git a/vendor/github.com/cilium/ebpf/syscalls.go b/vendor/github.com/cilium/ebpf/syscalls.go index 70f8c127a..2b713d06a 100644 --- a/vendor/github.com/cilium/ebpf/syscalls.go +++ b/vendor/github.com/cilium/ebpf/syscalls.go @@ -1,15 +1,19 @@ package ebpf import ( - "path/filepath" - "strings" + "errors" + "fmt" + "os" "unsafe" "github.com/cilium/ebpf/internal" "github.com/cilium/ebpf/internal/btf" "github.com/cilium/ebpf/internal/unix" +) - "github.com/pkg/errors" +// Generic errors returned by BPF syscalls. +var ( + ErrNotExist = errors.New("requested object does not exist") ) // bpfObjName is a null-terminated string made up of @@ -17,18 +21,15 @@ import ( type bpfObjName [unix.BPF_OBJ_NAME_LEN]byte // newBPFObjName truncates the result if it is too long. -func newBPFObjName(name string) (bpfObjName, error) { - idx := strings.IndexFunc(name, invalidBPFObjNameChar) - if idx != -1 { - return bpfObjName{}, errors.Errorf("invalid character '%c' in name '%s'", name[idx], name) - } - +func newBPFObjName(name string) bpfObjName { var result bpfObjName copy(result[:unix.BPF_OBJ_NAME_LEN-1], name) - return result, nil + return result } func invalidBPFObjNameChar(char rune) bool { + dotAllowed := objNameAllowsDot() == nil + switch { case char >= 'A' && char <= 'Z': fallthrough @@ -36,6 +37,8 @@ func invalidBPFObjNameChar(char rune) bool { fallthrough case char >= '0' && char <= '9': fallthrough + case dotAllowed && char == '.': + fallthrough case char == '_': return false default: @@ -76,12 +79,6 @@ type bpfMapInfo struct { mapName bpfObjName // since 4.15 ad5b177bd73f } -type bpfPinObjAttr struct { - fileName internal.Pointer - fd uint32 - padding uint32 -} - type bpfProgLoadAttr struct { progType ProgramType insCount uint32 @@ -102,6 +99,8 @@ type bpfProgLoadAttr struct { lineInfoRecSize uint32 lineInfo internal.Pointer lineInfoCnt uint32 + attachBTFID btf.TypeID + attachProgFd uint32 } type bpfProgInfo struct { @@ -130,13 +129,6 @@ type bpfProgTestRunAttr struct { duration uint32 } -type bpfProgAlterAttr struct { - targetFd uint32 - attachBpfFd uint32 - attachType uint32 - attachFlags uint32 -} - type bpfObjGetInfoByFDAttr struct { fd uint32 infoLen uint32 @@ -148,9 +140,19 @@ type bpfGetFDByIDAttr struct { next uint32 } +type bpfMapFreezeAttr struct { + mapFd uint32 +} + +type bpfObjGetNextIDAttr struct { + startID uint32 + nextID uint32 + openFlags uint32 +} + func bpfProgLoad(attr *bpfProgLoadAttr) (*internal.FD, error) { for { - fd, err := internal.BPF(_ProgLoad, unsafe.Pointer(attr), unsafe.Sizeof(*attr)) + fd, err := internal.BPF(internal.BPF_PROG_LOAD, unsafe.Pointer(attr), unsafe.Sizeof(*attr)) // As of ~4.20 the verifier can be interrupted by a signal, // and returns EAGAIN in that case. if err == unix.EAGAIN { @@ -165,13 +167,17 @@ func bpfProgLoad(attr *bpfProgLoadAttr) (*internal.FD, error) { } } -func bpfProgAlter(cmd int, attr *bpfProgAlterAttr) error { - _, err := internal.BPF(cmd, unsafe.Pointer(attr), unsafe.Sizeof(*attr)) +func bpfProgTestRun(attr *bpfProgTestRunAttr) error { + _, err := internal.BPF(internal.BPF_PROG_TEST_RUN, unsafe.Pointer(attr), unsafe.Sizeof(*attr)) return err } func bpfMapCreate(attr *bpfMapCreateAttr) (*internal.FD, error) { - fd, err := internal.BPF(_MapCreate, unsafe.Pointer(attr), unsafe.Sizeof(*attr)) + fd, err := internal.BPF(internal.BPF_MAP_CREATE, unsafe.Pointer(attr), unsafe.Sizeof(*attr)) + if errors.Is(err, os.ErrPermission) { + return nil, errors.New("permission denied or insufficient rlimit to lock memory for map") + } + if err != nil { return nil, err } @@ -179,7 +185,7 @@ func bpfMapCreate(attr *bpfMapCreateAttr) (*internal.FD, error) { return internal.NewFD(uint32(fd)), nil } -var haveNestedMaps = internal.FeatureTest("nested maps", "4.12", func() bool { +var haveNestedMaps = internal.FeatureTest("nested maps", "4.12", func() (bool, error) { inner, err := bpfMapCreate(&bpfMapCreateAttr{ mapType: Array, keySize: 4, @@ -187,7 +193,7 @@ var haveNestedMaps = internal.FeatureTest("nested maps", "4.12", func() bool { maxEntries: 1, }) if err != nil { - return false + return false, err } defer inner.Close() @@ -200,11 +206,28 @@ var haveNestedMaps = internal.FeatureTest("nested maps", "4.12", func() bool { innerMapFd: innerFd, }) if err != nil { - return false + return false, nil } _ = nested.Close() - return true + return true, nil +}) + +var haveMapMutabilityModifiers = internal.FeatureTest("read- and write-only maps", "5.2", func() (bool, error) { + // This checks BPF_F_RDONLY_PROG and BPF_F_WRONLY_PROG. Since + // BPF_MAP_FREEZE appeared in 5.2 as well we don't do a separate check. + m, err := bpfMapCreate(&bpfMapCreateAttr{ + mapType: Array, + keySize: 4, + valueSize: 4, + maxEntries: 1, + flags: unix.BPF_F_RDONLY_PROG, + }) + if err != nil { + return false, nil + } + _ = m.Close() + return true, nil }) func bpfMapLookupElem(m *internal.FD, key, valueOut internal.Pointer) error { @@ -218,8 +241,8 @@ func bpfMapLookupElem(m *internal.FD, key, valueOut internal.Pointer) error { key: key, value: valueOut, } - _, err = internal.BPF(_MapLookupElem, unsafe.Pointer(&attr), unsafe.Sizeof(attr)) - return err + _, err = internal.BPF(internal.BPF_MAP_LOOKUP_ELEM, unsafe.Pointer(&attr), unsafe.Sizeof(attr)) + return wrapMapError(err) } func bpfMapLookupAndDelete(m *internal.FD, key, valueOut internal.Pointer) error { @@ -233,8 +256,8 @@ func bpfMapLookupAndDelete(m *internal.FD, key, valueOut internal.Pointer) error key: key, value: valueOut, } - _, err = internal.BPF(_MapLookupAndDeleteElem, unsafe.Pointer(&attr), unsafe.Sizeof(attr)) - return err + _, err = internal.BPF(internal.BPF_MAP_LOOKUP_AND_DELETE_ELEM, unsafe.Pointer(&attr), unsafe.Sizeof(attr)) + return wrapMapError(err) } func bpfMapUpdateElem(m *internal.FD, key, valueOut internal.Pointer, flags uint64) error { @@ -249,8 +272,8 @@ func bpfMapUpdateElem(m *internal.FD, key, valueOut internal.Pointer, flags uint value: valueOut, flags: flags, } - _, err = internal.BPF(_MapUpdateElem, unsafe.Pointer(&attr), unsafe.Sizeof(attr)) - return err + _, err = internal.BPF(internal.BPF_MAP_UPDATE_ELEM, unsafe.Pointer(&attr), unsafe.Sizeof(attr)) + return wrapMapError(err) } func bpfMapDeleteElem(m *internal.FD, key internal.Pointer) error { @@ -263,8 +286,8 @@ func bpfMapDeleteElem(m *internal.FD, key internal.Pointer) error { mapFd: fd, key: key, } - _, err = internal.BPF(_MapDeleteElem, unsafe.Pointer(&attr), unsafe.Sizeof(attr)) - return err + _, err = internal.BPF(internal.BPF_MAP_DELETE_ELEM, unsafe.Pointer(&attr), unsafe.Sizeof(attr)) + return wrapMapError(err) } func bpfMapGetNextKey(m *internal.FD, key, nextKeyOut internal.Pointer) error { @@ -278,44 +301,58 @@ func bpfMapGetNextKey(m *internal.FD, key, nextKeyOut internal.Pointer) error { key: key, value: nextKeyOut, } - _, err = internal.BPF(_MapGetNextKey, unsafe.Pointer(&attr), unsafe.Sizeof(attr)) + _, err = internal.BPF(internal.BPF_MAP_GET_NEXT_KEY, unsafe.Pointer(&attr), unsafe.Sizeof(attr)) + return wrapMapError(err) +} + +func objGetNextID(cmd internal.BPFCmd, start uint32) (uint32, error) { + attr := bpfObjGetNextIDAttr{ + startID: start, + } + _, err := internal.BPF(cmd, unsafe.Pointer(&attr), unsafe.Sizeof(attr)) + return attr.nextID, wrapObjError(err) +} + +func wrapObjError(err error) error { + if err == nil { + return nil + } + if errors.Is(err, unix.ENOENT) { + return fmt.Errorf("%w", ErrNotExist) + } + + return errors.New(err.Error()) +} + +func wrapMapError(err error) error { + if err == nil { + return nil + } + + if errors.Is(err, unix.ENOENT) { + return ErrKeyNotExist + } + + if errors.Is(err, unix.EEXIST) { + return ErrKeyExist + } + + return errors.New(err.Error()) +} + +func bpfMapFreeze(m *internal.FD) error { + fd, err := m.Value() + if err != nil { + return err + } + + attr := bpfMapFreezeAttr{ + mapFd: fd, + } + _, err = internal.BPF(internal.BPF_MAP_FREEZE, unsafe.Pointer(&attr), unsafe.Sizeof(attr)) return err } -const bpfFSType = 0xcafe4a11 - -func bpfPinObject(fileName string, fd *internal.FD) error { - dirName := filepath.Dir(fileName) - var statfs unix.Statfs_t - if err := unix.Statfs(dirName, &statfs); err != nil { - return err - } - if uint64(statfs.Type) != bpfFSType { - return errors.Errorf("%s is not on a bpf filesystem", fileName) - } - - value, err := fd.Value() - if err != nil { - return err - } - - _, err = internal.BPF(_ObjPin, unsafe.Pointer(&bpfPinObjAttr{ - fileName: internal.NewStringPointer(fileName), - fd: value, - }), 16) - return errors.Wrapf(err, "pin object %s", fileName) -} - -func bpfGetObject(fileName string) (*internal.FD, error) { - ptr, err := internal.BPF(_ObjGet, unsafe.Pointer(&bpfPinObjAttr{ - fileName: internal.NewStringPointer(fileName), - }), 16) - if err != nil { - return nil, errors.Wrapf(err, "get object %s", fileName) - } - return internal.NewFD(uint32(ptr)), nil -} - func bpfGetObjectInfoByFD(fd *internal.FD, info unsafe.Pointer, size uintptr) error { value, err := fd.Value() if err != nil { @@ -328,28 +365,51 @@ func bpfGetObjectInfoByFD(fd *internal.FD, info unsafe.Pointer, size uintptr) er infoLen: uint32(size), info: internal.NewPointer(info), } - _, err = internal.BPF(_ObjGetInfoByFD, unsafe.Pointer(&attr), unsafe.Sizeof(attr)) - return errors.Wrapf(err, "fd %d", fd) + _, err = internal.BPF(internal.BPF_OBJ_GET_INFO_BY_FD, unsafe.Pointer(&attr), unsafe.Sizeof(attr)) + if err != nil { + return fmt.Errorf("fd %d: %w", fd, err) + } + return nil } func bpfGetProgInfoByFD(fd *internal.FD) (*bpfProgInfo, error) { var info bpfProgInfo - err := bpfGetObjectInfoByFD(fd, unsafe.Pointer(&info), unsafe.Sizeof(info)) - return &info, errors.Wrap(err, "can't get program info") + if err := bpfGetObjectInfoByFD(fd, unsafe.Pointer(&info), unsafe.Sizeof(info)); err != nil { + return nil, fmt.Errorf("can't get program info: %w", err) + } + return &info, nil } func bpfGetMapInfoByFD(fd *internal.FD) (*bpfMapInfo, error) { var info bpfMapInfo err := bpfGetObjectInfoByFD(fd, unsafe.Pointer(&info), unsafe.Sizeof(info)) - return &info, errors.Wrap(err, "can't get map info") + if err != nil { + return nil, fmt.Errorf("can't get map info: %w", err) + } + return &info, nil } -var haveObjName = internal.FeatureTest("object names", "4.15", func() bool { - name, err := newBPFObjName("feature_test") +var haveObjName = internal.FeatureTest("object names", "4.15", func() (bool, error) { + attr := bpfMapCreateAttr{ + mapType: Array, + keySize: 4, + valueSize: 4, + maxEntries: 1, + mapName: newBPFObjName("feature_test"), + } + + fd, err := bpfMapCreate(&attr) if err != nil { - // This really is a fatal error, but it should be caught - // by the unit tests not working. - return false + return false, nil + } + + _ = fd.Close() + return true, nil +}) + +var objNameAllowsDot = internal.FeatureTest("dot in object names", "5.2", func() (bool, error) { + if err := haveObjName(); err != nil { + return false, err } attr := bpfMapCreateAttr{ @@ -357,38 +417,22 @@ var haveObjName = internal.FeatureTest("object names", "4.15", func() bool { keySize: 4, valueSize: 4, maxEntries: 1, - mapName: name, + mapName: newBPFObjName(".test"), } fd, err := bpfMapCreate(&attr) if err != nil { - return false + return false, nil } _ = fd.Close() - return true + return true, nil }) -func bpfGetMapFDByID(id uint32) (*internal.FD, error) { - // available from 4.13 +func bpfObjGetFDByID(cmd internal.BPFCmd, id uint32) (*internal.FD, error) { attr := bpfGetFDByIDAttr{ id: id, } - ptr, err := internal.BPF(_MapGetFDByID, unsafe.Pointer(&attr), unsafe.Sizeof(attr)) - if err != nil { - return nil, errors.Wrapf(err, "can't get fd for map id %d", id) - } - return internal.NewFD(uint32(ptr)), nil -} - -func bpfGetProgramFDByID(id uint32) (*internal.FD, error) { - // available from 4.13 - attr := bpfGetFDByIDAttr{ - id: id, - } - ptr, err := internal.BPF(_ProgGetFDByID, unsafe.Pointer(&attr), unsafe.Sizeof(attr)) - if err != nil { - return nil, errors.Wrapf(err, "can't get fd for program id %d", id) - } - return internal.NewFD(uint32(ptr)), nil + ptr, err := internal.BPF(cmd, unsafe.Pointer(&attr), unsafe.Sizeof(attr)) + return internal.NewFD(uint32(ptr)), wrapObjError(err) } diff --git a/vendor/github.com/cilium/ebpf/types.go b/vendor/github.com/cilium/ebpf/types.go index 6a0228dc7..1ffc62123 100644 --- a/vendor/github.com/cilium/ebpf/types.go +++ b/vendor/github.com/cilium/ebpf/types.go @@ -1,6 +1,6 @@ package ebpf -//go:generate stringer -output types_string.go -type=MapType,ProgramType +//go:generate stringer -output types_string.go -type=MapType,ProgramType,AttachType // MapType indicates the type map structure // that will be initialized in the kernel. @@ -85,44 +85,12 @@ const ( // hasPerCPUValue returns true if the Map stores a value per CPU. func (mt MapType) hasPerCPUValue() bool { - if mt == PerCPUHash || mt == PerCPUArray { + if mt == PerCPUHash || mt == PerCPUArray || mt == LRUCPUHash { return true } return false } -const ( - _MapCreate = iota - _MapLookupElem - _MapUpdateElem - _MapDeleteElem - _MapGetNextKey - _ProgLoad - _ObjPin - _ObjGet - _ProgAttach - _ProgDetach - _ProgTestRun - _ProgGetNextID - _MapGetNextID - _ProgGetFDByID - _MapGetFDByID - _ObjGetInfoByFD - _ProgQuery - _RawTracepointOpen - _BTFLoad - _BTFGetFDByID - _TaskFDQuery - _MapLookupAndDeleteElem - _MapFreeze -) - -const ( - _Any = iota - _NoExist - _Exist -) - // ProgramType of the eBPF program type ProgramType uint32 @@ -219,6 +187,9 @@ const ( AttachTraceRawTp AttachTraceFEntry AttachTraceFExit + AttachModifyReturn + AttachLSMMac + AttachTraceIter ) // AttachFlags of the eBPF program used in BPF_PROG_ATTACH command diff --git a/vendor/github.com/cilium/ebpf/types_string.go b/vendor/github.com/cilium/ebpf/types_string.go index f41ba77df..c7139578e 100644 --- a/vendor/github.com/cilium/ebpf/types_string.go +++ b/vendor/github.com/cilium/ebpf/types_string.go @@ -1,4 +1,4 @@ -// Code generated by "stringer -output types_string.go -type=MapType,ProgramType"; DO NOT EDIT. +// Code generated by "stringer -output types_string.go -type=MapType,ProgramType,AttachType"; DO NOT EDIT. package ebpf @@ -89,3 +89,49 @@ func (i ProgramType) String() string { } return _ProgramType_name[_ProgramType_index[i]:_ProgramType_index[i+1]] } +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[AttachNone-0] + _ = x[AttachCGroupInetIngress-0] + _ = x[AttachCGroupInetEgress-1] + _ = x[AttachCGroupInetSockCreate-2] + _ = x[AttachCGroupSockOps-3] + _ = x[AttachSkSKBStreamParser-4] + _ = x[AttachSkSKBStreamVerdict-5] + _ = x[AttachCGroupDevice-6] + _ = x[AttachSkMsgVerdict-7] + _ = x[AttachCGroupInet4Bind-8] + _ = x[AttachCGroupInet6Bind-9] + _ = x[AttachCGroupInet4Connect-10] + _ = x[AttachCGroupInet6Connect-11] + _ = x[AttachCGroupInet4PostBind-12] + _ = x[AttachCGroupInet6PostBind-13] + _ = x[AttachCGroupUDP4Sendmsg-14] + _ = x[AttachCGroupUDP6Sendmsg-15] + _ = x[AttachLircMode2-16] + _ = x[AttachFlowDissector-17] + _ = x[AttachCGroupSysctl-18] + _ = x[AttachCGroupUDP4Recvmsg-19] + _ = x[AttachCGroupUDP6Recvmsg-20] + _ = x[AttachCGroupGetsockopt-21] + _ = x[AttachCGroupSetsockopt-22] + _ = x[AttachTraceRawTp-23] + _ = x[AttachTraceFEntry-24] + _ = x[AttachTraceFExit-25] + _ = x[AttachModifyReturn-26] + _ = x[AttachLSMMac-27] + _ = x[AttachTraceIter-28] +} + +const _AttachType_name = "AttachNoneAttachCGroupInetEgressAttachCGroupInetSockCreateAttachCGroupSockOpsAttachSkSKBStreamParserAttachSkSKBStreamVerdictAttachCGroupDeviceAttachSkMsgVerdictAttachCGroupInet4BindAttachCGroupInet6BindAttachCGroupInet4ConnectAttachCGroupInet6ConnectAttachCGroupInet4PostBindAttachCGroupInet6PostBindAttachCGroupUDP4SendmsgAttachCGroupUDP6SendmsgAttachLircMode2AttachFlowDissectorAttachCGroupSysctlAttachCGroupUDP4RecvmsgAttachCGroupUDP6RecvmsgAttachCGroupGetsockoptAttachCGroupSetsockoptAttachTraceRawTpAttachTraceFEntryAttachTraceFExitAttachModifyReturnAttachLSMMacAttachTraceIter" + +var _AttachType_index = [...]uint16{0, 10, 32, 58, 77, 100, 124, 142, 160, 181, 202, 226, 250, 275, 300, 323, 346, 361, 380, 398, 421, 444, 466, 488, 504, 521, 537, 555, 567, 582} + +func (i AttachType) String() string { + if i >= AttachType(len(_AttachType_index)-1) { + return "AttachType(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _AttachType_name[_AttachType_index[i]:_AttachType_index[i+1]] +} diff --git a/vendor/github.com/containerd/cgroups/README.md b/vendor/github.com/containerd/cgroups/README.md index 7fe2b1a17..d4b09f3d6 100644 --- a/vendor/github.com/containerd/cgroups/README.md +++ b/vendor/github.com/containerd/cgroups/README.md @@ -1,6 +1,6 @@ # cgroups -[![Build Status](https://travis-ci.org/containerd/cgroups.svg?branch=master)](https://travis-ci.org/containerd/cgroups) +[![Build Status](https://github.com/containerd/cgroups/workflows/CI/badge.svg)](https://github.com/containerd/cgroups/actions?query=workflow%3ACI) [![codecov](https://codecov.io/gh/containerd/cgroups/branch/master/graph/badge.svg)](https://codecov.io/gh/containerd/cgroups) [![GoDoc](https://godoc.org/github.com/containerd/cgroups?status.svg)](https://godoc.org/github.com/containerd/cgroups) [![Go Report Card](https://goreportcard.com/badge/github.com/containerd/cgroups)](https://goreportcard.com/report/github.com/containerd/cgroups) @@ -65,7 +65,7 @@ To update the resources applied in the cgroup ```go shares = uint64(200) if err := control.Update(&specs.LinuxResources{ - CPU: &specs.CPU{ + CPU: &specs.LinuxCPU{ Shares: &shares, }, }); err != nil { @@ -112,6 +112,27 @@ err := control.MoveTo(destination) subCgroup, err := control.New("child", resources) ``` +### Registering for memory events + +This allows you to get notified by an eventfd for v1 memory cgroups events. + +```go +event := cgroups.MemoryThresholdEvent(50 * 1024 * 1024, false) +efd, err := control.RegisterMemoryEvent(event) +``` + +```go +event := cgroups.MemoryPressureEvent(cgroups.MediumPressure, cgroups.DefaultMode) +efd, err := control.RegisterMemoryEvent(event) +``` + +```go +efd, err := control.OOMEventFD() +// or by using RegisterMemoryEvent +event := cgroups.OOMEvent() +efd, err := control.RegisterMemoryEvent(event) +``` + ### Attention All static path should not include `/sys/fs/cgroup/` prefix, it should start with your own cgroups name diff --git a/vendor/github.com/containerd/cgroups/cgroup.go b/vendor/github.com/containerd/cgroups/cgroup.go index 1cb1cfef5..263f5438a 100644 --- a/vendor/github.com/containerd/cgroups/cgroup.go +++ b/vendor/github.com/containerd/cgroups/cgroup.go @@ -458,7 +458,26 @@ func (c *cgroup) OOMEventFD() (uintptr, error) { if err != nil { return 0, err } - return s.(*memoryController).OOMEventFD(sp) + return s.(*memoryController).memoryEvent(sp, OOMEvent()) +} + +// RegisterMemoryEvent allows the ability to register for all v1 memory cgroups +// notifications. +func (c *cgroup) RegisterMemoryEvent(event MemoryEvent) (uintptr, error) { + c.mu.Lock() + defer c.mu.Unlock() + if c.err != nil { + return 0, c.err + } + s := c.getSubsystem(Memory) + if s == nil { + return 0, ErrMemoryNotSupported + } + sp, err := c.path(Memory) + if err != nil { + return 0, err + } + return s.(*memoryController).memoryEvent(sp, event) } // State returns the state of the cgroup and its processes diff --git a/vendor/github.com/containerd/cgroups/control.go b/vendor/github.com/containerd/cgroups/control.go index a024fd653..a4cb9b832 100644 --- a/vendor/github.com/containerd/cgroups/control.go +++ b/vendor/github.com/containerd/cgroups/control.go @@ -82,6 +82,9 @@ type Cgroup interface { Thaw() error // OOMEventFD returns the memory subsystem's event fd for OOM events OOMEventFD() (uintptr, error) + // RegisterMemoryEvent returns the memory subsystems event fd for whatever memory event was + // registered for. Can alternatively register for the oom event with this method. + RegisterMemoryEvent(MemoryEvent) (uintptr, error) // State returns the cgroups current state State() State // Subsystems returns all the subsystems in the cgroup diff --git a/vendor/github.com/containerd/cgroups/cpuset.go b/vendor/github.com/containerd/cgroups/cpuset.go index 30208515e..fdf091bf1 100644 --- a/vendor/github.com/containerd/cgroups/cpuset.go +++ b/vendor/github.com/containerd/cgroups/cpuset.go @@ -26,7 +26,7 @@ import ( specs "github.com/opencontainers/runtime-spec/specs-go" ) -func NewCputset(root string) *cpusetController { +func NewCpuset(root string) *cpusetController { return &cpusetController{ root: filepath.Join(root, string(Cpuset)), } diff --git a/vendor/github.com/containerd/cgroups/go.mod b/vendor/github.com/containerd/cgroups/go.mod index e6257f69e..64be56187 100644 --- a/vendor/github.com/containerd/cgroups/go.mod +++ b/vendor/github.com/containerd/cgroups/go.mod @@ -3,17 +3,16 @@ module github.com/containerd/cgroups go 1.13 require ( - github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3 + github.com/cilium/ebpf v0.0.0-20200702112145-1c8d4c9ef775 github.com/coreos/go-systemd/v22 v22.0.0 github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect github.com/docker/go-units v0.4.0 github.com/godbus/dbus/v5 v5.0.3 github.com/gogo/protobuf v1.3.1 - github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect - github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700 + github.com/opencontainers/runtime-spec v1.0.2 github.com/pkg/errors v0.9.1 - github.com/sirupsen/logrus v1.4.2 + github.com/sirupsen/logrus v1.6.0 github.com/stretchr/testify v1.2.2 github.com/urfave/cli v1.22.2 - golang.org/x/sys v0.0.0-20200120151820-655fe14d7479 + golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9 ) diff --git a/vendor/github.com/containerd/cgroups/hierarchy.go b/vendor/github.com/containerd/cgroups/hierarchy.go index 9221bf3f1..ca3f1b938 100644 --- a/vendor/github.com/containerd/cgroups/hierarchy.go +++ b/vendor/github.com/containerd/cgroups/hierarchy.go @@ -16,5 +16,5 @@ package cgroups -// Hierarchy enableds both unified and split hierarchy for cgroups +// Hierarchy enables both unified and split hierarchy for cgroups type Hierarchy func() ([]Subsystem, error) diff --git a/vendor/github.com/containerd/cgroups/memory.go b/vendor/github.com/containerd/cgroups/memory.go index f39c008b2..74ad3714d 100644 --- a/vendor/github.com/containerd/cgroups/memory.go +++ b/vendor/github.com/containerd/cgroups/memory.go @@ -32,6 +32,128 @@ import ( "golang.org/x/sys/unix" ) +// MemoryEvent is an interface that V1 memory Cgroup notifications implement. Arg returns the +// file name whose fd should be written to "cgroups.event_control". EventFile returns the name of +// the file that supports the notification api e.g. "memory.usage_in_bytes". +type MemoryEvent interface { + Arg() string + EventFile() string +} + +type memoryThresholdEvent struct { + threshold uint64 + swap bool +} + +// MemoryThresholdEvent returns a new memory threshold event to be used with RegisterMemoryEvent. +// If swap is true, the event will be registered using memory.memsw.usage_in_bytes +func MemoryThresholdEvent(threshold uint64, swap bool) MemoryEvent { + return &memoryThresholdEvent{ + threshold, + swap, + } +} + +func (m *memoryThresholdEvent) Arg() string { + return strconv.FormatUint(m.threshold, 10) +} + +func (m *memoryThresholdEvent) EventFile() string { + if m.swap { + return "memory.memsw.usage_in_bytes" + } + return "memory.usage_in_bytes" +} + +type oomEvent struct{} + +// OOMEvent returns a new oom event to be used with RegisterMemoryEvent. +func OOMEvent() MemoryEvent { + return &oomEvent{} +} + +func (oom *oomEvent) Arg() string { + return "" +} + +func (oom *oomEvent) EventFile() string { + return "memory.oom_control" +} + +type memoryPressureEvent struct { + pressureLevel MemoryPressureLevel + hierarchy EventNotificationMode +} + +// MemoryPressureEvent returns a new memory pressure event to be used with RegisterMemoryEvent. +func MemoryPressureEvent(pressureLevel MemoryPressureLevel, hierarchy EventNotificationMode) MemoryEvent { + return &memoryPressureEvent{ + pressureLevel, + hierarchy, + } +} + +func (m *memoryPressureEvent) Arg() string { + return string(m.pressureLevel) + "," + string(m.hierarchy) +} + +func (m *memoryPressureEvent) EventFile() string { + return "memory.pressure_level" +} + +// MemoryPressureLevel corresponds to the memory pressure levels defined +// for memory cgroups. +type MemoryPressureLevel string + +// The three memory pressure levels are as follows. +// - The "low" level means that the system is reclaiming memory for new +// allocations. Monitoring this reclaiming activity might be useful for +// maintaining cache level. Upon notification, the program (typically +// "Activity Manager") might analyze vmstat and act in advance (i.e. +// prematurely shutdown unimportant services). +// - The "medium" level means that the system is experiencing medium memory +// pressure, the system might be making swap, paging out active file caches, +// etc. Upon this event applications may decide to further analyze +// vmstat/zoneinfo/memcg or internal memory usage statistics and free any +// resources that can be easily reconstructed or re-read from a disk. +// - The "critical" level means that the system is actively thrashing, it is +// about to out of memory (OOM) or even the in-kernel OOM killer is on its +// way to trigger. Applications should do whatever they can to help the +// system. It might be too late to consult with vmstat or any other +// statistics, so it is advisable to take an immediate action. +// "https://www.kernel.org/doc/Documentation/cgroup-v1/memory.txt" Section 11 +const ( + LowPressure MemoryPressureLevel = "low" + MediumPressure MemoryPressureLevel = "medium" + CriticalPressure MemoryPressureLevel = "critical" +) + +// EventNotificationMode corresponds to the notification modes +// for the memory cgroups pressure level notifications. +type EventNotificationMode string + +// There are three optional modes that specify different propagation behavior: +// - "default": this is the default behavior specified above. This mode is the +// same as omitting the optional mode parameter, preserved by backwards +// compatibility. +// - "hierarchy": events always propagate up to the root, similar to the default +// behavior, except that propagation continues regardless of whether there are +// event listeners at each level, with the "hierarchy" mode. In the above +// example, groups A, B, and C will receive notification of memory pressure. +// - "local": events are pass-through, i.e. they only receive notifications when +// memory pressure is experienced in the memcg for which the notification is +// registered. In the above example, group C will receive notification if +// registered for "local" notification and the group experiences memory +// pressure. However, group B will never receive notification, regardless if +// there is an event listener for group C or not, if group B is registered for +// local notification. +// "https://www.kernel.org/doc/Documentation/cgroup-v1/memory.txt" Section 11 +const ( + DefaultMode EventNotificationMode = "default" + LocalMode EventNotificationMode = "local" + HierarchyMode EventNotificationMode = "hierarchy" +) + // NewMemory returns a Memory controller given the root folder of cgroups. // It may optionally accept other configuration options, such as IgnoreModules(...) func NewMemory(root string, options ...func(*memoryController)) *memoryController { @@ -201,34 +323,6 @@ func (m *memoryController) Stat(path string, stats *v1.Metrics) error { return nil } -func (m *memoryController) OOMEventFD(path string) (uintptr, error) { - root := m.Path(path) - f, err := os.Open(filepath.Join(root, "memory.oom_control")) - if err != nil { - return 0, err - } - defer f.Close() - fd, _, serr := unix.RawSyscall(unix.SYS_EVENTFD2, 0, unix.EFD_CLOEXEC, 0) - if serr != 0 { - return 0, serr - } - if err := writeEventFD(root, f.Fd(), fd); err != nil { - unix.Close(int(fd)) - return 0, err - } - return fd, nil -} - -func writeEventFD(root string, cfd, efd uintptr) error { - f, err := os.OpenFile(filepath.Join(root, "cgroup.event_control"), os.O_WRONLY, 0) - if err != nil { - return err - } - _, err = f.WriteString(fmt.Sprintf("%d %d", efd, cfd)) - f.Close() - return err -} - func (m *memoryController) parseStats(r io.Reader, stat *v1.MemoryStat) error { var ( raw = make(map[string]uint64) @@ -359,3 +453,24 @@ func getOomControlValue(mem *specs.LinuxMemory) *int64 { } return nil } + +func (m *memoryController) memoryEvent(path string, event MemoryEvent) (uintptr, error) { + root := m.Path(path) + efd, err := unix.Eventfd(0, unix.EFD_CLOEXEC) + if err != nil { + return 0, err + } + evtFile, err := os.Open(filepath.Join(root, event.EventFile())) + if err != nil { + unix.Close(efd) + return 0, err + } + defer evtFile.Close() + data := fmt.Sprintf("%d %d %s", efd, evtFile.Fd(), event.Arg()) + evctlPath := filepath.Join(root, "cgroup.event_control") + if err := ioutil.WriteFile(evctlPath, []byte(data), 0700); err != nil { + unix.Close(efd) + return 0, err + } + return uintptr(efd), nil +} diff --git a/vendor/github.com/containerd/cgroups/utils.go b/vendor/github.com/containerd/cgroups/utils.go index 1e169d67a..7ba1cd9b4 100644 --- a/vendor/github.com/containerd/cgroups/utils.go +++ b/vendor/github.com/containerd/cgroups/utils.go @@ -121,7 +121,7 @@ func defaults(root string) ([]Subsystem, error) { NewNetCls(root), NewNetPrio(root), NewPerfEvent(root), - NewCputset(root), + NewCpuset(root), NewCpu(root), NewCpuacct(root), NewMemory(root), diff --git a/vendor/github.com/containerd/cgroups/v2/manager.go b/vendor/github.com/containerd/cgroups/v2/manager.go index 7b984dd5a..b1ec69ba4 100644 --- a/vendor/github.com/containerd/cgroups/v2/manager.go +++ b/vendor/github.com/containerd/cgroups/v2/manager.go @@ -166,6 +166,9 @@ func writeValues(path string, values []Value) error { } func NewManager(mountpoint string, group string, resources *Resources) (*Manager, error) { + if resources == nil { + return nil, errors.New("resources reference is nil") + } if err := VerifyGroupPath(group); err != nil { return nil, err } @@ -376,6 +379,12 @@ func (c *Manager) Stat() (*stats.Metrics, error) { return nil, err } } + memoryEvents := make(map[string]interface{}) + if err := readKVStatsFile(c.path, "memory.events", memoryEvents); err != nil { + if !os.IsNotExist(err) { + return nil, err + } + } var metrics stats.Metrics metrics.Pids = &stats.PidsStat{ @@ -427,7 +436,15 @@ func (c *Manager) Stat() (*stats.Metrics, error) { SwapUsage: getStatFileContentUint64(filepath.Join(c.path, "memory.swap.current")), SwapLimit: getStatFileContentUint64(filepath.Join(c.path, "memory.swap.max")), } - + if len(memoryEvents) > 0 { + metrics.MemoryEvents = &stats.MemoryEvents{ + Low: getUint64Value("low", memoryEvents), + High: getUint64Value("high", memoryEvents), + Max: getUint64Value("max", memoryEvents), + Oom: getUint64Value("oom", memoryEvents), + OomKill: getUint64Value("oom_kill", memoryEvents), + } + } metrics.Io = &stats.IOStat{Usage: readIoStats(c.path)} metrics.Rdma = &stats.RdmaStat{ Current: rdmaStats(filepath.Join(c.path, "rdma.current")), @@ -572,15 +589,44 @@ func (c *Manager) waitForEvents(ec chan<- Event, errCh chan<- error) { errCh <- err return } - var out map[string]interface{} if bytesRead >= syscall.SizeofInotifyEvent { - if err := readKVStatsFile(c.path, "memory.events", out); err != nil { - e := Event{ - High: out["high"].(uint64), - Low: out["low"].(uint64), - Max: out["max"].(uint64), - OOM: out["oom"].(uint64), - OOMKill: out["oom_kill"].(uint64), + out := make(map[string]interface{}) + if err := readKVStatsFile(c.path, "memory.events", out); err == nil { + e := Event{} + if v, ok := out["high"]; ok { + e.High, ok = v.(uint64) + if !ok { + errCh <- errors.Errorf("cannot convert high to uint64: %+v", v) + return + } + } + if v, ok := out["low"]; ok { + e.Low, ok = v.(uint64) + if !ok { + errCh <- errors.Errorf("cannot convert low to uint64: %+v", v) + return + } + } + if v, ok := out["max"]; ok { + e.Max, ok = v.(uint64) + if !ok { + errCh <- errors.Errorf("cannot convert max to uint64: %+v", v) + return + } + } + if v, ok := out["oom"]; ok { + e.OOM, ok = v.(uint64) + if !ok { + errCh <- errors.Errorf("cannot convert oom to uint64: %+v", v) + return + } + } + if v, ok := out["oom_kill"]; ok { + e.OOMKill, ok = v.(uint64) + if !ok { + errCh <- errors.Errorf("cannot convert oom_kill to uint64: %+v", v) + return + } } ec <- e } else { diff --git a/vendor/github.com/containerd/cgroups/v2/stats/metrics.pb.go b/vendor/github.com/containerd/cgroups/v2/stats/metrics.pb.go index 9d5a1e774..dd54edb69 100644 --- a/vendor/github.com/containerd/cgroups/v2/stats/metrics.pb.go +++ b/vendor/github.com/containerd/cgroups/v2/stats/metrics.pb.go @@ -31,6 +31,7 @@ type Metrics struct { Rdma *RdmaStat `protobuf:"bytes,5,opt,name=rdma,proto3" json:"rdma,omitempty"` Io *IOStat `protobuf:"bytes,6,opt,name=io,proto3" json:"io,omitempty"` Hugetlb []*HugeTlbStat `protobuf:"bytes,7,rep,name=hugetlb,proto3" json:"hugetlb,omitempty"` + MemoryEvents *MemoryEvents `protobuf:"bytes,8,opt,name=memory_events,json=memoryEvents,proto3" json:"memory_events,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -225,6 +226,49 @@ func (m *MemoryStat) XXX_DiscardUnknown() { var xxx_messageInfo_MemoryStat proto.InternalMessageInfo +type MemoryEvents struct { + Low uint64 `protobuf:"varint,1,opt,name=low,proto3" json:"low,omitempty"` + High uint64 `protobuf:"varint,2,opt,name=high,proto3" json:"high,omitempty"` + Max uint64 `protobuf:"varint,3,opt,name=max,proto3" json:"max,omitempty"` + Oom uint64 `protobuf:"varint,4,opt,name=oom,proto3" json:"oom,omitempty"` + OomKill uint64 `protobuf:"varint,5,opt,name=oom_kill,json=oomKill,proto3" json:"oom_kill,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *MemoryEvents) Reset() { *m = MemoryEvents{} } +func (*MemoryEvents) ProtoMessage() {} +func (*MemoryEvents) Descriptor() ([]byte, []int) { + return fileDescriptor_2fc6005842049e6b, []int{4} +} +func (m *MemoryEvents) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MemoryEvents) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MemoryEvents.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalTo(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MemoryEvents) XXX_Merge(src proto.Message) { + xxx_messageInfo_MemoryEvents.Merge(m, src) +} +func (m *MemoryEvents) XXX_Size() int { + return m.Size() +} +func (m *MemoryEvents) XXX_DiscardUnknown() { + xxx_messageInfo_MemoryEvents.DiscardUnknown(m) +} + +var xxx_messageInfo_MemoryEvents proto.InternalMessageInfo + type RdmaStat struct { Current []*RdmaEntry `protobuf:"bytes,1,rep,name=current,proto3" json:"current,omitempty"` Limit []*RdmaEntry `protobuf:"bytes,2,rep,name=limit,proto3" json:"limit,omitempty"` @@ -236,7 +280,7 @@ type RdmaStat struct { func (m *RdmaStat) Reset() { *m = RdmaStat{} } func (*RdmaStat) ProtoMessage() {} func (*RdmaStat) Descriptor() ([]byte, []int) { - return fileDescriptor_2fc6005842049e6b, []int{4} + return fileDescriptor_2fc6005842049e6b, []int{5} } func (m *RdmaStat) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -277,7 +321,7 @@ type RdmaEntry struct { func (m *RdmaEntry) Reset() { *m = RdmaEntry{} } func (*RdmaEntry) ProtoMessage() {} func (*RdmaEntry) Descriptor() ([]byte, []int) { - return fileDescriptor_2fc6005842049e6b, []int{5} + return fileDescriptor_2fc6005842049e6b, []int{6} } func (m *RdmaEntry) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -316,7 +360,7 @@ type IOStat struct { func (m *IOStat) Reset() { *m = IOStat{} } func (*IOStat) ProtoMessage() {} func (*IOStat) Descriptor() ([]byte, []int) { - return fileDescriptor_2fc6005842049e6b, []int{6} + return fileDescriptor_2fc6005842049e6b, []int{7} } func (m *IOStat) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -360,7 +404,7 @@ type IOEntry struct { func (m *IOEntry) Reset() { *m = IOEntry{} } func (*IOEntry) ProtoMessage() {} func (*IOEntry) Descriptor() ([]byte, []int) { - return fileDescriptor_2fc6005842049e6b, []int{7} + return fileDescriptor_2fc6005842049e6b, []int{8} } func (m *IOEntry) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -401,7 +445,7 @@ type HugeTlbStat struct { func (m *HugeTlbStat) Reset() { *m = HugeTlbStat{} } func (*HugeTlbStat) ProtoMessage() {} func (*HugeTlbStat) Descriptor() ([]byte, []int) { - return fileDescriptor_2fc6005842049e6b, []int{8} + return fileDescriptor_2fc6005842049e6b, []int{9} } func (m *HugeTlbStat) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -435,6 +479,7 @@ func init() { proto.RegisterType((*PidsStat)(nil), "io.containerd.cgroups.v2.PidsStat") proto.RegisterType((*CPUStat)(nil), "io.containerd.cgroups.v2.CPUStat") proto.RegisterType((*MemoryStat)(nil), "io.containerd.cgroups.v2.MemoryStat") + proto.RegisterType((*MemoryEvents)(nil), "io.containerd.cgroups.v2.MemoryEvents") proto.RegisterType((*RdmaStat)(nil), "io.containerd.cgroups.v2.RdmaStat") proto.RegisterType((*RdmaEntry)(nil), "io.containerd.cgroups.v2.RdmaEntry") proto.RegisterType((*IOStat)(nil), "io.containerd.cgroups.v2.IOStat") @@ -447,77 +492,82 @@ func init() { } var fileDescriptor_2fc6005842049e6b = []byte{ - // 1118 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x56, 0x4d, 0x6f, 0x1c, 0x45, - 0x10, 0xcd, 0xda, 0x9b, 0xfd, 0xe8, 0xb5, 0x13, 0xa7, 0xe3, 0x84, 0x4e, 0x42, 0xd6, 0xf6, 0x86, - 0xa0, 0x20, 0xc1, 0x2e, 0x32, 0x5f, 0x02, 0x05, 0x21, 0x27, 0x10, 0x05, 0x09, 0x13, 0x6b, 0xe2, - 0x15, 0xc7, 0x51, 0xef, 0x4c, 0x7b, 0x76, 0xec, 0xf9, 0x52, 0x77, 0x8f, 0xcd, 0xe6, 0xc4, 0x81, - 0x2b, 0xe2, 0x6f, 0xe5, 0x06, 0x47, 0x4e, 0x88, 0xf8, 0xc4, 0xcf, 0x40, 0x55, 0xd5, 0xb3, 0x33, - 0x1c, 0x6c, 0xb8, 0x75, 0xbd, 0x7a, 0xaf, 0xa6, 0xfa, 0xf5, 0x76, 0xf5, 0xb2, 0x8f, 0xa3, 0xd8, - 0xce, 0xcb, 0xd9, 0x38, 0xc8, 0xd3, 0x49, 0x90, 0x67, 0x56, 0xc6, 0x99, 0xd2, 0xe1, 0x24, 0x88, - 0x74, 0x5e, 0x16, 0x66, 0x72, 0xba, 0x3b, 0x31, 0x56, 0x5a, 0x33, 0x49, 0x95, 0xd5, 0x71, 0x60, - 0xc6, 0x85, 0xce, 0x6d, 0xce, 0x45, 0x9c, 0x8f, 0x6b, 0xf6, 0xd8, 0xb1, 0xc7, 0xa7, 0xbb, 0x77, - 0x37, 0xa3, 0x3c, 0xca, 0x91, 0x34, 0x81, 0x15, 0xf1, 0x47, 0x7f, 0xaf, 0xb0, 0xee, 0x3e, 0x55, - 0xe0, 0x9f, 0xb2, 0x76, 0x11, 0x87, 0x46, 0xb4, 0xb6, 0x5b, 0x8f, 0x06, 0xbb, 0xa3, 0xf1, 0x45, - 0xa5, 0xc6, 0x07, 0x71, 0x68, 0x5e, 0x5a, 0x69, 0x3d, 0xe4, 0xf3, 0xc7, 0x6c, 0x35, 0x28, 0x4a, - 0xb1, 0x82, 0xb2, 0x9d, 0x8b, 0x65, 0x4f, 0x0f, 0xa6, 0xa0, 0x7a, 0xd2, 0x3d, 0xff, 0x73, 0x6b, - 0xf5, 0xe9, 0xc1, 0xd4, 0x03, 0x19, 0x7f, 0xcc, 0x3a, 0xa9, 0x4a, 0x73, 0xbd, 0x10, 0x6d, 0x2c, - 0xf0, 0xce, 0xc5, 0x05, 0xf6, 0x91, 0x87, 0x5f, 0x76, 0x1a, 0xe8, 0x59, 0x87, 0xa9, 0x14, 0x57, - 0xff, 0xab, 0x67, 0x2f, 0x4c, 0x25, 0xf5, 0x0c, 0x7c, 0xfe, 0x21, 0x5b, 0x89, 0x73, 0xd1, 0x41, - 0xd5, 0xf6, 0xc5, 0xaa, 0x6f, 0x5f, 0xa0, 0x66, 0x25, 0xce, 0xf9, 0x57, 0xac, 0x3b, 0x2f, 0x23, - 0x65, 0x93, 0x99, 0xe8, 0x6e, 0xaf, 0x3e, 0x1a, 0xec, 0x3e, 0xbc, 0x58, 0xf6, 0xbc, 0x8c, 0xd4, - 0x61, 0x32, 0x43, 0x6d, 0xa5, 0x1a, 0x7d, 0xc1, 0x7a, 0x95, 0x71, 0x5c, 0xb0, 0x6e, 0x50, 0x6a, - 0xad, 0x32, 0x8b, 0x6e, 0xb7, 0xbd, 0x2a, 0xe4, 0x9b, 0xec, 0x6a, 0x12, 0xa7, 0xb1, 0x45, 0x3b, - 0xdb, 0x1e, 0x05, 0xa3, 0xdf, 0x5a, 0xac, 0xeb, 0xec, 0xe3, 0xf7, 0x19, 0x2b, 0x8d, 0x8c, 0x94, - 0x5f, 0x1a, 0x15, 0x38, 0x79, 0x1f, 0x91, 0xa9, 0x51, 0x01, 0xbf, 0xc7, 0xfa, 0xa5, 0x51, 0x9a, - 0xb2, 0x54, 0xa4, 0x07, 0x00, 0x26, 0xb7, 0xd8, 0xc0, 0x2c, 0x8c, 0x55, 0x29, 0xa5, 0x57, 0x31, - 0xcd, 0x08, 0x42, 0xc2, 0x7d, 0xc6, 0x32, 0xed, 0x17, 0x4a, 0xc7, 0x79, 0x68, 0xf0, 0x44, 0xda, - 0x5e, 0x3f, 0xd3, 0x07, 0x04, 0xf0, 0x1d, 0xb6, 0x96, 0x69, 0xdf, 0xce, 0x75, 0x6e, 0x6d, 0xa2, - 0x42, 0xb4, 0xbd, 0xed, 0x0d, 0x32, 0x7d, 0x58, 0x41, 0xfc, 0x21, 0xbb, 0xb6, 0xcc, 0xd3, 0x57, - 0x3a, 0x48, 0x5a, 0x5f, 0xa2, 0xf0, 0xa1, 0xd1, 0xaf, 0x7d, 0xc6, 0xea, 0xf3, 0xe4, 0x9c, 0xb5, - 0x65, 0x96, 0x67, 0x6e, 0x3b, 0xb8, 0x06, 0xec, 0x28, 0x4e, 0x94, 0xdb, 0x04, 0xae, 0xa1, 0x81, - 0x13, 0xa5, 0x33, 0x95, 0xf8, 0xc6, 0xca, 0xe0, 0xc4, 0xed, 0x60, 0x40, 0xd8, 0x4b, 0x80, 0x40, - 0x66, 0x12, 0x39, 0x73, 0xcd, 0xe3, 0x1a, 0xb1, 0x3c, 0x38, 0x71, 0xfd, 0xe2, 0x1a, 0x9c, 0x36, - 0xf3, 0x54, 0xa5, 0xae, 0x3f, 0x0a, 0xc0, 0x21, 0xf8, 0x90, 0x9f, 0xca, 0xa2, 0x50, 0xa1, 0xe8, - 0x92, 0x43, 0x00, 0xed, 0x23, 0x02, 0x0e, 0x21, 0x21, 0x8c, 0xb5, 0x5d, 0x88, 0x1e, 0x39, 0x04, - 0xc8, 0xd7, 0x00, 0xc0, 0xf6, 0x31, 0x7d, 0xa6, 0x63, 0xab, 0x66, 0xd0, 0x62, 0x9f, 0xb6, 0x0f, - 0xe8, 0x0f, 0x15, 0xc8, 0xef, 0xb0, 0x1e, 0xec, 0xd1, 0xb7, 0xf3, 0x42, 0x30, 0xfa, 0x05, 0x40, - 0x7c, 0x38, 0x2f, 0xf8, 0x03, 0xb6, 0x1e, 0x67, 0x32, 0xb0, 0xf1, 0xa9, 0xf2, 0xd1, 0x93, 0x01, - 0xe6, 0xd7, 0x2a, 0x70, 0x0f, 0xbc, 0xd9, 0x62, 0x83, 0x26, 0x65, 0x8d, 0xda, 0x6c, 0x10, 0x9a, - 0x55, 0xd0, 0xc5, 0xf5, 0x7f, 0x57, 0x79, 0x06, 0x6e, 0xd6, 0x55, 0x90, 0x72, 0xad, 0x59, 0x05, - 0x09, 0xdb, 0x6c, 0x50, 0x66, 0xea, 0x34, 0x0e, 0xac, 0x9c, 0x25, 0x4a, 0x5c, 0x27, 0xb7, 0x1b, - 0x10, 0x7f, 0x8f, 0x6d, 0x80, 0xc3, 0xbe, 0x56, 0x41, 0x22, 0xe3, 0x14, 0x69, 0x1b, 0x48, 0xbb, - 0x0e, 0xb8, 0x57, 0xc3, 0xfc, 0x03, 0xc6, 0x91, 0x5a, 0x66, 0x4d, 0xf2, 0x0d, 0x24, 0xdf, 0x80, - 0xcc, 0xb4, 0x99, 0x80, 0x3b, 0x52, 0x44, 0x47, 0xb2, 0x4c, 0xac, 0xe0, 0xe4, 0x90, 0x0b, 0xf9, - 0x90, 0xb1, 0x22, 0x4a, 0xe5, 0x31, 0x25, 0x6f, 0x52, 0xd7, 0x35, 0x02, 0x1f, 0x3a, 0xcb, 0xf5, - 0x49, 0x9c, 0x45, 0x46, 0x59, 0x5f, 0x2b, 0xe2, 0x6d, 0xd2, 0x87, 0xea, 0x8c, 0x47, 0x09, 0x3e, - 0x61, 0x37, 0x1b, 0x74, 0xdc, 0xbd, 0xb4, 0x4a, 0xdc, 0x42, 0x7e, 0xa3, 0xd2, 0x9e, 0xcb, 0xf0, - 0x4f, 0xd8, 0xed, 0x86, 0x20, 0xcb, 0x43, 0xe5, 0xfa, 0x16, 0xb7, 0x51, 0x73, 0xab, 0xce, 0x7e, - 0x5f, 0x27, 0xf9, 0x5d, 0xd6, 0x2b, 0x22, 0xad, 0x8e, 0xe2, 0x24, 0x11, 0x6f, 0xd1, 0xc5, 0xac, - 0x62, 0x7e, 0x9b, 0x75, 0x8a, 0xc8, 0x04, 0x32, 0x13, 0x02, 0x33, 0x2e, 0x22, 0x13, 0x8c, 0x55, - 0x32, 0x11, 0x77, 0x2a, 0x13, 0x30, 0x24, 0x13, 0x96, 0xcd, 0xde, 0xad, 0x4c, 0xa8, 0x10, 0x3e, - 0x62, 0x6b, 0x45, 0x14, 0xaa, 0x25, 0xe3, 0x1e, 0x9d, 0x7f, 0x13, 0xa3, 0x1a, 0x89, 0x7c, 0xb5, - 0x38, 0xd2, 0x4a, 0x89, 0xb7, 0xab, 0x1a, 0x15, 0x02, 0xc7, 0x5f, 0x47, 0xa1, 0xb8, 0x4f, 0xc7, - 0xdf, 0x80, 0xf8, 0xbb, 0xec, 0xba, 0x9d, 0x17, 0x3e, 0x1a, 0xe9, 0xcb, 0x24, 0xc9, 0x03, 0x31, - 0xac, 0xae, 0x7b, 0xf1, 0x0c, 0xd0, 0x3d, 0x00, 0xf9, 0xfb, 0x8c, 0x03, 0x2f, 0xc8, 0x93, 0x44, - 0x16, 0x46, 0x39, 0xea, 0x16, 0x52, 0x37, 0xec, 0xbc, 0x78, 0xea, 0x12, 0xc4, 0xde, 0x64, 0x57, - 0x71, 0xa0, 0x89, 0x6d, 0xba, 0x9a, 0x18, 0xc0, 0xaf, 0x95, 0x06, 0x1f, 0x0d, 0xc8, 0x1d, 0x6a, - 0x17, 0xa1, 0xef, 0x00, 0x81, 0xab, 0x69, 0xce, 0x64, 0xe1, 0x93, 0x76, 0x44, 0x57, 0x13, 0x90, - 0x29, 0xea, 0xab, 0x34, 0xc9, 0x1f, 0xd4, 0x69, 0x54, 0x8f, 0x7e, 0x6e, 0xb1, 0x5e, 0xf5, 0x4a, - 0xf0, 0x2f, 0x9b, 0x03, 0x1a, 0xa6, 0xfd, 0x83, 0xcb, 0x9f, 0x96, 0x6f, 0x32, 0xab, 0x17, 0xf5, - 0x14, 0xff, 0xbc, 0x9e, 0xe2, 0xff, 0x5b, 0xec, 0x46, 0xbd, 0x62, 0xfd, 0x25, 0x06, 0x3f, 0x8b, - 0x10, 0xee, 0x9a, 0xc2, 0xc1, 0xd8, 0xf7, 0x5c, 0x04, 0x56, 0xcc, 0x03, 0xe9, 0xcf, 0x65, 0x16, - 0x26, 0xca, 0xe0, 0x84, 0x5c, 0xf7, 0xd8, 0x3c, 0x90, 0xcf, 0x09, 0xa9, 0x08, 0xf9, 0xec, 0x58, - 0x05, 0xd6, 0xe0, 0x98, 0x24, 0xc2, 0x0b, 0x42, 0x46, 0x7b, 0xac, 0x43, 0x8f, 0x1b, 0xff, 0xac, - 0x32, 0x9b, 0x36, 0xba, 0x73, 0xd9, 0x6b, 0xe8, 0x3a, 0x45, 0xfe, 0xe8, 0x97, 0x16, 0xeb, 0x3a, - 0x08, 0x4e, 0x2c, 0x95, 0xc7, 0xb9, 0x76, 0x03, 0x9c, 0x02, 0x44, 0xe3, 0x2c, 0xd7, 0xd5, 0x63, - 0x86, 0x01, 0x6c, 0x4a, 0xcf, 0x16, 0x56, 0x19, 0x37, 0xbd, 0x5d, 0x04, 0xf8, 0x19, 0xe1, 0x34, - 0xba, 0x5d, 0x04, 0xc3, 0x5b, 0xc7, 0xb9, 0xa9, 0x86, 0x37, 0xac, 0x01, 0x3b, 0x03, 0x8c, 0x66, - 0x37, 0xae, 0x47, 0x53, 0x36, 0x68, 0x3c, 0xbc, 0x97, 0xbc, 0xb1, 0x1b, 0x6c, 0x35, 0x95, 0x3f, - 0xba, 0xa6, 0x60, 0x89, 0x57, 0x53, 0x46, 0xca, 0xc4, 0xaf, 0x14, 0x36, 0xd5, 0xf7, 0x96, 0xf1, - 0x13, 0xf1, 0xfa, 0xcd, 0xf0, 0xca, 0x1f, 0x6f, 0x86, 0x57, 0x7e, 0x3a, 0x1f, 0xb6, 0x5e, 0x9f, - 0x0f, 0x5b, 0xbf, 0x9f, 0x0f, 0x5b, 0x7f, 0x9d, 0x0f, 0x5b, 0xb3, 0x0e, 0xfe, 0x87, 0xfa, 0xe8, - 0x9f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x79, 0xd2, 0xcd, 0xe2, 0xab, 0x09, 0x00, 0x00, + // 1198 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x56, 0x4d, 0x73, 0xd4, 0x46, + 0x13, 0x66, 0xed, 0xc5, 0xeb, 0xed, 0xb5, 0xc1, 0x0c, 0x86, 0x57, 0xc0, 0xcb, 0xda, 0x5e, 0x02, + 0x45, 0xaa, 0x92, 0xdd, 0x94, 0xf3, 0x55, 0x49, 0x91, 0x4a, 0x19, 0x02, 0x45, 0x8a, 0x10, 0x5c, + 0x02, 0x57, 0x8e, 0xaa, 0x59, 0x69, 0x2c, 0x0d, 0x96, 0x34, 0xaa, 0x99, 0x91, 0x1d, 0x73, 0xca, + 0x21, 0xd7, 0x54, 0x7e, 0x4d, 0xfe, 0x03, 0xb7, 0xe4, 0x98, 0x53, 0x2a, 0xf8, 0x97, 0xa4, 0xba, + 0x67, 0x64, 0x29, 0x07, 0x43, 0x6e, 0xd3, 0x4f, 0x3f, 0xdd, 0xea, 0x8f, 0x99, 0x6e, 0xc1, 0x27, + 0xa9, 0xb4, 0x59, 0x3d, 0x9f, 0xc6, 0xaa, 0x98, 0xc5, 0xaa, 0xb4, 0x5c, 0x96, 0x42, 0x27, 0xb3, + 0x38, 0xd5, 0xaa, 0xae, 0xcc, 0xec, 0x70, 0x7b, 0x66, 0x2c, 0xb7, 0x66, 0x56, 0x08, 0xab, 0x65, + 0x6c, 0xa6, 0x95, 0x56, 0x56, 0xb1, 0x40, 0xaa, 0x69, 0xcb, 0x9e, 0x7a, 0xf6, 0xf4, 0x70, 0xfb, + 0xfa, 0x7a, 0xaa, 0x52, 0x45, 0xa4, 0x19, 0x9e, 0x1c, 0x7f, 0xf2, 0xdb, 0x22, 0x0c, 0x9e, 0x3a, + 0x0f, 0xec, 0x33, 0xe8, 0x57, 0x32, 0x31, 0x41, 0x6f, 0xb3, 0x77, 0x77, 0xb4, 0x3d, 0x99, 0x9e, + 0xe5, 0x6a, 0xba, 0x2b, 0x13, 0xf3, 0xdc, 0x72, 0x1b, 0x12, 0x9f, 0xdd, 0x83, 0xc5, 0xb8, 0xaa, + 0x83, 0x05, 0x32, 0xdb, 0x3a, 0xdb, 0xec, 0xc1, 0xee, 0x1e, 0x5a, 0xdd, 0x1f, 0x9c, 0xfc, 0xb5, + 0xb1, 0xf8, 0x60, 0x77, 0x2f, 0x44, 0x33, 0x76, 0x0f, 0x96, 0x0a, 0x51, 0x28, 0x7d, 0x1c, 0xf4, + 0xc9, 0xc1, 0x7b, 0x67, 0x3b, 0x78, 0x4a, 0x3c, 0xfa, 0xb2, 0xb7, 0xc1, 0x98, 0x75, 0x52, 0xf0, + 0xe0, 0xfc, 0xbb, 0x62, 0x0e, 0x93, 0x82, 0xbb, 0x98, 0x91, 0xcf, 0x3e, 0x82, 0x05, 0xa9, 0x82, + 0x25, 0xb2, 0xda, 0x3c, 0xdb, 0xea, 0xdb, 0x67, 0x64, 0xb3, 0x20, 0x15, 0xfb, 0x1a, 0x06, 0x59, + 0x9d, 0x0a, 0x9b, 0xcf, 0x83, 0xc1, 0xe6, 0xe2, 0xdd, 0xd1, 0xf6, 0xed, 0xb3, 0xcd, 0x1e, 0xd7, + 0xa9, 0x78, 0x91, 0xcf, 0xc9, 0xb6, 0xb1, 0x62, 0x4f, 0x60, 0xd5, 0x05, 0x1d, 0x89, 0x43, 0x51, + 0x5a, 0x13, 0x2c, 0xd3, 0xd7, 0xef, 0xbc, 0x2b, 0xdf, 0x87, 0xc4, 0x0e, 0x57, 0x8a, 0x8e, 0x34, + 0xf9, 0x12, 0x96, 0x9b, 0x2e, 0xb0, 0x00, 0x06, 0x71, 0xad, 0xb5, 0x28, 0x2d, 0xb5, 0xae, 0x1f, + 0x36, 0x22, 0x5b, 0x87, 0xf3, 0xb9, 0x2c, 0xa4, 0xa5, 0xde, 0xf4, 0x43, 0x27, 0x4c, 0x7e, 0xef, + 0xc1, 0xc0, 0xf7, 0x82, 0xdd, 0x04, 0xa8, 0x0d, 0x4f, 0x45, 0x54, 0x1b, 0x11, 0x7b, 0xf3, 0x21, + 0x21, 0x7b, 0x46, 0xc4, 0xec, 0x06, 0x0c, 0x6b, 0x23, 0xb4, 0xd3, 0x3a, 0x27, 0xcb, 0x08, 0x90, + 0x72, 0x03, 0x46, 0xe6, 0xd8, 0x58, 0x51, 0x38, 0xf5, 0x22, 0xa9, 0xc1, 0x41, 0x44, 0xb8, 0x09, + 0x50, 0xea, 0xa8, 0x12, 0x5a, 0xaa, 0xc4, 0x50, 0x7b, 0xfb, 0xe1, 0xb0, 0xd4, 0xbb, 0x0e, 0x60, + 0x5b, 0xb0, 0x52, 0xea, 0xc8, 0x66, 0x5a, 0x59, 0x9b, 0x8b, 0x84, 0x7a, 0xd8, 0x0f, 0x47, 0xa5, + 0x7e, 0xd1, 0x40, 0xec, 0x36, 0x5c, 0x38, 0xd5, 0xbb, 0xaf, 0x2c, 0x11, 0x69, 0xf5, 0x14, 0xc5, + 0x0f, 0x4d, 0x7e, 0x1d, 0x02, 0xb4, 0x97, 0x83, 0x31, 0xe8, 0xf3, 0x52, 0x95, 0x3e, 0x1d, 0x3a, + 0x23, 0xb6, 0x2f, 0x73, 0xe1, 0x93, 0xa0, 0x33, 0x06, 0x70, 0x20, 0x74, 0x29, 0xf2, 0xc8, 0x58, + 0x1e, 0x1f, 0xf8, 0x0c, 0x46, 0x0e, 0x7b, 0x8e, 0x10, 0x9a, 0x99, 0x9c, 0xcf, 0x7d, 0xf0, 0x74, + 0x26, 0x4c, 0xc5, 0x07, 0x3e, 0x5e, 0x3a, 0x63, 0xa5, 0x4d, 0x56, 0x88, 0xc2, 0xc7, 0xe7, 0x04, + 0xac, 0x10, 0x7e, 0x28, 0x2a, 0x78, 0x55, 0x89, 0x24, 0x18, 0xb8, 0x0a, 0x21, 0xf4, 0x94, 0x10, + 0xac, 0x10, 0x11, 0x12, 0xa9, 0xed, 0x31, 0x5d, 0x88, 0x7e, 0x38, 0x44, 0xe4, 0x1b, 0x04, 0x30, + 0x7d, 0x52, 0x1f, 0x69, 0x69, 0xc5, 0x1c, 0x43, 0x1c, 0xba, 0xf4, 0x11, 0xfd, 0xa1, 0x01, 0xd9, + 0x35, 0x58, 0xc6, 0x1c, 0x23, 0x9b, 0x55, 0x01, 0xb8, 0x1b, 0x80, 0xf2, 0x8b, 0xac, 0x62, 0xb7, + 0x60, 0x55, 0x96, 0x3c, 0xb6, 0xf2, 0x50, 0x44, 0x54, 0x93, 0x11, 0xe9, 0x57, 0x1a, 0x70, 0x07, + 0x6b, 0xb3, 0x01, 0xa3, 0x2e, 0x65, 0xc5, 0x85, 0xd9, 0x21, 0x74, 0xbd, 0x50, 0x15, 0x57, 0xff, + 0xed, 0xe5, 0x11, 0x56, 0xb3, 0xf5, 0x42, 0x94, 0x0b, 0x5d, 0x2f, 0x44, 0xd8, 0x84, 0x51, 0x5d, + 0x8a, 0x43, 0x19, 0x5b, 0x3e, 0xcf, 0x45, 0x70, 0xd1, 0x55, 0xbb, 0x03, 0xb1, 0xf7, 0x61, 0x0d, + 0x2b, 0x1c, 0x69, 0x11, 0xe7, 0x5c, 0x16, 0x44, 0x5b, 0x23, 0xda, 0x45, 0xc4, 0xc3, 0x16, 0x66, + 0x1f, 0x02, 0x23, 0x6a, 0x5d, 0x76, 0xc9, 0x97, 0x88, 0x7c, 0x09, 0x35, 0x7b, 0x5d, 0x05, 0xbe, + 0x91, 0x2a, 0xdd, 0xe7, 0x75, 0x6e, 0x03, 0xe6, 0x2a, 0xe4, 0x45, 0x36, 0x06, 0xa8, 0xd2, 0x82, + 0xbf, 0x74, 0xca, 0xcb, 0x2e, 0xea, 0x16, 0xc1, 0x0f, 0x1d, 0x29, 0x7d, 0x20, 0xcb, 0xd4, 0x08, + 0x1b, 0x69, 0xe1, 0x78, 0xeb, 0xee, 0x43, 0xad, 0x26, 0x74, 0x0a, 0x36, 0x83, 0xcb, 0x1d, 0x3a, + 0x65, 0xcf, 0xad, 0x08, 0xae, 0x10, 0xbf, 0xe3, 0x69, 0xc7, 0x6b, 0xd8, 0xa7, 0x70, 0xb5, 0x63, + 0x50, 0xaa, 0x44, 0xf8, 0xb8, 0x83, 0xab, 0x64, 0x73, 0xa5, 0xd5, 0x7e, 0xdf, 0x2a, 0xd9, 0x75, + 0x58, 0xae, 0x52, 0x2d, 0xf6, 0x65, 0x9e, 0x07, 0xff, 0x73, 0x0f, 0xb3, 0x91, 0xd9, 0x55, 0x58, + 0xaa, 0x52, 0x13, 0xf3, 0x32, 0x08, 0x48, 0xe3, 0x25, 0x57, 0x04, 0x63, 0x05, 0xcf, 0x83, 0x6b, + 0x4d, 0x11, 0x48, 0x74, 0x45, 0x38, 0x0d, 0xf6, 0x7a, 0x53, 0x84, 0x06, 0x61, 0x13, 0x58, 0xa9, + 0xd2, 0x44, 0x9c, 0x32, 0x6e, 0xb8, 0xfe, 0x77, 0x31, 0xe7, 0x23, 0xe7, 0xaf, 0x8e, 0xf7, 0xb5, + 0x10, 0xc1, 0xff, 0x1b, 0x1f, 0x0d, 0x82, 0xed, 0x6f, 0xa5, 0x24, 0xb8, 0xe9, 0xda, 0xdf, 0x81, + 0xd8, 0x1d, 0xb8, 0x68, 0xb3, 0x2a, 0xa2, 0x42, 0x46, 0x3c, 0xcf, 0x55, 0x1c, 0x8c, 0x9b, 0xe7, + 0x5e, 0x3d, 0x42, 0x74, 0x07, 0x41, 0xf6, 0x01, 0x30, 0xe4, 0xc5, 0x2a, 0xcf, 0x79, 0x65, 0x84, + 0xa7, 0x6e, 0x10, 0x75, 0xcd, 0x66, 0xd5, 0x03, 0xaf, 0x70, 0xec, 0x75, 0x38, 0x4f, 0x03, 0x2d, + 0xd8, 0x74, 0x4f, 0x93, 0x04, 0xbc, 0xad, 0x6e, 0xf0, 0xb9, 0x01, 0xb9, 0xe5, 0xc2, 0x25, 0xe8, + 0x3b, 0x44, 0xf0, 0x69, 0x9a, 0x23, 0x5e, 0x45, 0xce, 0x76, 0xe2, 0x9e, 0x26, 0x22, 0x7b, 0x64, + 0xdf, 0xa8, 0x9d, 0xf9, 0xad, 0x56, 0x4d, 0xd6, 0x13, 0x03, 0x2b, 0xdd, 0xe9, 0xcd, 0xd6, 0x60, + 0x31, 0x57, 0x47, 0x7e, 0x22, 0xe1, 0x11, 0xa7, 0x48, 0x26, 0xd3, 0xac, 0x19, 0x48, 0x78, 0x46, + 0x56, 0xc1, 0x7f, 0xf4, 0x73, 0x08, 0x8f, 0x88, 0x28, 0x55, 0xf8, 0xf1, 0x83, 0x47, 0x7c, 0xec, + 0x4a, 0x15, 0xd1, 0x01, 0x36, 0xde, 0x4d, 0xa0, 0x81, 0x52, 0xc5, 0x13, 0x99, 0xe7, 0x93, 0x9f, + 0x7b, 0xb0, 0xdc, 0xec, 0x39, 0xf6, 0x55, 0x77, 0x2b, 0xe0, 0xbe, 0xba, 0xf5, 0xf6, 0xe5, 0xf8, + 0xb0, 0xb4, 0xfa, 0xb8, 0x5d, 0x1d, 0x5f, 0xb4, 0xab, 0xe3, 0x3f, 0x1b, 0xfb, 0xfd, 0x22, 0x60, + 0x78, 0x8a, 0xe1, 0x5d, 0x4c, 0xf0, 0x81, 0x0b, 0xca, 0x7d, 0x18, 0x7a, 0x09, 0xeb, 0x9f, 0xc5, + 0x3c, 0xca, 0x78, 0x99, 0xe4, 0xc2, 0x50, 0x15, 0x56, 0x43, 0xc8, 0x62, 0xfe, 0xd8, 0x21, 0x0d, + 0x41, 0xcd, 0x5f, 0x8a, 0xd8, 0x1a, 0xaa, 0x89, 0x23, 0x3c, 0x73, 0xc8, 0x64, 0x07, 0x96, 0xdc, + 0x7a, 0x66, 0x9f, 0x37, 0x1d, 0x76, 0x89, 0x6e, 0xbd, 0x6d, 0x9f, 0xfb, 0x48, 0x89, 0x3f, 0xf9, + 0xa5, 0x07, 0x03, 0x0f, 0xe1, 0x35, 0x29, 0xf8, 0x4b, 0xa5, 0x7d, 0x8f, 0x9c, 0x40, 0xa8, 0x2c, + 0x95, 0x6e, 0x36, 0x28, 0x09, 0x98, 0x94, 0x9e, 0x1f, 0x5b, 0x61, 0x7c, 0xab, 0xbc, 0x84, 0xf8, + 0x91, 0xc3, 0x5d, 0xc3, 0xbc, 0x84, 0xbd, 0xd6, 0x52, 0x99, 0x66, 0x63, 0xe0, 0x19, 0xb1, 0x23, + 0xc4, 0xdc, 0xc2, 0xa0, 0xf3, 0x64, 0x0f, 0x46, 0x9d, 0x5f, 0x87, 0xb7, 0x2c, 0x76, 0x7f, 0x51, + 0x16, 0xda, 0x8b, 0x82, 0xf3, 0x80, 0xa7, 0xc2, 0xc8, 0x57, 0x82, 0x82, 0x1a, 0x86, 0xa7, 0xf2, + 0xfd, 0xe0, 0xf5, 0x9b, 0xf1, 0xb9, 0x3f, 0xdf, 0x8c, 0xcf, 0xfd, 0x74, 0x32, 0xee, 0xbd, 0x3e, + 0x19, 0xf7, 0xfe, 0x38, 0x19, 0xf7, 0xfe, 0x3e, 0x19, 0xf7, 0xe6, 0x4b, 0xf4, 0x17, 0xf8, 0xf1, + 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x4f, 0x2b, 0x30, 0xd6, 0x6d, 0x0a, 0x00, 0x00, } func (m *Metrics) Marshal() (dAtA []byte, err error) { @@ -597,6 +647,16 @@ func (m *Metrics) MarshalTo(dAtA []byte) (int, error) { i += n } } + if m.MemoryEvents != nil { + dAtA[i] = 0x42 + i++ + i = encodeVarintMetrics(dAtA, i, uint64(m.MemoryEvents.Size())) + n6, err := m.MemoryEvents.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n6 + } if m.XXX_unrecognized != nil { i += copy(dAtA[i:], m.XXX_unrecognized) } @@ -921,6 +981,52 @@ func (m *MemoryStat) MarshalTo(dAtA []byte) (int, error) { return i, nil } +func (m *MemoryEvents) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MemoryEvents) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if m.Low != 0 { + dAtA[i] = 0x8 + i++ + i = encodeVarintMetrics(dAtA, i, uint64(m.Low)) + } + if m.High != 0 { + dAtA[i] = 0x10 + i++ + i = encodeVarintMetrics(dAtA, i, uint64(m.High)) + } + if m.Max != 0 { + dAtA[i] = 0x18 + i++ + i = encodeVarintMetrics(dAtA, i, uint64(m.Max)) + } + if m.Oom != 0 { + dAtA[i] = 0x20 + i++ + i = encodeVarintMetrics(dAtA, i, uint64(m.Oom)) + } + if m.OomKill != 0 { + dAtA[i] = 0x28 + i++ + i = encodeVarintMetrics(dAtA, i, uint64(m.OomKill)) + } + if m.XXX_unrecognized != nil { + i += copy(dAtA[i:], m.XXX_unrecognized) + } + return i, nil +} + func (m *RdmaStat) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -1165,6 +1271,10 @@ func (m *Metrics) Size() (n int) { n += 1 + l + sovMetrics(uint64(l)) } } + if m.MemoryEvents != nil { + l = m.MemoryEvents.Size() + n += 1 + l + sovMetrics(uint64(l)) + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -1336,6 +1446,33 @@ func (m *MemoryStat) Size() (n int) { return n } +func (m *MemoryEvents) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Low != 0 { + n += 1 + sovMetrics(uint64(m.Low)) + } + if m.High != 0 { + n += 1 + sovMetrics(uint64(m.High)) + } + if m.Max != 0 { + n += 1 + sovMetrics(uint64(m.Max)) + } + if m.Oom != 0 { + n += 1 + sovMetrics(uint64(m.Oom)) + } + if m.OomKill != 0 { + n += 1 + sovMetrics(uint64(m.OomKill)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + func (m *RdmaStat) Size() (n int) { if m == nil { return 0 @@ -1476,6 +1613,7 @@ func (this *Metrics) String() string { `Rdma:` + strings.Replace(fmt.Sprintf("%v", this.Rdma), "RdmaStat", "RdmaStat", 1) + `,`, `Io:` + strings.Replace(fmt.Sprintf("%v", this.Io), "IOStat", "IOStat", 1) + `,`, `Hugetlb:` + strings.Replace(fmt.Sprintf("%v", this.Hugetlb), "HugeTlbStat", "HugeTlbStat", 1) + `,`, + `MemoryEvents:` + strings.Replace(fmt.Sprintf("%v", this.MemoryEvents), "MemoryEvents", "MemoryEvents", 1) + `,`, `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") @@ -1554,6 +1692,21 @@ func (this *MemoryStat) String() string { }, "") return s } +func (this *MemoryEvents) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&MemoryEvents{`, + `Low:` + fmt.Sprintf("%v", this.Low) + `,`, + `High:` + fmt.Sprintf("%v", this.High) + `,`, + `Max:` + fmt.Sprintf("%v", this.Max) + `,`, + `Oom:` + fmt.Sprintf("%v", this.Oom) + `,`, + `OomKill:` + fmt.Sprintf("%v", this.OomKill) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, + `}`, + }, "") + return s +} func (this *RdmaStat) String() string { if this == nil { return "nil" @@ -1870,6 +2023,42 @@ func (m *Metrics) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MemoryEvents", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthMetrics + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthMetrics + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.MemoryEvents == nil { + m.MemoryEvents = &MemoryEvents{} + } + if err := m.MemoryEvents.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipMetrics(dAtA[iNdEx:]) @@ -2874,6 +3063,155 @@ func (m *MemoryStat) Unmarshal(dAtA []byte) error { } return nil } +func (m *MemoryEvents) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MemoryEvents: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MemoryEvents: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Low", wireType) + } + m.Low = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Low |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field High", wireType) + } + m.High = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.High |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Max", wireType) + } + m.Max = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Max |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Oom", wireType) + } + m.Oom = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Oom |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field OomKill", wireType) + } + m.OomKill = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.OomKill |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipMetrics(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthMetrics + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthMetrics + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *RdmaStat) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/vendor/github.com/containerd/cgroups/v2/stats/metrics.proto b/vendor/github.com/containerd/cgroups/v2/stats/metrics.proto index 4a8535399..8ac472e46 100644 --- a/vendor/github.com/containerd/cgroups/v2/stats/metrics.proto +++ b/vendor/github.com/containerd/cgroups/v2/stats/metrics.proto @@ -11,6 +11,7 @@ message Metrics { RdmaStat rdma = 5; IOStat io = 6; repeated HugeTlbStat hugetlb = 7; + MemoryEvents memory_events = 8; } message PidsStat { @@ -65,6 +66,14 @@ message MemoryStat { uint64 swap_limit = 35; } +message MemoryEvents { + uint64 low = 1; + uint64 high = 2; + uint64 max = 3; + uint64 oom = 4; + uint64 oom_kill = 5; +} + message RdmaStat { repeated RdmaEntry current = 1; repeated RdmaEntry limit = 2; diff --git a/vendor/github.com/cpuguy83/go-md2man/README.md b/vendor/github.com/cpuguy83/go-md2man/README.md deleted file mode 100644 index 29ed7c9e9..000000000 --- a/vendor/github.com/cpuguy83/go-md2man/README.md +++ /dev/null @@ -1,21 +0,0 @@ -go-md2man -========= - -** Work in Progress ** -This still needs a lot of help to be complete, or even usable! - -Uses blackfriday to process markdown into man pages. - -### Usage - -./md2man -in /path/to/markdownfile.md -out /manfile/output/path - -### How to contribute - -We use [dep](https://github.com/golang/dep/) for vendoring Go packages. -See dep documentation for how to update. - -### TODO - -- Needs oh so much testing love -- Look into blackfriday's 2.0 API diff --git a/vendor/github.com/cpuguy83/go-md2man/go.mod b/vendor/github.com/cpuguy83/go-md2man/go.mod deleted file mode 100644 index 052bd20ea..000000000 --- a/vendor/github.com/cpuguy83/go-md2man/go.mod +++ /dev/null @@ -1,5 +0,0 @@ -module github.com/cpuguy83/go-md2man - -go 1.12 - -require github.com/russross/blackfriday v1.5.2 diff --git a/vendor/github.com/cpuguy83/go-md2man/md2man/md2man.go b/vendor/github.com/cpuguy83/go-md2man/md2man/md2man.go deleted file mode 100644 index af62279a6..000000000 --- a/vendor/github.com/cpuguy83/go-md2man/md2man/md2man.go +++ /dev/null @@ -1,20 +0,0 @@ -package md2man - -import ( - "github.com/russross/blackfriday" -) - -// Render converts a markdown document into a roff formatted document. -func Render(doc []byte) []byte { - renderer := RoffRenderer(0) - extensions := 0 - extensions |= blackfriday.EXTENSION_NO_INTRA_EMPHASIS - extensions |= blackfriday.EXTENSION_TABLES - extensions |= blackfriday.EXTENSION_FENCED_CODE - extensions |= blackfriday.EXTENSION_AUTOLINK - extensions |= blackfriday.EXTENSION_SPACE_HEADERS - extensions |= blackfriday.EXTENSION_FOOTNOTES - extensions |= blackfriday.EXTENSION_TITLEBLOCK - - return blackfriday.Markdown(doc, renderer, extensions) -} diff --git a/vendor/github.com/cpuguy83/go-md2man/md2man/roff.go b/vendor/github.com/cpuguy83/go-md2man/md2man/roff.go deleted file mode 100644 index 8c29ec687..000000000 --- a/vendor/github.com/cpuguy83/go-md2man/md2man/roff.go +++ /dev/null @@ -1,285 +0,0 @@ -package md2man - -import ( - "bytes" - "fmt" - "html" - "strings" - - "github.com/russross/blackfriday" -) - -type roffRenderer struct { - ListCounters []int -} - -// RoffRenderer creates a new blackfriday Renderer for generating roff documents -// from markdown -func RoffRenderer(flags int) blackfriday.Renderer { - return &roffRenderer{} -} - -func (r *roffRenderer) GetFlags() int { - return 0 -} - -func (r *roffRenderer) TitleBlock(out *bytes.Buffer, text []byte) { - out.WriteString(".TH ") - - splitText := bytes.Split(text, []byte("\n")) - for i, line := range splitText { - line = bytes.TrimPrefix(line, []byte("% ")) - if i == 0 { - line = bytes.Replace(line, []byte("("), []byte("\" \""), 1) - line = bytes.Replace(line, []byte(")"), []byte("\" \""), 1) - } - line = append([]byte("\""), line...) - line = append(line, []byte("\" ")...) - out.Write(line) - } - out.WriteString("\n") - - // disable hyphenation - out.WriteString(".nh\n") - // disable justification (adjust text to left margin only) - out.WriteString(".ad l\n") -} - -func (r *roffRenderer) BlockCode(out *bytes.Buffer, text []byte, lang string) { - out.WriteString("\n.PP\n.RS\n\n.nf\n") - escapeSpecialChars(out, text) - out.WriteString("\n.fi\n.RE\n") -} - -func (r *roffRenderer) BlockQuote(out *bytes.Buffer, text []byte) { - out.WriteString("\n.PP\n.RS\n") - out.Write(text) - out.WriteString("\n.RE\n") -} - -func (r *roffRenderer) BlockHtml(out *bytes.Buffer, text []byte) { // nolint: golint - out.Write(text) -} - -func (r *roffRenderer) Header(out *bytes.Buffer, text func() bool, level int, id string) { - marker := out.Len() - - switch { - case marker == 0: - // This is the doc header - out.WriteString(".TH ") - case level == 1: - out.WriteString("\n\n.SH ") - case level == 2: - out.WriteString("\n.SH ") - default: - out.WriteString("\n.SS ") - } - - if !text() { - out.Truncate(marker) - return - } -} - -func (r *roffRenderer) HRule(out *bytes.Buffer) { - out.WriteString("\n.ti 0\n\\l'\\n(.lu'\n") -} - -func (r *roffRenderer) List(out *bytes.Buffer, text func() bool, flags int) { - marker := out.Len() - r.ListCounters = append(r.ListCounters, 1) - out.WriteString("\n.RS\n") - if !text() { - out.Truncate(marker) - return - } - r.ListCounters = r.ListCounters[:len(r.ListCounters)-1] - out.WriteString("\n.RE\n") -} - -func (r *roffRenderer) ListItem(out *bytes.Buffer, text []byte, flags int) { - if flags&blackfriday.LIST_TYPE_ORDERED != 0 { - out.WriteString(fmt.Sprintf(".IP \"%3d.\" 5\n", r.ListCounters[len(r.ListCounters)-1])) - r.ListCounters[len(r.ListCounters)-1]++ - } else { - out.WriteString(".IP \\(bu 2\n") - } - out.Write(text) - out.WriteString("\n") -} - -func (r *roffRenderer) Paragraph(out *bytes.Buffer, text func() bool) { - marker := out.Len() - out.WriteString("\n.PP\n") - if !text() { - out.Truncate(marker) - return - } - if marker != 0 { - out.WriteString("\n") - } -} - -func (r *roffRenderer) Table(out *bytes.Buffer, header []byte, body []byte, columnData []int) { - out.WriteString("\n.TS\nallbox;\n") - - maxDelims := 0 - lines := strings.Split(strings.TrimRight(string(header), "\n")+"\n"+strings.TrimRight(string(body), "\n"), "\n") - for _, w := range lines { - curDelims := strings.Count(w, "\t") - if curDelims > maxDelims { - maxDelims = curDelims - } - } - out.Write([]byte(strings.Repeat("l ", maxDelims+1) + "\n")) - out.Write([]byte(strings.Repeat("l ", maxDelims+1) + ".\n")) - out.Write(header) - if len(header) > 0 { - out.Write([]byte("\n")) - } - - out.Write(body) - out.WriteString("\n.TE\n") -} - -func (r *roffRenderer) TableRow(out *bytes.Buffer, text []byte) { - if out.Len() > 0 { - out.WriteString("\n") - } - out.Write(text) -} - -func (r *roffRenderer) TableHeaderCell(out *bytes.Buffer, text []byte, align int) { - if out.Len() > 0 { - out.WriteString("\t") - } - if len(text) == 0 { - text = []byte{' '} - } - out.Write([]byte("\\fB\\fC" + string(text) + "\\fR")) -} - -func (r *roffRenderer) TableCell(out *bytes.Buffer, text []byte, align int) { - if out.Len() > 0 { - out.WriteString("\t") - } - if len(text) > 30 { - text = append([]byte("T{\n"), text...) - text = append(text, []byte("\nT}")...) - } - if len(text) == 0 { - text = []byte{' '} - } - out.Write(text) -} - -func (r *roffRenderer) Footnotes(out *bytes.Buffer, text func() bool) { - -} - -func (r *roffRenderer) FootnoteItem(out *bytes.Buffer, name, text []byte, flags int) { - -} - -func (r *roffRenderer) AutoLink(out *bytes.Buffer, link []byte, kind int) { - out.WriteString("\n\\[la]") - out.Write(link) - out.WriteString("\\[ra]") -} - -func (r *roffRenderer) CodeSpan(out *bytes.Buffer, text []byte) { - out.WriteString("\\fB\\fC") - escapeSpecialChars(out, text) - out.WriteString("\\fR") -} - -func (r *roffRenderer) DoubleEmphasis(out *bytes.Buffer, text []byte) { - out.WriteString("\\fB") - out.Write(text) - out.WriteString("\\fP") -} - -func (r *roffRenderer) Emphasis(out *bytes.Buffer, text []byte) { - out.WriteString("\\fI") - out.Write(text) - out.WriteString("\\fP") -} - -func (r *roffRenderer) Image(out *bytes.Buffer, link []byte, title []byte, alt []byte) { -} - -func (r *roffRenderer) LineBreak(out *bytes.Buffer) { - out.WriteString("\n.br\n") -} - -func (r *roffRenderer) Link(out *bytes.Buffer, link []byte, title []byte, content []byte) { - out.Write(content) - r.AutoLink(out, link, 0) -} - -func (r *roffRenderer) RawHtmlTag(out *bytes.Buffer, tag []byte) { // nolint: golint - out.Write(tag) -} - -func (r *roffRenderer) TripleEmphasis(out *bytes.Buffer, text []byte) { - out.WriteString("\\s+2") - out.Write(text) - out.WriteString("\\s-2") -} - -func (r *roffRenderer) StrikeThrough(out *bytes.Buffer, text []byte) { -} - -func (r *roffRenderer) FootnoteRef(out *bytes.Buffer, ref []byte, id int) { - -} - -func (r *roffRenderer) Entity(out *bytes.Buffer, entity []byte) { - out.WriteString(html.UnescapeString(string(entity))) -} - -func (r *roffRenderer) NormalText(out *bytes.Buffer, text []byte) { - escapeSpecialChars(out, text) -} - -func (r *roffRenderer) DocumentHeader(out *bytes.Buffer) { -} - -func (r *roffRenderer) DocumentFooter(out *bytes.Buffer) { -} - -func needsBackslash(c byte) bool { - for _, r := range []byte("-_&\\~") { - if c == r { - return true - } - } - return false -} - -func escapeSpecialChars(out *bytes.Buffer, text []byte) { - for i := 0; i < len(text); i++ { - // escape initial apostrophe or period - if len(text) >= 1 && (text[0] == '\'' || text[0] == '.') { - out.WriteString("\\&") - } - - // directly copy normal characters - org := i - - for i < len(text) && !needsBackslash(text[i]) { - i++ - } - if i > org { - out.Write(text[org:i]) - } - - // escape a character - if i >= len(text) { - break - } - out.WriteByte('\\') - out.WriteByte(text[i]) - } -} diff --git a/vendor/github.com/cpuguy83/go-md2man/LICENSE.md b/vendor/github.com/cpuguy83/go-md2man/v2/LICENSE.md similarity index 100% rename from vendor/github.com/cpuguy83/go-md2man/LICENSE.md rename to vendor/github.com/cpuguy83/go-md2man/v2/LICENSE.md diff --git a/vendor/github.com/cpuguy83/go-md2man/v2/README.md b/vendor/github.com/cpuguy83/go-md2man/v2/README.md new file mode 100644 index 000000000..0e30d3414 --- /dev/null +++ b/vendor/github.com/cpuguy83/go-md2man/v2/README.md @@ -0,0 +1,15 @@ +go-md2man +========= + +Converts markdown into roff (man pages). + +Uses blackfriday to process markdown into man pages. + +### Usage + +./md2man -in /path/to/markdownfile.md -out /manfile/output/path + +### How to contribute + +We use go modules to manage dependencies. +As such you must be using at lest go1.11. diff --git a/vendor/github.com/cpuguy83/go-md2man/v2/go.mod b/vendor/github.com/cpuguy83/go-md2man/v2/go.mod new file mode 100644 index 000000000..ae5345814 --- /dev/null +++ b/vendor/github.com/cpuguy83/go-md2man/v2/go.mod @@ -0,0 +1,9 @@ +module github.com/cpuguy83/go-md2man/v2 + +go 1.12 + +require ( + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/russross/blackfriday/v2 v2.0.1 + github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect +) diff --git a/vendor/github.com/cpuguy83/go-md2man/v2/md2man/md2man.go b/vendor/github.com/cpuguy83/go-md2man/v2/md2man/md2man.go new file mode 100644 index 000000000..b48005673 --- /dev/null +++ b/vendor/github.com/cpuguy83/go-md2man/v2/md2man/md2man.go @@ -0,0 +1,14 @@ +package md2man + +import ( + "github.com/russross/blackfriday/v2" +) + +// Render converts a markdown document into a roff formatted document. +func Render(doc []byte) []byte { + renderer := NewRoffRenderer() + + return blackfriday.Run(doc, + []blackfriday.Option{blackfriday.WithRenderer(renderer), + blackfriday.WithExtensions(renderer.GetExtensions())}...) +} diff --git a/vendor/github.com/cpuguy83/go-md2man/v2/md2man/roff.go b/vendor/github.com/cpuguy83/go-md2man/v2/md2man/roff.go new file mode 100644 index 000000000..0668a66cf --- /dev/null +++ b/vendor/github.com/cpuguy83/go-md2man/v2/md2man/roff.go @@ -0,0 +1,345 @@ +package md2man + +import ( + "fmt" + "io" + "os" + "strings" + + "github.com/russross/blackfriday/v2" +) + +// roffRenderer implements the blackfriday.Renderer interface for creating +// roff format (manpages) from markdown text +type roffRenderer struct { + extensions blackfriday.Extensions + listCounters []int + firstHeader bool + defineTerm bool + listDepth int +} + +const ( + titleHeader = ".TH " + topLevelHeader = "\n\n.SH " + secondLevelHdr = "\n.SH " + otherHeader = "\n.SS " + crTag = "\n" + emphTag = "\\fI" + emphCloseTag = "\\fP" + strongTag = "\\fB" + strongCloseTag = "\\fP" + breakTag = "\n.br\n" + paraTag = "\n.PP\n" + hruleTag = "\n.ti 0\n\\l'\\n(.lu'\n" + linkTag = "\n\\[la]" + linkCloseTag = "\\[ra]" + codespanTag = "\\fB\\fC" + codespanCloseTag = "\\fR" + codeTag = "\n.PP\n.RS\n\n.nf\n" + codeCloseTag = "\n.fi\n.RE\n" + quoteTag = "\n.PP\n.RS\n" + quoteCloseTag = "\n.RE\n" + listTag = "\n.RS\n" + listCloseTag = "\n.RE\n" + arglistTag = "\n.TP\n" + tableStart = "\n.TS\nallbox;\n" + tableEnd = ".TE\n" + tableCellStart = "T{\n" + tableCellEnd = "\nT}\n" +) + +// NewRoffRenderer creates a new blackfriday Renderer for generating roff documents +// from markdown +func NewRoffRenderer() *roffRenderer { // nolint: golint + var extensions blackfriday.Extensions + + extensions |= blackfriday.NoIntraEmphasis + extensions |= blackfriday.Tables + extensions |= blackfriday.FencedCode + extensions |= blackfriday.SpaceHeadings + extensions |= blackfriday.Footnotes + extensions |= blackfriday.Titleblock + extensions |= blackfriday.DefinitionLists + return &roffRenderer{ + extensions: extensions, + } +} + +// GetExtensions returns the list of extensions used by this renderer implementation +func (r *roffRenderer) GetExtensions() blackfriday.Extensions { + return r.extensions +} + +// RenderHeader handles outputting the header at document start +func (r *roffRenderer) RenderHeader(w io.Writer, ast *blackfriday.Node) { + // disable hyphenation + out(w, ".nh\n") +} + +// RenderFooter handles outputting the footer at the document end; the roff +// renderer has no footer information +func (r *roffRenderer) RenderFooter(w io.Writer, ast *blackfriday.Node) { +} + +// RenderNode is called for each node in a markdown document; based on the node +// type the equivalent roff output is sent to the writer +func (r *roffRenderer) RenderNode(w io.Writer, node *blackfriday.Node, entering bool) blackfriday.WalkStatus { + + var walkAction = blackfriday.GoToNext + + switch node.Type { + case blackfriday.Text: + r.handleText(w, node, entering) + case blackfriday.Softbreak: + out(w, crTag) + case blackfriday.Hardbreak: + out(w, breakTag) + case blackfriday.Emph: + if entering { + out(w, emphTag) + } else { + out(w, emphCloseTag) + } + case blackfriday.Strong: + if entering { + out(w, strongTag) + } else { + out(w, strongCloseTag) + } + case blackfriday.Link: + if !entering { + out(w, linkTag+string(node.LinkData.Destination)+linkCloseTag) + } + case blackfriday.Image: + // ignore images + walkAction = blackfriday.SkipChildren + case blackfriday.Code: + out(w, codespanTag) + escapeSpecialChars(w, node.Literal) + out(w, codespanCloseTag) + case blackfriday.Document: + break + case blackfriday.Paragraph: + // roff .PP markers break lists + if r.listDepth > 0 { + return blackfriday.GoToNext + } + if entering { + out(w, paraTag) + } else { + out(w, crTag) + } + case blackfriday.BlockQuote: + if entering { + out(w, quoteTag) + } else { + out(w, quoteCloseTag) + } + case blackfriday.Heading: + r.handleHeading(w, node, entering) + case blackfriday.HorizontalRule: + out(w, hruleTag) + case blackfriday.List: + r.handleList(w, node, entering) + case blackfriday.Item: + r.handleItem(w, node, entering) + case blackfriday.CodeBlock: + out(w, codeTag) + escapeSpecialChars(w, node.Literal) + out(w, codeCloseTag) + case blackfriday.Table: + r.handleTable(w, node, entering) + case blackfriday.TableCell: + r.handleTableCell(w, node, entering) + case blackfriday.TableHead: + case blackfriday.TableBody: + case blackfriday.TableRow: + // no action as cell entries do all the nroff formatting + return blackfriday.GoToNext + default: + fmt.Fprintln(os.Stderr, "WARNING: go-md2man does not handle node type "+node.Type.String()) + } + return walkAction +} + +func (r *roffRenderer) handleText(w io.Writer, node *blackfriday.Node, entering bool) { + var ( + start, end string + ) + // handle special roff table cell text encapsulation + if node.Parent.Type == blackfriday.TableCell { + if len(node.Literal) > 30 { + start = tableCellStart + end = tableCellEnd + } else { + // end rows that aren't terminated by "tableCellEnd" with a cr if end of row + if node.Parent.Next == nil && !node.Parent.IsHeader { + end = crTag + } + } + } + out(w, start) + escapeSpecialChars(w, node.Literal) + out(w, end) +} + +func (r *roffRenderer) handleHeading(w io.Writer, node *blackfriday.Node, entering bool) { + if entering { + switch node.Level { + case 1: + if !r.firstHeader { + out(w, titleHeader) + r.firstHeader = true + break + } + out(w, topLevelHeader) + case 2: + out(w, secondLevelHdr) + default: + out(w, otherHeader) + } + } +} + +func (r *roffRenderer) handleList(w io.Writer, node *blackfriday.Node, entering bool) { + openTag := listTag + closeTag := listCloseTag + if node.ListFlags&blackfriday.ListTypeDefinition != 0 { + // tags for definition lists handled within Item node + openTag = "" + closeTag = "" + } + if entering { + r.listDepth++ + if node.ListFlags&blackfriday.ListTypeOrdered != 0 { + r.listCounters = append(r.listCounters, 1) + } + out(w, openTag) + } else { + if node.ListFlags&blackfriday.ListTypeOrdered != 0 { + r.listCounters = r.listCounters[:len(r.listCounters)-1] + } + out(w, closeTag) + r.listDepth-- + } +} + +func (r *roffRenderer) handleItem(w io.Writer, node *blackfriday.Node, entering bool) { + if entering { + if node.ListFlags&blackfriday.ListTypeOrdered != 0 { + out(w, fmt.Sprintf(".IP \"%3d.\" 5\n", r.listCounters[len(r.listCounters)-1])) + r.listCounters[len(r.listCounters)-1]++ + } else if node.ListFlags&blackfriday.ListTypeDefinition != 0 { + // state machine for handling terms and following definitions + // since blackfriday does not distinguish them properly, nor + // does it seperate them into separate lists as it should + if !r.defineTerm { + out(w, arglistTag) + r.defineTerm = true + } else { + r.defineTerm = false + } + } else { + out(w, ".IP \\(bu 2\n") + } + } else { + out(w, "\n") + } +} + +func (r *roffRenderer) handleTable(w io.Writer, node *blackfriday.Node, entering bool) { + if entering { + out(w, tableStart) + //call walker to count cells (and rows?) so format section can be produced + columns := countColumns(node) + out(w, strings.Repeat("l ", columns)+"\n") + out(w, strings.Repeat("l ", columns)+".\n") + } else { + out(w, tableEnd) + } +} + +func (r *roffRenderer) handleTableCell(w io.Writer, node *blackfriday.Node, entering bool) { + var ( + start, end string + ) + if node.IsHeader { + start = codespanTag + end = codespanCloseTag + } + if entering { + if node.Prev != nil && node.Prev.Type == blackfriday.TableCell { + out(w, "\t"+start) + } else { + out(w, start) + } + } else { + // need to carriage return if we are at the end of the header row + if node.IsHeader && node.Next == nil { + end = end + crTag + } + out(w, end) + } +} + +// because roff format requires knowing the column count before outputting any table +// data we need to walk a table tree and count the columns +func countColumns(node *blackfriday.Node) int { + var columns int + + node.Walk(func(node *blackfriday.Node, entering bool) blackfriday.WalkStatus { + switch node.Type { + case blackfriday.TableRow: + if !entering { + return blackfriday.Terminate + } + case blackfriday.TableCell: + if entering { + columns++ + } + default: + } + return blackfriday.GoToNext + }) + return columns +} + +func out(w io.Writer, output string) { + io.WriteString(w, output) // nolint: errcheck +} + +func needsBackslash(c byte) bool { + for _, r := range []byte("-_&\\~") { + if c == r { + return true + } + } + return false +} + +func escapeSpecialChars(w io.Writer, text []byte) { + for i := 0; i < len(text); i++ { + // escape initial apostrophe or period + if len(text) >= 1 && (text[0] == '\'' || text[0] == '.') { + out(w, "\\&") + } + + // directly copy normal characters + org := i + + for i < len(text) && !needsBackslash(text[i]) { + i++ + } + if i > org { + w.Write(text[org:i]) // nolint: errcheck + } + + // escape a character + if i >= len(text) { + break + } + + w.Write([]byte{'\\', text[i]}) // nolint: errcheck + } +} diff --git a/vendor/github.com/golang/protobuf/go.mod b/vendor/github.com/golang/protobuf/go.mod index de28f6f0a..aa055824d 100644 --- a/vendor/github.com/golang/protobuf/go.mod +++ b/vendor/github.com/golang/protobuf/go.mod @@ -1,3 +1,3 @@ module github.com/golang/protobuf -go 1.12 +go 1.9 diff --git a/vendor/github.com/golang/protobuf/ptypes/any/any.pb.go b/vendor/github.com/golang/protobuf/ptypes/any/any.pb.go index 78ee52334..7b0ad1ad8 100644 --- a/vendor/github.com/golang/protobuf/ptypes/any/any.pb.go +++ b/vendor/github.com/golang/protobuf/ptypes/any/any.pb.go @@ -102,7 +102,8 @@ const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package // type Any struct { // A URL/resource name that uniquely identifies the type of the serialized - // protocol buffer message. The last segment of the URL's path must represent + // protocol buffer message. This string must contain at least + // one "/" character. The last segment of the URL's path must represent // the fully qualified name of the type (as in // `path/google.protobuf.Duration`). The name should be in a canonical form // (e.g., leading "." is not accepted). @@ -181,7 +182,9 @@ func init() { proto.RegisterType((*Any)(nil), "google.protobuf.Any") } -func init() { proto.RegisterFile("google/protobuf/any.proto", fileDescriptor_b53526c13ae22eb4) } +func init() { + proto.RegisterFile("google/protobuf/any.proto", fileDescriptor_b53526c13ae22eb4) +} var fileDescriptor_b53526c13ae22eb4 = []byte{ // 185 bytes of a gzipped FileDescriptorProto diff --git a/vendor/github.com/golang/protobuf/ptypes/any/any.proto b/vendor/github.com/golang/protobuf/ptypes/any/any.proto index 493294255..c9be85416 100644 --- a/vendor/github.com/golang/protobuf/ptypes/any/any.proto +++ b/vendor/github.com/golang/protobuf/ptypes/any/any.proto @@ -121,7 +121,8 @@ option objc_class_prefix = "GPB"; // message Any { // A URL/resource name that uniquely identifies the type of the serialized - // protocol buffer message. The last segment of the URL's path must represent + // protocol buffer message. This string must contain at least + // one "/" character. The last segment of the URL's path must represent // the fully qualified name of the type (as in // `path/google.protobuf.Duration`). The name should be in a canonical form // (e.g., leading "." is not accepted). diff --git a/vendor/github.com/golang/protobuf/ptypes/duration/duration.pb.go b/vendor/github.com/golang/protobuf/ptypes/duration/duration.pb.go index 0d681ee21..58b078699 100644 --- a/vendor/github.com/golang/protobuf/ptypes/duration/duration.pb.go +++ b/vendor/github.com/golang/protobuf/ptypes/duration/duration.pb.go @@ -41,7 +41,7 @@ const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package // if (duration.seconds < 0 && duration.nanos > 0) { // duration.seconds += 1; // duration.nanos -= 1000000000; -// } else if (durations.seconds > 0 && duration.nanos < 0) { +// } else if (duration.seconds > 0 && duration.nanos < 0) { // duration.seconds -= 1; // duration.nanos += 1000000000; // } @@ -142,7 +142,9 @@ func init() { proto.RegisterType((*Duration)(nil), "google.protobuf.Duration") } -func init() { proto.RegisterFile("google/protobuf/duration.proto", fileDescriptor_23597b2ebd7ac6c5) } +func init() { + proto.RegisterFile("google/protobuf/duration.proto", fileDescriptor_23597b2ebd7ac6c5) +} var fileDescriptor_23597b2ebd7ac6c5 = []byte{ // 190 bytes of a gzipped FileDescriptorProto diff --git a/vendor/github.com/golang/protobuf/ptypes/duration/duration.proto b/vendor/github.com/golang/protobuf/ptypes/duration/duration.proto index 975fce41a..99cb102c3 100644 --- a/vendor/github.com/golang/protobuf/ptypes/duration/duration.proto +++ b/vendor/github.com/golang/protobuf/ptypes/duration/duration.proto @@ -61,7 +61,7 @@ option objc_class_prefix = "GPB"; // if (duration.seconds < 0 && duration.nanos > 0) { // duration.seconds += 1; // duration.nanos -= 1000000000; -// } else if (durations.seconds > 0 && duration.nanos < 0) { +// } else if (duration.seconds > 0 && duration.nanos < 0) { // duration.seconds -= 1; // duration.nanos += 1000000000; // } @@ -101,7 +101,6 @@ option objc_class_prefix = "GPB"; // // message Duration { - // Signed seconds of the span of time. Must be from -315,576,000,000 // to +315,576,000,000 inclusive. Note: these bounds are computed from: // 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years diff --git a/vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.pb.go b/vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.pb.go index 31cd846de..7a3b1e40e 100644 --- a/vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.pb.go +++ b/vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.pb.go @@ -20,17 +20,19 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package -// A Timestamp represents a point in time independent of any time zone -// or calendar, represented as seconds and fractions of seconds at -// nanosecond resolution in UTC Epoch time. It is encoded using the -// Proleptic Gregorian Calendar which extends the Gregorian calendar -// backwards to year one. It is encoded assuming all minutes are 60 -// seconds long, i.e. leap seconds are "smeared" so that no leap second -// table is needed for interpretation. Range is from -// 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. -// By restricting to that range, we ensure that we can convert to -// and from RFC 3339 date strings. -// See [https://www.ietf.org/rfc/rfc3339.txt](https://www.ietf.org/rfc/rfc3339.txt). +// A Timestamp represents a point in time independent of any time zone or local +// calendar, encoded as a count of seconds and fractions of seconds at +// nanosecond resolution. The count is relative to an epoch at UTC midnight on +// January 1, 1970, in the proleptic Gregorian calendar which extends the +// Gregorian calendar backwards to year one. +// +// All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap +// second table is needed for interpretation, using a [24-hour linear +// smear](https://developers.google.com/time/smear). +// +// The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By +// restricting to that range, we ensure that we can convert to and from [RFC +// 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. // // # Examples // @@ -91,12 +93,14 @@ const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package // 01:30 UTC on January 15, 2017. // // In JavaScript, one can convert a Date object to this format using the -// standard [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString] +// standard +// [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) // method. In Python, a standard `datetime.datetime` object can be converted -// to this format using [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) -// with the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one -// can use the Joda Time's [`ISODateTimeFormat.dateTime()`]( -// http://www.joda.org/joda-time/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime-- +// to this format using +// [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with +// the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use +// the Joda Time's [`ISODateTimeFormat.dateTime()`]( +// http://www.joda.org/joda-time/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime%2D%2D // ) to obtain a formatter capable of generating timestamps in this format. // // @@ -160,7 +164,9 @@ func init() { proto.RegisterType((*Timestamp)(nil), "google.protobuf.Timestamp") } -func init() { proto.RegisterFile("google/protobuf/timestamp.proto", fileDescriptor_292007bbfe81227e) } +func init() { + proto.RegisterFile("google/protobuf/timestamp.proto", fileDescriptor_292007bbfe81227e) +} var fileDescriptor_292007bbfe81227e = []byte{ // 191 bytes of a gzipped FileDescriptorProto diff --git a/vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.proto b/vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.proto index eafb3fa03..cd357864a 100644 --- a/vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.proto +++ b/vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.proto @@ -40,17 +40,19 @@ option java_outer_classname = "TimestampProto"; option java_multiple_files = true; option objc_class_prefix = "GPB"; -// A Timestamp represents a point in time independent of any time zone -// or calendar, represented as seconds and fractions of seconds at -// nanosecond resolution in UTC Epoch time. It is encoded using the -// Proleptic Gregorian Calendar which extends the Gregorian calendar -// backwards to year one. It is encoded assuming all minutes are 60 -// seconds long, i.e. leap seconds are "smeared" so that no leap second -// table is needed for interpretation. Range is from -// 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. -// By restricting to that range, we ensure that we can convert to -// and from RFC 3339 date strings. -// See [https://www.ietf.org/rfc/rfc3339.txt](https://www.ietf.org/rfc/rfc3339.txt). +// A Timestamp represents a point in time independent of any time zone or local +// calendar, encoded as a count of seconds and fractions of seconds at +// nanosecond resolution. The count is relative to an epoch at UTC midnight on +// January 1, 1970, in the proleptic Gregorian calendar which extends the +// Gregorian calendar backwards to year one. +// +// All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap +// second table is needed for interpretation, using a [24-hour linear +// smear](https://developers.google.com/time/smear). +// +// The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By +// restricting to that range, we ensure that we can convert to and from [RFC +// 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. // // # Examples // @@ -111,17 +113,18 @@ option objc_class_prefix = "GPB"; // 01:30 UTC on January 15, 2017. // // In JavaScript, one can convert a Date object to this format using the -// standard [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString] +// standard +// [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) // method. In Python, a standard `datetime.datetime` object can be converted -// to this format using [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) -// with the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one -// can use the Joda Time's [`ISODateTimeFormat.dateTime()`]( -// http://www.joda.org/joda-time/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime-- +// to this format using +// [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with +// the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use +// the Joda Time's [`ISODateTimeFormat.dateTime()`]( +// http://www.joda.org/joda-time/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime%2D%2D // ) to obtain a formatter capable of generating timestamps in this format. // // message Timestamp { - // Represents seconds of UTC time since Unix epoch // 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to // 9999-12-31T23:59:59Z inclusive. diff --git a/vendor/github.com/opencontainers/runc/README.md b/vendor/github.com/opencontainers/runc/README.md index a806f2729..aeef59895 100644 --- a/vendor/github.com/opencontainers/runc/README.md +++ b/vendor/github.com/opencontainers/runc/README.md @@ -3,6 +3,7 @@ [![Build Status](https://travis-ci.org/opencontainers/runc.svg?branch=master)](https://travis-ci.org/opencontainers/runc) [![Go Report Card](https://goreportcard.com/badge/github.com/opencontainers/runc)](https://goreportcard.com/report/github.com/opencontainers/runc) [![GoDoc](https://godoc.org/github.com/opencontainers/runc?status.svg)](https://godoc.org/github.com/opencontainers/runc) +[![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/588/badge)](https://bestpractices.coreinfrastructure.org/projects/588) ## Introduction @@ -18,22 +19,23 @@ You can find official releases of `runc` on the [release](https://github.com/ope Currently, the following features are not considered to be production-ready: -* Support for cgroup v2 +* [Support for cgroup v2](./docs/cgroup-v2.md) ## Security -The reporting process and disclosure communications are outlined in [/org/security](https://github.com/opencontainers/org/blob/master/security/). +The reporting process and disclosure communications are outlined [here](https://github.com/opencontainers/org/blob/master/SECURITY.md). + +### Security Audit +A third party security audit was performed by Cure53, you can see the full report [here](https://github.com/opencontainers/runc/blob/master/docs/Security-Audit.pdf). ## Building `runc` currently supports the Linux platform with various architecture support. -It must be built with Go version 1.6 or higher in order for some features to function properly. +It must be built with Go version 1.13 or higher. In order to enable seccomp support you will need to install `libseccomp` on your platform. > e.g. `libseccomp-devel` for CentOS, or `libseccomp-dev` for Ubuntu -Otherwise, if you do not want to build `runc` with seccomp support you can add `BUILDTAGS=""` when running make. - ```bash # create a 'github.com/opencontainers' in your GOPATH/src cd github.com/opencontainers @@ -58,20 +60,22 @@ sudo make install #### Build Tags -`runc` supports optional build tags for compiling support of various features. -To add build tags to the make option the `BUILDTAGS` variable must be set. +`runc` supports optional build tags for compiling support of various features, +with some of them enabled by default (see `BUILDTAGS` in top-level `Makefile`). + +To change build tags from the default, set the `BUILDTAGS` variable for make, +e.g. ```bash make BUILDTAGS='seccomp apparmor' ``` -| Build Tag | Feature | Dependency | -|-----------|------------------------------------|-------------| -| seccomp | Syscall filtering | libseccomp | -| selinux | selinux process and mount labeling | | -| apparmor | apparmor profile support | | -| ambient | ambient capability support | kernel 4.3 | -| nokmem | disable kernel memory account | | +| Build Tag | Feature | Enabled by default | Dependency | +|-----------|------------------------------------|--------------------|------------| +| seccomp | Syscall filtering | yes | libseccomp | +| selinux | selinux process and mount labeling | yes | | +| apparmor | apparmor profile support | yes | | +| nokmem | disable kernel memory accounting | no | | ### Running the test suite @@ -97,17 +101,30 @@ You can run a specific integration test by setting the `TESTPATH` variable. # make test TESTPATH="/checkpoint.bats" ``` -You can run a test in your proxy environment by setting `DOCKER_BUILD_PROXY` and `DOCKER_RUN_PROXY` variables. +You can run a specific rootless integration test by setting the `ROOTLESS_TESTPATH` variable. ```bash -# make test DOCKER_BUILD_PROXY="--build-arg HTTP_PROXY=http://yourproxy/" DOCKER_RUN_PROXY="-e HTTP_PROXY=http://yourproxy/" +# make test ROOTLESS_TESTPATH="/checkpoint.bats" +``` + +You can run a test using your container engine's flags by setting `CONTAINER_ENGINE_BUILD_FLAGS` and `CONTAINER_ENGINE_RUN_FLAGS` variables. + +```bash +# make test CONTAINER_ENGINE_BUILD_FLAGS="--build-arg http_proxy=http://yourproxy/" CONTAINER_ENGINE_RUN_FLAGS="-e http_proxy=http://yourproxy/" ``` ### Dependencies Management -`runc` uses [vndr](https://github.com/LK4D4/vndr) for dependencies management. -Please refer to [vndr](https://github.com/LK4D4/vndr) for how to add or update -new dependencies. +`runc` uses [Go Modules](https://github.com/golang/go/wiki/Modules) for dependencies management. +Please refer to [Go Modules](https://github.com/golang/go/wiki/Modules) for how to add or update +new dependencies. When updating dependencies, be sure that you are running Go `1.14` or newer. + +``` +# Update vendored dependencies +make vendor +# Verify all dependencies +make verify-dependencies +``` ## Using runc @@ -275,6 +292,9 @@ PIDFile=/run/mycontainerid.pid WantedBy=multi-user.target ``` +#### cgroup v2 +See [`./docs/cgroup-v2.md`](./docs/cgroup-v2.md). + ## License The code and docs are released under the [Apache 2.0 license](LICENSE). diff --git a/vendor/github.com/opencontainers/runc/go.mod b/vendor/github.com/opencontainers/runc/go.mod new file mode 100644 index 000000000..3c6f6d47e --- /dev/null +++ b/vendor/github.com/opencontainers/runc/go.mod @@ -0,0 +1,26 @@ +module github.com/opencontainers/runc + +go 1.14 + +require ( + github.com/checkpoint-restore/go-criu/v4 v4.0.2 + github.com/cilium/ebpf v0.0.0-20200507155900-a9f01edf17e3 + github.com/containerd/console v1.0.0 + github.com/coreos/go-systemd/v22 v22.0.0 + github.com/cyphar/filepath-securejoin v0.2.2 + github.com/docker/go-units v0.4.0 + github.com/godbus/dbus/v5 v5.0.3 + github.com/golang/protobuf v1.3.5 + github.com/moby/sys/mountinfo v0.1.3 + github.com/mrunalp/fileutils v0.0.0-20171103030105-7d4729fb3618 + github.com/opencontainers/runtime-spec v1.0.3-0.20200520003142-237cc4f519e2 + github.com/opencontainers/selinux v1.5.1 + github.com/pkg/errors v0.9.1 + github.com/seccomp/libseccomp-golang v0.9.1 + github.com/sirupsen/logrus v1.6.0 + github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2 + // NOTE: urfave/cli must be <= v1.22.1 due to a regression: https://github.com/urfave/cli/issues/1092 + github.com/urfave/cli v1.22.1 + github.com/vishvananda/netlink v1.1.0 + golang.org/x/sys v0.0.0-20200327173247-9dae0f8f5775 +) diff --git a/vendor/github.com/opencontainers/runc/libcontainer/README.md b/vendor/github.com/opencontainers/runc/libcontainer/README.md index a791ca2d2..6803ef56c 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/README.md +++ b/vendor/github.com/opencontainers/runc/libcontainer/README.md @@ -155,8 +155,7 @@ config := &configs.Config{ Parent: "system", Resources: &configs.Resources{ MemorySwappiness: nil, - AllowAllDevices: nil, - AllowedDevices: configs.DefaultAllowedDevices, + Devices: specconv.AllowedDevices, }, }, MaskPaths: []string{ @@ -166,7 +165,7 @@ config := &configs.Config{ ReadonlyPaths: []string{ "/proc/sys", "/proc/sysrq-trigger", "/proc/irq", "/proc/bus", }, - Devices: configs.DefaultAutoCreatedDevices, + Devices: specconv.AllowedDevices, Hostname: "testing", Mounts: []*configs.Mount{ { diff --git a/vendor/github.com/opencontainers/runc/libcontainer/configs/cgroup_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/configs/cgroup_linux.go index 58ed19c9e..f1a5bd11f 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/configs/cgroup_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/configs/cgroup_linux.go @@ -1,5 +1,9 @@ package configs +import ( + systemdDbus "github.com/coreos/go-systemd/v22/dbus" +) + type FreezerState string const ( @@ -29,18 +33,16 @@ type Cgroup struct { // Resources contains various cgroups settings to apply *Resources + + // SystemdProps are any additional properties for systemd, + // derived from org.systemd.property.xxx annotations. + // Ignored unless systemd is used for managing cgroups. + SystemdProps []systemdDbus.Property `json:"-"` } type Resources struct { - // If this is true allow access to any kind of device within the container. If false, allow access only to devices explicitly listed in the allowed_devices list. - // Deprecated - AllowAllDevices *bool `json:"allow_all_devices,omitempty"` - // Deprecated - AllowedDevices []*Device `json:"allowed_devices,omitempty"` - // Deprecated - DeniedDevices []*Device `json:"denied_devices,omitempty"` - - Devices []*Device `json:"devices"` + // Devices is the set of access rules for devices in the container. + Devices []*DeviceRule `json:"devices"` // Memory limit (in bytes) Memory int64 `json:"memory"` @@ -124,7 +126,4 @@ type Resources struct { // CpuWeight sets a proportional bandwidth limit. CpuWeight uint64 `json:"cpu_weight"` - - // CpuMax sets she maximum bandwidth limit (format: max period). - CpuMax string `json:"cpu_max"` } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/configs/config.go b/vendor/github.com/opencontainers/runc/libcontainer/configs/config.go index 24989e9f5..ac523b417 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/configs/config.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/configs/config.go @@ -8,7 +8,7 @@ import ( "time" "github.com/opencontainers/runtime-spec/specs-go" - + "github.com/pkg/errors" "github.com/sirupsen/logrus" ) @@ -70,9 +70,10 @@ type Arg struct { // Syscall is a rule to match a syscall in Seccomp type Syscall struct { - Name string `json:"name"` - Action Action `json:"action"` - Args []*Arg `json:"args"` + Name string `json:"name"` + Action Action `json:"action"` + ErrnoRet *uint `json:"errnoRet"` + Args []*Arg `json:"args"` } // TODO Windows. Many of these fields should be factored out into those parts @@ -175,7 +176,7 @@ type Config struct { // Hooks are a collection of actions to perform at various container lifecycle events. // CommandHooks are serialized to JSON, but other hooks are not. - Hooks *Hooks + Hooks Hooks // Version is the version of opencontainer specification that is supported. Version string `json:"version"` @@ -202,17 +203,50 @@ type Config struct { RootlessCgroups bool `json:"rootless_cgroups,omitempty"` } -type Hooks struct { +type HookName string +type HookList []Hook +type Hooks map[HookName]HookList + +const ( // Prestart commands are executed after the container namespaces are created, // but before the user supplied command is executed from init. - Prestart []Hook + // Note: This hook is now deprecated + // Prestart commands are called in the Runtime namespace. + Prestart HookName = "prestart" + + // CreateRuntime commands MUST be called as part of the create operation after + // the runtime environment has been created but before the pivot_root has been executed. + // CreateRuntime is called immediately after the deprecated Prestart hook. + // CreateRuntime commands are called in the Runtime Namespace. + CreateRuntime = "createRuntime" + + // CreateContainer commands MUST be called as part of the create operation after + // the runtime environment has been created but before the pivot_root has been executed. + // CreateContainer commands are called in the Container namespace. + CreateContainer = "createContainer" + + // StartContainer commands MUST be called as part of the start operation and before + // the container process is started. + // StartContainer commands are called in the Container namespace. + StartContainer = "startContainer" // Poststart commands are executed after the container init process starts. - Poststart []Hook + // Poststart commands are called in the Runtime Namespace. + Poststart = "poststart" // Poststop commands are executed after the container init process exits. - Poststop []Hook -} + // Poststop commands are called in the Runtime Namespace. + Poststop = "poststop" +) + +// TODO move this to runtime-spec +// See: https://github.com/opencontainers/runtime-spec/pull/1046 +const ( + Creating = "creating" + Created = "created" + Running = "running" + Stopped = "stopped" +) type Capabilities struct { // Bounding is the set of capabilities checked by the kernel. @@ -227,32 +261,39 @@ type Capabilities struct { Ambient []string } -func (hooks *Hooks) UnmarshalJSON(b []byte) error { - var state struct { - Prestart []CommandHook - Poststart []CommandHook - Poststop []CommandHook +func (hooks HookList) RunHooks(state *specs.State) error { + for i, h := range hooks { + if err := h.Run(state); err != nil { + return errors.Wrapf(err, "Running hook #%d:", i) + } } + return nil +} + +func (hooks *Hooks) UnmarshalJSON(b []byte) error { + var state map[HookName][]CommandHook + if err := json.Unmarshal(b, &state); err != nil { return err } - deserialize := func(shooks []CommandHook) (hooks []Hook) { - for _, shook := range shooks { - hooks = append(hooks, shook) + *hooks = Hooks{} + for n, commandHooks := range state { + if len(commandHooks) == 0 { + continue } - return hooks + (*hooks)[n] = HookList{} + for _, h := range commandHooks { + (*hooks)[n] = append((*hooks)[n], h) + } } - hooks.Prestart = deserialize(state.Prestart) - hooks.Poststart = deserialize(state.Poststart) - hooks.Poststop = deserialize(state.Poststop) return nil } -func (hooks Hooks) MarshalJSON() ([]byte, error) { +func (hooks *Hooks) MarshalJSON() ([]byte, error) { serialize := func(hooks []Hook) (serializableHooks []CommandHook) { for _, hook := range hooks { switch chook := hook.(type) { @@ -267,9 +308,12 @@ func (hooks Hooks) MarshalJSON() ([]byte, error) { } return json.Marshal(map[string]interface{}{ - "prestart": serialize(hooks.Prestart), - "poststart": serialize(hooks.Poststart), - "poststop": serialize(hooks.Poststop), + "prestart": serialize((*hooks)[Prestart]), + "createRuntime": serialize((*hooks)[CreateRuntime]), + "createContainer": serialize((*hooks)[CreateContainer]), + "startContainer": serialize((*hooks)[StartContainer]), + "poststart": serialize((*hooks)[Poststart]), + "poststop": serialize((*hooks)[Poststop]), }) } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/configs/device.go b/vendor/github.com/opencontainers/runc/libcontainer/configs/device.go index 8701bb212..24c5bbfa6 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/configs/device.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/configs/device.go @@ -1,8 +1,12 @@ package configs import ( + "errors" "fmt" "os" + "strconv" + + "golang.org/x/sys/unix" ) const ( @@ -12,21 +16,11 @@ const ( // TODO Windows: This can be factored out in the future type Device struct { - // Device type, block, char, etc. - Type rune `json:"type"` + DeviceRule // Path to the device. Path string `json:"path"` - // Major is the device's major number. - Major int64 `json:"major"` - - // Minor is the device's minor number. - Minor int64 `json:"minor"` - - // Cgroup permissions format, rwm. - Permissions string `json:"permissions"` - // FileMode permission bits for the device. FileMode os.FileMode `json:"file_mode"` @@ -35,23 +29,154 @@ type Device struct { // Gid of the device. Gid uint32 `json:"gid"` +} - // Write the file to the allowed list +// DevicePermissions is a cgroupv1-style string to represent device access. It +// has to be a string for backward compatibility reasons, hence why it has +// methods to do set operations. +type DevicePermissions string + +const ( + deviceRead uint = (1 << iota) + deviceWrite + deviceMknod +) + +func (p DevicePermissions) toSet() uint { + var set uint + for _, perm := range p { + switch perm { + case 'r': + set |= deviceRead + case 'w': + set |= deviceWrite + case 'm': + set |= deviceMknod + } + } + return set +} + +func fromSet(set uint) DevicePermissions { + var perm string + if set&deviceRead == deviceRead { + perm += "r" + } + if set&deviceWrite == deviceWrite { + perm += "w" + } + if set&deviceMknod == deviceMknod { + perm += "m" + } + return DevicePermissions(perm) +} + +// Union returns the union of the two sets of DevicePermissions. +func (p DevicePermissions) Union(o DevicePermissions) DevicePermissions { + lhs := p.toSet() + rhs := o.toSet() + return fromSet(lhs | rhs) +} + +// Difference returns the set difference of the two sets of DevicePermissions. +// In set notation, A.Difference(B) gives you A\B. +func (p DevicePermissions) Difference(o DevicePermissions) DevicePermissions { + lhs := p.toSet() + rhs := o.toSet() + return fromSet(lhs &^ rhs) +} + +// Intersection computes the intersection of the two sets of DevicePermissions. +func (p DevicePermissions) Intersection(o DevicePermissions) DevicePermissions { + lhs := p.toSet() + rhs := o.toSet() + return fromSet(lhs & rhs) +} + +// IsEmpty returns whether the set of permissions in a DevicePermissions is +// empty. +func (p DevicePermissions) IsEmpty() bool { + return p == DevicePermissions("") +} + +// IsValid returns whether the set of permissions is a subset of valid +// permissions (namely, {r,w,m}). +func (p DevicePermissions) IsValid() bool { + return p == fromSet(p.toSet()) +} + +type DeviceType rune + +const ( + WildcardDevice DeviceType = 'a' + BlockDevice DeviceType = 'b' + CharDevice DeviceType = 'c' // or 'u' + FifoDevice DeviceType = 'p' +) + +func (t DeviceType) IsValid() bool { + switch t { + case WildcardDevice, BlockDevice, CharDevice, FifoDevice: + return true + default: + return false + } +} + +func (t DeviceType) CanMknod() bool { + switch t { + case BlockDevice, CharDevice, FifoDevice: + return true + default: + return false + } +} + +func (t DeviceType) CanCgroup() bool { + switch t { + case WildcardDevice, BlockDevice, CharDevice: + return true + default: + return false + } +} + +type DeviceRule struct { + // Type of device ('c' for char, 'b' for block). If set to 'a', this rule + // acts as a wildcard and all fields other than Allow are ignored. + Type DeviceType `json:"type"` + + // Major is the device's major number. + Major int64 `json:"major"` + + // Minor is the device's minor number. + Minor int64 `json:"minor"` + + // Permissions is the set of permissions that this rule applies to (in the + // cgroupv1 format -- any combination of "rwm"). + Permissions DevicePermissions `json:"permissions"` + + // Allow specifies whether this rule is allowed. Allow bool `json:"allow"` } -func (d *Device) CgroupString() string { - return fmt.Sprintf("%c %s:%s %s", d.Type, deviceNumberString(d.Major), deviceNumberString(d.Minor), d.Permissions) -} - -func (d *Device) Mkdev() int { - return int((d.Major << 8) | (d.Minor & 0xff) | ((d.Minor & 0xfff00) << 12)) -} - -// deviceNumberString converts the device number to a string return result. -func deviceNumberString(number int64) string { - if number == Wildcard { - return "*" +func (d *DeviceRule) CgroupString() string { + var ( + major = strconv.FormatInt(d.Major, 10) + minor = strconv.FormatInt(d.Minor, 10) + ) + if d.Major == Wildcard { + major = "*" } - return fmt.Sprint(number) + if d.Minor == Wildcard { + minor = "*" + } + return fmt.Sprintf("%c %s:%s %s", d.Type, major, minor, d.Permissions) +} + +func (d *DeviceRule) Mkdev() (uint64, error) { + if d.Major == Wildcard || d.Minor == Wildcard { + return 0, errors.New("cannot mkdev() device with wildcards") + } + return unix.Mkdev(uint32(d.Major), uint32(d.Minor)), nil } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/configs/device_defaults.go b/vendor/github.com/opencontainers/runc/libcontainer/configs/device_defaults.go deleted file mode 100644 index e4f423c52..000000000 --- a/vendor/github.com/opencontainers/runc/libcontainer/configs/device_defaults.go +++ /dev/null @@ -1,111 +0,0 @@ -// +build linux - -package configs - -var ( - // DefaultSimpleDevices are devices that are to be both allowed and created. - DefaultSimpleDevices = []*Device{ - // /dev/null and zero - { - Path: "/dev/null", - Type: 'c', - Major: 1, - Minor: 3, - Permissions: "rwm", - FileMode: 0666, - }, - { - Path: "/dev/zero", - Type: 'c', - Major: 1, - Minor: 5, - Permissions: "rwm", - FileMode: 0666, - }, - - { - Path: "/dev/full", - Type: 'c', - Major: 1, - Minor: 7, - Permissions: "rwm", - FileMode: 0666, - }, - - // consoles and ttys - { - Path: "/dev/tty", - Type: 'c', - Major: 5, - Minor: 0, - Permissions: "rwm", - FileMode: 0666, - }, - - // /dev/urandom,/dev/random - { - Path: "/dev/urandom", - Type: 'c', - Major: 1, - Minor: 9, - Permissions: "rwm", - FileMode: 0666, - }, - { - Path: "/dev/random", - Type: 'c', - Major: 1, - Minor: 8, - Permissions: "rwm", - FileMode: 0666, - }, - } - DefaultAllowedDevices = append([]*Device{ - // allow mknod for any device - { - Type: 'c', - Major: Wildcard, - Minor: Wildcard, - Permissions: "m", - }, - { - Type: 'b', - Major: Wildcard, - Minor: Wildcard, - Permissions: "m", - }, - - { - Path: "/dev/console", - Type: 'c', - Major: 5, - Minor: 1, - Permissions: "rwm", - }, - // /dev/pts/ - pts namespaces are "coming soon" - { - Path: "", - Type: 'c', - Major: 136, - Minor: Wildcard, - Permissions: "rwm", - }, - { - Path: "", - Type: 'c', - Major: 5, - Minor: 2, - Permissions: "rwm", - }, - - // tuntap - { - Path: "", - Type: 'c', - Major: 10, - Minor: 200, - Permissions: "rwm", - }, - }, DefaultSimpleDevices...) - DefaultAutoCreatedDevices = append([]*Device{}, DefaultSimpleDevices...) -) diff --git a/vendor/github.com/opencontainers/runc/libcontainer/devices/devices.go b/vendor/github.com/opencontainers/runc/libcontainer/devices/devices.go index 5dabe06ce..702f913ec 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/devices/devices.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/devices/devices.go @@ -31,33 +31,33 @@ func DeviceFromPath(path, permissions string) (*configs.Device, error) { } var ( + devType configs.DeviceType + mode = stat.Mode devNumber = uint64(stat.Rdev) major = unix.Major(devNumber) minor = unix.Minor(devNumber) ) - if major == 0 { - return nil, ErrNotADevice - } - - var ( - devType rune - mode = stat.Mode - ) switch { case mode&unix.S_IFBLK == unix.S_IFBLK: - devType = 'b' + devType = configs.BlockDevice case mode&unix.S_IFCHR == unix.S_IFCHR: - devType = 'c' + devType = configs.CharDevice + case mode&unix.S_IFIFO == unix.S_IFIFO: + devType = configs.FifoDevice + default: + return nil, ErrNotADevice } return &configs.Device{ - Type: devType, - Path: path, - Major: int64(major), - Minor: int64(minor), - Permissions: permissions, - FileMode: os.FileMode(mode), - Uid: stat.Uid, - Gid: stat.Gid, + DeviceRule: configs.DeviceRule{ + Type: devType, + Major: int64(major), + Minor: int64(minor), + Permissions: configs.DevicePermissions(permissions), + }, + Path: path, + FileMode: os.FileMode(mode), + Uid: stat.Uid, + Gid: stat.Gid, }, nil } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/nsenter/cloned_binary.c b/vendor/github.com/opencontainers/runc/libcontainer/nsenter/cloned_binary.c index ad10f1406..24cc8c6e1 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/nsenter/cloned_binary.c +++ b/vendor/github.com/opencontainers/runc/libcontainer/nsenter/cloned_binary.c @@ -1,7 +1,14 @@ +// SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later /* * Copyright (C) 2019 Aleksa Sarai * Copyright (C) 2019 SUSE LLC * + * This work is dual licensed under the following licenses. You may use, + * redistribute, and/or modify the work under the conditions of either (or + * both) licenses. + * + * === Apache-2.0 === + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -13,6 +20,23 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. + * + * === LGPL-2.1-or-later === + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + * */ #define _GNU_SOURCE @@ -95,8 +119,10 @@ static int is_self_cloned(void) struct statfs fsbuf = {}; fd = open("/proc/self/exe", O_RDONLY|O_CLOEXEC); - if (fd < 0) + if (fd < 0) { + fprintf(stderr, "you have no read access to runc binary file\n"); return -ENOTRECOVERABLE; + } /* * Is the binary a fully-sealed memfd? We don't need CLONED_BINARY_ENV for diff --git a/vendor/github.com/opencontainers/runc/libcontainer/nsenter/nsexec.c b/vendor/github.com/opencontainers/runc/libcontainer/nsenter/nsexec.c index 072656831..a33f2fcc3 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/nsenter/nsexec.c +++ b/vendor/github.com/opencontainers/runc/libcontainer/nsenter/nsexec.c @@ -714,12 +714,12 @@ void nsexec(void) * ready, so we can receive all possible error codes * generated by children. */ + syncfd = sync_child_pipe[1]; + close(sync_child_pipe[0]); + while (!ready) { enum sync_t s; - syncfd = sync_child_pipe[1]; - close(sync_child_pipe[0]); - if (read(syncfd, &s, sizeof(s)) != sizeof(s)) bail("failed to sync with child: next state"); @@ -789,13 +789,13 @@ void nsexec(void) /* Now sync with grandchild. */ + syncfd = sync_grandchild_pipe[1]; + close(sync_grandchild_pipe[0]); + ready = false; while (!ready) { enum sync_t s; - syncfd = sync_grandchild_pipe[1]; - close(sync_grandchild_pipe[0]); - s = SYNC_GRANDCHILD; if (write(syncfd, &s, sizeof(s)) != sizeof(s)) { kill(child, SIGKILL); diff --git a/vendor/github.com/opencontainers/runc/libcontainer/seccomp/seccomp_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/seccomp/seccomp_linux.go index 1b7a07118..73ddf3d18 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/seccomp/seccomp_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/seccomp/seccomp_linux.go @@ -4,6 +4,7 @@ package seccomp import ( "bufio" + "errors" "fmt" "os" "strings" @@ -34,12 +35,12 @@ const ( // of the init until they join the namespace func InitSeccomp(config *configs.Seccomp) error { if config == nil { - return fmt.Errorf("cannot initialize Seccomp - nil config passed") + return errors.New("cannot initialize Seccomp - nil config passed") } - defaultAction, err := getAction(config.DefaultAction) + defaultAction, err := getAction(config.DefaultAction, nil) if err != nil { - return fmt.Errorf("error initializing seccomp - invalid default action") + return errors.New("error initializing seccomp - invalid default action") } filter, err := libseccomp.NewFilter(defaultAction) @@ -67,7 +68,7 @@ func InitSeccomp(config *configs.Seccomp) error { // Add a rule for each syscall for _, call := range config.Syscalls { if call == nil { - return fmt.Errorf("encountered nil syscall while initializing Seccomp") + return errors.New("encountered nil syscall while initializing Seccomp") } if err = matchCall(filter, call); err != nil { @@ -101,22 +102,28 @@ func IsEnabled() bool { } // Convert Libcontainer Action to Libseccomp ScmpAction -func getAction(act configs.Action) (libseccomp.ScmpAction, error) { +func getAction(act configs.Action, errnoRet *uint) (libseccomp.ScmpAction, error) { switch act { case configs.Kill: return actKill, nil case configs.Errno: + if errnoRet != nil { + return libseccomp.ActErrno.SetReturnCode(int16(*errnoRet)), nil + } return actErrno, nil case configs.Trap: return actTrap, nil case configs.Allow: return actAllow, nil case configs.Trace: + if errnoRet != nil { + return libseccomp.ActTrace.SetReturnCode(int16(*errnoRet)), nil + } return actTrace, nil case configs.Log: return actLog, nil default: - return libseccomp.ActInvalid, fmt.Errorf("invalid action, cannot use in rule") + return libseccomp.ActInvalid, errors.New("invalid action, cannot use in rule") } } @@ -138,7 +145,7 @@ func getOperator(op configs.Operator) (libseccomp.ScmpCompareOp, error) { case configs.MaskEqualTo: return libseccomp.CompareMaskedEqual, nil default: - return libseccomp.CompareInvalid, fmt.Errorf("invalid operator, cannot use in rule") + return libseccomp.CompareInvalid, errors.New("invalid operator, cannot use in rule") } } @@ -147,7 +154,7 @@ func getCondition(arg *configs.Arg) (libseccomp.ScmpCondition, error) { cond := libseccomp.ScmpCondition{} if arg == nil { - return cond, fmt.Errorf("cannot convert nil to syscall condition") + return cond, errors.New("cannot convert nil to syscall condition") } op, err := getOperator(arg.Op) @@ -161,11 +168,11 @@ func getCondition(arg *configs.Arg) (libseccomp.ScmpCondition, error) { // Add a rule to match a single syscall func matchCall(filter *libseccomp.ScmpFilter, call *configs.Syscall) error { if call == nil || filter == nil { - return fmt.Errorf("cannot use nil as syscall to block") + return errors.New("cannot use nil as syscall to block") } if len(call.Name) == 0 { - return fmt.Errorf("empty string is not a valid syscall") + return errors.New("empty string is not a valid syscall") } // If we can't resolve the syscall, assume it's not supported on this kernel @@ -176,7 +183,7 @@ func matchCall(filter *libseccomp.ScmpFilter, call *configs.Syscall) error { } // Convert the call's action to the libseccomp equivalent - callAct, err := getAction(call.Action) + callAct, err := getAction(call.Action, call.ErrnoRet) if err != nil { return fmt.Errorf("action in seccomp profile is invalid: %s", err) } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/user/user.go b/vendor/github.com/opencontainers/runc/libcontainer/user/user.go index 7b912bbf8..de30982ba 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/user/user.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/user/user.go @@ -162,10 +162,6 @@ func ParsePasswdFilter(r io.Reader, filter func(User) bool) ([]User, error) { ) for s.Scan() { - if err := s.Err(); err != nil { - return nil, err - } - line := strings.TrimSpace(s.Text()) if line == "" { continue @@ -183,6 +179,9 @@ func ParsePasswdFilter(r io.Reader, filter func(User) bool) ([]User, error) { out = append(out, p) } } + if err := s.Err(); err != nil { + return nil, err + } return out, nil } @@ -221,10 +220,6 @@ func ParseGroupFilter(r io.Reader, filter func(Group) bool) ([]Group, error) { ) for s.Scan() { - if err := s.Err(); err != nil { - return nil, err - } - text := s.Text() if text == "" { continue @@ -242,6 +237,9 @@ func ParseGroupFilter(r io.Reader, filter func(Group) bool) ([]Group, error) { out = append(out, p) } } + if err := s.Err(); err != nil { + return nil, err + } return out, nil } @@ -532,10 +530,6 @@ func ParseSubIDFilter(r io.Reader, filter func(SubID) bool) ([]SubID, error) { ) for s.Scan() { - if err := s.Err(); err != nil { - return nil, err - } - line := strings.TrimSpace(s.Text()) if line == "" { continue @@ -549,6 +543,9 @@ func ParseSubIDFilter(r io.Reader, filter func(SubID) bool) ([]SubID, error) { out = append(out, p) } } + if err := s.Err(); err != nil { + return nil, err + } return out, nil } @@ -586,10 +583,6 @@ func ParseIDMapFilter(r io.Reader, filter func(IDMap) bool) ([]IDMap, error) { ) for s.Scan() { - if err := s.Err(); err != nil { - return nil, err - } - line := strings.TrimSpace(s.Text()) if line == "" { continue @@ -603,6 +596,9 @@ func ParseIDMapFilter(r io.Reader, filter func(IDMap) bool) ([]IDMap, error) { out = append(out, p) } } + if err := s.Err(); err != nil { + return nil, err + } return out, nil } diff --git a/vendor/github.com/opencontainers/runc/vendor.conf b/vendor/github.com/opencontainers/runc/vendor.conf deleted file mode 100644 index dd51785e6..000000000 --- a/vendor/github.com/opencontainers/runc/vendor.conf +++ /dev/null @@ -1,31 +0,0 @@ -# OCI runtime-spec. When updating this, make sure you use a version tag rather -# than a commit ID so it's much more obvious what version of the spec we are -# using. -github.com/opencontainers/runtime-spec 29686dbc5559d93fb1ef402eeda3e35c38d75af4 # v1.0.1-59-g29686db - -# Core libcontainer functionality. -github.com/checkpoint-restore/go-criu 17b0214f6c48980c45dc47ecb0cfd6d9e02df723 # v3.11 -github.com/mrunalp/fileutils 7d4729fb36185a7c1719923406c9d40e54fb93c7 -github.com/opencontainers/selinux 5215b1806f52b1fcc2070a8826c542c9d33cd3cf # v1.3.0 (+ CVE-2019-16884) -github.com/seccomp/libseccomp-golang 689e3c1541a84461afc49c1c87352a6cedf72e9c # v0.9.1 -github.com/sirupsen/logrus 8bdbc7bcc01dcbb8ec23dc8a28e332258d25251f # v1.4.1 -github.com/syndtr/gocapability d98352740cb2c55f81556b63d4a1ec64c5a319c2 -github.com/vishvananda/netlink 1e2e08e8a2dcdacaae3f14ac44c5cfa31361f270 - -# systemd integration. -github.com/coreos/go-systemd 95778dfbb74eb7e4dbaf43bf7d71809650ef8076 # v19 -github.com/godbus/dbus 2ff6f7ffd60f0f2410b3105864bdd12c7894f844 # v5.0.1 -github.com/golang/protobuf 925541529c1fa6821df4e44ce2723319eb2be768 # v1.0.0 - -# Command-line interface. -github.com/cyphar/filepath-securejoin a261ee33d7a517f054effbf451841abaafe3e0fd # v0.2.2 -github.com/docker/go-units 47565b4f722fb6ceae66b95f853feed578a4a51c # v0.3.3 -github.com/urfave/cli cfb38830724cc34fedffe9a2a29fb54fa9169cd1 # v1.20.0 -golang.org/x/sys 9eafafc0a87e0fd0aeeba439a4573537970c44c7 https://github.com/golang/sys - -# console dependencies -github.com/containerd/console 0650fd9eeb50bab4fc99dceb9f2e14cf58f36e7f -github.com/pkg/errors ba968bfe8b2f7e042a574c888954fccecfa385b4 # v0.8.1 - -# ebpf dependencies -github.com/cilium/ebpf 95b36a581eed7b0f127306ed1d16cc0ddc06cf67 diff --git a/vendor/github.com/opencontainers/runtime-spec/specs-go/config.go b/vendor/github.com/opencontainers/runtime-spec/specs-go/config.go index c7c7c3d08..7b60f8bb3 100644 --- a/vendor/github.com/opencontainers/runtime-spec/specs-go/config.go +++ b/vendor/github.com/opencontainers/runtime-spec/specs-go/config.go @@ -667,9 +667,10 @@ type LinuxSeccompArg struct { // LinuxSyscall is used to match a syscall in Seccomp type LinuxSyscall struct { - Names []string `json:"names"` - Action LinuxSeccompAction `json:"action"` - Args []LinuxSeccompArg `json:"args,omitempty"` + Names []string `json:"names"` + Action LinuxSeccompAction `json:"action"` + ErrnoRet *uint `json:"errnoRet,omitempty"` + Args []LinuxSeccompArg `json:"args,omitempty"` } // LinuxIntelRdt has container runtime resource constraints for Intel RDT diff --git a/vendor/github.com/opencontainers/runtime-spec/specs-go/version.go b/vendor/github.com/opencontainers/runtime-spec/specs-go/version.go index bda7e1ca9..596af0c2f 100644 --- a/vendor/github.com/opencontainers/runtime-spec/specs-go/version.go +++ b/vendor/github.com/opencontainers/runtime-spec/specs-go/version.go @@ -11,7 +11,7 @@ const ( VersionPatch = 2 // VersionDev indicates development branch. Releases will be empty string. - VersionDev = "" + VersionDev = "-dev" ) // Version is the specification version that the package types support. diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/label/label.go b/vendor/github.com/opencontainers/selinux/go-selinux/label/label.go index fea096c18..6e38d3d32 100644 --- a/vendor/github.com/opencontainers/selinux/go-selinux/label/label.go +++ b/vendor/github.com/opencontainers/selinux/go-selinux/label/label.go @@ -1,8 +1,6 @@ package label import ( - "fmt" - "github.com/opencontainers/selinux/go-selinux" ) @@ -48,7 +46,7 @@ var PidLabel = selinux.PidLabel // Init initialises the labeling system func Init() { - _ = selinux.GetEnabled() + selinux.GetEnabled() } // ClearLabels will clear all reserved labels @@ -77,21 +75,3 @@ func ReleaseLabel(label string) error { // can be used to set duplicate labels on future container processes // Deprecated: use selinux.DupSecOpt var DupSecOpt = selinux.DupSecOpt - -// FormatMountLabel returns a string to be used by the mount command. -// The format of this string will be used to alter the labeling of the mountpoint. -// The string returned is suitable to be used as the options field of the mount command. -// If you need to have additional mount point options, you can pass them in as -// the first parameter. Second parameter is the label that you wish to apply -// to all content in the mount point. -func FormatMountLabel(src, mountLabel string) string { - if mountLabel != "" { - switch src { - case "": - src = fmt.Sprintf("context=%q", mountLabel) - default: - src = fmt.Sprintf("%s,context=%q", src, mountLabel) - } - } - return src -} diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/label/label_selinux.go b/vendor/github.com/opencontainers/selinux/go-selinux/label/label_selinux.go index 10ac15a85..903829958 100644 --- a/vendor/github.com/opencontainers/selinux/go-selinux/label/label_selinux.go +++ b/vendor/github.com/opencontainers/selinux/go-selinux/label/label_selinux.go @@ -3,6 +3,7 @@ package label import ( + "fmt" "os" "os/user" "strings" @@ -42,7 +43,7 @@ func InitLabels(options []string) (plabel string, mlabel string, Err error) { if err != nil { return "", "", err } - mcsLevel := pcon["level"] + mcon, err := selinux.NewContext(mountLabel) if err != nil { return "", "", err @@ -61,21 +62,16 @@ func InitLabels(options []string) (plabel string, mlabel string, Err error) { } if con[0] == "filetype" { mcon["type"] = con[1] - continue } pcon[con[0]] = con[1] if con[0] == "level" || con[0] == "user" { mcon[con[0]] = con[1] } } - if pcon.Get() != processLabel { - if pcon["level"] != mcsLevel { - selinux.ReleaseLabel(processLabel) - } - processLabel = pcon.Get() - selinux.ReserveLabel(processLabel) - } + selinux.ReleaseLabel(processLabel) + processLabel = pcon.Get() mountLabel = mcon.Get() + selinux.ReserveLabel(processLabel) } return processLabel, mountLabel, nil } @@ -86,6 +82,24 @@ func GenLabels(options string) (string, string, error) { return InitLabels(strings.Fields(options)) } +// FormatMountLabel returns a string to be used by the mount command. +// The format of this string will be used to alter the labeling of the mountpoint. +// The string returned is suitable to be used as the options field of the mount command. +// If you need to have additional mount point options, you can pass them in as +// the first parameter. Second parameter is the label that you wish to apply +// to all content in the mount point. +func FormatMountLabel(src, mountLabel string) string { + if mountLabel != "" { + switch src { + case "": + src = fmt.Sprintf("context=%q", mountLabel) + default: + src = fmt.Sprintf("%s,context=%q", src, mountLabel) + } + } + return src +} + // SetFileLabel modifies the "path" label to the specified file label func SetFileLabel(path string, fileLabel string) error { if !selinux.GetEnabled() || fileLabel == "" { diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/label/label_stub.go b/vendor/github.com/opencontainers/selinux/go-selinux/label/label_stub.go index c2bdd35d7..cda59d671 100644 --- a/vendor/github.com/opencontainers/selinux/go-selinux/label/label_stub.go +++ b/vendor/github.com/opencontainers/selinux/go-selinux/label/label_stub.go @@ -15,6 +15,10 @@ func GenLabels(options string) (string, string, error) { return "", "", nil } +func FormatMountLabel(src string, mountLabel string) string { + return src +} + func SetFileLabel(path string, fileLabel string) error { return nil } diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go b/vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go index f22c04b6c..9c979e5e2 100644 --- a/vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go +++ b/vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go @@ -31,9 +31,6 @@ const ( // Disabled constant to indicate SELinux is disabled Disabled = -1 - // DefaultCategoryRange is the upper bound on the category range - DefaultCategoryRange = uint32(1024) - contextFile = "/usr/share/containers/selinux/contexts" selinuxDir = "/etc/selinux/" selinuxConfig = selinuxDir + "config" @@ -60,9 +57,6 @@ var ( // InvalidLabel is returned when an invalid label is specified. InvalidLabel = errors.New("Invalid Label") - // CategoryRange allows the upper bound on the category range to be adjusted - CategoryRange = DefaultCategoryRange - assignRegex = regexp.MustCompile(`^([^=]+)=(.*)$`) roFileLabel string state = selinuxState{ @@ -796,7 +790,7 @@ func ContainerLabels() (processLabel string, fileLabel string) { func addMcs(processLabel, fileLabel string) (string, string) { scon, _ := NewContext(processLabel) if scon["level"] != "" { - mcs := uniqMcs(CategoryRange) + mcs := uniqMcs(1024) scon["level"] = mcs processLabel = scon.Get() scon, _ = NewContext(fileLabel) diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/selinux_stub.go b/vendor/github.com/opencontainers/selinux/go-selinux/selinux_stub.go index c5fbba2fa..f9f5e2061 100644 --- a/vendor/github.com/opencontainers/selinux/go-selinux/selinux_stub.go +++ b/vendor/github.com/opencontainers/selinux/go-selinux/selinux_stub.go @@ -13,8 +13,6 @@ const ( Permissive = 0 // Disabled constant to indicate SELinux is disabled Disabled = -1 - // DefaultCategoryRange is the upper bound on the category range - DefaultCategoryRange = uint32(1024) ) var ( @@ -22,8 +20,6 @@ var ( ErrMCSAlreadyExists = errors.New("MCS label already exists") // ErrEmptyPath is returned when an empty path has been specified. ErrEmptyPath = errors.New("empty path") - // CategoryRange allows the upper bound on the category range to be adjusted - CategoryRange = DefaultCategoryRange ) // Context is a representation of the SELinux label broken into 4 parts diff --git a/vendor/github.com/russross/blackfriday/doc.go b/vendor/github.com/russross/blackfriday/doc.go deleted file mode 100644 index 9656c42a1..000000000 --- a/vendor/github.com/russross/blackfriday/doc.go +++ /dev/null @@ -1,32 +0,0 @@ -// Package blackfriday is a Markdown processor. -// -// It translates plain text with simple formatting rules into HTML or LaTeX. -// -// Sanitized Anchor Names -// -// Blackfriday includes an algorithm for creating sanitized anchor names -// corresponding to a given input text. This algorithm is used to create -// anchors for headings when EXTENSION_AUTO_HEADER_IDS is enabled. The -// algorithm is specified below, so that other packages can create -// compatible anchor names and links to those anchors. -// -// The algorithm iterates over the input text, interpreted as UTF-8, -// one Unicode code point (rune) at a time. All runes that are letters (category L) -// or numbers (category N) are considered valid characters. They are mapped to -// lower case, and included in the output. All other runes are considered -// invalid characters. Invalid characters that preceed the first valid character, -// as well as invalid character that follow the last valid character -// are dropped completely. All other sequences of invalid characters -// between two valid characters are replaced with a single dash character '-'. -// -// SanitizedAnchorName exposes this functionality, and can be used to -// create compatible links to the anchor names generated by blackfriday. -// This algorithm is also implemented in a small standalone package at -// github.com/shurcooL/sanitized_anchor_name. It can be useful for clients -// that want a small package and don't need full functionality of blackfriday. -package blackfriday - -// NOTE: Keep Sanitized Anchor Name algorithm in sync with package -// github.com/shurcooL/sanitized_anchor_name. -// Otherwise, users of sanitized_anchor_name will get anchor names -// that are incompatible with those generated by blackfriday. diff --git a/vendor/github.com/russross/blackfriday/go.mod b/vendor/github.com/russross/blackfriday/go.mod deleted file mode 100644 index b05561a06..000000000 --- a/vendor/github.com/russross/blackfriday/go.mod +++ /dev/null @@ -1 +0,0 @@ -module github.com/russross/blackfriday diff --git a/vendor/github.com/russross/blackfriday/html.go b/vendor/github.com/russross/blackfriday/html.go deleted file mode 100644 index e0a6c69c9..000000000 --- a/vendor/github.com/russross/blackfriday/html.go +++ /dev/null @@ -1,938 +0,0 @@ -// -// Blackfriday Markdown Processor -// Available at http://github.com/russross/blackfriday -// -// Copyright © 2011 Russ Ross . -// Distributed under the Simplified BSD License. -// See README.md for details. -// - -// -// -// HTML rendering backend -// -// - -package blackfriday - -import ( - "bytes" - "fmt" - "regexp" - "strconv" - "strings" -) - -// Html renderer configuration options. -const ( - HTML_SKIP_HTML = 1 << iota // skip preformatted HTML blocks - HTML_SKIP_STYLE // skip embedded