Skip to content

Commit 44982d3

Browse files
committed
btf: use line info to annotate poisoned CO-RE relocations
Add a line info when poisoning an instruction to make the action explicit in the verifier log. Given a program like: ; return bpf_core_enum_value(enum nonexist_enum, NON_EXIST); 0: LdImmDW dst: r0 imm: 1 2: Exit The verifier output now is: 0: R1=ctx(off=0,imm=0) R10=fp0 ; instruction poisoned by CO-RE 0: (18) r10 = 0xbad2310 frame pointer is read only Signed-off-by: Lorenz Bauer <[email protected]>
1 parent 3aca741 commit 44982d3

2 files changed

Lines changed: 45 additions & 0 deletions

File tree

btf/core.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,12 @@ func (f *COREFixup) Apply(ins *asm.Instruction) error {
5454
// Replace all single size instruction with a invalid call instruction.
5555
*ins = asm.BuiltinFunc(COREBadRelocationSentinel).Call()
5656
}
57+
58+
// Add context to the kernel verifier output.
59+
*ins = ins.WithSource(&Line{
60+
line: "instruction poisoned by CO-RE",
61+
})
62+
5763
return nil
5864
}
5965

btf/core_reloc_test.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package btf_test
22

33
import (
4+
"bytes"
45
"io"
56
"os"
67
"strings"
@@ -10,6 +11,8 @@ import (
1011
"github.com/cilium/ebpf/btf"
1112
"github.com/cilium/ebpf/internal"
1213
"github.com/cilium/ebpf/internal/testutils"
14+
15+
"github.com/go-quicktest/qt"
1316
)
1417

1518
func TestCORERelocationLoad(t *testing.T) {
@@ -121,3 +124,39 @@ func TestLD64IMMReloc(t *testing.T) {
121124
}
122125
defer coll.Close()
123126
}
127+
128+
func TestCOREPoisonLineInfo(t *testing.T) {
129+
testutils.SkipOnOldKernel(t, "5.0", "program ext_infos")
130+
131+
spec, err := ebpf.LoadCollectionSpec(testutils.NativeFile(t, "../testdata/errors-%s.elf"))
132+
qt.Assert(t, qt.IsNil(err))
133+
134+
var b btf.Builder
135+
raw, err := b.Marshal(nil, nil)
136+
qt.Assert(t, qt.IsNil(err))
137+
empty, err := btf.LoadSpecFromReader(bytes.NewReader(raw))
138+
qt.Assert(t, qt.IsNil(err))
139+
140+
for _, test := range []struct {
141+
name string
142+
}{
143+
{"poisoned_single"},
144+
{"poisoned_double"},
145+
} {
146+
progSpec := spec.Programs[test.name]
147+
qt.Assert(t, qt.IsNotNil(progSpec))
148+
149+
t.Run(test.name, func(t *testing.T) {
150+
t.Log(progSpec.Instructions)
151+
_, err := ebpf.NewProgramWithOptions(progSpec, ebpf.ProgramOptions{
152+
KernelTypes: empty,
153+
})
154+
testutils.SkipIfNotSupported(t, err)
155+
156+
var ve *ebpf.VerifierError
157+
qt.Assert(t, qt.ErrorAs(err, &ve))
158+
qt.Assert(t, qt.SliceContains(ve.Log, "; instruction poisoned by CO-RE"))
159+
t.Logf("%-5v", ve)
160+
})
161+
}
162+
}

0 commit comments

Comments
 (0)