From b45a91a8aacc72cd4204155f9beaafa2fdde97ca Mon Sep 17 00:00:00 2001 From: Timo Beckers Date: Fri, 4 Mar 2022 17:54:23 +0100 Subject: [PATCH] btf: add CO-RE read test that fails unless relocations were correctly applied The linker rework in 9d739bd caused a piece of code that appended CORERelos to the entrypoint instruction stream to be forgotten. The existing CO-RE tests were all written in a way where the BPF programs would return 0 (success) if no CO-RE relocations were applied at all. This caused CO-RE relocations against functions (subprogs) that were only included by a bpf2bpf call to be skipped. This patch adds a broken test program that returns non-zero if left unaltered, and requires CO-RE relocation against another BTF blob to return 0. Additionally, the checks are performed from a non-inlined subprogram to ensure CO-RE relocations against subprogs work. Signed-off-by: Timo Beckers --- Makefile | 4 +- internal/btf/core_reloc_test.go | 61 ++++++++++++++++++- internal/btf/testdata/relocs_read-eb.elf | Bin 0 -> 1968 bytes internal/btf/testdata/relocs_read-el.elf | Bin 0 -> 1968 bytes internal/btf/testdata/relocs_read.c | 37 +++++++++++ internal/btf/testdata/relocs_read_tgt-eb.elf | Bin 0 -> 1272 bytes internal/btf/testdata/relocs_read_tgt-el.elf | Bin 0 -> 1272 bytes internal/btf/testdata/relocs_read_tgt.c | 16 +++++ 8 files changed, 116 insertions(+), 2 deletions(-) create mode 100644 internal/btf/testdata/relocs_read-eb.elf create mode 100644 internal/btf/testdata/relocs_read-el.elf create mode 100644 internal/btf/testdata/relocs_read.c create mode 100644 internal/btf/testdata/relocs_read_tgt-eb.elf create mode 100644 internal/btf/testdata/relocs_read_tgt-el.elf create mode 100644 internal/btf/testdata/relocs_read_tgt.c diff --git a/Makefile b/Makefile index 76a448caa..2384847a6 100644 --- a/Makefile +++ b/Makefile @@ -35,7 +35,9 @@ TARGETS := \ testdata/map_spin_lock \ testdata/subprog_reloc \ testdata/fwd_decl \ - internal/btf/testdata/relocs + internal/btf/testdata/relocs \ + internal/btf/testdata/relocs_read \ + internal/btf/testdata/relocs_read_tgt .PHONY: all clean container-all container-shell generate diff --git a/internal/btf/core_reloc_test.go b/internal/btf/core_reloc_test.go index f4cf2bafe..d8c2b59d0 100644 --- a/internal/btf/core_reloc_test.go +++ b/internal/btf/core_reloc_test.go @@ -1,17 +1,19 @@ package btf_test import ( + "fmt" "io" "os" "strings" "testing" "github.com/cilium/ebpf" + "github.com/cilium/ebpf/internal" "github.com/cilium/ebpf/internal/testutils" ) func TestCoreRelocationLoad(t *testing.T) { - testutils.Files(t, testutils.Glob(t, "testdata/*-el.elf"), func(t *testing.T, file string) { + testutils.Files(t, testutils.Glob(t, "testdata/relocs-*.elf"), func(t *testing.T, file string) { fh, err := os.Open(file) if err != nil { t.Fatal(err) @@ -23,6 +25,10 @@ func TestCoreRelocationLoad(t *testing.T) { t.Fatal(err) } + if spec.ByteOrder != internal.NativeEndian { + return + } + for _, progSpec := range spec.Programs { t.Run(progSpec.Name, func(t *testing.T) { if _, err := fh.Seek(0, io.SeekStart); err != nil { @@ -60,3 +66,56 @@ func TestCoreRelocationLoad(t *testing.T) { } }) } + +func TestCoreRelocationRead(t *testing.T) { + testutils.Files(t, testutils.Glob(t, "testdata/relocs_read-*.elf"), func(t *testing.T, file string) { + fh, err := os.Open(file) + if err != nil { + t.Fatal(err) + } + defer fh.Close() + + spec, err := ebpf.LoadCollectionSpecFromReader(fh) + if err != nil { + t.Fatal(err) + } + + if spec.ByteOrder != internal.NativeEndian { + return + } + + tgt, err := os.Open(fmt.Sprintf("testdata/relocs_read_tgt-%s.elf", internal.ClangEndian)) + if err != nil { + t.Fatal(err) + } + defer tgt.Close() + + testutils.SkipOnOldKernel(t, "4.16", "bpf2bpf calls") + + for _, progSpec := range spec.Programs { + t.Run(progSpec.Name, func(t *testing.T) { + if _, err := tgt.Seek(0, io.SeekStart); err != nil { + t.Fatal(err) + } + + prog, err := ebpf.NewProgramWithOptions(progSpec, ebpf.ProgramOptions{ + TargetBTF: tgt, + }) + if err != nil { + t.Fatal("Load program:", err) + } + defer prog.Close() + + ret, _, err := prog.Test(make([]byte, 14)) + testutils.SkipIfNotSupported(t, err) + if err != nil { + t.Fatal("Error when running:", err) + } + + if ret != 0 { + t.Error("Assertion failed on line", ret) + } + }) + } + }) +} diff --git a/internal/btf/testdata/relocs_read-eb.elf b/internal/btf/testdata/relocs_read-eb.elf new file mode 100644 index 0000000000000000000000000000000000000000..d5e6c328fcf4b1176678ac2a9524831c6b15a187 GIT binary patch literal 1968 zcmb_cy=xRf6n}TQd|ZqWMdL@~77BMDcNgu{$Pq|Lks?I|3t_Xjw=qX9w{dqOib^7q z#zN9qt6*timr~1sg{IQVf565<5SyI8-|oygw?we;!JGGf?`z)7zS+&0`PqCvCq2r^ zPw1AR=YcXS^s(kmO&)N4bdP!8v`P0;B^xIF_D~=FLJH!??%v zfk{um)JMSFmc%;5cI|y#Ye-rhB~jot-FTz19)-81qJn!$DpfdwsN=P(4YgcVL9Cjd z@~TnL4*l3=M#UG`^^}TQjSUsJZmHA>Tb*{R6O_vivK_l@sq8$EVyvPKUpcX}9EQ#m zEU`4i6Mw~vq;_Reimhd*`J z^NH6)>PH|;8b1?RoPf^3q@S1rR@eBA$kHk3H#LSxXay_dKZ>lgC-%YtAkqF+LopuK{^~Es-c9^V8Ec_cHeQ zAH+V%q~u?is>xc{I`7k_5eslU|CY~tB#oz{x7zs&u$uf{fL7k8GPj*^*ztURHnu|Z zGdll-Wu$7y&jDxWQil&LX=Mkp2sZO)`sdkMo4!M6;JY^R{QP&DeM~;>{Js1o-)twJ pbiOgz`Io}(JZDq3xb#thc_jP1SzL!9$)}^A3i}%0>bL)?_Zvjpwj2Ne literal 0 HcmV?d00001 diff --git a/internal/btf/testdata/relocs_read-el.elf b/internal/btf/testdata/relocs_read-el.elf new file mode 100644 index 0000000000000000000000000000000000000000..50b6c886afd898eb161686124941557a9b8b9493 GIT binary patch literal 1968 zcmbtVJ8KkC6h7m|yoDsh_-LF$VHad~qn#RA0tpr=Qbe#2CbN@?S+dzlW+tMjBqC`n zB#pHSmKJs?wG3F8R9g85Y%Bz^$@+bF?%i20DFi<_d(L+r_j&H@*38`O3C9rwM}A4p zj8~+3GPi5WtjVAZ$R3iJzk2?tP4|a4Dkyz$9<|%;J9BVT$q8GE&U-_hPOKFTv%J02j5qh2Do;hVT%_Am-!>u)lQiKG?Wdl|!50 zrQW1*BdaH0gACO~iqPaQAQKB{&Mw{yUeo*?^qEDGJDNi&tl*dRpCQhAwiY%3LH{?% z@Z)@5mA9L(k-1z08|pcPxCJ5qMDlMabPgoXzpYG1xI`NTcB+L-;A36mU^faElt0fO z(SD-_VQ{&;9)dQn2dAw-&TE>_XeYjCaWkK(-?rkr7JqH=_ZHvp;++4h#ea5juD3_` zl$n3nyg59s^7O)NSv^1y-NkI(#CoL7=KVF#Us{Tj2A(Y5RqEHFAFe5lL1b=vy6Rok zQ~#IZaw*wYFdwR>O>>?m(r*l{*`CMMn{yno^6mP0U2mnyNA1|r=V{^=l_3OdA9H7P ztBqShi>hamccqy{WRaH*>}Cr8ELl&Q^>g3EID|19KXkp>KfmLg$J84?KQG7Cs|H8x s079^yJ!RKlfv+&vj-a+79UL$ju=i{88glefncl&nuD{#yWQJY;2LTthW&i*H literal 0 HcmV?d00001 diff --git a/internal/btf/testdata/relocs_read.c b/internal/btf/testdata/relocs_read.c new file mode 100644 index 000000000..ccb4f499a --- /dev/null +++ b/internal/btf/testdata/relocs_read.c @@ -0,0 +1,37 @@ +#include "../../../testdata/common.h" + +#define core_access __builtin_preserve_access_index + +// Struct with the members declared in the wrong order. Accesses need +// a successful CO-RE relocation against the type in relocs_read_tgt.c +// for the test below to pass. +struct s { + char b; + char a; +}; + +// Perform a read from a subprog to ensure CO-RE relocations +// occurring there are tracked and executed in the final linked program. +__attribute__((noinline)) int read_subprog() { + struct s foo = { + .a = 0, + .b = 1, + }; + + if (core_access(foo.a) == 0) + return __LINE__; + + if (core_access(foo.b) == 1) + return __LINE__; + + return 0; +} + +__section("socket") int reads() { + int ret = read_subprog(); + if (ret) + return ret; + + return 0; +} + diff --git a/internal/btf/testdata/relocs_read_tgt-eb.elf b/internal/btf/testdata/relocs_read_tgt-eb.elf new file mode 100644 index 0000000000000000000000000000000000000000..b0effd5f86f2c6f01c7945a480f91c5fda96e4c2 GIT binary patch literal 1272 zcmb_b!Dz>Kkb?&c-c-Hns_N>lp3g7#cH%gaMk4tQJ8(2BFyc$g2JYLD z)$>hj%i3L$#bR-Fnk;#JztOhV>5|HKr!Rh5_lBcyp^2~Lclg0(K;#-(flk10-d^@b z_he-m!?+Jz11K7x-2sftXPu55PK*?@s+vn?$|ECL51vv_)VMb??|P=JO`(kH>2f^H z>!B`HF*FAz%bA(j%(R;v%epSjOiz-0s>`9u^Rlkfv^IK{o22d@pJb}LCABCSN&a4G z=|AlQkHsB2L1UB$4%^VLfJXqEz6H3x{;lA9rnLDUF_MqUs^$Ew|#FuqRIaQV)$W7 literal 0 HcmV?d00001 diff --git a/internal/btf/testdata/relocs_read_tgt-el.elf b/internal/btf/testdata/relocs_read_tgt-el.elf new file mode 100644 index 0000000000000000000000000000000000000000..34c056daa2d61f6431b0d9cda2310558c1fbf2fd GIT binary patch literal 1272 zcmbtS&ubGw6n>l3{y+;=JQOc(ZyS(Jyopr^f<>VR4<0-S>14CkLN<|^i8R#GdiUy0 z5dVsL^AGY|^kn?L-8V_xi-Hfny!U-G-(=ptIeWan*N7qs5y=l(u%L?kY%J<-S$1Vz zR^{85N?(KN*K9Vs(0y*F(%nvV+C@d>qvp@wBiYvaB{K0|InpMNshkq6ppHSWRN6J_ zBLI6=xbF?XHHHOPuLB-Hl-+?xay0TXm=wiSQlB4tN!w6zJ2Jy|-@j`6-1&j=rfu`# zICDLln?cVX`ZS|6E}cm$K9LQZ`-vUJ+1TbilV!PcN#eYnWIlGSlhf3+cEyR2zGSbB zmCpSRa97xLT;56KCNl8=cm~`7cm+v*)k*WgOV-yyBhyc*$N))wk}Ip(@XOQGVYzxX>?=d-BCmWoewf&Ebm_up216L~}H<@7@R2P$&De7eEU nC&@^F@T5yYf4-{!;j)Oj-s>%B&HdRJ=^U8HrTXWB7Ipt`?#5xk literal 0 HcmV?d00001 diff --git a/internal/btf/testdata/relocs_read_tgt.c b/internal/btf/testdata/relocs_read_tgt.c new file mode 100644 index 000000000..38bb4b156 --- /dev/null +++ b/internal/btf/testdata/relocs_read_tgt.c @@ -0,0 +1,16 @@ +/* + This file exists to emit ELFs with specific BTF types to use as target BTF + in tests. It can be made redundant when btf.Spec can be handcrafted and + passed as a CO-RE target in the future. +*/ + +#define core_access __builtin_preserve_access_index + +struct s { + char a; + char b; +}; + +int dummy() { + return core_access((struct s){}.a); +}