aboutsummaryrefslogtreecommitdiffstats
path: root/samples/bpf
diff options
context:
space:
mode:
authorJosef Bacik <jbacik@fb.com>2016-09-28 10:54:32 -0400
committerDavid S. Miller <davem@davemloft.net>2016-09-29 01:35:35 -0400
commit484611357c19f9e19ef742ebef4505a07d243cc9 (patch)
tree34f14c2b2ac71d0bf0a53cab096960e7c91ae87f /samples/bpf
parent7836667cec5e02ed2ae3eb09b88047b5b5f2343a (diff)
bpf: allow access into map value arrays
Suppose you have a map array value that is something like this struct foo { unsigned iter; int array[SOME_CONSTANT]; }; You can easily insert this into an array, but you cannot modify the contents of foo->array[] after the fact. This is because we have no way to verify we won't go off the end of the array at verification time. This patch provides a start for this work. We accomplish this by keeping track of a minimum and maximum value a register could be while we're checking the code. Then at the time we try to do an access into a MAP_VALUE we verify that the maximum offset into that region is a valid access into that memory region. So in practice, code such as this unsigned index = 0; if (foo->iter >= SOME_CONSTANT) foo->iter = index; else index = foo->iter++; foo->array[index] = bar; would be allowed, as we can verify that index will always be between 0 and SOME_CONSTANT-1. If you wish to use signed values you'll have to have an extra check to make sure the index isn't less than 0, or do something like index %= SOME_CONSTANT. Signed-off-by: Josef Bacik <jbacik@fb.com> Acked-by: Alexei Starovoitov <ast@kernel.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'samples/bpf')
-rw-r--r--samples/bpf/libbpf.h8
-rw-r--r--samples/bpf/test_verifier.c243
2 files changed, 247 insertions, 4 deletions
diff --git a/samples/bpf/libbpf.h b/samples/bpf/libbpf.h
index 364582b77888..ac6edb61b64a 100644
--- a/samples/bpf/libbpf.h
+++ b/samples/bpf/libbpf.h
@@ -85,6 +85,14 @@ extern char bpf_log_buf[LOG_BUF_SIZE];
85 .off = 0, \ 85 .off = 0, \
86 .imm = IMM }) 86 .imm = IMM })
87 87
88#define BPF_MOV32_IMM(DST, IMM) \
89 ((struct bpf_insn) { \
90 .code = BPF_ALU | BPF_MOV | BPF_K, \
91 .dst_reg = DST, \
92 .src_reg = 0, \
93 .off = 0, \
94 .imm = IMM })
95
88/* BPF_LD_IMM64 macro encodes single 'load 64-bit immediate' insn */ 96/* BPF_LD_IMM64 macro encodes single 'load 64-bit immediate' insn */
89#define BPF_LD_IMM64(DST, IMM) \ 97#define BPF_LD_IMM64(DST, IMM) \
90 BPF_LD_IMM64_RAW(DST, 0, IMM) 98 BPF_LD_IMM64_RAW(DST, 0, IMM)
diff --git a/samples/bpf/test_verifier.c b/samples/bpf/test_verifier.c
index ac590d4b7f02..369ffaad3799 100644
--- a/samples/bpf/test_verifier.c
+++ b/samples/bpf/test_verifier.c
@@ -29,6 +29,7 @@ struct bpf_test {
29 struct bpf_insn insns[MAX_INSNS]; 29 struct bpf_insn insns[MAX_INSNS];
30 int fixup[MAX_FIXUPS]; 30 int fixup[MAX_FIXUPS];
31 int prog_array_fixup[MAX_FIXUPS]; 31 int prog_array_fixup[MAX_FIXUPS];
32 int test_val_map_fixup[MAX_FIXUPS];
32 const char *errstr; 33 const char *errstr;
33 const char *errstr_unpriv; 34 const char *errstr_unpriv;
34 enum { 35 enum {
@@ -39,6 +40,19 @@ struct bpf_test {
39 enum bpf_prog_type prog_type; 40 enum bpf_prog_type prog_type;
40}; 41};
41 42
43/* Note we want this to be 64 bit aligned so that the end of our array is
44 * actually the end of the structure.
45 */
46#define MAX_ENTRIES 11
47struct test_val {
48 unsigned index;
49 int foo[MAX_ENTRIES];
50};
51
52struct other_val {
53 unsigned int action[32];
54};
55
42static struct bpf_test tests[] = { 56static struct bpf_test tests[] = {
43 { 57 {
44 "add+sub+mul", 58 "add+sub+mul",
@@ -2163,6 +2177,212 @@ static struct bpf_test tests[] = {
2163 .errstr = "invalid access to packet", 2177 .errstr = "invalid access to packet",
2164 .prog_type = BPF_PROG_TYPE_SCHED_CLS, 2178 .prog_type = BPF_PROG_TYPE_SCHED_CLS,
2165 }, 2179 },
2180 {
2181 "valid map access into an array with a constant",
2182 .insns = {
2183 BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
2184 BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
2185 BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
2186 BPF_LD_MAP_FD(BPF_REG_1, 0),
2187 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
2188 BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1),
2189 BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, offsetof(struct test_val, foo)),
2190 BPF_EXIT_INSN(),
2191 },
2192 .test_val_map_fixup = {3},
2193 .errstr_unpriv = "R0 leaks addr",
2194 .result_unpriv = REJECT,
2195 .result = ACCEPT,
2196 },
2197 {
2198 "valid map access into an array with a register",
2199 .insns = {
2200 BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
2201 BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
2202 BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
2203 BPF_LD_MAP_FD(BPF_REG_1, 0),
2204 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
2205 BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4),
2206 BPF_MOV64_IMM(BPF_REG_1, 4),
2207 BPF_ALU64_IMM(BPF_LSH, BPF_REG_1, 2),
2208 BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
2209 BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, offsetof(struct test_val, foo)),
2210 BPF_EXIT_INSN(),
2211 },
2212 .test_val_map_fixup = {3},
2213 .errstr_unpriv = "R0 leaks addr",
2214 .result_unpriv = REJECT,
2215 .result = ACCEPT,
2216 },
2217 {
2218 "valid map access into an array with a variable",
2219 .insns = {
2220 BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
2221 BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
2222 BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
2223 BPF_LD_MAP_FD(BPF_REG_1, 0),
2224 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
2225 BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 5),
2226 BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, 0),
2227 BPF_JMP_IMM(BPF_JGE, BPF_REG_1, MAX_ENTRIES, 3),
2228 BPF_ALU64_IMM(BPF_LSH, BPF_REG_1, 2),
2229 BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
2230 BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, offsetof(struct test_val, foo)),
2231 BPF_EXIT_INSN(),
2232 },
2233 .test_val_map_fixup = {3},
2234 .errstr_unpriv = "R0 leaks addr",
2235 .result_unpriv = REJECT,
2236 .result = ACCEPT,
2237 },
2238 {
2239 "valid map access into an array with a signed variable",
2240 .insns = {
2241 BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
2242 BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
2243 BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
2244 BPF_LD_MAP_FD(BPF_REG_1, 0),
2245 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
2246 BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 9),
2247 BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, 0),
2248 BPF_JMP_IMM(BPF_JSGT, BPF_REG_1, 0xffffffff, 1),
2249 BPF_MOV32_IMM(BPF_REG_1, 0),
2250 BPF_MOV32_IMM(BPF_REG_2, MAX_ENTRIES),
2251 BPF_JMP_REG(BPF_JSGT, BPF_REG_2, BPF_REG_1, 1),
2252 BPF_MOV32_IMM(BPF_REG_1, 0),
2253 BPF_ALU32_IMM(BPF_LSH, BPF_REG_1, 2),
2254 BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
2255 BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, offsetof(struct test_val, foo)),
2256 BPF_EXIT_INSN(),
2257 },
2258 .test_val_map_fixup = {3},
2259 .errstr_unpriv = "R0 leaks addr",
2260 .result_unpriv = REJECT,
2261 .result = ACCEPT,
2262 },
2263 {
2264 "invalid map access into an array with a constant",
2265 .insns = {
2266 BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
2267 BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
2268 BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
2269 BPF_LD_MAP_FD(BPF_REG_1, 0),
2270 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
2271 BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1),
2272 BPF_ST_MEM(BPF_DW, BPF_REG_0, (MAX_ENTRIES + 1) << 2,
2273 offsetof(struct test_val, foo)),
2274 BPF_EXIT_INSN(),
2275 },
2276 .test_val_map_fixup = {3},
2277 .errstr = "invalid access to map value, value_size=48 off=48 size=8",
2278 .result = REJECT,
2279 },
2280 {
2281 "invalid map access into an array with a register",
2282 .insns = {
2283 BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
2284 BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
2285 BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
2286 BPF_LD_MAP_FD(BPF_REG_1, 0),
2287 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
2288 BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4),
2289 BPF_MOV64_IMM(BPF_REG_1, MAX_ENTRIES + 1),
2290 BPF_ALU64_IMM(BPF_LSH, BPF_REG_1, 2),
2291 BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
2292 BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, offsetof(struct test_val, foo)),
2293 BPF_EXIT_INSN(),
2294 },
2295 .test_val_map_fixup = {3},
2296 .errstr = "R0 min value is outside of the array range",
2297 .result = REJECT,
2298 },
2299 {
2300 "invalid map access into an array with a variable",
2301 .insns = {
2302 BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
2303 BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
2304 BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
2305 BPF_LD_MAP_FD(BPF_REG_1, 0),
2306 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
2307 BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4),
2308 BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, 0),
2309 BPF_ALU64_IMM(BPF_LSH, BPF_REG_1, 2),
2310 BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
2311 BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, offsetof(struct test_val, foo)),
2312 BPF_EXIT_INSN(),
2313 },
2314 .test_val_map_fixup = {3},
2315 .errstr = "R0 min value is negative, either use unsigned index or do a if (index >=0) check.",
2316 .result = REJECT,
2317 },
2318 {
2319 "invalid map access into an array with no floor check",
2320 .insns = {
2321 BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
2322 BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
2323 BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
2324 BPF_LD_MAP_FD(BPF_REG_1, 0),
2325 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
2326 BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 7),
2327 BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, 0),
2328 BPF_MOV32_IMM(BPF_REG_2, MAX_ENTRIES),
2329 BPF_JMP_REG(BPF_JSGT, BPF_REG_2, BPF_REG_1, 1),
2330 BPF_MOV32_IMM(BPF_REG_1, 0),
2331 BPF_ALU32_IMM(BPF_LSH, BPF_REG_1, 2),
2332 BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
2333 BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, offsetof(struct test_val, foo)),
2334 BPF_EXIT_INSN(),
2335 },
2336 .test_val_map_fixup = {3},
2337 .errstr = "R0 min value is negative, either use unsigned index or do a if (index >=0) check.",
2338 .result = REJECT,
2339 },
2340 {
2341 "invalid map access into an array with a invalid max check",
2342 .insns = {
2343 BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
2344 BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
2345 BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
2346 BPF_LD_MAP_FD(BPF_REG_1, 0),
2347 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
2348 BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 7),
2349 BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, 0),
2350 BPF_MOV32_IMM(BPF_REG_2, MAX_ENTRIES + 1),
2351 BPF_JMP_REG(BPF_JGT, BPF_REG_2, BPF_REG_1, 1),
2352 BPF_MOV32_IMM(BPF_REG_1, 0),
2353 BPF_ALU32_IMM(BPF_LSH, BPF_REG_1, 2),
2354 BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
2355 BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, offsetof(struct test_val, foo)),
2356 BPF_EXIT_INSN(),
2357 },
2358 .test_val_map_fixup = {3},
2359 .errstr = "invalid access to map value, value_size=48 off=44 size=8",
2360 .result = REJECT,
2361 },
2362 {
2363 "invalid map access into an array with a invalid max check",
2364 .insns = {
2365 BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
2366 BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
2367 BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
2368 BPF_LD_MAP_FD(BPF_REG_1, 0),
2369 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
2370 BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 10),
2371 BPF_MOV64_REG(BPF_REG_8, BPF_REG_0),
2372 BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
2373 BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
2374 BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
2375 BPF_LD_MAP_FD(BPF_REG_1, 0),
2376 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
2377 BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2),
2378 BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_8),
2379 BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_0, offsetof(struct test_val, foo)),
2380 BPF_EXIT_INSN(),
2381 },
2382 .test_val_map_fixup = {3, 11},
2383 .errstr = "R0 min value is negative, either use unsigned index or do a if (index >=0) check.",
2384 .result = REJECT,
2385 },
2166}; 2386};
2167 2387
2168static int probe_filter_length(struct bpf_insn *fp) 2388static int probe_filter_length(struct bpf_insn *fp)
@@ -2176,12 +2396,12 @@ static int probe_filter_length(struct bpf_insn *fp)
2176 return len + 1; 2396 return len + 1;
2177} 2397}
2178 2398
2179static int create_map(void) 2399static int create_map(size_t val_size, int num)
2180{ 2400{
2181 int map_fd; 2401 int map_fd;
2182 2402
2183 map_fd = bpf_create_map(BPF_MAP_TYPE_HASH, 2403 map_fd = bpf_create_map(BPF_MAP_TYPE_HASH,
2184 sizeof(long long), sizeof(long long), 1024, 0); 2404 sizeof(long long), val_size, num, 0);
2185 if (map_fd < 0) 2405 if (map_fd < 0)
2186 printf("failed to create map '%s'\n", strerror(errno)); 2406 printf("failed to create map '%s'\n", strerror(errno));
2187 2407
@@ -2211,12 +2431,13 @@ static int test(void)
2211 int prog_len = probe_filter_length(prog); 2431 int prog_len = probe_filter_length(prog);
2212 int *fixup = tests[i].fixup; 2432 int *fixup = tests[i].fixup;
2213 int *prog_array_fixup = tests[i].prog_array_fixup; 2433 int *prog_array_fixup = tests[i].prog_array_fixup;
2434 int *test_val_map_fixup = tests[i].test_val_map_fixup;
2214 int expected_result; 2435 int expected_result;
2215 const char *expected_errstr; 2436 const char *expected_errstr;
2216 int map_fd = -1, prog_array_fd = -1; 2437 int map_fd = -1, prog_array_fd = -1, test_val_map_fd = -1;
2217 2438
2218 if (*fixup) { 2439 if (*fixup) {
2219 map_fd = create_map(); 2440 map_fd = create_map(sizeof(long long), 1024);
2220 2441
2221 do { 2442 do {
2222 prog[*fixup].imm = map_fd; 2443 prog[*fixup].imm = map_fd;
@@ -2231,6 +2452,18 @@ static int test(void)
2231 prog_array_fixup++; 2452 prog_array_fixup++;
2232 } while (*prog_array_fixup); 2453 } while (*prog_array_fixup);
2233 } 2454 }
2455 if (*test_val_map_fixup) {
2456 /* Unprivileged can't create a hash map.*/
2457 if (unpriv)
2458 continue;
2459 test_val_map_fd = create_map(sizeof(struct test_val),
2460 256);
2461 do {
2462 prog[*test_val_map_fixup].imm = test_val_map_fd;
2463 test_val_map_fixup++;
2464 } while (*test_val_map_fixup);
2465 }
2466
2234 printf("#%d %s ", i, tests[i].descr); 2467 printf("#%d %s ", i, tests[i].descr);
2235 2468
2236 prog_fd = bpf_prog_load(prog_type ?: BPF_PROG_TYPE_SOCKET_FILTER, 2469 prog_fd = bpf_prog_load(prog_type ?: BPF_PROG_TYPE_SOCKET_FILTER,
@@ -2277,6 +2510,8 @@ fail:
2277 close(map_fd); 2510 close(map_fd);
2278 if (prog_array_fd >= 0) 2511 if (prog_array_fd >= 0)
2279 close(prog_array_fd); 2512 close(prog_array_fd);
2513 if (test_val_map_fd >= 0)
2514 close(test_val_map_fd);
2280 close(prog_fd); 2515 close(prog_fd);
2281 2516
2282 } 2517 }