← Documents Documentation/networking/filter.rst GitHub 원문 ↗

Linux 6.18.37 · Networking

Linux Socket Filtering aka Berkeley Packet Filter (BPF)

고전 BPF 소켓 필터의 부착 API, 명령 집합, Linux 확장, bpf_asm·bpf_dbg·JIT 도구 체인과 eBPF 내부 변환을 설명합니다.

Source pathDocumentation/networking/filter.rst
Source versionLinux v6.18.37
TranslationDUJINLABS 전문 번역 + 해설

요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.

1. 요약·해설

원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.

요약·해설

filter.rst:1-685

이 문서는 `sock_filter` 4튜플에서 시작해 필터를 소켓에 부착하고 잠그는 방법, 고전 BPF 가상 머신의 레지스터와 명령, Linux 전용 적재 확장, 디버거와 JIT 검사 방법까지 한 흐름으로 연결합니다. 현대 커널이 고전 프로그램을 eBPF 내부 표현으로 바꿔 실행하는 경계도 함께 설명합니다.

문서의 실행 계층
계층구성 요소역할
사용자 공간libpcap, tcpdump, bpf_asm필터 생성
소켓 APISO_ATTACH_FILTER, SO_LOCK_FILTER부착과 정책 고정
검증/변환bpf_check_classic(), classic -> eBPF안전성 검사와 내부 표현 변환
실행인터프리터 또는 JIT패킷별 반환값 계산
시험bpf_dbg, bpf_jit_disasm, test_bpf동작과 생성 코드 검증

사용자 필터에서 커널 실행까지의 층을 정리했습니다.

2. 영어 원문 전체

번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.

