📘

eBPF第5章演習

2024/07/25に公開

5.11 演習

1.bpftool btf dump map / bpftool btf dump progを実行して、それぞれMapとプログラムに関連するBTF情報を確認する問題

MapのBTF情報はそのままProgに含まれていることを確認。またID、名前などから指定できる。

Map のBTF情報

$ sudo bpftool map list
98: hash  name my_config  flags 0x0
	key 4B  value 12B  max_entries 10240  memlock 1002112B
	btf_id 85

# or specify by ID: sudo bpftool btf dump map id 98
$ sudo bpftool btf dump map name my_config
[12] TYPEDEF 'u32' type_id=13
[16] STRUCT 'user_msg_t' size=12 vlen=1
	'message' type_id=18 bits_offset=0

Ditto for prog

$ sudo bpftool prog list
...
221: kprobe  name hello  tag aade5e7208515a74  gpl
	loaded_at 2024-07-11T12:46:24+0000  uid 0
	xlated 512B  jited 274B  memlock 4096B  map_ids 101,98,100,97
	btf_id 85

# or specify by ID: sudo bpftool btf dump prog id 221
$ sudo bpftool btf dump prog name hello
[1] PTR '(anon)' type_id=3
...
[12] TYPEDEF 'u32' type_id=13
[13] TYPEDEF '__u32' type_id=14
[14] INT 'unsigned int' size=4 bits_offset=0 nr_bits=32 encoding=(none)
[15] PTR '(anon)' type_id=16
[16] STRUCT 'user_msg_t' size=12 vlen=1
	'message' type_id=18 bits_offset=0
...

2. bpftool btf dump file & dump progが同じ出力であることを確認する問題

$ sudo bpftool btf dump file hello-buffer-config.bpf.o
[1] PTR '(anon)' type_id=3
[2] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED
...

$ sudo bpftool btf dump prog id 221
[1] PTR '(anon)' type_id=3
[2] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED

3 bpftool -d prog load からのデバッグ出力を眺める問題

