Skip to content

Commit 33b393e

Browse files
info: Return dedicated error when program info is restricted
On systems where the `kernel.kptr_restrict` and `net.core.bpf_jit_harden` sysctls are enabled, certain fields in the program info may be restricted. When this is the case xlated and jitted instruction, line info, and function info are unavailable. When such fields are unavailable, we do get ..len fields set to non-zero values, but the kernel will have not written any data to the pointers provided. At present when this happens we don't recognize this and attempt to parse the empty buffers resulting in a `parse func info: offset 0: type ID 0 is a *btf.Void, but expected a Func` error. The only clue we have that this is happening is that the kernel will zero out the insns pointer. This commit adds logic to detect when this happens and then returns a dedicated `ErrInfoRestricted` error so this case can be handled gracefully. Signed-off-by: Dylan Reimerink <[email protected]>
1 parent ae22611 commit 33b393e

File tree

2 files changed

+37
-0
lines changed

2 files changed

+37
-0
lines changed

info.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,8 @@ type ProgramInfo struct {
301301
btf btf.ID
302302
loadTime time.Duration
303303

304+
restricted bool
305+
304306
maps []MapID
305307
insns []byte
306308
jitedSize uint32
@@ -477,6 +479,14 @@ func newProgramInfoFromFd(fd *sys.FD) (*ProgramInfo, error) {
477479
}
478480
}
479481

482+
if info.XlatedProgLen > 0 && info2.XlatedProgInsns.IsNil() {
483+
pi.restricted = true
484+
pi.insns = nil
485+
pi.lineInfos = nil
486+
pi.funcInfos = nil
487+
pi.jitedInfo = programJitedInfo{}
488+
}
489+
480490
return &pi, nil
481491
}
482492

@@ -556,6 +566,9 @@ func (pi *ProgramInfo) btfSpec() (*btf.Spec, error) {
556566
return spec, nil
557567
}
558568

569+
// ErrInfoRestricted is returned when the kernel readback of certain info.
570+
var ErrInfoRestricted = errors.New("info restricted by kernel")
571+
559572
// LineInfos returns the BTF line information of the program.
560573
//
561574
// Available from 5.0.
@@ -564,6 +577,10 @@ func (pi *ProgramInfo) btfSpec() (*btf.Spec, error) {
564577
// ErrNotSupported if the program was created without BTF or if the kernel
565578
// doesn't support the field.
566579
func (pi *ProgramInfo) LineInfos() (btf.LineOffsets, error) {
580+
if pi.restricted {
581+
return nil, fmt.Errorf("line info restricted by combination of kernel.kptr_restrict and net.core.bpf_jit_harden: %w", ErrInfoRestricted)
582+
}
583+
567584
if len(pi.lineInfos) == 0 {
568585
return nil, fmt.Errorf("insufficient permissions or unsupported kernel: %w", ErrNotSupported)
569586
}
@@ -606,6 +623,10 @@ func (pi *ProgramInfo) Instructions() (asm.Instructions, error) {
606623
return nil, fmt.Errorf("read instructions: %w", internal.ErrNotSupportedOnOS)
607624
}
608625

626+
if pi.restricted {
627+
return nil, fmt.Errorf("instructions restricted by combination of kernel.kptr_restrict and net.core.bpf_jit_harden: %w", ErrInfoRestricted)
628+
}
629+
609630
// If the calling process is not BPF-capable or if the kernel doesn't
610631
// support getting xlated instructions, the field will be zero.
611632
if len(pi.insns) == 0 {
@@ -676,6 +697,10 @@ func (pi *ProgramInfo) Instructions() (asm.Instructions, error) {
676697
//
677698
// Available from 4.13. Reading this metadata requires CAP_BPF or equivalent.
678699
func (pi *ProgramInfo) JitedSize() (uint32, error) {
700+
if pi.restricted {
701+
return 0, fmt.Errorf("jited size restricted by combination of kernel.kptr_restrict and net.core.bpf_jit_harden: %w", ErrInfoRestricted)
702+
}
703+
679704
if pi.jitedSize == 0 {
680705
return 0, fmt.Errorf("insufficient permissions, unsupported kernel, or JIT compiler disabled: %w", ErrNotSupported)
681706
}
@@ -687,6 +712,10 @@ func (pi *ProgramInfo) JitedSize() (uint32, error) {
687712
//
688713
// Available from 4.13. Reading this metadata requires CAP_BPF or equivalent.
689714
func (pi *ProgramInfo) TranslatedSize() (int, error) {
715+
if pi.restricted {
716+
return 0, fmt.Errorf("xlated size restricted by combination of kernel.kptr_restrict and net.core.bpf_jit_harden: %w", ErrInfoRestricted)
717+
}
718+
690719
insns := len(pi.insns)
691720
if insns == 0 {
692721
return 0, fmt.Errorf("insufficient permissions or unsupported kernel: %w", ErrNotSupported)
@@ -786,6 +815,10 @@ func (pi *ProgramInfo) JitedFuncLens() ([]uint32, bool) {
786815
// ErrNotSupported if the program was created without BTF or if the kernel
787816
// doesn't support the field.
788817
func (pi *ProgramInfo) FuncInfos() (btf.FuncOffsets, error) {
818+
if pi.restricted {
819+
return nil, fmt.Errorf("func info restricted by combination of kernel.kptr_restrict and net.core.bpf_jit_harden: %w", ErrInfoRestricted)
820+
}
821+
789822
if len(pi.funcInfos) == 0 {
790823
return nil, fmt.Errorf("insufficient permissions or unsupported kernel: %w", ErrNotSupported)
791824
}

internal/sys/ptr.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ type TypedPointer[T any] struct {
2828
ptr Pointer
2929
}
3030

31+
func (p TypedPointer[T]) IsNil() bool {
32+
return p.ptr.ptr == nil
33+
}
34+
3135
// SlicePointer creates a [TypedPointer] from a slice.
3236
func SlicePointer[T comparable](s []T) TypedPointer[T] {
3337
return TypedPointer[T]{ptr: UnsafeSlicePointer(s)}

0 commit comments

Comments
 (0)