From 901f16dab4e3046a2a3bc9c12fb1643547b633ce Mon Sep 17 00:00:00 2001 From: Lorenz Bauer Date: Tue, 31 Oct 2023 18:14:34 +0000 Subject: [PATCH] btf: fix CO-RE relocations for local type id At some point the kernel gained the ability to dynamically allocated typed memory via a bpf_obj_new helper (see [1]). This helper receives the ID of the type to allocate as an argument. Trying to use this helper with the library will currently fail, since we took a short-cut when implementing on the fly BTF generation. At that point in time there was no use of the local_type_id relocation in the kernel, so we just stuck with the value present in ext_infos. This is of course not correct when building a BTF blob from scratch: type IDs are reallocated, and only used types are passed to the kernel in the first place. Fix this by allocating an ID for any type that is the target of a local_type_id relocation. 1: https://lwn.net/Articles/915404/ Signed-off-by: Lorenz Bauer --- btf/core.go | 17 ++++++++-------- btf/core_reloc_test.go | 1 + btf/core_test.go | 4 ++-- btf/ext_info.go | 24 +++++++---------------- btf/marshal.go | 5 +++++ btf/testdata/relocs-eb.elf | Bin 15536 -> 15560 bytes btf/testdata/relocs-el.elf | Bin 15536 -> 15560 bytes btf/testdata/relocs.c | 39 +++++++++++++++++-------------------- linker.go | 4 ++-- prog.go | 32 ++++++++++++++++++++++-------- syscalls.go | 33 +++++++++++++++++++++++++++++++ syscalls_test.go | 4 ++++ 12 files changed, 105 insertions(+), 58 deletions(-) diff --git a/btf/core.go b/btf/core.go index ded7d43d4..f19d56bb2 100644 --- a/btf/core.go +++ b/btf/core.go @@ -164,7 +164,7 @@ func (k coreKind) String() string { // // Fixups are returned in the order of relos, e.g. fixup[i] is the solution // for relos[i]. -func CORERelocate(relos []*CORERelocation, target *Spec, bo binary.ByteOrder) ([]COREFixup, error) { +func CORERelocate(relos []*CORERelocation, target *Spec, bo binary.ByteOrder, typeID func(Type) (TypeID, error)) ([]COREFixup, error) { if target == nil { var err error target, _, err = kernelSpec() @@ -194,14 +194,15 @@ func CORERelocate(relos []*CORERelocation, target *Spec, bo binary.ByteOrder) ([ return nil, fmt.Errorf("%s: unexpected accessor %v", relo.kind, relo.accessor) } + id, err := typeID(relo.typ) + if err != nil { + return nil, fmt.Errorf("%s: get type id: %w", relo.kind, err) + } + result[i] = COREFixup{ - kind: relo.kind, - local: uint64(relo.id), - // NB: Using relo.id as the target here is incorrect, since - // it doesn't match the BTF we generate on the fly. This isn't - // too bad for now since there are no uses of the local type ID - // in the kernel, yet. - target: uint64(relo.id), + kind: relo.kind, + local: uint64(relo.id), + target: uint64(id), } continue } diff --git a/btf/core_reloc_test.go b/btf/core_reloc_test.go index 037d8419c..d6c9dd00f 100644 --- a/btf/core_reloc_test.go +++ b/btf/core_reloc_test.go @@ -39,6 +39,7 @@ func TestCORERelocationLoad(t *testing.T) { prog, err := ebpf.NewProgramWithOptions(progSpec, ebpf.ProgramOptions{ KernelTypes: spec.Types, }) + testutils.SkipIfNotSupported(t, err) if strings.HasPrefix(progSpec.Name, "err_") { if err == nil { diff --git a/btf/core_test.go b/btf/core_test.go index 75420ddca..fab618395 100644 --- a/btf/core_test.go +++ b/btf/core_test.go @@ -590,7 +590,7 @@ func TestCORERelocation(t *testing.T) { relos = append(relos, reloInfo.relo) } - fixups, err := CORERelocate(relos, spec, spec.byteOrder) + fixups, err := CORERelocate(relos, spec, spec.byteOrder, spec.TypeID) if want := errs[name]; want != nil { if !errors.Is(err, want) { t.Fatal("Expected", want, "got", err) @@ -737,7 +737,7 @@ func BenchmarkCORESkBuff(b *testing.B) { b.ReportAllocs() for i := 0; i < b.N; i++ { - _, err = CORERelocate([]*CORERelocation{relo}, spec, spec.byteOrder) + _, err = CORERelocate([]*CORERelocation{relo}, spec, spec.byteOrder, spec.TypeID) if err != nil { b.Fatal(err) } diff --git a/btf/ext_info.go b/btf/ext_info.go index 3eae08b28..96e970f81 100644 --- a/btf/ext_info.go +++ b/btf/ext_info.go @@ -142,15 +142,7 @@ func AssignMetadataToInstructions( // MarshalExtInfos encodes function and line info embedded in insns into kernel // wire format. -// -// Returns ErrNotSupported if the kernel doesn't support BTF-associated programs. -func MarshalExtInfos(insns asm.Instructions) (_ *Handle, funcInfos, lineInfos []byte, _ error) { - // Bail out early if the kernel doesn't support Func(Proto). If this is the - // case, func_info will also be unsupported. - if err := haveProgBTF(); err != nil { - return nil, nil, nil, err - } - +func MarshalExtInfos(insns asm.Instructions, b *Builder) (funcInfos, lineInfos []byte, _ error) { iter := insns.Iterate() for iter.Next() { _, ok := iter.Ins.Source().(*Line) @@ -160,10 +152,9 @@ func MarshalExtInfos(insns asm.Instructions) (_ *Handle, funcInfos, lineInfos [] } } - return nil, nil, nil, nil + return nil, nil, nil marshal: - var b Builder var fiBuf, liBuf bytes.Buffer for { if fn := FuncMetadata(iter.Ins); fn != nil { @@ -171,8 +162,8 @@ marshal: fn: fn, offset: iter.Offset, } - if err := fi.marshal(&fiBuf, &b); err != nil { - return nil, nil, nil, fmt.Errorf("write func info: %w", err) + if err := fi.marshal(&fiBuf, b); err != nil { + return nil, nil, fmt.Errorf("write func info: %w", err) } } @@ -181,8 +172,8 @@ marshal: line: line, offset: iter.Offset, } - if err := li.marshal(&liBuf, &b); err != nil { - return nil, nil, nil, fmt.Errorf("write line info: %w", err) + if err := li.marshal(&liBuf, b); err != nil { + return nil, nil, fmt.Errorf("write line info: %w", err) } } @@ -191,8 +182,7 @@ marshal: } } - handle, err := NewHandle(&b) - return handle, fiBuf.Bytes(), liBuf.Bytes(), err + return fiBuf.Bytes(), liBuf.Bytes(), nil } // btfExtHeader is found at the start of the .BTF.ext section. diff --git a/btf/marshal.go b/btf/marshal.go index 0d093c665..cdaf08a6c 100644 --- a/btf/marshal.go +++ b/btf/marshal.go @@ -93,6 +93,11 @@ func NewBuilder(types []Type) (*Builder, error) { return b, nil } +// Empty returns true if [Add] has not been invoked on the builder. +func (b *Builder) Empty() bool { + return len(b.types) == 0 +} + // Add a Type and allocate a stable ID for it. // // Adding the identical Type multiple times is valid and will return the same ID. diff --git a/btf/testdata/relocs-eb.elf b/btf/testdata/relocs-eb.elf index 7af281b3049b62b0c921923762eed9263823f566..4fce1add7910a12ec5c00aa1f31290dec0fa255b 100644 GIT binary patch delta 3948 zcmZXXe{5S<701tg*FRodr*a0BleNX}XjcaYacN7O{ve6iXao~=%T@)ch)nE<$J#B7 z!rW2j{82{4U(Qb1JXTQt7*d2PEm|fu(u$TphU!g4ibf|q7$Qhv3)-ZaQbefugYS9o zyy{}E^zM6~bMCqKoO{lF&z?WsJY63!V>8998JHQ%nc_?(XLij@=gjA3=5l7wOfzTp z&aCCk=h-(oGsp$>B_2aR#1-`WcpCkFoo&>} z+C}Mz4skUU_6e!*%RCnfKjsL(!mUu)?FhfhzRjDh+;2ZSbQn_`M@K&uK+{Ar|ItKYIkjK=z%FD1m4XNyC zBz+RR!QmgMwGX)uxv$n|I3LfNA95+4>v^hUr=Q_UJhzEA{clv~z&So1&+)7Aw0V}B z@tk>{*U_jgrF%H&`~$+^Zw zX#b&FNr{}0C?(f<0@{B%T1jlA{TJ7vT~}=ewn=C+y3POQrPP4A!R^#xvv*-+!%N0I z#qD&qZ)Y00z`$FHk}<3%&!~f>&-w0b_o`~Q5~VVHXZKMrbqhDTcXxkL728p*C%M%< z(ETfw?1W@>;o}?M_hR=y_UI|Tk=YqOi#CE;=9-w?enjB&yEkBFMWjgSrA3(LZb%14Q=3b&LW!K3iH@=vHn??PaDRq!g& zif~E!k3_4&Et!JwqVgSN?hsy6J__G?cXIeu>N_;WgzZ8L5e&@(@65mCP04-cTR+$e;#l*e4ZiCL=`< zV!MDZCiK@Ci+ex6KF1GCC+kqK&GQTZb>ZLfw2o1q}# zlW~gx(x90&+$05O$crJI-~a{R)=-`pCGSodsgWffCvOanMyX0Ld3Ot!aABUrugNP5 zkK?L{;63v05kWN^klcv65^gB(ChvaXMdf4URfJp0Rq{>iSN&_`o#NMW zQf%H?L=YVLPeCaS4)_SJSDx_@@Gi1a%{0=%nhO6LWb>k*QhmgAZ@}dYFig-l%ZL)hrKiR=k$~VYL3ZnDvhm2xth6B3tWF;rj z0gu@8RX<8ra^$H4T@jC{{z0;mGH;@TtI9tndtCIoBV8BBPDrtNb2{J(S;?ulq}(Pe zIrUm0r;23H3AdGx;gtZk>R{?gvgd{Ks(*p(tZ+&B64@7p%gXPNy-*WDB@}G%$j%E- zDSwje>%tA?yT~?$=anBKdqudZ{508R;T7dylD#UtuG}Om$2FEwzDD-G6%iCdL3#_> zRpF74(FYALq9EruZuUBg_5Z#{PhbkzrI#=c`kCf~$8xO#EH-j{Epv^*~1dj-%6 zxP-qRPJi$O91%cnv%aWNJ;P$K=|&Eu}Pu+ab-AM3k+BVMIG>pvUnU# z2x~i`ypFqYRaq890Jg3y3kuIE%Ywp7%Ceqtiw=hi$buqh>ww@78BQ#ABXB?_M2qFo zi9<3WS}bx{CPYgg;Y@$lEODW~xNy9Gcg7rBs1GGQGs=zqgXRP;?;kd8&KwvvWiF#1 J=lX&Ce*sqF<`@6~ delta 3960 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 L%02Sp=DPm@sEgw- delta 4002 zcmZ9Oe{7Xk8OP6g-`?Ka(%ZDK+8@we>RNU?wzNuTTWM+8z@Z7VLx`OLDVZcyV0MaH zaBxwx1kFfVpNz3=(-J{2S)^G_RwE|-VHNF&jTu|#SXPn|%f{BmY_3z5`2C*yyysr} z!a48zd7kr}^E}Tv&$+#LVD!LH+BOe2F1Mc>-k7qj!@EmZuINr3H0~LY4rEY1o{nf4gE%m1u6RlX+Zx)*%;iB+_5xe z_`HPnCHbC{RC~#0Iqf9NyyQW->?BDqc}Qa69d?H_hO65ttX*ooZVSGia+F=6AKx!Q z%@Gy$^G?H+zbVJU%Jy$L>AhaM$MG7^d-0XCZuath@+Pbwb)#2%>9-v>dLF=6&U%%X zKPLASRJMP|jjr?3?>f%q=KEk;m*Bn4u5fR9{sTD#>p>^2^wI;4D?A?r)4IUPm%2Bt ze<+t={kW4Rz4VadC7ut1X`OKLgnQFEBek(gdqnPyrQ$yVBh&J1EF}kH#dXKQ6}ApN zY|)-ZtFXCvPRQw4%043#=%15o=%1HZVaonO8VXb8zr^Tmw#e-htw&^AVV6BAPoe*t zTt+`B74cU4vTTkw*-LUL{($|vOvJnFl*AGb*vqmx(PdwiV~JM#noJ~`s;4naE{0AY z!#^ciR9XFoYP0!i^^sqZPH5j$Ene{IGkm$2W@R6=*Gb3@{v*QN{=Xy7L;LP6+6GY8 z_J&-7_WfJ5x$MlzC(wSN+N@XA-m4Ggp5n^t|EM;*E6aRDAIT1A7jDrez4pIy4BG#x zwhZrWHg5Q4o^Q$@i<|5x@?PJHgM(SIO$~ zI(ewPKE7|){zv-LyX9(G&Dco!UyEe#@|N{`!fbkBVR$**mi2&WmZSY6yS(Gu(YIxn zaLkmSk*mwonOBUd0#Lwu32-FZlzCc%E5`IHPmpJ_<2Zhf{I)SC@Fq7Sq~L}z^Om4vf%C*>npv{_D<#pr@ z^0nHU%p=^L?bdLYcs}@Wi4530XWii<|CS~ra6$EdCZDo?6J95uwPus*|4n|unm*-H z)Il(coG90me`ho1s0vys7)O$nd&uXl8CBj(zF^Ho<)4uMgrq4SCtpO2%IC;0BZHd6 zN%FMyn|PgkC4-1`KoEmq1`#ROk>9qaNBMs8tTp}0JIOb4yF5sq$0n%$X)=xilIAk{ zd-6hV*Iy-PZXzNbFh>FY!AWO;K-_~h9lNb63tRzZe?hbIGz!Y}1in5V1_xUMzf}jx zI4W%z)_``3yghLBlA+)d1$}|vn-9s~2>e#mphAOzz!yv>c|RQ033rkQ1E2cCQy;qPk6e|&Jn7JM<2#>wls8a+cW90* z;vwao)HjDd4&{tLQ-?XACCmk)yr2_2L+%LO4MGPZ?$*H0Q{Nq$fkk{o`6~5W;lM47 zQj3m2ya)q&Ltpt3C$wWEc5tXjUr!nEXO$+LV7q9t};8@&#}v z7!M7cauZzVfb-Zx<>DpasnDEIzMK3?XfTHx{~&o98C2d!z7m=lw^M>KF%h+p%?KT}_)T}y#Ev*_pREy_0(xQnzD z_AAhE3=9%z_;+EU8GHZJFIu}tPS*dWjz5k(^&G((|0)<6an~xXC*`LNO_@nZ5r;ds zlyVf=;9PNj&P!%NwcuTa#u?k#;aQ2s&kp6Za}f7iym|eJY41=vR&= z7|hdif)TWGw8#No>Jd{vg;tTLpHb%g)F%*F%`9N<+G8DQtlraT6^ zOP%`2zITy*e;(6*DBm9IyWjHs2}be^pf;m<2KY2n=<-tNE_rg~z>Mmn0Opmcr+pRD z5M_+(yT1h@0S9ctfczBpDn}CxfTN7i{wO%#fe~;tANAvT_T(ur|He%gvtaNstAaI{ zg=~-~4tQ9(O8KC2v+}dbo0KsjO--NjTgroZdImV8yrvlOQ*c%VT#$T0nG2F}D>#R^ zAQ?p+MF2uJP|r!zH!aiKx1>6T{m{JJs#M! c{AO*d?UAc%yX>^ob#&P_*@eDaPIlb+e=+IRVgLXD diff --git a/btf/testdata/relocs.c b/btf/testdata/relocs.c index 766dc8158..92f83400f 100644 --- a/btf/testdata/relocs.c +++ b/btf/testdata/relocs.c @@ -29,13 +29,6 @@ union u { typedef union u u_t; -#define local_id_zero(expr) \ - ({ \ - if (bpf_core_type_id_local(expr) != 0) { \ - return __LINE__; \ - } \ - }) - #define local_id_not_zero(expr) \ ({ \ if (bpf_core_type_id_local(expr) == 0) { \ @@ -43,9 +36,9 @@ typedef union u u_t; } \ }) -#define target_and_local_id_match(expr) \ +#define target_and_local_id_dont_match(expr) \ ({ \ - if (bpf_core_type_id_kernel(expr) != bpf_core_type_id_local(expr)) { \ + if (bpf_core_type_id_kernel(expr) == bpf_core_type_id_local(expr)) { \ return __LINE__; \ } \ }) @@ -69,19 +62,23 @@ __section("socket_filter/type_ids") int type_ids() { local_id_not_zero(const u_t); local_id_not_zero(volatile u_t); + // In this context, target is the BTF generated by clang. local is + // generated on the fly by the library. There is a low chance that + // the order on both is the same, so we assert this to make sure that + // CO-RE uses the IDs from the dynamic BTF. // Qualifiers on types crash clang. - target_and_local_id_match(struct s); - target_and_local_id_match(s_t); - // target_and_local_id_match(const s_t); - // target_and_local_id_match(volatile s_t); - target_and_local_id_match(enum e); - target_and_local_id_match(e_t); - // target_and_local_id_match(const e_t); - // target_and_local_id_match(volatile e_t); - target_and_local_id_match(union u); - target_and_local_id_match(u_t); - // target_and_local_id_match(const u_t); - // target_and_local_id_match(volatile u_t); + target_and_local_id_dont_match(struct s); + target_and_local_id_dont_match(s_t); + // target_and_local_id_dont_match(const s_t); + // target_and_local_id_dont_match(volatile s_t); + target_and_local_id_dont_match(enum e); + target_and_local_id_dont_match(e_t); + // target_and_local_id_dont_match(const e_t); + // target_and_local_id_dont_match(volatile e_t); + target_and_local_id_dont_match(union u); + target_and_local_id_dont_match(u_t); + // target_and_local_id_dont_match(const u_t); + // target_and_local_id_dont_match(volatile u_t); return 0; } diff --git a/linker.go b/linker.go index b653b805e..38cc12536 100644 --- a/linker.go +++ b/linker.go @@ -106,7 +106,7 @@ func hasFunctionReferences(insns asm.Instructions) bool { // // Passing a nil target will relocate against the running kernel. insns are // modified in place. -func applyRelocations(insns asm.Instructions, target *btf.Spec, bo binary.ByteOrder) error { +func applyRelocations(insns asm.Instructions, target *btf.Spec, bo binary.ByteOrder, b *btf.Builder) error { var relos []*btf.CORERelocation var reloInsns []*asm.Instruction iter := insns.Iterate() @@ -125,7 +125,7 @@ func applyRelocations(insns asm.Instructions, target *btf.Spec, bo binary.ByteOr bo = internal.NativeEndian } - fixups, err := btf.CORERelocate(relos, target, bo) + fixups, err := btf.CORERelocate(relos, target, bo, b.Add) if err != nil { return err } diff --git a/prog.go b/prog.go index 6d46a0422..ca2974a5a 100644 --- a/prog.go +++ b/prog.go @@ -242,14 +242,24 @@ func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions) (*Program, er insns := make(asm.Instructions, len(spec.Instructions)) copy(insns, spec.Instructions) - handle, fib, lib, err := btf.MarshalExtInfos(insns) - if err != nil && !errors.Is(err, btf.ErrNotSupported) { - return nil, fmt.Errorf("load ext_infos: %w", err) + var b btf.Builder + if err := applyRelocations(insns, opts.KernelTypes, spec.ByteOrder, &b); err != nil { + return nil, fmt.Errorf("apply CO-RE relocations: %w", err) } - if handle != nil { - defer handle.Close() - attr.ProgBtfFd = uint32(handle.FD()) + if !b.Empty() && haveProgramExtInfos() != nil { + // Return ErrNotSupported instead of E2BIG if CO-RE relies on BTF + // being present. + return nil, haveProgramExtInfos() + } + + if haveProgramExtInfos() == nil { + // Only add func and line info if the kernel supports it. This allows + // BPF compiled with modern toolchains to work on old kernels. + fib, lib, err := btf.MarshalExtInfos(insns, &b) + if err != nil { + return nil, fmt.Errorf("marshal ext_infos: %w", err) + } attr.FuncInfoRecSize = btf.FuncInfoSize attr.FuncInfoCnt = uint32(len(fib)) / btf.FuncInfoSize @@ -260,8 +270,14 @@ func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions) (*Program, er attr.LineInfo = sys.NewSlicePointer(lib) } - if err := applyRelocations(insns, opts.KernelTypes, spec.ByteOrder); err != nil { - return nil, fmt.Errorf("apply CO-RE relocations: %w", err) + if !b.Empty() { + handle, err := btf.NewHandle(&b) + if err != nil { + return nil, fmt.Errorf("load BTF: %w", err) + } + defer handle.Close() + + attr.ProgBtfFd = uint32(handle.FD()) } kconfig, err := resolveKconfigReferences(insns) diff --git a/syscalls.go b/syscalls.go index cdf1fcf2e..4aef7faeb 100644 --- a/syscalls.go +++ b/syscalls.go @@ -4,6 +4,7 @@ import ( "bytes" "errors" "fmt" + "math" "os" "runtime" @@ -302,3 +303,35 @@ var haveSyscallWrapper = internal.NewFeatureTest("syscall wrapper", "4.17", func return evt.Close() }) + +var haveProgramExtInfos = internal.NewFeatureTest("program ext_infos", "5.0", func() error { + insns := asm.Instructions{ + asm.Mov.Imm(asm.R0, 0), + asm.Return(), + } + + buf := bytes.NewBuffer(make([]byte, 0, insns.Size())) + if err := insns.Marshal(buf, internal.NativeEndian); err != nil { + return err + } + bytecode := buf.Bytes() + + _, err := sys.ProgLoad(&sys.ProgLoadAttr{ + ProgType: sys.ProgType(SocketFilter), + License: sys.NewStringPointer("MIT"), + Insns: sys.NewSlicePointer(bytecode), + InsnCnt: uint32(len(bytecode) / asm.InstructionSize), + FuncInfoCnt: 1, + ProgBtfFd: math.MaxUint32, + }) + + if errors.Is(err, unix.EBADF) { + return nil + } + + if errors.Is(err, unix.E2BIG) { + return ErrNotSupported + } + + return err +}) diff --git a/syscalls_test.go b/syscalls_test.go index 9558bfa74..ff32c3622 100644 --- a/syscalls_test.go +++ b/syscalls_test.go @@ -62,3 +62,7 @@ func TestHaveBPFToBPFCalls(t *testing.T) { func TestHaveSyscallWrapper(t *testing.T) { testutils.CheckFeatureTest(t, haveSyscallWrapper) } + +func TestHaveProgramExtInfos(t *testing.T) { + testutils.CheckFeatureTest(t, haveProgramExtInfos) +}