원문 전체 펼치기
1 .. SPDX-License-Identifier: GPL-2.0
2
3 .. _networking-filter:
4
5 =======================================================
6 Linux Socket Filtering aka Berkeley Packet Filter (BPF)
7 =======================================================
8
9 Notice
10 ------
11
12 This file used to document the eBPF format and mechanisms even when not
13 related to socket filtering. The ../bpf/index.rst has more details
14 on eBPF.
15
16 Introduction
17 ------------
18
19 Linux Socket Filtering (LSF) is derived from the Berkeley Packet Filter.
20 Though there are some distinct differences between the BSD and Linux
21 Kernel filtering, but when we speak of BPF or LSF in Linux context, we
22 mean the very same mechanism of filtering in the Linux kernel.
23
24 BPF allows a user-space program to attach a filter onto any socket and
25 allow or disallow certain types of data to come through the socket. LSF
26 follows exactly the same filter code structure as BSD's BPF, so referring
27 to the BSD bpf.4 manpage is very helpful in creating filters.
28
29 On Linux, BPF is much simpler than on BSD. One does not have to worry
30 about devices or anything like that. You simply create your filter code,
31 send it to the kernel via the SO_ATTACH_FILTER option and if your filter
32 code passes the kernel check on it, you then immediately begin filtering
33 data on that socket.
34
35 You can also detach filters from your socket via the SO_DETACH_FILTER
36 option. This will probably not be used much since when you close a socket
37 that has a filter on it the filter is automagically removed. The other
38 less common case may be adding a different filter on the same socket where
39 you had another filter that is still running: the kernel takes care of
40 removing the old one and placing your new one in its place, assuming your
41 filter has passed the checks, otherwise if it fails the old filter will
42 remain on that socket.
43
44 SO_LOCK_FILTER option allows to lock the filter attached to a socket. Once
45 set, a filter cannot be removed or changed. This allows one process to
46 setup a socket, attach a filter, lock it then drop privileges and be
47 assured that the filter will be kept until the socket is closed.
48
49 The biggest user of this construct might be libpcap. Issuing a high-level
50 filter command like `tcpdump -i em1 port 22` passes through the libpcap
51 internal compiler that generates a structure that can eventually be loaded
52 via SO_ATTACH_FILTER to the kernel. `tcpdump -i em1 port 22 -ddd`
53 displays what is being placed into this structure.
54
55 Although we were only speaking about sockets here, BPF in Linux is used
56 in many more places. There's xt_bpf for netfilter, cls_bpf in the kernel
57 qdisc layer, SECCOMP-BPF (SECure COMPuting [1]_), and lots of other places
58 such as team driver, PTP code, etc where BPF is being used.
59
60 .. [1] Documentation/userspace-api/seccomp_filter.rst
61
62 Original BPF paper:
63
64 Steven McCanne and Van Jacobson. 1993. The BSD packet filter: a new
65 architecture for user-level packet capture. In Proceedings of the
66 USENIX Winter 1993 Conference Proceedings on USENIX Winter 1993
67 Conference Proceedings (USENIX'93). USENIX Association, Berkeley,
68 CA, USA, 2-2. [http://www.tcpdump.org/papers/bpf-usenix93.pdf]
69
70 Structure
71 ---------
72
73 User space applications include <linux/filter.h> which contains the
74 following relevant structures::
75
76 struct sock_filter { /* Filter block */
77 __u16 code; /* Actual filter code */
78 __u8 jt; /* Jump true */
79 __u8 jf; /* Jump false */
80 __u32 k; /* Generic multiuse field */
81 };
82
83 Such a structure is assembled as an array of 4-tuples, that contains
84 a code, jt, jf and k value. jt and jf are jump offsets and k a generic
85 value to be used for a provided code::
86
87 struct sock_fprog { /* Required for SO_ATTACH_FILTER. */
88 unsigned short len; /* Number of filter blocks */
89 struct sock_filter __user *filter;
90 };
91
92 For socket filtering, a pointer to this structure (as shown in
93 follow-up example) is being passed to the kernel through setsockopt(2).
94
95 Example
96 -------
97
98 ::
99
100 #include <sys/socket.h>
101 #include <sys/types.h>
102 #include <arpa/inet.h>
103 #include <linux/if_ether.h>
104 /* ... */
105
106 /* From the example above: tcpdump -i em1 port 22 -dd */
107 struct sock_filter code[] = {
108 { 0x28, 0, 0, 0x0000000c },
109 { 0x15, 0, 8, 0x000086dd },
110 { 0x30, 0, 0, 0x00000014 },
111 { 0x15, 2, 0, 0x00000084 },
112 { 0x15, 1, 0, 0x00000006 },
113 { 0x15, 0, 17, 0x00000011 },
114 { 0x28, 0, 0, 0x00000036 },
115 { 0x15, 14, 0, 0x00000016 },
116 { 0x28, 0, 0, 0x00000038 },
117 { 0x15, 12, 13, 0x00000016 },
118 { 0x15, 0, 12, 0x00000800 },
119 { 0x30, 0, 0, 0x00000017 },
120 { 0x15, 2, 0, 0x00000084 },
121 { 0x15, 1, 0, 0x00000006 },
122 { 0x15, 0, 8, 0x00000011 },
123 { 0x28, 0, 0, 0x00000014 },
124 { 0x45, 6, 0, 0x00001fff },
125 { 0xb1, 0, 0, 0x0000000e },
126 { 0x48, 0, 0, 0x0000000e },
127 { 0x15, 2, 0, 0x00000016 },
128 { 0x48, 0, 0, 0x00000010 },
129 { 0x15, 0, 1, 0x00000016 },
130 { 0x06, 0, 0, 0x0000ffff },
131 { 0x06, 0, 0, 0x00000000 },
132 };
133
134 struct sock_fprog bpf = {
135 .len = ARRAY_SIZE(code),
136 .filter = code,
137 };
138
139 sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
140 if (sock < 0)
141 /* ... bail out ... */
142
143 ret = setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &bpf, sizeof(bpf));
144 if (ret < 0)
145 /* ... bail out ... */
146
147 /* ... */
148 close(sock);
149
150 The above example code attaches a socket filter for a PF_PACKET socket
151 in order to let all IPv4/IPv6 packets with port 22 pass. The rest will
152 be dropped for this socket.
153
154 The setsockopt(2) call to SO_DETACH_FILTER doesn't need any arguments
155 and SO_LOCK_FILTER for preventing the filter to be detached, takes an
156 integer value with 0 or 1.
157
158 Note that socket filters are not restricted to PF_PACKET sockets only,
159 but can also be used on other socket families.
160
161 Summary of system calls:
162
163 * setsockopt(sockfd, SOL_SOCKET, SO_ATTACH_FILTER, &val, sizeof(val));
164 * setsockopt(sockfd, SOL_SOCKET, SO_DETACH_FILTER, &val, sizeof(val));
165 * setsockopt(sockfd, SOL_SOCKET, SO_LOCK_FILTER, &val, sizeof(val));
166
167 Normally, most use cases for socket filtering on packet sockets will be
168 covered by libpcap in high-level syntax, so as an application developer
169 you should stick to that. libpcap wraps its own layer around all that.
170
171 Unless i) using/linking to libpcap is not an option, ii) the required BPF
172 filters use Linux extensions that are not supported by libpcap's compiler,
173 iii) a filter might be more complex and not cleanly implementable with
174 libpcap's compiler, or iv) particular filter codes should be optimized
175 differently than libpcap's internal compiler does; then in such cases
176 writing such a filter "by hand" can be of an alternative. For example,
177 xt_bpf and cls_bpf users might have requirements that could result in
178 more complex filter code, or one that cannot be expressed with libpcap
179 (e.g. different return codes for various code paths). Moreover, BPF JIT
180 implementors may wish to manually write test cases and thus need low-level
181 access to BPF code as well.
182
183 BPF engine and instruction set
184 ------------------------------
185
186 Under tools/bpf/ there's a small helper tool called bpf_asm which can
187 be used to write low-level filters for example scenarios mentioned in the
188 previous section. Asm-like syntax mentioned here has been implemented in
189 bpf_asm and will be used for further explanations (instead of dealing with
190 less readable opcodes directly, principles are the same). The syntax is
191 closely modelled after Steven McCanne's and Van Jacobson's BPF paper.
192
193 The BPF architecture consists of the following basic elements:
194
195 ======= ====================================================
196 Element Description
197 ======= ====================================================
198 A 32 bit wide accumulator
199 X 32 bit wide X register
200 M[] 16 x 32 bit wide misc registers aka "scratch memory
201 store", addressable from 0 to 15
202 ======= ====================================================
203
204 A program, that is translated by bpf_asm into "opcodes" is an array that
205 consists of the following elements (as already mentioned)::
206
207 op:16, jt:8, jf:8, k:32
208
209 The element op is a 16 bit wide opcode that has a particular instruction
210 encoded. jt and jf are two 8 bit wide jump targets, one for condition
211 "jump if true", the other one "jump if false". Eventually, element k
212 contains a miscellaneous argument that can be interpreted in different
213 ways depending on the given instruction in op.
214
215 The instruction set consists of load, store, branch, alu, miscellaneous
216 and return instructions that are also represented in bpf_asm syntax. This
217 table lists all bpf_asm instructions available resp. what their underlying
218 opcodes as defined in linux/filter.h stand for:
219
220 =========== =================== =====================
221 Instruction Addressing mode Description
222 =========== =================== =====================
223 ld 1, 2, 3, 4, 12 Load word into A
224 ldi 4 Load word into A
225 ldh 1, 2 Load half-word into A
226 ldb 1, 2 Load byte into A
227 ldx 3, 4, 5, 12 Load word into X
228 ldxi 4 Load word into X
229 ldxb 5 Load byte into X
230
231 st 3 Store A into M[]
232 stx 3 Store X into M[]
233
234 jmp 6 Jump to label
235 ja 6 Jump to label
236 jeq 7, 8, 9, 10 Jump on A == <x>
237 jneq 9, 10 Jump on A != <x>
238 jne 9, 10 Jump on A != <x>
239 jlt 9, 10 Jump on A < <x>
240 jle 9, 10 Jump on A <= <x>
241 jgt 7, 8, 9, 10 Jump on A > <x>
242 jge 7, 8, 9, 10 Jump on A >= <x>
243 jset 7, 8, 9, 10 Jump on A & <x>
244
245 add 0, 4 A + <x>
246 sub 0, 4 A - <x>
247 mul 0, 4 A * <x>
248 div 0, 4 A / <x>
249 mod 0, 4 A % <x>
250 neg !A
251 and 0, 4 A & <x>
252 or 0, 4 A | <x>
253 xor 0, 4 A ^ <x>
254 lsh 0, 4 A << <x>
255 rsh 0, 4 A >> <x>
256
257 tax Copy A into X
258 txa Copy X into A
259
260 ret 4, 11 Return
261 =========== =================== =====================
262
263 The next table shows addressing formats from the 2nd column:
264
265 =============== =================== ===============================================
266 Addressing mode Syntax Description
267 =============== =================== ===============================================
268 0 x/%x Register X
269 1 [k] BHW at byte offset k in the packet
270 2 [x + k] BHW at the offset X + k in the packet
271 3 M[k] Word at offset k in M[]
272 4 #k Literal value stored in k
273 5 4*([k]&0xf) Lower nibble * 4 at byte offset k in the packet
274 6 L Jump label L
275 7 #k,Lt,Lf Jump to Lt if true, otherwise jump to Lf
276 8 x/%x,Lt,Lf Jump to Lt if true, otherwise jump to Lf
277 9 #k,Lt Jump to Lt if predicate is true
278 10 x/%x,Lt Jump to Lt if predicate is true
279 11 a/%a Accumulator A
280 12 extension BPF extension
281 =============== =================== ===============================================
282
283 The Linux kernel also has a couple of BPF extensions that are used along
284 with the class of load instructions by "overloading" the k argument with
285 a negative offset + a particular extension offset. The result of such BPF
286 extensions are loaded into A.
287
288 Possible BPF extensions are shown in the following table:
289
290 =================================== =================================================
291 Extension Description
292 =================================== =================================================
293 len skb->len
294 proto skb->protocol
295 type skb->pkt_type
296 poff Payload start offset
297 ifidx skb->dev->ifindex
298 nla Netlink attribute of type X with offset A
299 nlan Nested Netlink attribute of type X with offset A
300 mark skb->mark
301 queue skb->queue_mapping
302 hatype skb->dev->type
303 rxhash skb->hash
304 cpu raw_smp_processor_id()
305 vlan_tci skb_vlan_tag_get(skb)
306 vlan_avail skb_vlan_tag_present(skb)
307 vlan_tpid skb->vlan_proto
308 rand get_random_u32()
309 =================================== =================================================
310
311 These extensions can also be prefixed with '#'.
312 Examples for low-level BPF:
313
314 **ARP packets**::
315
316 ldh [12]
317 jne #0x806, drop
318 ret #-1
319 drop: ret #0
320
321 **IPv4 TCP packets**::
322
323 ldh [12]
324 jne #0x800, drop
325 ldb [23]
326 jneq #6, drop
327 ret #-1
328 drop: ret #0
329
330 **icmp random packet sampling, 1 in 4**::
331
332 ldh [12]
333 jne #0x800, drop
334 ldb [23]
335 jneq #1, drop
336 # get a random uint32 number
337 ld rand
338 mod #4
339 jneq #1, drop
340 ret #-1
341 drop: ret #0
342
343 **SECCOMP filter example**::
344
345 ld [4] /* offsetof(struct seccomp_data, arch) */
346 jne #0xc000003e, bad /* AUDIT_ARCH_X86_64 */
347 ld [0] /* offsetof(struct seccomp_data, nr) */
348 jeq #15, good /* __NR_rt_sigreturn */
349 jeq #231, good /* __NR_exit_group */
350 jeq #60, good /* __NR_exit */
351 jeq #0, good /* __NR_read */
352 jeq #1, good /* __NR_write */
353 jeq #5, good /* __NR_fstat */
354 jeq #9, good /* __NR_mmap */
355 jeq #14, good /* __NR_rt_sigprocmask */
356 jeq #13, good /* __NR_rt_sigaction */
357 jeq #35, good /* __NR_nanosleep */
358 bad: ret #0 /* SECCOMP_RET_KILL_THREAD */
359 good: ret #0x7fff0000 /* SECCOMP_RET_ALLOW */
360
361 Examples for low-level BPF extension:
362
363 **Packet for interface index 13**::
364
365 ld ifidx
366 jneq #13, drop
367 ret #-1
368 drop: ret #0
369
370 **(Accelerated) VLAN w/ id 10**::
371
372 ld vlan_tci
373 jneq #10, drop
374 ret #-1
375 drop: ret #0
376
377 The above example code can be placed into a file (here called "foo"), and
378 then be passed to the bpf_asm tool for generating opcodes, output that xt_bpf
379 and cls_bpf understands and can directly be loaded with. Example with above
380 ARP code::
381
382 $ ./bpf_asm foo
383 4,40 0 0 12,21 0 1 2054,6 0 0 4294967295,6 0 0 0,
384
385 In copy and paste C-like output::
386
387 $ ./bpf_asm -c foo
388 { 0x28, 0, 0, 0x0000000c },
389 { 0x15, 0, 1, 0x00000806 },
390 { 0x06, 0, 0, 0xffffffff },
391 { 0x06, 0, 0, 0000000000 },
392
393 In particular, as usage with xt_bpf or cls_bpf can result in more complex BPF
394 filters that might not be obvious at first, it's good to test filters before
395 attaching to a live system. For that purpose, there's a small tool called
396 bpf_dbg under tools/bpf/ in the kernel source directory. This debugger allows
397 for testing BPF filters against given pcap files, single stepping through the
398 BPF code on the pcap's packets and to do BPF machine register dumps.
399
400 Starting bpf_dbg is trivial and just requires issuing::
401
402 # ./bpf_dbg
403
404 In case input and output do not equal stdin/stdout, bpf_dbg takes an
405 alternative stdin source as a first argument, and an alternative stdout
406 sink as a second one, e.g. `./bpf_dbg test_in.txt test_out.txt`.
407
408 Other than that, a particular libreadline configuration can be set via
409 file "~/.bpf_dbg_init" and the command history is stored in the file
410 "~/.bpf_dbg_history".
411
412 Interaction in bpf_dbg happens through a shell that also has auto-completion
413 support (follow-up example commands starting with '>' denote bpf_dbg shell).
414 The usual workflow would be to ...
415
416 * load bpf 6,40 0 0 12,21 0 3 2048,48 0 0 23,21 0 1 1,6 0 0 65535,6 0 0 0
417 Loads a BPF filter from standard output of bpf_asm, or transformed via
418 e.g. ``tcpdump -iem1 -ddd port 22 | tr '\n' ','``. Note that for JIT
419 debugging (next section), this command creates a temporary socket and
420 loads the BPF code into the kernel. Thus, this will also be useful for
421 JIT developers.
422
423 * load pcap foo.pcap
424
425 Loads standard tcpdump pcap file.
426
427 * run [<n>]
428
429 bpf passes:1 fails:9
430 Runs through all packets from a pcap to account how many passes and fails
431 the filter will generate. A limit of packets to traverse can be given.
432
433 * disassemble::
434
435 l0: ldh [12]
436 l1: jeq #0x800, l2, l5
437 l2: ldb [23]
438 l3: jeq #0x1, l4, l5
439 l4: ret #0xffff
440 l5: ret #0
441
442 Prints out BPF code disassembly.
443
444 * dump::
445
446 /* { op, jt, jf, k }, */
447 { 0x28, 0, 0, 0x0000000c },
448 { 0x15, 0, 3, 0x00000800 },
449 { 0x30, 0, 0, 0x00000017 },
450 { 0x15, 0, 1, 0x00000001 },
451 { 0x06, 0, 0, 0x0000ffff },
452 { 0x06, 0, 0, 0000000000 },
453
454 Prints out C-style BPF code dump.
455
456 * breakpoint 0::
457
458 breakpoint at: l0: ldh [12]
459
460 * breakpoint 1::
461
462 breakpoint at: l1: jeq #0x800, l2, l5
463
464 ...
465
466 Sets breakpoints at particular BPF instructions. Issuing a `run` command
467 will walk through the pcap file continuing from the current packet and
468 break when a breakpoint is being hit (another `run` will continue from
469 the currently active breakpoint executing next instructions):
470
471 * run::
472
473 -- register dump --
474 pc: [0] <-- program counter
475 code: [40] jt[0] jf[0] k[12] <-- plain BPF code of current instruction
476 curr: l0: ldh [12] <-- disassembly of current instruction
477 A: [00000000][0] <-- content of A (hex, decimal)
478 X: [00000000][0] <-- content of X (hex, decimal)
479 M[0,15]: [00000000][0] <-- folded content of M (hex, decimal)
480 -- packet dump -- <-- Current packet from pcap (hex)
481 len: 42
482 0: 00 19 cb 55 55 a4 00 14 a4 43 78 69 08 06 00 01
483 16: 08 00 06 04 00 01 00 14 a4 43 78 69 0a 3b 01 26
484 32: 00 00 00 00 00 00 0a 3b 01 01
485 (breakpoint)
486 >
487
488 * breakpoint::
489
490 breakpoints: 0 1
491
492 Prints currently set breakpoints.
493
494 * step [-<n>, +<n>]
495
496 Performs single stepping through the BPF program from the current pc
497 offset. Thus, on each step invocation, above register dump is issued.
498 This can go forwards and backwards in time, a plain `step` will break
499 on the next BPF instruction, thus +1. (No `run` needs to be issued here.)
500
501 * select <n>
502
503 Selects a given packet from the pcap file to continue from. Thus, on
504 the next `run` or `step`, the BPF program is being evaluated against
505 the user pre-selected packet. Numbering starts just as in Wireshark
506 with index 1.
507
508 * quit
509
510 Exits bpf_dbg.
511
512 JIT compiler
513 ------------
514
515 The Linux kernel has a built-in BPF JIT compiler for x86_64, SPARC,
516 PowerPC, ARM, ARM64, MIPS, RISC-V, s390, and ARC and can be enabled through
517 CONFIG_BPF_JIT. The JIT compiler is transparently invoked for each
518 attached filter from user space or for internal kernel users if it has
519 been previously enabled by root::
520
521 echo 1 > /proc/sys/net/core/bpf_jit_enable
522
523 For JIT developers, doing audits etc, each compile run can output the generated
524 opcode image into the kernel log via::
525
526 echo 2 > /proc/sys/net/core/bpf_jit_enable
527
528 Example output from dmesg::
529
530 [ 3389.935842] flen=6 proglen=70 pass=3 image=ffffffffa0069c8f
531 [ 3389.935847] JIT code: 00000000: 55 48 89 e5 48 83 ec 60 48 89 5d f8 44 8b 4f 68
532 [ 3389.935849] JIT code: 00000010: 44 2b 4f 6c 4c 8b 87 d8 00 00 00 be 0c 00 00 00
533 [ 3389.935850] JIT code: 00000020: e8 1d 94 ff e0 3d 00 08 00 00 75 16 be 17 00 00
534 [ 3389.935851] JIT code: 00000030: 00 e8 28 94 ff e0 83 f8 01 75 07 b8 ff ff 00 00
535 [ 3389.935852] JIT code: 00000040: eb 02 31 c0 c9 c3
536
537 When CONFIG_BPF_JIT_ALWAYS_ON is enabled, bpf_jit_enable is permanently set to 1 and
538 setting any other value than that will return in failure. This is even the case for
539 setting bpf_jit_enable to 2, since dumping the final JIT image into the kernel log
540 is discouraged and introspection through bpftool (under tools/bpf/bpftool/) is the
541 generally recommended approach instead.
542
543 In the kernel source tree under tools/bpf/, there's bpf_jit_disasm for
544 generating disassembly out of the kernel log's hexdump::
545
546 # ./bpf_jit_disasm
547 70 bytes emitted from JIT compiler (pass:3, flen:6)
548 ffffffffa0069c8f + <x>:
549 0: push %rbp
550 1: mov %rsp,%rbp
551 4: sub $0x60,%rsp
552 8: mov %rbx,-0x8(%rbp)
553 c: mov 0x68(%rdi),%r9d
554 10: sub 0x6c(%rdi),%r9d
555 14: mov 0xd8(%rdi),%r8
556 1b: mov $0xc,%esi
557 20: callq 0xffffffffe0ff9442
558 25: cmp $0x800,%eax
559 2a: jne 0x0000000000000042
560 2c: mov $0x17,%esi
561 31: callq 0xffffffffe0ff945e
562 36: cmp $0x1,%eax
563 39: jne 0x0000000000000042
564 3b: mov $0xffff,%eax
565 40: jmp 0x0000000000000044
566 42: xor %eax,%eax
567 44: leaveq
568 45: retq
569
570 Issuing option `-o` will "annotate" opcodes to resulting assembler
571 instructions, which can be very useful for JIT developers:
572
573 # ./bpf_jit_disasm -o
574 70 bytes emitted from JIT compiler (pass:3, flen:6)
575 ffffffffa0069c8f + <x>:
576 0: push %rbp
577 55
578 1: mov %rsp,%rbp
579 48 89 e5
580 4: sub $0x60,%rsp
581 48 83 ec 60
582 8: mov %rbx,-0x8(%rbp)
583 48 89 5d f8
584 c: mov 0x68(%rdi),%r9d
585 44 8b 4f 68
586 10: sub 0x6c(%rdi),%r9d
587 44 2b 4f 6c
588 14: mov 0xd8(%rdi),%r8
589 4c 8b 87 d8 00 00 00
590 1b: mov $0xc,%esi
591 be 0c 00 00 00
592 20: callq 0xffffffffe0ff9442
593 e8 1d 94 ff e0
594 25: cmp $0x800,%eax
595 3d 00 08 00 00
596 2a: jne 0x0000000000000042
597 75 16
598 2c: mov $0x17,%esi
599 be 17 00 00 00
600 31: callq 0xffffffffe0ff945e
601 e8 28 94 ff e0
602 36: cmp $0x1,%eax
603 83 f8 01
604 39: jne 0x0000000000000042
605 75 07
606 3b: mov $0xffff,%eax
607 b8 ff ff 00 00
608 40: jmp 0x0000000000000044
609 eb 02
610 42: xor %eax,%eax
611 31 c0
612 44: leaveq
613 c9
614 45: retq
615 c3
616
617 For BPF JIT developers, bpf_jit_disasm, bpf_asm and bpf_dbg provides a useful
618 toolchain for developing and testing the kernel's JIT compiler.
619
620 BPF kernel internals
621 --------------------
622 Internally, for the kernel interpreter, a different instruction set
623 format with similar underlying principles from BPF described in previous
624 paragraphs is being used. However, the instruction set format is modelled
625 closer to the underlying architecture to mimic native instruction sets, so
626 that a better performance can be achieved (more details later). This new
627 ISA is called eBPF. See the ../bpf/index.rst for details. (Note: eBPF which
628 originates from [e]xtended BPF is not the same as BPF extensions! While
629 eBPF is an ISA, BPF extensions date back to classic BPF's 'overloading'
630 of BPF_LD | BPF_{B,H,W} | BPF_ABS instruction.)
631
632 The new instruction set was originally designed with the possible goal in
633 mind to write programs in "restricted C" and compile into eBPF with a optional
634 GCC/LLVM backend, so that it can just-in-time map to modern 64-bit CPUs with
635 minimal performance overhead over two steps, that is, C -> eBPF -> native code.
636
637 Currently, the new format is being used for running user BPF programs, which
638 includes seccomp BPF, classic socket filters, cls_bpf traffic classifier,
639 team driver's classifier for its load-balancing mode, netfilter's xt_bpf
640 extension, PTP dissector/classifier, and much more. They are all internally
641 converted by the kernel into the new instruction set representation and run
642 in the eBPF interpreter. For in-kernel handlers, this all works transparently
643 by using bpf_prog_create() for setting up the filter, resp.
644 bpf_prog_destroy() for destroying it. The function
645 bpf_prog_run(filter, ctx) transparently invokes eBPF interpreter or JITed
646 code to run the filter. 'filter' is a pointer to struct bpf_prog that we
647 got from bpf_prog_create(), and 'ctx' the given context (e.g.
648 skb pointer). All constraints and restrictions from bpf_check_classic() apply
649 before a conversion to the new layout is being done behind the scenes!
650
651 Currently, the classic BPF format is being used for JITing on most
652 32-bit architectures, whereas x86-64, aarch64, s390x, powerpc64,
653 sparc64, arm32, riscv64, riscv32, loongarch64, arc perform JIT compilation
654 from eBPF instruction set.
655
656 Testing
657 -------
658
659 Next to the BPF toolchain, the kernel also ships a test module that contains
660 various test cases for classic and eBPF that can be executed against
661 the BPF interpreter and JIT compiler. It can be found in lib/test_bpf.c and
662 enabled via Kconfig::
663
664 CONFIG_TEST_BPF=m
665
666 After the module has been built and installed, the test suite can be executed
667 via insmod or modprobe against 'test_bpf' module. Results of the test cases
668 including timings in nsec can be found in the kernel log (dmesg).
669
670 Misc
671 ----
672
673 Also trinity, the Linux syscall fuzzer, has built-in support for BPF and
674 SECCOMP-BPF kernel fuzzing.
675
676 Written by
677 ----------
678
679 The document was written in the hope that it is found useful and in order
680 to give potential BPF hackers or security auditors a better overview of
681 the underlying architecture.
682
683 - Jay Schulist <jschlst@samba.org>
684 - Daniel Borkmann <daniel@iogearbox.net>
685 - Alexei Starovoitov <ast@kernel.org>
686

