@@ -46,13 +46,9 @@ const (
46
46
outputPad = 256 + 2
47
47
)
48
48
49
- // DefaultVerifierLogSize is the default number of bytes allocated for the
49
+ // minVerifierLogSize is the default number of bytes allocated for the
50
50
// verifier log.
51
- const DefaultVerifierLogSize = 64 * 1024
52
-
53
- // maxVerifierLogSize is the maximum size of verifier log buffer the kernel
54
- // will accept before returning EINVAL.
55
- const maxVerifierLogSize = math .MaxUint32 >> 2
51
+ const minVerifierLogSize = 64 * 1024
56
52
57
53
// ProgramOptions control loading a program into the kernel.
58
54
type ProgramOptions struct {
@@ -73,17 +69,6 @@ type ProgramOptions struct {
73
69
// attempt at loading the program.
74
70
LogLevel LogLevel
75
71
76
- // Controls the output buffer size for the verifier log, in bytes. See the
77
- // documentation on ProgramOptions.LogLevel for details about how this value
78
- // is used.
79
- //
80
- // If this value is set too low to fit the verifier log, the resulting
81
- // [ebpf.VerifierError]'s Truncated flag will be true, and the error string
82
- // will also contain a hint to that effect.
83
- //
84
- // Defaults to DefaultVerifierLogSize.
85
- LogSize int
86
-
87
72
// Disables the verifier log completely, regardless of other options.
88
73
LogDisabled bool
89
74
@@ -262,10 +247,6 @@ func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions) (*Program, er
262
247
return nil , fmt .Errorf ("can't load %s program on %s" , spec .ByteOrder , internal .NativeEndian )
263
248
}
264
249
265
- if opts .LogSize < 0 {
266
- return nil , errors .New ("ProgramOptions.LogSize must be a positive value; disable verifier logs using ProgramOptions.LogDisabled" )
267
- }
268
-
269
250
// Kernels before 5.0 (6c4fc209fcf9 "bpf: remove useless version check for prog load")
270
251
// require the version field to be set to the value of the KERNEL_VERSION
271
252
// macro for kprobe-type programs.
@@ -404,37 +385,59 @@ func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions) (*Program, er
404
385
}
405
386
}
406
387
407
- if opts .LogSize == 0 {
408
- opts .LogSize = DefaultVerifierLogSize
409
- }
410
-
411
- // The caller requested a specific verifier log level. Set up the log buffer.
388
+ // The caller requested a specific verifier log level. Set up the log buffer
389
+ // so that there is a chance of loading the program in a single shot.
412
390
var logBuf []byte
413
391
if ! opts .LogDisabled && opts .LogLevel != 0 {
414
- logBuf = make ([]byte , opts . LogSize )
392
+ logBuf = make ([]byte , minVerifierLogSize )
415
393
attr .LogLevel = opts .LogLevel
416
394
attr .LogSize = uint32 (len (logBuf ))
417
395
attr .LogBuf = sys .NewSlicePointer (logBuf )
418
396
}
419
397
420
- fd , err := sys .ProgLoad (attr )
421
- if err == nil {
422
- return & Program {unix .ByteSliceToString (logBuf ), fd , spec .Name , "" , spec .Type }, nil
423
- }
398
+ for {
399
+ var fd * sys.FD
400
+ fd , err = sys .ProgLoad (attr )
401
+ if err == nil {
402
+ return & Program {unix .ByteSliceToString (logBuf ), fd , spec .Name , "" , spec .Type }, nil
403
+ }
424
404
425
- // An error occurred loading the program, but the caller did not explicitly
426
- // enable the verifier log. Re-run with branch-level verifier logs enabled to
427
- // obtain more info. Preserve the original error to return it to the caller.
428
- // An undersized log buffer will result in ENOSPC regardless of the underlying
429
- // cause.
430
- var err2 error
431
- if ! opts .LogDisabled && opts .LogLevel == 0 {
432
- logBuf = make ([]byte , opts .LogSize )
433
- attr .LogLevel = LogLevelBranch
434
- attr .LogSize = uint32 (len (logBuf ))
435
- attr .LogBuf = sys .NewSlicePointer (logBuf )
405
+ if opts .LogDisabled {
406
+ break
407
+ }
436
408
437
- _ , err2 = sys .ProgLoad (attr )
409
+ if attr .LogTrueSize != 0 && attr .LogSize >= attr .LogTrueSize {
410
+ // The log buffer already has the correct size.
411
+ break
412
+ }
413
+
414
+ if attr .LogSize != 0 && ! errors .Is (err , unix .ENOSPC ) {
415
+ // Logging is enabled and the error is not ENOSPC, so we can infer
416
+ // that the log buffer is large enough.
417
+ break
418
+ }
419
+
420
+ if attr .LogLevel == 0 {
421
+ // Logging is not enabled but loading the program failed. Enable
422
+ // basic logging.
423
+ attr .LogLevel = LogLevelBranch
424
+ }
425
+
426
+ // Make an educated guess how large the buffer should be. Start
427
+ // at minVerifierLogSize and then double the size.
428
+ logSize := uint32 (max (len (logBuf )* 2 , minVerifierLogSize ))
429
+ if int (logSize ) < len (logBuf ) {
430
+ return nil , errors .New ("overflow while probing log buffer size" )
431
+ }
432
+
433
+ if attr .LogTrueSize != 0 {
434
+ // The kernel has given us a hint how large the log buffer has to be.
435
+ logSize = attr .LogTrueSize
436
+ }
437
+
438
+ logBuf = make ([]byte , logSize )
439
+ attr .LogSize = logSize
440
+ attr .LogBuf = sys .NewSlicePointer (logBuf )
438
441
}
439
442
440
443
end := bytes .IndexByte (logBuf , 0 )
@@ -452,10 +455,6 @@ func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions) (*Program, er
452
455
}
453
456
454
457
case errors .Is (err , unix .EINVAL ):
455
- if opts .LogSize > maxVerifierLogSize {
456
- return nil , fmt .Errorf ("load program: %w (ProgramOptions.LogSize exceeds maximum value of %d)" , err , maxVerifierLogSize )
457
- }
458
-
459
458
if bytes .Contains (tail , coreBadCall ) {
460
459
err = errBadRelocation
461
460
break
@@ -479,8 +478,7 @@ func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions) (*Program, er
479
478
}
480
479
}
481
480
482
- truncated := errors .Is (err , unix .ENOSPC ) || errors .Is (err2 , unix .ENOSPC )
483
- return nil , internal .ErrorWithLog ("load program" , err , logBuf , truncated )
481
+ return nil , internal .ErrorWithLog ("load program" , err , logBuf )
484
482
}
485
483
486
484
// NewProgramFromFD creates a program from a raw fd.
0 commit comments