$ sudo bpftool -d prog load hello-buffer-config.bpf.o /sys/fs/bpf/hello
Output
libbpf: loading hello-buffer-config.bpf.o
libbpf: elf: section(3) ksyscall/execve, size 792, link 0, flags 6, type=1 # here, セクションロード
libbpf: sec 'ksyscall/execve': found program 'hello' at insn offset 0 (0 bytes), code size 99 insns (792 bytes)
libbpf: elf: section(4) .relksyscall/execve, size 96, link 13, flags 40, type=9
libbpf: elf: section(5) .data, size 12, link 0, flags 3, type=1
libbpf: elf: section(6) license, size 13, link 0, flags 3, type=1 # here, ライセンス
libbpf: license of hello-buffer-config.bpf.o is Dual BSD/GPL
libbpf: elf: section(7) .maps, size 56, link 0, flags 3, type=1
libbpf: elf: section(8) .BTF, size 1805, link 0, flags 0, type=1
libbpf: elf: section(10) .BTF.ext, size 668, link 0, flags 0, type=1
libbpf: elf: section(13) .symtab, size 264, link 1, flags 0, type=2
libbpf: looking for externs among 11 symbols...
libbpf: collected 1 externs total
libbpf: extern (kcfg) #0: symbol 6, off 0, name LINUX_HAS_SYSCALL_WRAPPER
libbpf: map 'output': at sec_idx 7, offset 0.
libbpf: map 'output': found type = 4.
libbpf: map 'output': found key_size = 4.
libbpf: map 'output': found value_size = 4.
libbpf: map 'my_config': at sec_idx 7, offset 24.
libbpf: map 'my_config': found type = 1.
libbpf: map 'my_config': found key [12], sz = 4.
libbpf: map 'my_config': found value [16], sz = 12.
libbpf: map 'my_config': found max_entries = 10240.
libbpf: map 'hello_bu.data' (global data): at sec_idx 5, offset 0, flags 400.
libbpf: map 2 is "hello_bu.data"
libbpf: map 'hello_b.kconfig' (global data): at sec_idx 13, offset 0, flags 480.
libbpf: map 3 is "hello_b.kconfig"
libbpf: sec '.relksyscall/execve': collecting relocation for section(3) 'ksyscall/execve'
libbpf: sec '.relksyscall/execve': relo #0: insn #1 against 'LINUX_HAS_SYSCALL_WRAPPER'
libbpf: prog 'hello': found extern #0 'LINUX_HAS_SYSCALL_WRAPPER' (sym 6) for insn #1
libbpf: sec '.relksyscall/execve': relo #1: insn #41 against 'my_config'
libbpf: prog 'hello': found map 1 (my_config, sec 7, off 24) for insn #41
libbpf: sec '.relksyscall/execve': relo #2: insn #44 against 'message'
libbpf: prog 'hello': found data map 2 (hello_bu.data, sec 5, off 0) for insn 44
libbpf: sec '.relksyscall/execve': relo #3: insn #77 against 'my_config'
libbpf: prog 'hello': found map 1 (my_config, sec 7, off 24) for insn #77
libbpf: sec '.relksyscall/execve': relo #4: insn #80 against 'message'
libbpf: prog 'hello': found data map 2 (hello_bu.data, sec 5, off 0) for insn 80
libbpf: sec '.relksyscall/execve': relo #5: insn #91 against 'output'
libbpf: prog 'hello': found map 0 (output, sec 7, off 0) for insn #91
libbpf: loading kernel BTF '/sys/kernel/btf/vmlinux': 0
libbpf: extern (kcfg) 'LINUX_HAS_SYSCALL_WRAPPER': set to 0x1
libbpf: sec 'ksyscall/execve': found 3 CO-RE relocations
libbpf: CO-RE relocating [22] struct pt_regs: found target candidate [83] struct pt_regs in [vmlinux] # 再配置
libbpf: prog 'hello': relo #0: <byte_off> [22] struct pt_regs.di (0:14 @ offset 112)
libbpf: prog 'hello': relo #0: matching candidate #0 <byte_off> [83] struct pt_regs.di (0:14 @ offset 112)
libbpf: prog 'hello': relo #0: patched insn #5 (ALU/ALU64) imm 112 -> 112
libbpf: prog 'hello': relo #1: <byte_off> [22] struct pt_regs.di (0:14 @ offset 112)
libbpf: prog 'hello': relo #1: matching candidate #0 <byte_off> [83] struct pt_regs.di (0:14 @ offset 112)
libbpf: prog 'hello': relo #1: patched insn #6 (LDX/ST/STX) off 112 -> 112
libbpf: prog 'hello': relo #2: <byte_off> [22] struct pt_regs.di (0:14 @ offset 112)
libbpf: prog 'hello': relo #2: matching candidate #0 <byte_off> [83] struct pt_regs.di (0:14 @ offset 112)
libbpf: prog 'hello': relo #2: patched insn #48 (LDX/ST/STX) off 112 -> 112
libbpf: map 'output': setting size to 16
libbpf: map 'output': created successfully, fd=4
libbpf: map 'my_config': created successfully, fd=5
libbpf: map 'hello_bu.data': created successfully, fd=6
libbpf: map 'hello_b.kconfig': created successfully, fd=7
libbpf: prog 'hello': -- BEGIN PROG LOAD LOG --
func#0 @0
0: R1=ctx() R10=fp0
; int BPF_KPROBE_SYSCALL(hello, const char *pathname)
0: (bf) r6 = r1                       ; R1=ctx() R6_w=ctx()
; int BPF_KPROBE_SYSCALL(hello, const char *pathname)
1: (18) r1 = 0xffffa776033fe000       ; R1_w=map_value(map=hello_b.kconfig,ks=4,vs=1)
3: (71) r1 = *(u8 *)(r1 +0)           ; R1_w=1
4: (15) if r1 == 0x0 goto pc+43
mark_precise: frame0: last_idx 4 first_idx 0 subseq_idx -1
mark_precise: frame0: regs=r1 stack= before 3: (71) r1 = *(u8 *)(r1 +0)
4: R1_w=1
5: (b7) r1 = 112                      ; R1_w=112
6: (79) r3 = *(u64 *)(r6 +112)        ; R3_w=scalar() R6_w=ctx()
7: (0f) r3 += r1                      ; R1_w=112 R3_w=scalar()
8: (bf) r1 = r10                      ; R1_w=fp0 R10=fp0
9: (07) r1 += -56                     ; R1_w=fp-56
; int BPF_KPROBE_SYSCALL(hello, const char *pathname)
10: (b7) r2 = 8                       ; R2_w=8
11: (85) call bpf_probe_read_kernel#113
mark_precise: frame0: last_idx 11 first_idx 0 subseq_idx -1
mark_precise: frame0: regs=r2 stack= before 10: (b7) r2 = 8
12: R0=scalar() fp-56=mmmmmmmm
; int BPF_KPROBE_SYSCALL(hello, const char *pathname)
12: (79) r7 = *(u64 *)(r10 -56)       ; R7_w=scalar() R10=fp0 fp-56=mmmmmmmm
13: (b7) r1 = 0                       ; R1_w=0
; struct data_t data = {};
14: (63) *(u32 *)(r10 -12) = r1
mark_precise: frame0: last_idx 14 first_idx 12 subseq_idx -1
mark_precise: frame0: regs=r1 stack= before 13: (b7) r1 = 0
15: R1_w=0 R10=fp0 fp-16=0000????
15: (63) *(u32 *)(r10 -16) = r1       ; R1_w=0 R10=fp0 fp-16=00000
16: (63) *(u32 *)(r10 -20) = r1
mark_precise: frame0: last_idx 16 first_idx 12 subseq_idx -1
mark_precise: frame0: regs=r1 stack= before 15: (63) *(u32 *)(r10 -16) = r1
mark_precise: frame0: regs=r1 stack= before 14: (63) *(u32 *)(r10 -12) = r1
mark_precise: frame0: regs=r1 stack= before 13: (b7) r1 = 0
17: R1_w=0 R10=fp0 fp-24=0000????
17: (63) *(u32 *)(r10 -24) = r1       ; R1_w=0 R10=fp0 fp-24=00000
18: (63) *(u32 *)(r10 -28) = r1
mark_precise: frame0: last_idx 18 first_idx 12 subseq_idx -1
mark_precise: frame0: regs=r1 stack= before 17: (63) *(u32 *)(r10 -24) = r1
mark_precise: frame0: regs=r1 stack= before 16: (63) *(u32 *)(r10 -20) = r1
mark_precise: frame0: regs=r1 stack= before 15: (63) *(u32 *)(r10 -16) = r1
mark_precise: frame0: regs=r1 stack= before 14: (63) *(u32 *)(r10 -12) = r1
mark_precise: frame0: regs=r1 stack= before 13: (b7) r1 = 0
19: R1_w=0 R10=fp0 fp-32=0000????
19: (63) *(u32 *)(r10 -32) = r1       ; R1_w=0 R10=fp0 fp-32=00000
20: (63) *(u32 *)(r10 -36) = r1
mark_precise: frame0: last_idx 20 first_idx 12 subseq_idx -1
mark_precise: frame0: regs=r1 stack= before 19: (63) *(u32 *)(r10 -32) = r1
mark_precise: frame0: regs=r1 stack= before 18: (63) *(u32 *)(r10 -28) = r1
mark_precise: frame0: regs=r1 stack= before 17: (63) *(u32 *)(r10 -24) = r1
mark_precise: frame0: regs=r1 stack= before 16: (63) *(u32 *)(r10 -20) = r1
mark_precise: frame0: regs=r1 stack= before 15: (63) *(u32 *)(r10 -16) = r1
mark_precise: frame0: regs=r1 stack= before 14: (63) *(u32 *)(r10 -12) = r1
mark_precise: frame0: regs=r1 stack= before 13: (b7) r1 = 0
21: R1_w=0 R10=fp0 fp-40=0000????
21: (63) *(u32 *)(r10 -40) = r1       ; R1_w=0 R10=fp0 fp-40=00000
22: (63) *(u32 *)(r10 -44) = r1
mark_precise: frame0: last_idx 22 first_idx 12 subseq_idx -1
mark_precise: frame0: regs=r1 stack= before 21: (63) *(u32 *)(r10 -40) = r1
mark_precise: frame0: regs=r1 stack= before 20: (63) *(u32 *)(r10 -36) = r1
mark_precise: frame0: regs=r1 stack= before 19: (63) *(u32 *)(r10 -32) = r1
mark_precise: frame0: regs=r1 stack= before 18: (63) *(u32 *)(r10 -28) = r1
mark_precise: frame0: regs=r1 stack= before 17: (63) *(u32 *)(r10 -24) = r1
mark_precise: frame0: regs=r1 stack= before 16: (63) *(u32 *)(r10 -20) = r1
mark_precise: frame0: regs=r1 stack= before 15: (63) *(u32 *)(r10 -16) = r1
mark_precise: frame0: regs=r1 stack= before 14: (63) *(u32 *)(r10 -12) = r1
mark_precise: frame0: regs=r1 stack= before 13: (b7) r1 = 0
23: R1_w=0 R10=fp0 fp-48=0000????
23: (63) *(u32 *)(r10 -48) = r1       ; R1_w=0 R10=fp0 fp-48=00000
24: (63) *(u32 *)(r10 -8) = r1        ; R1_w=0 R10=fp0 fp-8=????0
; data.pid = bpf_get_current_pid_tgid() >> 32;
25: (85) call bpf_get_current_pid_tgid#14     ; R0_w=scalar()
; data.pid = bpf_get_current_pid_tgid() >> 32;
26: (77) r0 >>= 32                    ; R0_w=scalar(smin=0,smax=umax=0xffffffff,var_off=(0x0; 0xffffffff))
; data.pid = bpf_get_current_pid_tgid() >> 32;
27: (63) *(u32 *)(r10 -56) = r0       ; R0_w=scalar(smin=0,smax=umax=0xffffffff,var_off=(0x0; 0xffffffff)) R10=fp0 fp-56=mmmmscalar(smin=0,smax=umax=0xffffffff,var_off=(0x0; 0xffffffff))
; data.uid = bpf_get_current_uid_gid() & 0xFFFFFFFF;
28: (85) call bpf_get_current_uid_gid#15      ; R0=scalar()
; data.uid = bpf_get_current_uid_gid() & 0xFFFFFFFF;
29: (63) *(u32 *)(r10 -52) = r0       ; R0=scalar() R10=fp0 fp-56=mmmmmmmm
; struct data_t data = {};
30: (bf) r1 = r10                     ; R1_w=fp0 R10=fp0
31: (07) r1 += -48                    ; R1_w=fp-48
; bpf_get_current_comm(&data.command, sizeof(data.command));
32: (b7) r2 = 16                      ; R2_w=16
33: (85) call bpf_get_current_comm#16
mark_precise: frame0: last_idx 33 first_idx 29 subseq_idx -1
mark_precise: frame0: regs=r2 stack= before 32: (b7) r2 = 16
34: R0_w=scalar() fp-40=mmmmmmmm fp-48=mmmmmmmm
; struct data_t data = {};
34: (bf) r1 = r10                     ; R1_w=fp0 R10=fp0
35: (07) r1 += -20                    ; R1_w=fp-20
; bpf_probe_read_user_str(&data.path, sizeof(data.path), pathname);
36: (b7) r2 = 16                      ; R2_w=16
37: (bf) r3 = r7                      ; R3_w=scalar(id=1) R7=scalar(id=1)
38: (85) call bpf_probe_read_user_str#114
mark_precise: frame0: last_idx 38 first_idx 29 subseq_idx -1
mark_precise: frame0: regs=r2 stack= before 37: (bf) r3 = r7
mark_precise: frame0: regs=r2 stack= before 36: (b7) r2 = 16
39: R0=scalar(smin=smin32=-4095,smax=smax32=16) fp-8=????mmmm fp-16=mmmmmmmm fp-24=mmmmmmmm
; data.uid = bpf_get_current_uid_gid() & 0xFFFFFFFF;
39: (bf) r2 = r10                     ; R2_w=fp0 R10=fp0
40: (07) r2 += -52                    ; R2_w=fp-52
; p = bpf_map_lookup_elem(&my_config, &data.uid);
41: (18) r1 = 0xffff96e656576c00      ; R1_w=map_ptr(map=my_config,ks=4,vs=12)
43: (85) call bpf_map_lookup_elem#1   ; R0_w=map_value_or_null(id=2,map=my_config,ks=4,vs=12)
44: (18) r3 = 0xffffa776033f6000      ; R3_w=map_value(map=hello_bu.data,ks=4,vs=12)
46: (15) if r0 == 0x0 goto pc+37      ; R0_w=map_value(map=my_config,ks=4,vs=12)
47: (05) goto pc+35
; p = bpf_map_lookup_elem(&my_config, &data.uid);
83: (bf) r3 = r0                      ; R0=map_value(map=my_config,ks=4,vs=12) R3=map_value(map=my_config,ks=4,vs=12)
; struct data_t data = {};
84: (bf) r1 = r10                     ; R1_w=fp0 R10=fp0
85: (07) r1 += -32                    ; R1_w=fp-32
;
86: (b7) r2 = 12                      ; R2_w=12
87: (85) call bpf_probe_read_kernel_str#115
mark_precise: frame0: last_idx 87 first_idx 84 subseq_idx -1
mark_precise: frame0: regs=r2 stack= before 86: (b7) r2 = 12
88: R0_w=scalar(smin=smin32=-4095,smax=smax32=12) fp-24=mmmmmmmm fp-32=mmmmmmmm
88: (bf) r4 = r10                     ; R4_w=fp0 R10=fp0
; struct data_t data = {};
89: (07) r4 += -56                    ; R4_w=fp-56
; bpf_perf_event_output(ctx, &output, BPF_F_CURRENT_CPU, &data, sizeof(data));
90: (bf) r1 = r6                      ; R1_w=ctx() R6=ctx()
91: (18) r2 = 0xffff96e60c2c2600      ; R2_w=map_ptr(map=output,ks=4,vs=4)
93: (18) r3 = 0xffffffff              ; R3_w=0xffffffff
95: (b7) r5 = 52                      ; R5_w=52
96: (85) call bpf_perf_event_output#25
mark_precise: frame0: last_idx 96 first_idx 84 subseq_idx -1
mark_precise: frame0: regs=r5 stack= before 95: (b7) r5 = 52
97: R0=scalar()
; int BPF_KPROBE_SYSCALL(hello, const char *pathname)
97: (b7) r0 = 0                       ; R0_w=0
98: (95) exit