3. 한국어 전문 번역

영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.

문서 범위 안내

1-15

이 문서는 Linux 소켓 필터링과 고전 BPF를 설명합니다. 과거에는 소켓 필터링과 직접 관련이 없는 eBPF 형식과 메커니즘도 함께 다뤘지만, 현재 eBPF의 자세한 내용은 `../bpf/index.rst`에 정리되어 있습니다.

.. SPDX-License-Identifier: GPL-2.0

.. _networking-filter:

=======================================================
Linux Socket Filtering aka Berkeley Packet Filter (BPF)
=======================================================

Notice
------

This file used to document the eBPF format and mechanisms even when not
related to socket filtering.  The ../bpf/index.rst has more details
on eBPF.

소개

16-69

Linux Socket Filtering(LSF)은 Berkeley Packet Filter에서 유래했습니다. BSD와 Linux 커널의 필터링에는 차이가 있지만 Linux 문맥에서 BPF 또는 LSF라고 하면 같은 커널 필터링 메커니즘을 뜻합니다. 사용자 공간 프로그램은 임의의 소켓에 필터를 붙여 특정 데이터가 소켓을 통과하도록 허용하거나 차단할 수 있으며, Linux의 필터 코드 구조는 BSD BPF와 같아서 BSD `bpf(4)` 매뉴얼도 필터 작성에 도움이 됩니다.

