1 /* 2 * Copyright (C) 2016 Netronome Systems, Inc. 3 * 4 * This software is dual licensed under the GNU General License Version 2, 5 * June 1991 as shown in the file COPYING in the top-level directory of this 6 * source tree or the BSD 2-Clause License provided below. You have the 7 * option to license this software under the complete terms of either license. 8 * 9 * The BSD 2-Clause License: 10 * 11 * Redistribution and use in source and binary forms, with or 12 * without modification, are permitted provided that the following 13 * conditions are met: 14 * 15 * 1. Redistributions of source code must retain the above 16 * copyright notice, this list of conditions and the following 17 * disclaimer. 18 * 19 * 2. Redistributions in binary form must reproduce the above 20 * copyright notice, this list of conditions and the following 21 * disclaimer in the documentation and/or other materials 22 * provided with the distribution. 23 * 24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 27 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 28 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 29 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 30 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 31 * SOFTWARE. 32 */ 33 34 #define pr_fmt(fmt) "NFP net bpf: " fmt 35 36 #include <linux/bpf.h> 37 #include <linux/bpf_verifier.h> 38 #include <linux/kernel.h> 39 #include <linux/pkt_cls.h> 40 41 #include "main.h" 42 43 /* Analyzer/verifier definitions */ 44 struct nfp_bpf_analyzer_priv { 45 struct nfp_prog *prog; 46 struct nfp_insn_meta *meta; 47 }; 48 49 static struct nfp_insn_meta * 50 nfp_bpf_goto_meta(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta, 51 unsigned int insn_idx, unsigned int n_insns) 52 { 53 unsigned int forward, backward, i; 54 55 backward = meta->n - insn_idx; 56 forward = insn_idx - meta->n; 57 58 if (min(forward, backward) > n_insns - insn_idx - 1) { 59 backward = n_insns - insn_idx - 1; 60 meta = nfp_prog_last_meta(nfp_prog); 61 } 62 if (min(forward, backward) > insn_idx && backward > insn_idx) { 63 forward = insn_idx; 64 meta = nfp_prog_first_meta(nfp_prog); 65 } 66 67 if (forward < backward) 68 for (i = 0; i < forward; i++) 69 meta = nfp_meta_next(meta); 70 else 71 for (i = 0; i < backward; i++) 72 meta = nfp_meta_prev(meta); 73 74 return meta; 75 } 76 77 static int 78 nfp_bpf_check_exit(struct nfp_prog *nfp_prog, 79 const struct bpf_verifier_env *env) 80 { 81 const struct bpf_reg_state *reg0 = &env->cur_state.regs[0]; 82 u64 imm; 83 84 if (nfp_prog->act == NN_ACT_XDP) 85 return 0; 86 87 if (!(reg0->type == SCALAR_VALUE && tnum_is_const(reg0->var_off))) { 88 char tn_buf[48]; 89 90 tnum_strn(tn_buf, sizeof(tn_buf), reg0->var_off); 91 pr_info("unsupported exit state: %d, var_off: %s\n", 92 reg0->type, tn_buf); 93 return -EINVAL; 94 } 95 96 imm = reg0->var_off.value; 97 if (nfp_prog->act != NN_ACT_DIRECT && imm != 0 && (imm & ~0U) != ~0U) { 98 pr_info("unsupported exit state: %d, imm: %llx\n", 99 reg0->type, imm); 100 return -EINVAL; 101 } 102 103 if (nfp_prog->act == NN_ACT_DIRECT && imm <= TC_ACT_REDIRECT && 104 imm != TC_ACT_SHOT && imm != TC_ACT_STOLEN && 105 imm != TC_ACT_QUEUED) { 106 pr_info("unsupported exit state: %d, imm: %llx\n", 107 reg0->type, imm); 108 return -EINVAL; 109 } 110 111 return 0; 112 } 113 114 static int 115 nfp_bpf_check_ctx_ptr(struct nfp_prog *nfp_prog, 116 const struct bpf_verifier_env *env, u8 reg) 117 { 118 if (env->cur_state.regs[reg].type != PTR_TO_CTX) 119 return -EINVAL; 120 121 return 0; 122 } 123 124 static int 125 nfp_verify_insn(struct bpf_verifier_env *env, int insn_idx, int prev_insn_idx) 126 { 127 struct nfp_bpf_analyzer_priv *priv = env->analyzer_priv; 128 struct nfp_insn_meta *meta = priv->meta; 129 130 meta = nfp_bpf_goto_meta(priv->prog, meta, insn_idx, env->prog->len); 131 priv->meta = meta; 132 133 if (meta->insn.src_reg == BPF_REG_10 || 134 meta->insn.dst_reg == BPF_REG_10) { 135 pr_err("stack not yet supported\n"); 136 return -EINVAL; 137 } 138 if (meta->insn.src_reg >= MAX_BPF_REG || 139 meta->insn.dst_reg >= MAX_BPF_REG) { 140 pr_err("program uses extended registers - jit hardening?\n"); 141 return -EINVAL; 142 } 143 144 if (meta->insn.code == (BPF_JMP | BPF_EXIT)) 145 return nfp_bpf_check_exit(priv->prog, env); 146 147 if ((meta->insn.code & ~BPF_SIZE_MASK) == (BPF_LDX | BPF_MEM)) 148 return nfp_bpf_check_ctx_ptr(priv->prog, env, 149 meta->insn.src_reg); 150 if ((meta->insn.code & ~BPF_SIZE_MASK) == (BPF_STX | BPF_MEM)) 151 return nfp_bpf_check_ctx_ptr(priv->prog, env, 152 meta->insn.dst_reg); 153 154 return 0; 155 } 156 157 static const struct bpf_ext_analyzer_ops nfp_bpf_analyzer_ops = { 158 .insn_hook = nfp_verify_insn, 159 }; 160 161 int nfp_prog_verify(struct nfp_prog *nfp_prog, struct bpf_prog *prog) 162 { 163 struct nfp_bpf_analyzer_priv *priv; 164 int ret; 165 166 priv = kzalloc(sizeof(*priv), GFP_KERNEL); 167 if (!priv) 168 return -ENOMEM; 169 170 priv->prog = nfp_prog; 171 priv->meta = nfp_prog_first_meta(nfp_prog); 172 173 ret = bpf_analyzer(prog, &nfp_bpf_analyzer_ops, priv); 174 175 kfree(priv); 176 177 return ret; 178 } 179