1 /* Copyright (c) 2012 The Chromium OS Authors. All rights reserved. 2 * Use of this source code is governed by a BSD-style license that can be 3 * found in the LICENSE file. 4 */ 5 6 #include <stdint.h> 7 #include <stdio.h> 8 #include <stdlib.h> 9 #include <string.h> 10 11 #include "bpf.h" 12 #include "util.h" 13 14 /* Architecture validation. */ 15 size_t bpf_validate_arch(struct sock_filter *filter) 16 { 17 struct sock_filter *curr_block = filter; 18 set_bpf_stmt(curr_block++, BPF_LD + BPF_W + BPF_ABS, arch_nr); 19 set_bpf_jump(curr_block++, BPF_JMP + BPF_JEQ + BPF_K, ARCH_NR, SKIP, 20 NEXT); 21 set_bpf_ret_kill(curr_block++); 22 return curr_block - filter; 23 } 24 25 /* Syscall number eval functions. */ 26 size_t bpf_allow_syscall(struct sock_filter *filter, int nr) 27 { 28 struct sock_filter *curr_block = filter; 29 set_bpf_jump(curr_block++, BPF_JMP + BPF_JEQ + BPF_K, nr, NEXT, SKIP); 30 set_bpf_stmt(curr_block++, BPF_RET + BPF_K, SECCOMP_RET_ALLOW); 31 return curr_block - filter; 32 } 33 34 size_t bpf_allow_syscall_args(struct sock_filter *filter, int nr, 35 unsigned int id) 36 { 37 struct sock_filter *curr_block = filter; 38 set_bpf_jump(curr_block++, BPF_JMP + BPF_JEQ + BPF_K, nr, NEXT, SKIP); 39 set_bpf_jump_lbl(curr_block++, id); 40 return curr_block - filter; 41 } 42 43 /* Size-aware arg loaders. */ 44 #if defined(BITS32) 45 size_t bpf_load_arg(struct sock_filter *filter, int argidx) 46 { 47 set_bpf_stmt(filter, BPF_LD + BPF_W + BPF_ABS, LO_ARG(argidx)); 48 return 1U; 49 } 50 #elif defined(BITS64) 51 size_t bpf_load_arg(struct sock_filter *filter, int argidx) 52 { 53 struct sock_filter *curr_block = filter; 54 set_bpf_stmt(curr_block++, BPF_LD + BPF_W + BPF_ABS, LO_ARG(argidx)); 55 set_bpf_stmt(curr_block++, BPF_ST, 0); /* lo -> M[0] */ 56 set_bpf_stmt(curr_block++, BPF_LD + BPF_W + BPF_ABS, HI_ARG(argidx)); 57 set_bpf_stmt(curr_block++, BPF_ST, 1); /* hi -> M[1] */ 58 return curr_block - filter; 59 } 60 #endif 61 62 /* Size-aware equality comparison. */ 63 size_t bpf_comp_jeq32(struct sock_filter *filter, unsigned long c, 64 unsigned char jt, unsigned char jf) 65 { 66 unsigned int lo = (unsigned int)(c & 0xFFFFFFFF); 67 set_bpf_jump(filter, BPF_JMP + BPF_JEQ + BPF_K, lo, jt, jf); 68 return 1U; 69 } 70 71 /* 72 * On 64 bits, we have to do two 32-bit comparisons. 73 * We jump true when *both* comparisons are true. 74 */ 75 #if defined(BITS64) 76 size_t bpf_comp_jeq64(struct sock_filter *filter, uint64_t c, unsigned char jt, 77 unsigned char jf) 78 { 79 unsigned int lo = (unsigned int)(c & 0xFFFFFFFF); 80 unsigned int hi = (unsigned int)(c >> 32); 81 82 struct sock_filter *curr_block = filter; 83 84 /* bpf_load_arg leaves |hi| in A */ 85 curr_block += bpf_comp_jeq32(curr_block, hi, NEXT, SKIPN(2) + jf); 86 set_bpf_stmt(curr_block++, BPF_LD + BPF_MEM, 0); /* swap in |lo| */ 87 curr_block += bpf_comp_jeq32(curr_block, lo, jt, jf); 88 89 return curr_block - filter; 90 } 91 #endif 92 93 /* Size-aware bitwise AND. */ 94 size_t bpf_comp_jset32(struct sock_filter *filter, unsigned long mask, 95 unsigned char jt, unsigned char jf) 96 { 97 unsigned int mask_lo = (unsigned int)(mask & 0xFFFFFFFF); 98 set_bpf_jump(filter, BPF_JMP + BPF_JSET + BPF_K, mask_lo, jt, jf); 99 return 1U; 100 } 101 102 /* 103 * On 64 bits, we have to do two 32-bit bitwise ANDs. 104 * We jump true when *either* bitwise AND is true (non-zero). 105 */ 106 #if defined(BITS64) 107 size_t bpf_comp_jset64(struct sock_filter *filter, uint64_t mask, 108 unsigned char jt, unsigned char jf) 109 { 110 unsigned int mask_lo = (unsigned int)(mask & 0xFFFFFFFF); 111 unsigned int mask_hi = (unsigned int)(mask >> 32); 112 113 struct sock_filter *curr_block = filter; 114 115 /* bpf_load_arg leaves |hi| in A */ 116 curr_block += bpf_comp_jset32(curr_block, mask_hi, SKIPN(2) + jt, NEXT); 117 set_bpf_stmt(curr_block++, BPF_LD + BPF_MEM, 0); /* swap in |lo| */ 118 curr_block += bpf_comp_jset32(curr_block, mask_lo, jt, jf); 119 120 return curr_block - filter; 121 } 122 #endif 123 124 size_t bpf_comp_jin(struct sock_filter *filter, unsigned long mask, 125 unsigned char jt, unsigned char jf) 126 { 127 unsigned long negative_mask = ~mask; 128 /* 129 * The mask is negated, so the comparison will be true when the argument 130 * includes a flag that wasn't listed in the original (non-negated) 131 * mask. This would be the failure case, so we switch |jt| and |jf|. 132 */ 133 return bpf_comp_jset(filter, negative_mask, jf, jt); 134 } 135 136 size_t bpf_arg_comp(struct sock_filter **pfilter, int op, int argidx, 137 unsigned long c, unsigned int label_id) 138 { 139 struct sock_filter *filter = 140 calloc(BPF_ARG_COMP_LEN + 1, sizeof(struct sock_filter)); 141 struct sock_filter *curr_block = filter; 142 size_t (*comp_function)(struct sock_filter * filter, unsigned long k, 143 unsigned char jt, unsigned char jf); 144 int flip = 0; 145 146 /* Load arg */ 147 curr_block += bpf_load_arg(curr_block, argidx); 148 149 /* Jump type */ 150 switch (op) { 151 case EQ: 152 comp_function = bpf_comp_jeq; 153 flip = 0; 154 break; 155 case NE: 156 comp_function = bpf_comp_jeq; 157 flip = 1; 158 break; 159 case SET: 160 comp_function = bpf_comp_jset; 161 flip = 0; 162 break; 163 case IN: 164 comp_function = bpf_comp_jin; 165 flip = 0; 166 break; 167 default: 168 *pfilter = NULL; 169 return 0; 170 } 171 172 /* 173 * It's easier for the rest of the code to have the true branch 174 * skip and the false branch fall through. 175 */ 176 unsigned char jt = flip ? NEXT : SKIP; 177 unsigned char jf = flip ? SKIP : NEXT; 178 curr_block += comp_function(curr_block, c, jt, jf); 179 curr_block += set_bpf_jump_lbl(curr_block, label_id); 180 181 *pfilter = filter; 182 return curr_block - filter; 183 } 184 185 void dump_bpf_filter(struct sock_filter *filter, unsigned short len) 186 { 187 int i = 0; 188 189 printf("len == %d\n", len); 190 printf("filter:\n"); 191 for (i = 0; i < len; i++) { 192 printf("%d: \t{ code=%#x, jt=%u, jf=%u, k=%#x \t}\n", i, 193 filter[i].code, filter[i].jt, filter[i].jf, filter[i].k); 194 } 195 } 196 197 void dump_bpf_prog(struct sock_fprog *fprog) 198 { 199 struct sock_filter *filter = fprog->filter; 200 unsigned short len = fprog->len; 201 dump_bpf_filter(filter, len); 202 } 203 204 int bpf_resolve_jumps(struct bpf_labels *labels, struct sock_filter *filter, 205 size_t len) 206 { 207 struct sock_filter *instr; 208 size_t i, offset; 209 210 if (len > BPF_MAXINSNS) 211 return -1; 212 213 /* 214 * Walk it once, backwards, to build the label table and do fixups. 215 * Since backward jumps are disallowed by BPF, this is easy. 216 */ 217 for (i = 0; i < len; i++) { 218 offset = len - i - 1; 219 instr = &filter[offset]; 220 if (instr->code != (BPF_JMP + BPF_JA)) 221 continue; 222 switch ((instr->jt << 8) | instr->jf) { 223 case (JUMP_JT << 8) | JUMP_JF: 224 if (instr->k >= labels->count) { 225 warn("nonexistent label id: %u", instr->k); 226 return -1; 227 } 228 if (labels->labels[instr->k].location == 0xffffffff) { 229 warn("unresolved label: '%s'", 230 labels->labels[instr->k].label); 231 return -1; 232 } 233 instr->k = 234 labels->labels[instr->k].location - (offset + 1); 235 instr->jt = 0; 236 instr->jf = 0; 237 continue; 238 case (LABEL_JT << 8) | LABEL_JF: 239 if (labels->labels[instr->k].location != 0xffffffff) { 240 warn("duplicate label: '%s'", 241 labels->labels[instr->k].label); 242 return -1; 243 } 244 labels->labels[instr->k].location = offset; 245 instr->k = 0; /* Fall through. */ 246 instr->jt = 0; 247 instr->jf = 0; 248 continue; 249 } 250 } 251 return 0; 252 } 253 254 /* Simple lookup table for labels. */ 255 int bpf_label_id(struct bpf_labels *labels, const char *label) 256 { 257 struct __bpf_label *begin = labels->labels, *end; 258 int id; 259 if (labels->count == 0) { 260 begin->label = strndup(label, MAX_BPF_LABEL_LEN); 261 if (!begin->label) { 262 return -1; 263 } 264 begin->location = 0xffffffff; 265 labels->count++; 266 return 0; 267 } 268 end = begin + labels->count; 269 for (id = 0; begin < end; ++begin, ++id) { 270 if (!strcmp(label, begin->label)) { 271 return id; 272 } 273 } 274 275 /* The label wasn't found. Insert it only if there's space. */ 276 if (labels->count == BPF_LABELS_MAX) { 277 return -1; 278 } 279 begin->label = strndup(label, MAX_BPF_LABEL_LEN); 280 if (!begin->label) { 281 return -1; 282 } 283 begin->location = 0xffffffff; 284 labels->count++; 285 return id; 286 } 287 288 void free_label_strings(struct bpf_labels *labels) 289 { 290 if (labels->count == 0) 291 return; 292 293 struct __bpf_label *begin = labels->labels, *end; 294 295 end = begin + labels->count; 296 for (; begin < end; ++begin) { 297 if (begin->label) 298 free((void *)(begin->label)); 299 } 300 301 labels->count = 0; 302 } 303