Linux에서는 장치를 따로 관리할 필요 없이 필터 코드를 만든 뒤 `SO_ATTACH_FILTER`로 커널에 전달합니다. 커널 검사를 통과하면 즉시 해당 소켓의 데이터를 필터링합니다. `SO_DETACH_FILTER`로 필터를 떼어낼 수 있고 소켓을 닫으면 자동으로 제거됩니다. 같은 소켓에 새 필터를 붙이면 검사를 통과한 경우에만 기존 필터를 교체하며, 실패하면 기존 필터가 유지됩니다.

`SO_LOCK_FILTER`는 붙어 있는 필터를 잠가 이후 제거하거나 변경하지 못하게 합니다. 권한 있는 프로세스가 소켓을 만들고 필터를 붙여 잠근 다음 권한을 내려도 소켓이 닫힐 때까지 필터가 유지됩니다. 대표 사용자는 libpcap입니다. 예를 들어 `tcpdump -i em1 port 22`는 libpcap 컴파일러를 거쳐 `SO_ATTACH_FILTER`로 적재할 구조를 만들고, `-ddd` 옵션은 실제 구조 내용을 표시합니다.

BPF는 소켓 외에도 netfilter의 `xt_bpf`, qdisc 계층의 `cls_bpf`, `SECCOMP-BPF`, team 드라이버와 PTP 코드 등 여러 곳에서 쓰입니다. 원전은 Steven McCanne과 Van Jacobson이 1993년 발표한 BSD packet filter 논문이며, seccomp 관련 참고 문서는 `Documentation/userspace-api/seccomp_filter.rst`입니다.

Introduction
------------

Linux Socket Filtering (LSF) is derived from the Berkeley Packet Filter.
Though there are some distinct differences between the BSD and Linux
Kernel filtering, but when we speak of BPF or LSF in Linux context, we
mean the very same mechanism of filtering in the Linux kernel.

BPF allows a user-space program to attach a filter onto any socket and
allow or disallow certain types of data to come through the socket. LSF
follows exactly the same filter code structure as BSD's BPF, so referring
to the BSD bpf.4 manpage is very helpful in creating filters.

On Linux, BPF is much simpler than on BSD. One does not have to worry
about devices or anything like that. You simply create your filter code,
send it to the kernel via the SO_ATTACH_FILTER option and if your filter
code passes the kernel check on it, you then immediately begin filtering
data on that socket.

You can also detach filters from your socket via the SO_DETACH_FILTER
option. This will probably not be used much since when you close a socket
that has a filter on it the filter is automagically removed. The other
less common case may be adding a different filter on the same socket where
you had another filter that is still running: the kernel takes care of
removing the old one and placing your new one in its place, assuming your
filter has passed the checks, otherwise if it fails the old filter will
remain on that socket.

SO_LOCK_FILTER option allows to lock the filter attached to a socket. Once
set, a filter cannot be removed or changed. This allows one process to
setup a socket, attach a filter, lock it then drop privileges and be
assured that the filter will be kept until the socket is closed.

The biggest user of this construct might be libpcap. Issuing a high-level
filter command like `tcpdump -i em1 port 22` passes through the libpcap
internal compiler that generates a structure that can eventually be loaded
via SO_ATTACH_FILTER to the kernel. `tcpdump -i em1 port 22 -ddd`
displays what is being placed into this structure.

Although we were only speaking about sockets here, BPF in Linux is used
in many more places. There's xt_bpf for netfilter, cls_bpf in the kernel
qdisc layer, SECCOMP-BPF (SECure COMPuting [1]_), and lots of other places
such as team driver, PTP code, etc where BPF is being used.

.. [1] Documentation/userspace-api/seccomp_filter.rst

Original BPF paper:

