LCOV - code coverage report
Current view: top level - bpfilter/cgen - stub.c (source / functions) Coverage Total Hit
Test: lcov.out Lines: 0.0 % 110 0
Test Date: 2025-05-27 09:39:07 Functions: 0.0 % 6 0

            Line data    Source code
       1              : /* SPDX-License-Identifier: GPL-2.0-only */
       2              : /*
       3              :  * Copyright (c) 2023 Meta Platforms, Inc. and affiliates.
       4              :  */
       5              : 
       6              : #include "bpfilter/cgen/stub.h"
       7              : 
       8              : #include <linux/bpf.h>
       9              : #include <linux/bpf_common.h>
      10              : #include <linux/icmpv6.h>
      11              : #include <linux/if_ether.h>
      12              : #include <linux/in.h> // NOLINT
      13              : #include <linux/in6.h>
      14              : #include <linux/ip.h>
      15              : #include <linux/ipv6.h>
      16              : #include <linux/tcp.h>
      17              : #include <linux/udp.h>
      18              : 
      19              : #include <endian.h>
      20              : #include <stddef.h>
      21              : 
      22              : #include "bpfilter/cgen/fixup.h"
      23              : #include "bpfilter/cgen/jmp.h"
      24              : #include "bpfilter/cgen/printer.h"
      25              : #include "bpfilter/cgen/program.h"
      26              : #include "bpfilter/cgen/swich.h"
      27              : #include "bpfilter/opts.h"
      28              : #include "core/flavor.h"
      29              : #include "core/helper.h"
      30              : #include "core/verdict.h"
      31              : 
      32              : #include "external/filter.h"
      33              : 
      34              : /**
      35              :  * Generate stub to create a dynptr.
      36              :  *
      37              :  * @param program Program to generate the stub for. Must not be NULL.
      38              :  * @param arg_reg Register where the first argument to the dynptr creation
      39              :  *        function is located (SKB or xdp_md structure).
      40              :  * @param kfunc Name of the kfunc to use to create the dynamic pointer.
      41              :  * @return 0 on success, or negative errno value on error.
      42              :  */
      43            0 : static int _bf_stub_make_ctx_dynptr(struct bf_program *program, int arg_reg,
      44              :                                     const char *kfunc)
      45              : {
      46            0 :     bf_assert(program && kfunc);
      47              : 
      48              :     // Call bpf_dynptr_from_xxx()
      49            0 :     if (arg_reg != BPF_REG_1)
      50            0 :         EMIT(program, BPF_MOV64_IMM(BPF_REG_1, arg_reg));
      51            0 :     EMIT(program, BPF_MOV64_IMM(BPF_REG_2, 0));
      52            0 :     EMIT(program, BPF_MOV64_REG(BPF_REG_3, BPF_REG_10));
      53            0 :     EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, BF_PROG_CTX_OFF(dynptr)));
      54            0 :     EMIT_KFUNC_CALL(program, kfunc);
      55              : 
      56              :     // If the function call failed, quit the program
      57              :     {
      58            0 :         _clean_bf_jmpctx_ struct bf_jmpctx _ =
      59            0 :             bf_jmpctx_get(program, BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 0));
      60              : 
      61              :         // Update the error counter
      62            0 :         EMIT(program,
      63              :              BPF_MOV32_IMM(BPF_REG_1, bf_program_error_counter_idx(program)));
      64            0 :         EMIT(program, BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_10,
      65              :                                   BF_PROG_CTX_OFF(pkt_size)));
      66            0 :         EMIT_FIXUP_CALL(program, BF_FIXUP_FUNC_UPDATE_COUNTERS);
      67              : 
      68            0 :         if (bf_opts_is_verbose(BF_VERBOSE_BPF))
      69            0 :             EMIT_PRINT(program, "failed to create a new dynamic pointer");
      70              : 
      71            0 :         EMIT(program,
      72              :              BPF_MOV64_IMM(BPF_REG_0, program->runtime.ops->get_verdict(
      73              :                                           BF_VERDICT_ACCEPT)));
      74            0 :         EMIT(program, BPF_EXIT_INSN());
      75              :     }
      76              : 
      77            0 :     return 0;
      78              : }
      79              : 
      80            0 : int bf_stub_make_ctx_xdp_dynptr(struct bf_program *program, int md_reg)
      81              : {
      82            0 :     bf_assert(program);
      83              : 
      84            0 :     return _bf_stub_make_ctx_dynptr(program, md_reg, "bpf_dynptr_from_xdp");
      85              : }
      86              : 
      87            0 : int bf_stub_make_ctx_skb_dynptr(struct bf_program *program, int skb_reg)
      88              : {
      89            0 :     bf_assert(program);
      90              : 
      91            0 :     return _bf_stub_make_ctx_dynptr(program, skb_reg, "bpf_dynptr_from_skb");
      92              : }
      93              : 
      94            0 : int bf_stub_parse_l2_ethhdr(struct bf_program *program)
      95              : {
      96            0 :     bf_assert(program);
      97              : 
      98              :     // Call bpf_dynptr_slice()
      99            0 :     EMIT(program, BPF_MOV64_REG(BPF_REG_1, BPF_REG_10));
     100            0 :     EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, BF_PROG_CTX_OFF(dynptr)));
     101            0 :     EMIT(program, BPF_MOV64_IMM(BPF_REG_2, 0));
     102            0 :     EMIT(program, BPF_MOV64_REG(BPF_REG_3, BPF_REG_10));
     103            0 :     EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, BF_PROG_CTX_OFF(l2)));
     104            0 :     EMIT(program, BPF_MOV64_IMM(BPF_REG_4, sizeof(struct ethhdr)));
     105            0 :     EMIT_KFUNC_CALL(program, "bpf_dynptr_slice");
     106              : 
     107              :     // If the function call failed, quit the program
     108              :     {
     109            0 :         _clean_bf_jmpctx_ struct bf_jmpctx _ =
     110            0 :             bf_jmpctx_get(program, BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 0));
     111              : 
     112              :         // Update the error counter
     113            0 :         EMIT(program,
     114              :              BPF_MOV32_IMM(BPF_REG_1, bf_program_error_counter_idx(program)));
     115            0 :         EMIT(program, BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_10,
     116              :                                   BF_PROG_CTX_OFF(pkt_size)));
     117            0 :         EMIT_FIXUP_CALL(program, BF_FIXUP_FUNC_UPDATE_COUNTERS);
     118              : 
     119            0 :         if (bf_opts_is_verbose(BF_VERBOSE_BPF))
     120            0 :             EMIT_PRINT(program, "failed to create L2 dynamic pointer slice");
     121              : 
     122            0 :         EMIT(program,
     123              :              BPF_MOV64_IMM(BPF_REG_0, program->runtime.ops->get_verdict(
     124              :                                           BF_VERDICT_ACCEPT)));
     125            0 :         EMIT(program, BPF_EXIT_INSN());
     126              :     }
     127              : 
     128              :     // Store the L2 header address into the runtime context
     129            0 :     EMIT(program,
     130              :          BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_0, BF_PROG_CTX_OFF(l2_hdr)));
     131              : 
     132              :     // Store the L3 protocol ID in r7
     133            0 :     EMIT(program, BPF_LDX_MEM(BPF_H, BPF_REG_7, BPF_REG_0,
     134              :                               offsetof(struct ethhdr, h_proto)));
     135              : 
     136              :     // Set bf_program_context.l3_offset
     137            0 :     EMIT(program, BPF_ST_MEM(BPF_W, BPF_REG_10, BF_PROG_CTX_OFF(l3_offset),
     138              :                              sizeof(struct ethhdr)));
     139              : 
     140            0 :     return 0;
     141              : }
     142              : 
     143            0 : int bf_stub_parse_l3_hdr(struct bf_program *program)
     144              : {
     145            0 :     _clean_bf_jmpctx_ struct bf_jmpctx _ = bf_jmpctx_default();
     146              :     int r;
     147              : 
     148            0 :     bf_assert(program);
     149              : 
     150              :     /* Store the size of the L3 protocol header in r4, depending on the protocol
     151              :      * ID stored in r7. If the protocol is not supported, we store 0 into r7
     152              :      * and we skip the instructions below. */
     153              :     {
     154            0 :         _clean_bf_swich_ struct bf_swich swich =
     155            0 :             bf_swich_get(program, BPF_REG_7);
     156              : 
     157            0 :         EMIT_SWICH_OPTION(&swich, htobe16(ETH_P_IP),
     158              :                           BPF_MOV64_IMM(BPF_REG_4, sizeof(struct iphdr)));
     159            0 :         EMIT_SWICH_OPTION(&swich, htobe16(ETH_P_IPV6),
     160              :                           BPF_MOV64_IMM(BPF_REG_4, sizeof(struct ipv6hdr)));
     161            0 :         EMIT_SWICH_DEFAULT(&swich, BPF_MOV64_IMM(BPF_REG_7, 0));
     162              : 
     163            0 :         r = bf_swich_generate(&swich);
     164            0 :         if (r)
     165              :             return r;
     166              :     }
     167            0 :     _ = bf_jmpctx_get(program, BPF_JMP_IMM(BPF_JEQ, BPF_REG_7, 0, 0));
     168              : 
     169              :     // Call bpf_dynptr_slice()
     170            0 :     EMIT(program, BPF_MOV64_REG(BPF_REG_1, BPF_REG_10));
     171            0 :     EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, BF_PROG_CTX_OFF(dynptr)));
     172            0 :     EMIT(program,
     173              :          BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_10, BF_PROG_CTX_OFF(l3_offset)));
     174            0 :     EMIT(program, BPF_MOV64_REG(BPF_REG_3, BPF_REG_10));
     175            0 :     EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, BF_PROG_CTX_OFF(l2)));
     176            0 :     EMIT_KFUNC_CALL(program, "bpf_dynptr_slice");
     177              : 
     178              :     // If the function call failed, quit the program
     179              :     {
     180            0 :         _clean_bf_jmpctx_ struct bf_jmpctx _ =
     181            0 :             bf_jmpctx_get(program, BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 0));
     182              : 
     183              :         // Update the error counter
     184            0 :         EMIT(program,
     185              :              BPF_MOV32_IMM(BPF_REG_1, bf_program_error_counter_idx(program)));
     186            0 :         EMIT(program, BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_10,
     187              :                                   BF_PROG_CTX_OFF(pkt_size)));
     188            0 :         EMIT_FIXUP_CALL(program, BF_FIXUP_FUNC_UPDATE_COUNTERS);
     189              : 
     190            0 :         if (bf_opts_is_verbose(BF_VERBOSE_BPF))
     191            0 :             EMIT_PRINT(program, "failed to create L3 dynamic pointer slice");
     192              : 
     193            0 :         EMIT(program,
     194              :              BPF_MOV64_IMM(BPF_REG_0, program->runtime.ops->get_verdict(
     195              :                                           BF_VERDICT_ACCEPT)));
     196            0 :         EMIT(program, BPF_EXIT_INSN());
     197              :     }
     198              : 
     199              :     // Store the L3 header address into the runtime context
     200            0 :     EMIT(program,
     201              :          BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_0, BF_PROG_CTX_OFF(l3_hdr)));
     202              : 
     203              :     /* Unsupported L3 protocols have been filtered out at the beginning of this
     204              :      * function and would jump over the block below, so there is no need to
     205              :      * worry about them here. */
     206              :     {
     207            0 :         _clean_bf_swich_ struct bf_swich swich =
     208            0 :             bf_swich_get(program, BPF_REG_7);
     209              : 
     210            0 :         EMIT_SWICH_OPTION(&swich, htobe16(ETH_P_IP),
     211              :                           BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0),
     212              :                           BPF_ALU64_IMM(BPF_AND, BPF_REG_1, 0x0f),
     213              :                           BPF_ALU64_IMM(BPF_LSH, BPF_REG_1, 2),
     214              :                           BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_10,
     215              :                                       BF_PROG_CTX_OFF(l3_offset)),
     216              :                           BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_2),
     217              :                           BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_1,
     218              :                                       BF_PROG_CTX_OFF(l4_offset)),
     219              :                           BPF_LDX_MEM(BPF_B, BPF_REG_8, BPF_REG_0,
     220              :                                       offsetof(struct iphdr, protocol)));
     221            0 :         EMIT_SWICH_OPTION(&swich, htobe16(ETH_P_IPV6),
     222              :                           BPF_MOV64_IMM(BPF_REG_1, sizeof(struct ipv6hdr)),
     223              :                           BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_10,
     224              :                                       BF_PROG_CTX_OFF(l3_offset)),
     225              :                           BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_2),
     226              :                           BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_1,
     227              :                                       BF_PROG_CTX_OFF(l4_offset)),
     228              :                           BPF_LDX_MEM(BPF_B, BPF_REG_8, BPF_REG_0,
     229              :                                       offsetof(struct ipv6hdr, nexthdr)));
     230              : 
     231            0 :         r = bf_swich_generate(&swich);
     232            0 :         if (r)
     233              :             return r;
     234              :     }
     235              : 
     236            0 :     return 0;
     237              : }
     238              : 
     239            0 : int bf_stub_parse_l4_hdr(struct bf_program *program)
     240              : {
     241            0 :     _clean_bf_jmpctx_ struct bf_jmpctx _ = bf_jmpctx_default();
     242              :     int r;
     243              : 
     244            0 :     bf_assert(program);
     245              : 
     246              :     /* Parse the L4 protocol and handle unuspported protocol, similarly to
     247              :      * bf_stub_parse_l3_hdr() above. */
     248              :     {
     249            0 :         _clean_bf_swich_ struct bf_swich swich =
     250            0 :             bf_swich_get(program, BPF_REG_8);
     251              : 
     252            0 :         EMIT_SWICH_OPTION(&swich, IPPROTO_TCP,
     253              :                           BPF_MOV64_IMM(BPF_REG_4, sizeof(struct tcphdr)));
     254            0 :         EMIT_SWICH_OPTION(&swich, IPPROTO_UDP,
     255              :                           BPF_MOV64_IMM(BPF_REG_4, sizeof(struct udphdr)));
     256            0 :         EMIT_SWICH_OPTION(&swich, IPPROTO_ICMP,
     257              :                           BPF_MOV64_IMM(BPF_REG_4, sizeof(struct udphdr)));
     258            0 :         EMIT_SWICH_OPTION(&swich, IPPROTO_ICMPV6,
     259              :                           BPF_MOV64_IMM(BPF_REG_4, sizeof(struct icmp6hdr)));
     260            0 :         EMIT_SWICH_DEFAULT(&swich, BPF_MOV64_IMM(BPF_REG_8, 0));
     261              : 
     262            0 :         r = bf_swich_generate(&swich);
     263            0 :         if (r)
     264              :             return r;
     265              :     }
     266            0 :     _ = bf_jmpctx_get(program, BPF_JMP_IMM(BPF_JEQ, BPF_REG_8, 0, 0));
     267              : 
     268              :     // Call bpf_dynptr_slice()
     269            0 :     EMIT(program, BPF_MOV64_REG(BPF_REG_1, BPF_REG_10));
     270            0 :     EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, BF_PROG_CTX_OFF(dynptr)));
     271            0 :     EMIT(program,
     272              :          BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_10, BF_PROG_CTX_OFF(l4_offset)));
     273            0 :     EMIT(program, BPF_MOV64_REG(BPF_REG_3, BPF_REG_10));
     274            0 :     EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, BF_PROG_CTX_OFF(l4)));
     275            0 :     EMIT_KFUNC_CALL(program, "bpf_dynptr_slice");
     276              : 
     277              :     // If the function call failed, quit the program
     278              :     {
     279            0 :         _clean_bf_jmpctx_ struct bf_jmpctx _ =
     280            0 :             bf_jmpctx_get(program, BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 0));
     281              : 
     282              :         // Update the error counter
     283            0 :         EMIT(program,
     284              :              BPF_MOV32_IMM(BPF_REG_1, bf_program_error_counter_idx(program)));
     285            0 :         EMIT(program, BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_10,
     286              :                                   BF_PROG_CTX_OFF(pkt_size)));
     287            0 :         EMIT_FIXUP_CALL(program, BF_FIXUP_FUNC_UPDATE_COUNTERS);
     288              : 
     289            0 :         if (bf_opts_is_verbose(BF_VERBOSE_BPF))
     290            0 :             EMIT_PRINT(program, "failed to create L4 dynamic pointer slice");
     291              : 
     292            0 :         EMIT(program,
     293              :              BPF_MOV64_IMM(BPF_REG_0, program->runtime.ops->get_verdict(
     294              :                                           BF_VERDICT_ACCEPT)));
     295            0 :         EMIT(program, BPF_EXIT_INSN());
     296              :     }
     297              : 
     298              :     // Store the L4 header address into the runtime context
     299            0 :     EMIT(program,
     300              :          BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_0, BF_PROG_CTX_OFF(l4_hdr)));
     301              : 
     302            0 :     return 0;
     303              : }
        

Generated by: LCOV version 2.0-1