from 46 to 84: R0_w=0 R3_w=map_value(map=hello_bu.data,ks=4,vs=12) R6=ctx() R7=scalar(id=1) R10=fp0 fp-8=????mmmm fp-16=mmmmmmmm fp-24=mmmmmmmm fp-32=00000 fp-40=mmmmmmmm fp-48=mmmmmmmm fp-56=mmmmmmmm
84: R0_w=0 R3_w=map_value(map=hello_bu.data,ks=4,vs=12) R6=ctx() R7=scalar(id=1) R10=fp0 fp-8=????mmmm fp-16=mmmmmmmm fp-24=mmmmmmmm fp-32=00000 fp-40=mmmmmmmm fp-48=mmmmmmmm fp-56=mmmmmmmm
; struct data_t data = {};
84: (bf) r1 = r10                     ; R1_w=fp0 R10=fp0
85: (07) r1 += -32                    ; R1_w=fp-32
;
86: (b7) r2 = 12                      ; R2_w=12
87: (85) call bpf_probe_read_kernel_str#115
mark_precise: frame0: last_idx 87 first_idx 39 subseq_idx -1
mark_precise: frame0: regs=r2 stack= before 86: (b7) r2 = 12
88: R0_w=scalar(smin=smin32=-4095,smax=smax32=12) fp-24=mmmmmmmm fp-32=mmmmmmmm
88: (bf) r4 = r10                     ; R4_w=fp0 R10=fp0
; struct data_t data = {};
89: (07) r4 += -56                    ; R4_w=fp-56
; bpf_perf_event_output(ctx, &output, BPF_F_CURRENT_CPU, &data, sizeof(data));
90: (bf) r1 = r6                      ; R1_w=ctx() R6=ctx()
91: (18) r2 = 0xffff96e60c2c2600      ; R2_w=map_ptr(map=output,ks=4,vs=4)
93: (18) r3 = 0xffffffff              ; R3_w=0xffffffff
95: (b7) r5 = 52                      ; R5_w=52
96: (85) call bpf_perf_event_output#25
mark_precise: frame0: last_idx 96 first_idx 39 subseq_idx -1
mark_precise: frame0: regs=r5 stack= before 95: (b7) r5 = 52
97: safe
verification time 205 usec
stack depth 56
processed 71 insns (limit 1000000) max_states_per_insn 1 total_states 5 peak_states 5 mark_read 4
-- END PROG LOAD LOG --
Error: failed to pin program ksyscall/execve