Steven McCanne and Van Jacobson. 1993. The BSD packet filter: a new
architecture for user-level packet capture. In Proceedings of the
USENIX Winter 1993 Conference Proceedings on USENIX Winter 1993
Conference Proceedings (USENIX'93). USENIX Association, Berkeley,
CA, USA, 2-2. [http://www.tcpdump.org/papers/bpf-usenix93.pdf]

필터 구조체

70-94

사용자 공간 프로그램은 `<linux/filter.h>`의 `struct sock_filter`를 사용합니다. 각 필터 블록은 실제 명령 코드인 16비트 `code`, 참과 거짓 분기 오프셋인 8비트 `jt`와 `jf`, 명령별 범용 인수인 32비트 `k`의 4튜플입니다.

`SO_ATTACH_FILTER`에 전달하는 `struct sock_fprog`는 필터 블록 수 `len`과 `struct sock_filter __user *filter`를 담습니다. 소켓 필터링에서는 이 구조체를 가리키는 포인터를 `setsockopt(2)`로 커널에 넘깁니다.

고전 BPF 명령 형식
필드역할
code16비트연산 코드
jt8비트조건이 참일 때의 점프 오프셋
jf8비트조건이 거짓일 때의 점프 오프셋
k32비트명령에 따라 해석되는 범용 값

한 명령을 이루는 네 필드를 구조화했습니다.

Structure
---------

User space applications include <linux/filter.h> which contains the
following relevant structures::

        struct sock_filter {        /* Filter block */
                __u16        code;   /* Actual filter code */
                __u8        jt;        /* Jump true */
                __u8        jf;        /* Jump false */
                __u32        k;      /* Generic multiuse field */
        };

Such a structure is assembled as an array of 4-tuples, that contains
a code, jt, jf and k value. jt and jf are jump offsets and k a generic
value to be used for a provided code::

        struct sock_fprog {                        /* Required for SO_ATTACH_FILTER. */
                unsigned short                   len;        /* Number of filter blocks */
                struct sock_filter __user *filter;
        };

For socket filtering, a pointer to this structure (as shown in
follow-up example) is being passed to the kernel through setsockopt(2).

소켓 필터 예제

95-182

예제는 `PF_PACKET`, `SOCK_RAW`, `ETH_P_ALL` 소켓을 만들고 `tcpdump -i em1 port 22 -dd`가 만든 `struct sock_filter` 배열을 `sock_fprog`에 넣어 `SO_ATTACH_FILTER`로 부착합니다. 이 필터는 포트 22를 사용하는 IPv4와 IPv6 패킷만 통과시키고 나머지 패킷은 해당 소켓에서 버립니다.

`SO_DETACH_FILTER`를 사용하는 `setsockopt(2)` 호출에는 별도 인수가 필요하지 않으며, 필터 분리를 막는 `SO_LOCK_FILTER`에는 0 또는 1의 정수를 전달합니다. 소켓 필터는 `PF_PACKET`에만 제한되지 않고 다른 소켓 주소군에도 사용할 수 있습니다.

패킷 소켓의 일반적인 필터링은 고수준 문법을 제공하는 libpcap으로 처리하는 편이 좋습니다. 직접 작성은 libpcap을 연결할 수 없거나, Linux 전용 확장이 필요하거나, libpcap 컴파일러로 깔끔하게 표현하기 어려운 복잡한 필터가 있거나, 생성 코드를 다르게 최적화해야 할 때 유용합니다. `xt_bpf`, `cls_bpf`, 여러 반환 코드를 가진 경로, BPF JIT 시험 사례가 대표적입니다.

소켓 필터 제어
옵션역할
SO_ATTACH_FILTER검증된 필터를 부착하거나 기존 필터 교체
SO_DETACH_FILTER부착한 필터 제거
SO_LOCK_FILTER소켓이 닫힐 때까지 제거와 변경 금지

필터의 생명 주기를 담당하는 소켓 옵션입니다.

Example
-------

::

    #include <sys/socket.h>
    #include <sys/types.h>
    #include <arpa/inet.h>
    #include <linux/if_ether.h>
    /* ... */

    /* From the example above: tcpdump -i em1 port 22 -dd */
    struct sock_filter code[] = {
            { 0x28,  0,  0, 0x0000000c },
            { 0x15,  0,  8, 0x000086dd },
            { 0x30,  0,  0, 0x00000014 },
            { 0x15,  2,  0, 0x00000084 },
            { 0x15,  1,  0, 0x00000006 },
            { 0x15,  0, 17, 0x00000011 },
            { 0x28,  0,  0, 0x00000036 },
            { 0x15, 14,  0, 0x00000016 },
            { 0x28,  0,  0, 0x00000038 },
            { 0x15, 12, 13, 0x00000016 },
            { 0x15,  0, 12, 0x00000800 },
            { 0x30,  0,  0, 0x00000017 },
            { 0x15,  2,  0, 0x00000084 },
            { 0x15,  1,  0, 0x00000006 },
            { 0x15,  0,  8, 0x00000011 },
            { 0x28,  0,  0, 0x00000014 },
            { 0x45,  6,  0, 0x00001fff },
            { 0xb1,  0,  0, 0x0000000e },
            { 0x48,  0,  0, 0x0000000e },
            { 0x15,  2,  0, 0x00000016 },
            { 0x48,  0,  0, 0x00000010 },
            { 0x15,  0,  1, 0x00000016 },
            { 0x06,  0,  0, 0x0000ffff },
            { 0x06,  0,  0, 0x00000000 },
    };

    struct sock_fprog bpf = {
            .len = ARRAY_SIZE(code),
            .filter = code,
    };

    sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
    if (sock < 0)
            /* ... bail out ... */

    ret = setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &bpf, sizeof(bpf));
    if (ret < 0)
            /* ... bail out ... */

    /* ... */
    close(sock);

The above example code attaches a socket filter for a PF_PACKET socket
in order to let all IPv4/IPv6 packets with port 22 pass. The rest will
be dropped for this socket.

The setsockopt(2) call to SO_DETACH_FILTER doesn't need any arguments
and SO_LOCK_FILTER for preventing the filter to be detached, takes an
integer value with 0 or 1.

Note that socket filters are not restricted to PF_PACKET sockets only,
but can also be used on other socket families.

Summary of system calls:

 * setsockopt(sockfd, SOL_SOCKET, SO_ATTACH_FILTER, &val, sizeof(val));
 * setsockopt(sockfd, SOL_SOCKET, SO_DETACH_FILTER, &val, sizeof(val));
 * setsockopt(sockfd, SOL_SOCKET, SO_LOCK_FILTER,   &val, sizeof(val));

Normally, most use cases for socket filtering on packet sockets will be
covered by libpcap in high-level syntax, so as an application developer
you should stick to that. libpcap wraps its own layer around all that.

Unless i) using/linking to libpcap is not an option, ii) the required BPF
filters use Linux extensions that are not supported by libpcap's compiler,
iii) a filter might be more complex and not cleanly implementable with
libpcap's compiler, or iv) particular filter codes should be optimized
differently than libpcap's internal compiler does; then in such cases
writing such a filter "by hand" can be of an alternative. For example,
xt_bpf and cls_bpf users might have requirements that could result in
more complex filter code, or one that cannot be expressed with libpcap
(e.g. different return codes for various code paths). Moreover, BPF JIT
implementors may wish to manually write test cases and thus need low-level
access to BPF code as well.

BPF 엔진과 명령 형식

183-219

커널 소스의 `tools/bpf/`에는 저수준 필터를 작성하는 `bpf_asm` 도구가 있습니다. 이 문서는 읽기 어려운 원시 opcode 대신 Steven McCanne과 Van Jacobson의 논문을 본뜬 어셈블리형 문법을 사용합니다. 원리는 원시 opcode와 같습니다.

고전 BPF 아키텍처는 32비트 누산기 `A`, 32비트 인덱스 레지스터 `X`, 0부터 15까지 접근할 수 있는 16개의 32비트 임시 레지스터 `M[]`로 구성됩니다. `bpf_asm`이 opcode로 바꾸는 각 명령은 `op:16, jt:8, jf:8, k:32` 형식입니다. `op`는 명령, `jt`와 `jf`는 참/거짓 점프 대상, `k`는 명령에 따라 다르게 해석되는 인수입니다.

명령 집합에는 적재, 저장, 분기, 산술/논리, 기타 변환, 반환 명령이 있습니다. 이어지는 표의 `bpf_asm` 문법은 `<linux/filter.h>`에 정의된 실제 opcode와 대응합니다.

BPF engine and instruction set
------------------------------

Under tools/bpf/ there's a small helper tool called bpf_asm which can
be used to write low-level filters for example scenarios mentioned in the
previous section. Asm-like syntax mentioned here has been implemented in
bpf_asm and will be used for further explanations (instead of dealing with
less readable opcodes directly, principles are the same). The syntax is
closely modelled after Steven McCanne's and Van Jacobson's BPF paper.

The BPF architecture consists of the following basic elements:

  =======          ====================================================
  Element          Description
  =======          ====================================================
  A                32 bit wide accumulator
  X                32 bit wide X register
  M[]              16 x 32 bit wide misc registers aka "scratch memory
                   store", addressable from 0 to 15
  =======          ====================================================

A program, that is translated by bpf_asm into "opcodes" is an array that
consists of the following elements (as already mentioned)::

  op:16, jt:8, jf:8, k:32

The element op is a 16 bit wide opcode that has a particular instruction
encoded. jt and jf are two 8 bit wide jump targets, one for condition
"jump if true", the other one "jump if false". Eventually, element k
contains a miscellaneous argument that can be interpreted in different
ways depending on the given instruction in op.

The instruction set consists of load, store, branch, alu, miscellaneous
and return instructions that are also represented in bpf_asm syntax. This
table lists all bpf_asm instructions available resp. what their underlying
opcodes as defined in linux/filter.h stand for:

명령, 주소 지정, 커널 확장

220-309

`ld`, `ldh`, `ldb`는 패킷이나 메모리에서 word, half-word, byte를 `A`로 읽고 `ldx`, `ldxb`는 `X`로 읽습니다. `st`와 `stx`는 `A`와 `X`를 `M[]`에 저장합니다. `jmp`/`ja`는 무조건 분기하고 `jeq`, `jneq`/`jne`, `jlt`, `jle`, `jgt`, `jge`, `jset`은 비교 또는 비트 검사의 결과에 따라 분기합니다.

산술/논리 명령은 `add`, `sub`, `mul`, `div`, `mod`, `neg`, `and`, `or`, `xor`, `lsh`, `rsh`입니다. `tax`는 `A`를 `X`로, `txa`는 `X`를 `A`로 복사하고 `ret`은 필터 결과를 반환합니다. 주소 지정은 `X`, 패킷의 고정 오프셋 `[k]`, 인덱스 오프셋 `[x + k]`, 임시 메모리 `M[k]`, 리터럴 `#k`, IPv4 헤더 길이형 `4*([k]&0xf)`, 레이블과 조건 분기 대상, `A`, BPF 확장을 지원합니다.

