Skip to content

Commit e8b05c5

Browse files
committed
prog: add ProgramOptions.LogSizeStart to obtain full log after verifier bug
When the verifier hits a bug, it returns EFAULT while clobbering other retcodes. This defeats the buffer growth algorithm, so the user needs a break-glass procedure for obtaining the full verifier log. Also, reinstate maxVerifierLogSize since the maxu32 >> 2 limit is still in effect in the Linux kernel. This can be removed if the limit is removed one day and someone has a verifier log that's actually this big. EFAULT can't be reliably triggered in CI, and I'm currently out of ideas for testing this. Signed-off-by: Timo Beckers <[email protected]>
1 parent f283106 commit e8b05c5

File tree

1 file changed

+23
-7
lines changed

1 file changed

+23
-7
lines changed

prog.go

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@ const (
5151
// verifier log.
5252
const minVerifierLogSize = 64 * 1024
5353

54+
// maxVerifierLogSize is the maximum size of verifier log buffer the kernel
55+
// will accept before returning EINVAL. May be increased to MaxUint32 in the
56+
// future, but avoid the unnecessary EINVAL for now.
57+
const maxVerifierLogSize = math.MaxUint32 >> 2
58+
5459
// ProgramOptions control loading a program into the kernel.
5560
type ProgramOptions struct {
5661
// Bitmap controlling the detail emitted by the kernel's eBPF verifier log.
@@ -70,6 +75,11 @@ type ProgramOptions struct {
7075
// attempt at loading the program.
7176
LogLevel LogLevel
7277

78+
// Starting size of the verifier log buffer. If the verifier log is larger
79+
// than this size, the buffer will be grown to fit the entire log. Leave at
80+
// its default value unless troubleshooting.
81+
LogSizeStart uint32
82+
7383
// Disables the verifier log completely, regardless of other options.
7484
LogDisabled bool
7585

@@ -401,9 +411,10 @@ func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions) (*Program, er
401411

402412
// The caller requested a specific verifier log level. Set up the log buffer
403413
// so that there is a chance of loading the program in a single shot.
414+
logSize := internal.Between(opts.LogSizeStart, minVerifierLogSize, maxVerifierLogSize)
404415
var logBuf []byte
405416
if !opts.LogDisabled && opts.LogLevel != 0 {
406-
logBuf = make([]byte, minVerifierLogSize)
417+
logBuf = make([]byte, logSize)
407418
attr.LogLevel = opts.LogLevel
408419
attr.LogSize = uint32(len(logBuf))
409420
attr.LogBuf = sys.NewSlicePointer(logBuf)
@@ -437,12 +448,11 @@ func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions) (*Program, er
437448
attr.LogLevel = LogLevelBranch
438449
}
439450

440-
// Make an educated guess how large the buffer should be. Start
441-
// at minVerifierLogSize and then double the size.
442-
logSize := uint32(max(len(logBuf)*2, minVerifierLogSize))
443-
if int(logSize) < len(logBuf) {
444-
return nil, errors.New("overflow while probing log buffer size")
445-
}
451+
// Make an educated guess how large the buffer should be by multiplying.
452+
// Ensure the size doesn't overflow.
453+
const factor = 2
454+
logSize := internal.Between(logSize, minVerifierLogSize, maxVerifierLogSize/factor)
455+
logSize *= factor
446456

447457
if attr.LogTrueSize != 0 {
448458
// The kernel has given us a hint how large the log buffer has to be.
@@ -468,6 +478,12 @@ func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions) (*Program, er
468478
return nil, fmt.Errorf("load program: %w (MEMLOCK may be too low, consider rlimit.RemoveMemlock)", err)
469479
}
470480

481+
case errors.Is(err, unix.EFAULT):
482+
// EFAULT is returned when the kernel hits a verifier bug, and always
483+
// overrides ENOSPC, defeating the buffer growth strategy. Warn the user
484+
// that they may need to increase the buffer size manually.
485+
return nil, fmt.Errorf("load program: %w (hit verifier bug, increase LogSizeStart to fit the log and check dmesg)", err)
486+
471487
case errors.Is(err, unix.EINVAL):
472488
if bytes.Contains(tail, coreBadCall) {
473489
err = errBadRelocation

0 commit comments

Comments
 (0)