4 BTFHubからさまざまなヘッダファイルをダウンロードして、それぞれを使ってBPFプログラムをビルドする問題

自分のVMのアーキテクチャ

$ uname -a
Linux rmitani-cloudvm 6.8.0-1010-aws #10-Ubuntu SMP Thu Jun 13 17:36:15 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux

こちらのREADMEがいい感じに説明してくれている。

https://github.com/aquasecurity/btfhub/blob/main/docs/generating-tailored-btfs.md

別で traceeのレポジトリもクローンしておく必要がある。

$ git clone https://github.com/aquasecurity/tracee.git
$ make all

btfhub repository: (READMEに書かれているのと少し違う)

$ sudo ./tools/btfgen.sh -a x86_64 -o $HOME/indeed/tracee/dist/tracee.bpf.o
Processing 4.14.336-256.557.amzn2.x86_64.btf...
Processing 4.14.318-241.531.amzn2.x86_64.btf...
Processing 4.14.256-197.484.amzn2.x86_64.btf...
...

custom-archive/fedora/30/x86_64/5.0.9-301.fc30.x86_64.btf で試してみる。

$ find custom-archive
custom-archive
custom-archive/.gitignore
custom-archive/fedora
custom-archive/fedora/30
custom-archive/fedora/30/x86_64
custom-archive/fedora/30/x86_64/5.0.9-301.fc30.x86_64.btf
custom-archive/fedora/30/x86_64/5.6.13-100.fc30.x86_64.btf
custom-archive/fedora/26