Linux 커널 확장은 적재 명령의 `k`를 음수 오프셋과 확장 오프셋 조합으로 오버로드하며 결과를 `A`에 넣습니다. `len`, `proto`, `type`, `poff`, `ifidx`, `nla`, `nlan`, `mark`, `queue`, `hatype`, `rxhash`, `cpu`, `vlan_tci`, `vlan_avail`, `vlan_tpid`, `rand`가 각각 `skb` 길이와 프로토콜, 패킷 유형, payload 시작점, 인터페이스, netlink 속성, mark/queue, 장치 유형, 해시, CPU, VLAN 정보, 난수에 접근합니다. 확장 이름 앞에는 `#`도 붙일 수 있습니다.

BPF 실행 자원
범주대표 명령데이터 흐름
적재ld, ldh, ldb, ldx패킷/상수/확장 -> A 또는 X
저장st, stxA 또는 X -> M[0..15]
분기ja, jeq, jset조건 -> 참/거짓 레이블
ALUadd, div, xor, lshA와 피연산자 -> A
변환/반환tax, txa, ret레지스터 복사 또는 결과 반환

명령 표를 실행 관점에서 묶었습니다.

  ===========      ===================  =====================
  Instruction      Addressing mode      Description
  ===========      ===================  =====================
  ld               1, 2, 3, 4, 12       Load word into A
  ldi              4                    Load word into A
  ldh              1, 2                 Load half-word into A
  ldb              1, 2                 Load byte into A
  ldx              3, 4, 5, 12          Load word into X
  ldxi             4                    Load word into X
  ldxb             5                    Load byte into X

  st               3                    Store A into M[]
  stx              3                    Store X into M[]

  jmp              6                    Jump to label
  ja               6                    Jump to label
  jeq              7, 8, 9, 10          Jump on A == <x>
  jneq             9, 10                Jump on A != <x>
  jne              9, 10                Jump on A != <x>
  jlt              9, 10                Jump on A <  <x>
  jle              9, 10                Jump on A <= <x>
  jgt              7, 8, 9, 10          Jump on A >  <x>
  jge              7, 8, 9, 10          Jump on A >= <x>
  jset             7, 8, 9, 10          Jump on A &  <x>

  add              0, 4                 A + <x>
  sub              0, 4                 A - <x>
  mul              0, 4                 A * <x>
  div              0, 4                 A / <x>
  mod              0, 4                 A % <x>
  neg                                   !A
  and              0, 4                 A & <x>
  or               0, 4                 A | <x>
  xor              0, 4                 A ^ <x>
  lsh              0, 4                 A << <x>
  rsh              0, 4                 A >> <x>

  tax                                   Copy A into X
  txa                                   Copy X into A

  ret              4, 11                Return
  ===========      ===================  =====================

The next table shows addressing formats from the 2nd column:

  ===============  ===================  ===============================================
  Addressing mode  Syntax               Description
  ===============  ===================  ===============================================
   0               x/%x                 Register X
   1               [k]                  BHW at byte offset k in the packet
   2               [x + k]              BHW at the offset X + k in the packet
   3               M[k]                 Word at offset k in M[]
   4               #k                   Literal value stored in k
   5               4*([k]&0xf)          Lower nibble * 4 at byte offset k in the packet
   6               L                    Jump label L
   7               #k,Lt,Lf             Jump to Lt if true, otherwise jump to Lf
   8               x/%x,Lt,Lf           Jump to Lt if true, otherwise jump to Lf
   9               #k,Lt                Jump to Lt if predicate is true
  10               x/%x,Lt              Jump to Lt if predicate is true
  11               a/%a                 Accumulator A
  12               extension            BPF extension
  ===============  ===================  ===============================================

The Linux kernel also has a couple of BPF extensions that are used along
with the class of load instructions by "overloading" the k argument with
a negative offset + a particular extension offset. The result of such BPF
extensions are loaded into A.

Possible BPF extensions are shown in the following table:

  ===================================   =================================================
  Extension                             Description
  ===================================   =================================================
  len                                   skb->len
  proto                                 skb->protocol
  type                                  skb->pkt_type
  poff                                  Payload start offset
  ifidx                                 skb->dev->ifindex
  nla                                   Netlink attribute of type X with offset A
  nlan                                  Nested Netlink attribute of type X with offset A
  mark                                  skb->mark
  queue                                 skb->queue_mapping
  hatype                                skb->dev->type
  rxhash                                skb->hash
  cpu                                   raw_smp_processor_id()
  vlan_tci                              skb_vlan_tag_get(skb)
  vlan_avail                            skb_vlan_tag_present(skb)
  vlan_tpid                             skb->vlan_proto
  rand                                  get_random_u32()
  ===================================   =================================================

저수준 필터 예제

310-376

ARP 예제는 이더넷 유형 필드 `[12]`를 half-word로 읽어 `0x806`이 아니면 버리고, 맞으면 `-1`을 반환해 통과시킵니다. IPv4 TCP 예제는 EtherType `0x800`과 IP 프로토콜 번호 6을 차례로 확인합니다. ICMP 무작위 표본 예제는 IPv4와 ICMP를 확인한 뒤 `rand`를 4로 나눈 나머지가 1인 패킷만 통과시켜 약 4개 중 1개를 선택합니다.

SECCOMP 예제는 `struct seccomp_data`에서 아키텍처와 시스템 호출 번호를 읽습니다. `AUDIT_ARCH_X86_64`가 아니면 스레드를 종료하고, `rt_sigreturn`, `exit_group`, `exit`, `read`, `write`, `fstat`, `mmap`, `rt_sigprocmask`, `rt_sigaction`, `nanosleep`만 `SECCOMP_RET_ALLOW`로 허용합니다.

확장 예제는 `ifidx`가 13인 패킷과 가속 VLAN 태그 ID가 10인 패킷을 각각 선택합니다. 모든 어셈블리와 정확한 opcode, 상수, 레이블은 아래 원문 블록에 그대로 보존되어 있습니다.


These extensions can also be prefixed with '#'.
Examples for low-level BPF:

**ARP packets**::

  ldh [12]
  jne #0x806, drop
  ret #-1
  drop: ret #0

**IPv4 TCP packets**::

  ldh [12]
  jne #0x800, drop
  ldb [23]
  jneq #6, drop
  ret #-1
  drop: ret #0

**icmp random packet sampling, 1 in 4**::

  ldh [12]
  jne #0x800, drop
  ldb [23]
  jneq #1, drop
  # get a random uint32 number
  ld rand
  mod #4
  jneq #1, drop
  ret #-1
  drop: ret #0

**SECCOMP filter example**::

  ld [4]                  /* offsetof(struct seccomp_data, arch) */
  jne #0xc000003e, bad    /* AUDIT_ARCH_X86_64 */
  ld [0]                  /* offsetof(struct seccomp_data, nr) */
  jeq #15, good           /* __NR_rt_sigreturn */
  jeq #231, good          /* __NR_exit_group */
  jeq #60, good           /* __NR_exit */
  jeq #0, good            /* __NR_read */
  jeq #1, good            /* __NR_write */
  jeq #5, good            /* __NR_fstat */
  jeq #9, good            /* __NR_mmap */
  jeq #14, good           /* __NR_rt_sigprocmask */
  jeq #13, good           /* __NR_rt_sigaction */
  jeq #35, good           /* __NR_nanosleep */
  bad: ret #0             /* SECCOMP_RET_KILL_THREAD */
  good: ret #0x7fff0000   /* SECCOMP_RET_ALLOW */

Examples for low-level BPF extension:

**Packet for interface index 13**::

  ld ifidx
  jneq #13, drop
  ret #-1
  drop: ret #0

**(Accelerated) VLAN w/ id 10**::

  ld vlan_tci
  jneq #10, drop
  ret #-1
  drop: ret #0

bpf_asm과 bpf_dbg 시작

377-421

저수준 코드는 파일에 저장한 뒤 `bpf_asm`에 전달할 수 있습니다. 기본 출력은 `xt_bpf`와 `cls_bpf`가 바로 읽는 쉼표 구분 opcode이고, `-c`는 복사해 C 코드에 넣을 수 있는 `sock_filter` 초기화 형식을 출력합니다.

복잡한 필터는 운영 시스템에 붙이기 전에 `tools/bpf/bpf_dbg`로 시험하는 편이 좋습니다. 이 도구는 pcap 패킷을 대상으로 필터를 실행하고, 단일 단계로 명령을 진행하며 BPF 머신 레지스터를 덤프합니다. 인수 없이 실행하면 표준 입출력을 쓰고, 첫째와 둘째 인수로 대체 입력과 출력을 지정할 수 있습니다. readline 설정은 `~/.bpf_dbg_init`, 명령 기록은 `~/.bpf_dbg_history`에 저장됩니다.

`load bpf`는 `bpf_asm` 또는 `tcpdump -ddd`를 변환한 명령열을 읽습니다. JIT 디버깅 때는 임시 소켓을 만들고 코드를 커널에 적재하므로 JIT 개발자에게도 유용합니다. `load pcap`은 표준 tcpdump pcap 파일을 엽니다.

