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 83 if (nfp_prog->act == NN_ACT_XDP) 84 return 0; 85 86 if (reg0->type != CONST_IMM) { 87 pr_info("unsupported exit state: %d, imm: %llx\n", 88 reg0->type, reg0->imm); 89 return -EINVAL; 90 } 91 92 if (nfp_prog->act != NN_ACT_DIRECT && 93 reg0->imm != 0 && (reg0->imm & ~0U) != ~0U) { 94 pr_info("unsupported exit state: %d, imm: %llx\n", 95 reg0->type, reg0->imm); 96 return -EINVAL; 97 } 98 99 if (nfp_prog->act == NN_ACT_DIRECT && reg0->imm <= TC_ACT_REDIRECT && 100 reg0->imm != TC_ACT_SHOT && reg0->imm != TC_ACT_STOLEN && 101 reg0->imm != TC_ACT_QUEUED) { 102 pr_info("unsupported exit state: %d, imm: %llx\n", 103 reg0->type, reg0->imm); 104 return -EINVAL; 105 } 106 107 return 0; 108 } 109 110 static int 111 nfp_bpf_check_ctx_ptr(struct nfp_prog *nfp_prog, 112 const struct bpf_verifier_env *env, u8 reg) 113 { 114 if (env->cur_state.regs[reg].type != PTR_TO_CTX) 115 return -EINVAL; 116 117 return 0; 118 } 119 120 static int 121 nfp_verify_insn(struct bpf_verifier_env *env, int insn_idx, int prev_insn_idx) 122 { 123 struct nfp_bpf_analyzer_priv *priv = env->analyzer_priv; 124 struct nfp_insn_meta *meta = priv->meta; 125 126 meta = nfp_bpf_goto_meta(priv->prog, meta, insn_idx, env->prog->len); 127 priv->meta = meta; 128 129 if (meta->insn.src_reg == BPF_REG_10 || 130 meta->insn.dst_reg == BPF_REG_10) { 131 pr_err("stack not yet supported\n"); 132 return -EINVAL; 133 } 134 if (meta->insn.src_reg >= MAX_BPF_REG || 135 meta->insn.dst_reg >= MAX_BPF_REG) { 136 pr_err("program uses extended registers - jit hardening?\n"); 137 return -EINVAL; 138 } 139 140 if (meta->insn.code == (BPF_JMP | BPF_EXIT)) 141 return nfp_bpf_check_exit(priv->prog, env); 142 143 if ((meta->insn.code & ~BPF_SIZE_MASK) == (BPF_LDX | BPF_MEM)) 144 return nfp_bpf_check_ctx_ptr(priv->prog, env, 145 meta->insn.src_reg); 146 if ((meta->insn.code & ~BPF_SIZE_MASK) == (BPF_STX | BPF_MEM)) 147 return nfp_bpf_check_ctx_ptr(priv->prog, env, 148 meta->insn.dst_reg); 149 150 return 0; 151 } 152 153 static const struct bpf_ext_analyzer_ops nfp_bpf_analyzer_ops = { 154 .insn_hook = nfp_verify_insn, 155 }; 156 157 int nfp_prog_verify(struct nfp_prog *nfp_prog, struct bpf_prog *prog) 158 { 159 struct nfp_bpf_analyzer_priv *priv; 160 int ret; 161 162 priv = kzalloc(sizeof(*priv), GFP_KERNEL); 163 if (!priv) 164 return -ENOMEM; 165 166 priv->prog = nfp_prog; 167 priv->meta = nfp_prog_first_meta(nfp_prog); 168 169 ret = bpf_analyzer(prog, &nfp_bpf_analyzer_ops, priv); 170 171 kfree(priv); 172 173 return ret; 174 } 175