$ sudo bpftool btf dump file custom-archive/fedora/30/x86_64/5.0.9-301.fc30.x86_64.btf format c
# Cのコードが出力される

技評ページにもありましたが、こっちはうまくいきませんでした。。。異なるカーネルのvmlinux.hを生成するには

https://gihyo.jp/admin/serial/01/ubuntu-recipe/0694

5 hello-buffer-config.cプログラムを修正して異なるユーザに対して異なるメッセージを設定できるようにする。

mapを更新するコードを追加しました。

hello-buffer-config.cの変更点
int main()
{
    int err;
	struct perf_buffer *pb = NULL;

	libbpf_set_print(libbpf_print_fn);

	skel = hello_buffer_config_bpf__open_and_load();
	if (!skel) {
		printf("Failed to open BPF object\n");
		return 1;
	}

	err = hello_buffer_config_bpf__attach(skel);
	if (err) {
		fprintf(stderr, "Failed to attach BPF skeleton: %d\n", err);
		hello_buffer_config_bpf__destroy(skel);
         return 1;
        }

+       // Populate the my_config map with user-specific messages
+       __u32 uid = 1002; // User ID 1002
+       struct user_msg_t user_message_1002 = {"User 1002!"};
+
+       int fd = bpf_map__fd(skel->maps.my_config);
+       if (bpf_map_update_elem(fd, &uid, &user_message_1002, BPF_ANY) != 0) {
+               fprintf(stderr, "Failed to update BPF map for user 1002: %s\n",
strerror(errno));
+               hello_buffer_config_bpf__destroy(skel);
+               return 1;
+       }
+
+       __u32 root_uid = 0; // Root user ID
+       struct user_msg_t user_message_root = {"Root user!"};
+
+       if (bpf_map_update_elem(fd, &root_uid, &user_message_root, BPF_ANY) != 0
) {
+               fprintf(stderr, "Failed to update BPF map for root user: %s\n",
strerror(errno));
+               hello_buffer_config_bpf__destroy(skel);
+               return 1;
+       }
+

// 以下同じ
...

結果

$ sudo ./hello-buffer-config
9195   0      falcon-task      /opt/CrowdStrik  Root user!
9196   0      falcon-task      /opt/CrowdStrik  Root user!
9199   1002   bash             /usr/bin/id      User 1002!

6 SEC自作?

ELFファイルになんとかSection Nameを書き込む必要がある。

https://nakryiko.com/posts/libbpf-v1/

かつてはみんな自分のカスタムのセクションネームを追加していたらしい。今はカスタムの名前は禁止されている。

people started adding random suffixes
(e.g., SEC("xdp_my_prog1")) to create a unique identifier
both as a convenience and as a work around for the single
BPF program per SEC() limitation.

オブジェクトファイルのセクション名をXDPに直接書き換えるCのスクリプトを書いてみました(これが問題の意図かはわかりません)。

$ cat your_bpf_program.c
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>

SEC("custom_section")
int custom_prog(struct xdp_md *ctx) {
    // BPF program logic here
    return XDP_PASS;
}

char _license[] SEC("license") = "GPL";

Compile and check ELF file:

$ sudo clang -O2 -target bpf -c your_bpf_program.c -o your_bpf_program.o
$ readelf -S your_bpf_program.o
There are 7 section headers, starting at offset 0x118:

Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [ 0]                   NULL             0000000000000000  00000000
       0000000000000000  0000000000000000           0     0     0
  [ 1] .strtab           STRTAB           0000000000000000  000000ba
       000000000000005c  0000000000000000           0     0     1
  [ 2] .text             PROGBITS         0000000000000000  00000040
       0000000000000000  0000000000000000  AX       0     0     4
  [ 3] custom_section    PROGBITS         0000000000000000  00000040
       0000000000000010  0000000000000000  AX       0     0     8
ELFファイルのセクションを書き換える rename.c
$ cat rename_section.c
#include <libelf.h>
#include <fcntl.h>
#include <gelf.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

void rename_section(const char *filename, const char *old_name, const char *new_name) {
    if (elf_version(EV_CURRENT) == EV_NONE) {
        fprintf(stderr, "ELF library initialization failed: %s\n", elf_errmsg(-1));
        exit(EXIT_FAILURE);
    }

    int fd = open(filename, O_RDWR);
    if (fd < 0) {
        perror("open");
        exit(EXIT_FAILURE);
    }

    Elf *e = elf_begin(fd, ELF_C_RDWR, NULL);
    if (!e) {
        perror("elf_begin");
        close(fd);
        exit(EXIT_FAILURE);
    }

    size_t shstrndx;
    if (elf_getshstrndx(e, &shstrndx) != 0) {
        fprintf(stderr, "elf_getshstrndx() failed: %s\n", elf_errmsg(-1));
        elf_end(e);
        close(fd);
        exit(EXIT_FAILURE);
    }

    Elf_Scn *shstrscn = elf_getscn(e, shstrndx);
    if (!shstrscn) {
        fprintf(stderr, "elf_getscn() failed: %s\n", elf_errmsg(-1));
        elf_end(e);
        close(fd);
        exit(EXIT_FAILURE);
    }

    GElf_Shdr shstrshdr;
    if (!gelf_getshdr(shstrscn, &shstrshdr)) {
        fprintf(stderr, "gelf_getshdr() failed: %s\n", elf_errmsg(-1));
        elf_end(e);
        close(fd);
        exit(EXIT_FAILURE);
    }

    Elf_Data *shstrdata = elf_getdata(shstrscn, NULL);
    if (!shstrdata) {
        fprintf(stderr, "elf_getdata() failed: %s\n", elf_errmsg(-1));
        elf_end(e);
        close(fd);
        exit(EXIT_FAILURE);
    }

    // Find the section with old_name and update it to new_name
    Elf_Scn *scn = NULL;
    while ((scn = elf_nextscn(e, scn)) != NULL) {
        GElf_Shdr shdr;
        gelf_getshdr(scn, &shdr);
        const char *name = elf_strptr(e, shstrndx, shdr.sh_name);
        if (name && strcmp(name, old_name) == 0) {
            size_t old_name_len = strlen(old_name);
            size_t new_name_len = strlen(new_name);

            if (new_name_len > old_name_len) {
                fprintf(stderr, "New name is longer than old name, resizing not supported.\n");
                elf_end(e);
                close(fd);
                exit(EXIT_FAILURE);
            }

            // Update the string table in place
            char *shstrtab = (char *)shstrdata->d_buf;
            strncpy(&shstrtab[shdr.sh_name], new_name, new_name_len);
            // Null-terminate if new_name is shorter than old_name
            if (new_name_len < old_name_len) {
                shstrtab[shdr.sh_name + new_name_len] = '\0';
            }

            if (elf_update(e, ELF_C_WRITE) < 0) {
                fprintf(stderr, "elf_update() failed: %s\n", elf_errmsg(-1));
                elf_end(e);
                close(fd);
                exit(EXIT_FAILURE);
            }
            break;
        }
    }

    elf_end(e);
    close(fd);
}

int main() {
    const char *filename = "your_bpf_program.o";
    const char *old_name = "custom_section";
    const char *new_name = "xdp";
    rename_section(filename, old_name, new_name);
    return 0;
}
$ sudo gcc -o rename_section rename_section.c -lelf
$ sudo ./rename_section

XDPに変わったことがわかる:

$ readelf -S your_bpf_program.o
There are 7 section headers, starting at offset 0x118:

Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [ 0]                   NULL             0000000000000000  00000000
       0000000000000000  0000000000000000           0     0     0
  [ 1] .strtab           STRTAB           0000000000000000  00000040
       000000000000005c  0000000000000000           0     0     1
  [ 2] .text             PROGBITS         0000000000000000  0000009c
       0000000000000000  0000000000000000  AX       0     0     4
  [ 3] xdp               PROGBITS         0000000000000000  000000a0

「アタッチ用のコードを書く」とはちょっと違う気がするが。。。

Discussion