The above example code can be placed into a file (here called "foo"), and
then be passed to the bpf_asm tool for generating opcodes, output that xt_bpf
and cls_bpf understands and can directly be loaded with. Example with above
ARP code::

    $ ./bpf_asm foo
    4,40 0 0 12,21 0 1 2054,6 0 0 4294967295,6 0 0 0,

In copy and paste C-like output::

    $ ./bpf_asm -c foo
    { 0x28,  0,  0, 0x0000000c },
    { 0x15,  0,  1, 0x00000806 },
    { 0x06,  0,  0, 0xffffffff },
    { 0x06,  0,  0, 0000000000 },

In particular, as usage with xt_bpf or cls_bpf can result in more complex BPF
filters that might not be obvious at first, it's good to test filters before
attaching to a live system. For that purpose, there's a small tool called
bpf_dbg under tools/bpf/ in the kernel source directory. This debugger allows
for testing BPF filters against given pcap files, single stepping through the
BPF code on the pcap's packets and to do BPF machine register dumps.

Starting bpf_dbg is trivial and just requires issuing::

    # ./bpf_dbg

In case input and output do not equal stdin/stdout, bpf_dbg takes an
alternative stdin source as a first argument, and an alternative stdout
sink as a second one, e.g. `./bpf_dbg test_in.txt test_out.txt`.

Other than that, a particular libreadline configuration can be set via
file "~/.bpf_dbg_init" and the command history is stored in the file
"~/.bpf_dbg_history".

Interaction in bpf_dbg happens through a shell that also has auto-completion
support (follow-up example commands starting with '>' denote bpf_dbg shell).
The usual workflow would be to ...

* load bpf 6,40 0 0 12,21 0 3 2048,48 0 0 23,21 0 1 1,6 0 0 65535,6 0 0 0
  Loads a BPF filter from standard output of bpf_asm, or transformed via
  e.g. ``tcpdump -iem1 -ddd port 22 | tr '\n' ','``. Note that for JIT
  debugging (next section), this command creates a temporary socket and
  loads the BPF code into the kernel. Thus, this will also be useful for
  JIT developers.

bpf_dbg 명령

422-510

`run [n]`은 pcap의 전체 또는 지정한 수의 패킷에 필터를 실행해 통과와 실패 수를 집계합니다. `disassemble`은 레이블이 붙은 BPF 어셈블리를, `dump`는 C 형식의 `{ op, jt, jf, k }` 배열을 출력합니다.

`breakpoint n`은 지정한 BPF 명령에 중단점을 설정합니다. 이후 `run`은 현재 패킷부터 실행하다 중단점에서 멈추며, 다시 실행하면 다음 명령부터 계속합니다. 멈출 때는 프로그램 카운터, 현재 원시 명령, 디스어셈블 결과, `A`, `X`, `M[0..15]`, 현재 pcap 패킷의 16진 덤프가 표시됩니다. 인수 없는 `breakpoint`는 설정된 중단점 목록을 보여 줍니다.

`step [-n, +n]`은 현재 프로그램 카운터를 기준으로 앞이나 뒤로 단일 단계 실행하며 매번 레지스터 덤프를 냅니다. 인수 없는 `step`은 다음 명령으로 한 단계 이동합니다. `select n`은 Wireshark처럼 1부터 번호를 매긴 pcap 패킷을 골라 다음 `run` 또는 `step`의 입력으로 사용하고, `quit`은 디버거를 종료합니다.

bpf_dbg 시험 흐름
load bpfload pcaprun
disassemble / dumpbreakpointstepregister + packet dump
select packet재실행pass/fail 확인

필터와 패킷을 불러와 실행 상태를 조사하는 순서입니다.


* load pcap foo.pcap

  Loads standard tcpdump pcap file.

* run [<n>]

bpf passes:1 fails:9
  Runs through all packets from a pcap to account how many passes and fails
  the filter will generate. A limit of packets to traverse can be given.

* disassemble::

        l0:        ldh [12]
        l1:        jeq #0x800, l2, l5
        l2:        ldb [23]
        l3:        jeq #0x1, l4, l5
        l4:        ret #0xffff
        l5:        ret #0

  Prints out BPF code disassembly.

* dump::

        /* { op, jt, jf, k }, */
        { 0x28,  0,  0, 0x0000000c },
        { 0x15,  0,  3, 0x00000800 },
        { 0x30,  0,  0, 0x00000017 },
        { 0x15,  0,  1, 0x00000001 },
        { 0x06,  0,  0, 0x0000ffff },
        { 0x06,  0,  0, 0000000000 },

  Prints out C-style BPF code dump.

* breakpoint 0::

        breakpoint at: l0:        ldh [12]

* breakpoint 1::

        breakpoint at: l1:        jeq #0x800, l2, l5

  ...

  Sets breakpoints at particular BPF instructions. Issuing a `run` command
  will walk through the pcap file continuing from the current packet and
  break when a breakpoint is being hit (another `run` will continue from
  the currently active breakpoint executing next instructions):

  * run::

        -- register dump --
        pc:       [0]                       <-- program counter
        code:     [40] jt[0] jf[0] k[12]    <-- plain BPF code of current instruction
        curr:     l0:        ldh [12]              <-- disassembly of current instruction
        A:        [00000000][0]             <-- content of A (hex, decimal)
        X:        [00000000][0]             <-- content of X (hex, decimal)
        M[0,15]:  [00000000][0]             <-- folded content of M (hex, decimal)
        -- packet dump --                   <-- Current packet from pcap (hex)
        len: 42
            0: 00 19 cb 55 55 a4 00 14 a4 43 78 69 08 06 00 01
        16: 08 00 06 04 00 01 00 14 a4 43 78 69 0a 3b 01 26
        32: 00 00 00 00 00 00 0a 3b 01 01
        (breakpoint)
        >

  * breakpoint::

        breakpoints: 0 1

    Prints currently set breakpoints.

* step [-<n>, +<n>]

  Performs single stepping through the BPF program from the current pc
  offset. Thus, on each step invocation, above register dump is issued.
  This can go forwards and backwards in time, a plain `step` will break
  on the next BPF instruction, thus +1. (No `run` needs to be issued here.)

* select <n>

  Selects a given packet from the pcap file to continue from. Thus, on
  the next `run` or `step`, the BPF program is being evaluated against
  the user pre-selected packet. Numbering starts just as in Wireshark
  with index 1.

* quit

  Exits bpf_dbg.

JIT 컴파일러 제어

511-541

Linux 커널에는 x86_64, SPARC, PowerPC, ARM, ARM64, MIPS, RISC-V, s390, ARC용 BPF JIT 컴파일러가 있으며 `CONFIG_BPF_JIT`로 활성화합니다. root가 `/proc/sys/net/core/bpf_jit_enable`에 1을 쓰면 사용자 공간이나 커널 내부 사용자가 붙이는 필터마다 JIT가 투명하게 호출됩니다.

개발과 감사를 위해 값을 2로 설정하면 각 컴파일의 생성 opcode 이미지를 커널 로그에 기록합니다. `CONFIG_BPF_JIT_ALWAYS_ON`이면 값이 1로 고정되고 2를 포함한 다른 값은 거부됩니다. 최종 JIT 이미지를 커널 로그에 덤프하는 방식은 권장되지 않으며, 일반적인 검사는 `tools/bpf/bpftool/`의 bpftool을 사용하는 편이 좋습니다.


JIT compiler
------------

The Linux kernel has a built-in BPF JIT compiler for x86_64, SPARC,
PowerPC, ARM, ARM64, MIPS, RISC-V, s390, and ARC and can be enabled through
CONFIG_BPF_JIT. The JIT compiler is transparently invoked for each
attached filter from user space or for internal kernel users if it has
been previously enabled by root::

  echo 1 > /proc/sys/net/core/bpf_jit_enable

For JIT developers, doing audits etc, each compile run can output the generated
opcode image into the kernel log via::

  echo 2 > /proc/sys/net/core/bpf_jit_enable

Example output from dmesg::

    [ 3389.935842] flen=6 proglen=70 pass=3 image=ffffffffa0069c8f
    [ 3389.935847] JIT code: 00000000: 55 48 89 e5 48 83 ec 60 48 89 5d f8 44 8b 4f 68
    [ 3389.935849] JIT code: 00000010: 44 2b 4f 6c 4c 8b 87 d8 00 00 00 be 0c 00 00 00
    [ 3389.935850] JIT code: 00000020: e8 1d 94 ff e0 3d 00 08 00 00 75 16 be 17 00 00
    [ 3389.935851] JIT code: 00000030: 00 e8 28 94 ff e0 83 f8 01 75 07 b8 ff ff 00 00
    [ 3389.935852] JIT code: 00000040: eb 02 31 c0 c9 c3

When CONFIG_BPF_JIT_ALWAYS_ON is enabled, bpf_jit_enable is permanently set to 1 and
setting any other value than that will return in failure. This is even the case for
setting bpf_jit_enable to 2, since dumping the final JIT image into the kernel log
is discouraged and introspection through bpftool (under tools/bpf/bpftool/) is the
generally recommended approach instead.

JIT 코드 디스어셈블

542-619

커널 소스의 `tools/bpf/bpf_jit_disasm`은 커널 로그의 16진 JIT 덤프를 어셈블리로 변환합니다. 예제에서는 6개 BPF 명령이 세 번의 패스를 거쳐 70바이트 x86-64 코드가 되었고, 출력은 이미지 주소를 기준으로 push, move, call, compare, branch, return 명령을 보여 줍니다.

`bpf_jit_disasm -o`는 각 어셈블리 명령 아래에 대응하는 기계어 바이트를 함께 붙입니다. `bpf_jit_disasm`, `bpf_asm`, `bpf_dbg`는 BPF JIT 개발자가 필터 작성, 커널 적재, 실행 추적, 생성 코드 검사를 이어서 수행할 수 있는 도구 체인을 이룹니다.


In the kernel source tree under tools/bpf/, there's bpf_jit_disasm for
generating disassembly out of the kernel log's hexdump::

        # ./bpf_jit_disasm
        70 bytes emitted from JIT compiler (pass:3, flen:6)
        ffffffffa0069c8f + <x>:
        0:        push   %rbp
        1:        mov    %rsp,%rbp
        4:        sub    $0x60,%rsp
        8:        mov    %rbx,-0x8(%rbp)
        c:        mov    0x68(%rdi),%r9d
        10:        sub    0x6c(%rdi),%r9d
        14:        mov    0xd8(%rdi),%r8
        1b:        mov    $0xc,%esi
        20:        callq  0xffffffffe0ff9442
        25:        cmp    $0x800,%eax
        2a:        jne    0x0000000000000042
        2c:        mov    $0x17,%esi
        31:        callq  0xffffffffe0ff945e
        36:        cmp    $0x1,%eax
        39:        jne    0x0000000000000042
        3b:        mov    $0xffff,%eax
        40:        jmp    0x0000000000000044
        42:        xor    %eax,%eax
        44:        leaveq
        45:        retq

        Issuing option `-o` will "annotate" opcodes to resulting assembler
        instructions, which can be very useful for JIT developers:

        # ./bpf_jit_disasm -o
        70 bytes emitted from JIT compiler (pass:3, flen:6)
        ffffffffa0069c8f + <x>:
        0:        push   %rbp
                55
        1:        mov    %rsp,%rbp
                48 89 e5
        4:        sub    $0x60,%rsp
                48 83 ec 60
        8:        mov    %rbx,-0x8(%rbp)
                48 89 5d f8
        c:        mov    0x68(%rdi),%r9d
                44 8b 4f 68
        10:        sub    0x6c(%rdi),%r9d
                44 2b 4f 6c
        14:        mov    0xd8(%rdi),%r8
                4c 8b 87 d8 00 00 00
        1b:        mov    $0xc,%esi
                be 0c 00 00 00
        20:        callq  0xffffffffe0ff9442
                e8 1d 94 ff e0
        25:        cmp    $0x800,%eax
                3d 00 08 00 00
        2a:        jne    0x0000000000000042
                75 16
        2c:        mov    $0x17,%esi
                be 17 00 00 00
        31:        callq  0xffffffffe0ff945e
                e8 28 94 ff e0
        36:        cmp    $0x1,%eax
                83 f8 01
        39:        jne    0x0000000000000042
                75 07
        3b:        mov    $0xffff,%eax
                b8 ff ff 00 00
        40:        jmp    0x0000000000000044
                eb 02
        42:        xor    %eax,%eax
                31 c0
        44:        leaveq
                c9
        45:        retq
                c3

For BPF JIT developers, bpf_jit_disasm, bpf_asm and bpf_dbg provides a useful
toolchain for developing and testing the kernel's JIT compiler.

BPF 커널 내부

620-655

커널 인터프리터 내부에서는 앞에서 설명한 고전 BPF와 원리는 비슷하지만 형식이 다른 명령 집합을 사용합니다. 네이티브 명령 집합에 더 가깝게 설계해 성능을 높인 이 ISA가 eBPF입니다. eBPF의 `e`는 extended를 뜻하지만, 고전 BPF 적재 명령의 `k`를 오버로드하는 'BPF 확장'과는 다른 개념입니다.

새 형식은 제한된 C 프로그램을 GCC/LLVM 백엔드로 eBPF에 컴파일한 뒤 64비트 CPU 네이티브 코드로 JIT 변환해 `C -> eBPF -> native` 두 단계의 오버헤드를 최소화하려는 목표로 설계되었습니다.

seccomp BPF, 고전 소켓 필터, `cls_bpf`, team 드라이버 분류기, netfilter `xt_bpf`, PTP 분류기 등 사용자 BPF 프로그램은 커널 내부에서 eBPF 표현으로 변환되어 인터프리터 또는 JIT 코드에서 실행됩니다. 커널 내부 사용자는 `bpf_prog_create()`와 `bpf_prog_destroy()`로 프로그램을 관리하고 `bpf_prog_run(filter, ctx)`로 실행합니다. 변환 전에는 `bpf_check_classic()`의 모든 제약과 검사가 적용됩니다.

대부분의 32비트 아키텍처는 고전 BPF 형식에서 JIT하지만 x86-64, aarch64, s390x, powerpc64, sparc64, arm32, riscv64, riscv32, loongarch64, arc는 eBPF 명령 집합에서 JIT 컴파일합니다.

BPF kernel internals
--------------------
Internally, for the kernel interpreter, a different instruction set
format with similar underlying principles from BPF described in previous
paragraphs is being used. However, the instruction set format is modelled
closer to the underlying architecture to mimic native instruction sets, so
that a better performance can be achieved (more details later). This new
ISA is called eBPF.  See the ../bpf/index.rst for details.  (Note: eBPF which
originates from [e]xtended BPF is not the same as BPF extensions! While
eBPF is an ISA, BPF extensions date back to classic BPF's 'overloading'
of BPF_LD | BPF_{B,H,W} | BPF_ABS instruction.)

The new instruction set was originally designed with the possible goal in
mind to write programs in "restricted C" and compile into eBPF with a optional
GCC/LLVM backend, so that it can just-in-time map to modern 64-bit CPUs with
minimal performance overhead over two steps, that is, C -> eBPF -> native code.

Currently, the new format is being used for running user BPF programs, which
includes seccomp BPF, classic socket filters, cls_bpf traffic classifier,
team driver's classifier for its load-balancing mode, netfilter's xt_bpf
extension, PTP dissector/classifier, and much more. They are all internally
converted by the kernel into the new instruction set representation and run
in the eBPF interpreter. For in-kernel handlers, this all works transparently
by using bpf_prog_create() for setting up the filter, resp.
bpf_prog_destroy() for destroying it. The function
bpf_prog_run(filter, ctx) transparently invokes eBPF interpreter or JITed
code to run the filter. 'filter' is a pointer to struct bpf_prog that we
got from bpf_prog_create(), and 'ctx' the given context (e.g.
skb pointer). All constraints and restrictions from bpf_check_classic() apply
before a conversion to the new layout is being done behind the scenes!

Currently, the classic BPF format is being used for JITing on most
32-bit architectures, whereas x86-64, aarch64, s390x, powerpc64,
sparc64, arm32, riscv64, riscv32, loongarch64, arc perform JIT compilation
from eBPF instruction set.

시험

656-669

BPF 도구 체인 외에도 커널은 고전 BPF와 eBPF를 인터프리터와 JIT에서 실행하는 여러 시험 사례를 `lib/test_bpf.c`에 제공합니다. `CONFIG_TEST_BPF=m`으로 모듈을 빌드하고 설치한 뒤 `insmod` 또는 `modprobe test_bpf`로 시험 모음을 실행합니다. 각 시험 결과와 나노초 단위 실행 시간은 커널 로그에서 확인할 수 있습니다.

Testing
-------

Next to the BPF toolchain, the kernel also ships a test module that contains
various test cases for classic and eBPF that can be executed against
the BPF interpreter and JIT compiler. It can be found in lib/test_bpf.c and
enabled via Kconfig::

  CONFIG_TEST_BPF=m

After the module has been built and installed, the test suite can be executed
via insmod or modprobe against 'test_bpf' module. Results of the test cases
including timings in nsec can be found in the kernel log (dmesg).

기타 사항과 작성자

670-685

Linux 시스템 호출 퍼저 trinity도 BPF와 `SECCOMP-BPF` 커널 퍼징을 기본 지원합니다. 이 문서는 잠재적인 BPF 개발자와 보안 감사자가 기반 아키텍처를 더 잘 이해할 수 있도록 Jay Schulist, Daniel Borkmann, Alexei Starovoitov가 작성했습니다.

Misc
----

Also trinity, the Linux syscall fuzzer, has built-in support for BPF and
SECCOMP-BPF kernel fuzzing.

Written by
----------

The document was written in the hope that it is found useful and in order
to give potential BPF hackers or security auditors a better overview of
the underlying architecture.

- Jay Schulist <jschlst@samba.org>
- Daniel Borkmann <daniel@iogearbox.net>
- Alexei Starovoitov <ast@kernel.org>