diff options
Diffstat (limited to 'tools/testing/selftests/bpf/test_verifier.c')
-rw-r--r-- | tools/testing/selftests/bpf/test_verifier.c | 294 |
1 files changed, 289 insertions, 5 deletions
diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c index e1f5b9eea1e8..c848e90b6421 100644 --- a/tools/testing/selftests/bpf/test_verifier.c +++ b/tools/testing/selftests/bpf/test_verifier.c | |||
@@ -8,6 +8,8 @@ | |||
8 | * License as published by the Free Software Foundation. | 8 | * License as published by the Free Software Foundation. |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <asm/types.h> | ||
12 | #include <linux/types.h> | ||
11 | #include <stdint.h> | 13 | #include <stdint.h> |
12 | #include <stdio.h> | 14 | #include <stdio.h> |
13 | #include <stdlib.h> | 15 | #include <stdlib.h> |
@@ -28,6 +30,14 @@ | |||
28 | 30 | ||
29 | #include <bpf/bpf.h> | 31 | #include <bpf/bpf.h> |
30 | 32 | ||
33 | #ifdef HAVE_GENHDR | ||
34 | # include "autoconf.h" | ||
35 | #else | ||
36 | # if defined(__i386) || defined(__x86_64) || defined(__s390x__) || defined(__aarch64__) | ||
37 | # define CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 1 | ||
38 | # endif | ||
39 | #endif | ||
40 | |||
31 | #include "../../../include/linux/filter.h" | 41 | #include "../../../include/linux/filter.h" |
32 | 42 | ||
33 | #ifndef ARRAY_SIZE | 43 | #ifndef ARRAY_SIZE |
@@ -37,6 +47,8 @@ | |||
37 | #define MAX_INSNS 512 | 47 | #define MAX_INSNS 512 |
38 | #define MAX_FIXUPS 8 | 48 | #define MAX_FIXUPS 8 |
39 | 49 | ||
50 | #define F_NEEDS_EFFICIENT_UNALIGNED_ACCESS (1 << 0) | ||
51 | |||
40 | struct bpf_test { | 52 | struct bpf_test { |
41 | const char *descr; | 53 | const char *descr; |
42 | struct bpf_insn insns[MAX_INSNS]; | 54 | struct bpf_insn insns[MAX_INSNS]; |
@@ -51,6 +63,7 @@ struct bpf_test { | |||
51 | REJECT | 63 | REJECT |
52 | } result, result_unpriv; | 64 | } result, result_unpriv; |
53 | enum bpf_prog_type prog_type; | 65 | enum bpf_prog_type prog_type; |
66 | uint8_t flags; | ||
54 | }; | 67 | }; |
55 | 68 | ||
56 | /* Note we want this to be 64 bit aligned so that the end of our array is | 69 | /* Note we want this to be 64 bit aligned so that the end of our array is |
@@ -2430,6 +2443,30 @@ static struct bpf_test tests[] = { | |||
2430 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | 2443 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
2431 | }, | 2444 | }, |
2432 | { | 2445 | { |
2446 | "direct packet access: test15 (spill with xadd)", | ||
2447 | .insns = { | ||
2448 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | ||
2449 | offsetof(struct __sk_buff, data)), | ||
2450 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | ||
2451 | offsetof(struct __sk_buff, data_end)), | ||
2452 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_2), | ||
2453 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 8), | ||
2454 | BPF_JMP_REG(BPF_JGT, BPF_REG_0, BPF_REG_3, 8), | ||
2455 | BPF_MOV64_IMM(BPF_REG_5, 4096), | ||
2456 | BPF_MOV64_REG(BPF_REG_4, BPF_REG_10), | ||
2457 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, -8), | ||
2458 | BPF_STX_MEM(BPF_DW, BPF_REG_4, BPF_REG_2, 0), | ||
2459 | BPF_STX_XADD(BPF_DW, BPF_REG_4, BPF_REG_5, 0), | ||
2460 | BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_4, 0), | ||
2461 | BPF_STX_MEM(BPF_W, BPF_REG_2, BPF_REG_5, 0), | ||
2462 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
2463 | BPF_EXIT_INSN(), | ||
2464 | }, | ||
2465 | .errstr = "R2 invalid mem access 'inv'", | ||
2466 | .result = REJECT, | ||
2467 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
2468 | }, | ||
2469 | { | ||
2433 | "helper access to packet: test1, valid packet_ptr range", | 2470 | "helper access to packet: test1, valid packet_ptr range", |
2434 | .insns = { | 2471 | .insns = { |
2435 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | 2472 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, |
@@ -2932,6 +2969,7 @@ static struct bpf_test tests[] = { | |||
2932 | .errstr_unpriv = "R0 pointer arithmetic prohibited", | 2969 | .errstr_unpriv = "R0 pointer arithmetic prohibited", |
2933 | .result_unpriv = REJECT, | 2970 | .result_unpriv = REJECT, |
2934 | .result = ACCEPT, | 2971 | .result = ACCEPT, |
2972 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, | ||
2935 | }, | 2973 | }, |
2936 | { | 2974 | { |
2937 | "valid map access into an array with a variable", | 2975 | "valid map access into an array with a variable", |
@@ -2955,6 +2993,7 @@ static struct bpf_test tests[] = { | |||
2955 | .errstr_unpriv = "R0 pointer arithmetic prohibited", | 2993 | .errstr_unpriv = "R0 pointer arithmetic prohibited", |
2956 | .result_unpriv = REJECT, | 2994 | .result_unpriv = REJECT, |
2957 | .result = ACCEPT, | 2995 | .result = ACCEPT, |
2996 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, | ||
2958 | }, | 2997 | }, |
2959 | { | 2998 | { |
2960 | "valid map access into an array with a signed variable", | 2999 | "valid map access into an array with a signed variable", |
@@ -2982,6 +3021,7 @@ static struct bpf_test tests[] = { | |||
2982 | .errstr_unpriv = "R0 pointer arithmetic prohibited", | 3021 | .errstr_unpriv = "R0 pointer arithmetic prohibited", |
2983 | .result_unpriv = REJECT, | 3022 | .result_unpriv = REJECT, |
2984 | .result = ACCEPT, | 3023 | .result = ACCEPT, |
3024 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, | ||
2985 | }, | 3025 | }, |
2986 | { | 3026 | { |
2987 | "invalid map access into an array with a constant", | 3027 | "invalid map access into an array with a constant", |
@@ -3023,6 +3063,7 @@ static struct bpf_test tests[] = { | |||
3023 | .errstr = "R0 min value is outside of the array range", | 3063 | .errstr = "R0 min value is outside of the array range", |
3024 | .result_unpriv = REJECT, | 3064 | .result_unpriv = REJECT, |
3025 | .result = REJECT, | 3065 | .result = REJECT, |
3066 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, | ||
3026 | }, | 3067 | }, |
3027 | { | 3068 | { |
3028 | "invalid map access into an array with a variable", | 3069 | "invalid map access into an array with a variable", |
@@ -3046,6 +3087,7 @@ static struct bpf_test tests[] = { | |||
3046 | .errstr = "R0 min value is negative, either use unsigned index or do a if (index >=0) check.", | 3087 | .errstr = "R0 min value is negative, either use unsigned index or do a if (index >=0) check.", |
3047 | .result_unpriv = REJECT, | 3088 | .result_unpriv = REJECT, |
3048 | .result = REJECT, | 3089 | .result = REJECT, |
3090 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, | ||
3049 | }, | 3091 | }, |
3050 | { | 3092 | { |
3051 | "invalid map access into an array with no floor check", | 3093 | "invalid map access into an array with no floor check", |
@@ -3072,6 +3114,7 @@ static struct bpf_test tests[] = { | |||
3072 | .errstr = "R0 min value is negative, either use unsigned index or do a if (index >=0) check.", | 3114 | .errstr = "R0 min value is negative, either use unsigned index or do a if (index >=0) check.", |
3073 | .result_unpriv = REJECT, | 3115 | .result_unpriv = REJECT, |
3074 | .result = REJECT, | 3116 | .result = REJECT, |
3117 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, | ||
3075 | }, | 3118 | }, |
3076 | { | 3119 | { |
3077 | "invalid map access into an array with a invalid max check", | 3120 | "invalid map access into an array with a invalid max check", |
@@ -3098,6 +3141,7 @@ static struct bpf_test tests[] = { | |||
3098 | .errstr = "invalid access to map value, value_size=48 off=44 size=8", | 3141 | .errstr = "invalid access to map value, value_size=48 off=44 size=8", |
3099 | .result_unpriv = REJECT, | 3142 | .result_unpriv = REJECT, |
3100 | .result = REJECT, | 3143 | .result = REJECT, |
3144 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, | ||
3101 | }, | 3145 | }, |
3102 | { | 3146 | { |
3103 | "invalid map access into an array with a invalid max check", | 3147 | "invalid map access into an array with a invalid max check", |
@@ -3127,6 +3171,7 @@ static struct bpf_test tests[] = { | |||
3127 | .errstr = "R0 min value is negative, either use unsigned index or do a if (index >=0) check.", | 3171 | .errstr = "R0 min value is negative, either use unsigned index or do a if (index >=0) check.", |
3128 | .result_unpriv = REJECT, | 3172 | .result_unpriv = REJECT, |
3129 | .result = REJECT, | 3173 | .result = REJECT, |
3174 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, | ||
3130 | }, | 3175 | }, |
3131 | { | 3176 | { |
3132 | "multiple registers share map_lookup_elem result", | 3177 | "multiple registers share map_lookup_elem result", |
@@ -3250,6 +3295,7 @@ static struct bpf_test tests[] = { | |||
3250 | .result = REJECT, | 3295 | .result = REJECT, |
3251 | .errstr_unpriv = "R0 pointer arithmetic prohibited", | 3296 | .errstr_unpriv = "R0 pointer arithmetic prohibited", |
3252 | .result_unpriv = REJECT, | 3297 | .result_unpriv = REJECT, |
3298 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, | ||
3253 | }, | 3299 | }, |
3254 | { | 3300 | { |
3255 | "constant register |= constant should keep constant type", | 3301 | "constant register |= constant should keep constant type", |
@@ -3416,6 +3462,26 @@ static struct bpf_test tests[] = { | |||
3416 | .prog_type = BPF_PROG_TYPE_LWT_XMIT, | 3462 | .prog_type = BPF_PROG_TYPE_LWT_XMIT, |
3417 | }, | 3463 | }, |
3418 | { | 3464 | { |
3465 | "overlapping checks for direct packet access", | ||
3466 | .insns = { | ||
3467 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | ||
3468 | offsetof(struct __sk_buff, data)), | ||
3469 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | ||
3470 | offsetof(struct __sk_buff, data_end)), | ||
3471 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_2), | ||
3472 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 8), | ||
3473 | BPF_JMP_REG(BPF_JGT, BPF_REG_0, BPF_REG_3, 4), | ||
3474 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_2), | ||
3475 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 6), | ||
3476 | BPF_JMP_REG(BPF_JGT, BPF_REG_1, BPF_REG_3, 1), | ||
3477 | BPF_LDX_MEM(BPF_H, BPF_REG_0, BPF_REG_2, 6), | ||
3478 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
3479 | BPF_EXIT_INSN(), | ||
3480 | }, | ||
3481 | .result = ACCEPT, | ||
3482 | .prog_type = BPF_PROG_TYPE_LWT_XMIT, | ||
3483 | }, | ||
3484 | { | ||
3419 | "invalid access of tc_classid for LWT_IN", | 3485 | "invalid access of tc_classid for LWT_IN", |
3420 | .insns = { | 3486 | .insns = { |
3421 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, | 3487 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, |
@@ -3959,7 +4025,208 @@ static struct bpf_test tests[] = { | |||
3959 | .result_unpriv = REJECT, | 4025 | .result_unpriv = REJECT, |
3960 | }, | 4026 | }, |
3961 | { | 4027 | { |
3962 | "map element value (adjusted) is preserved across register spilling", | 4028 | "map element value or null is marked on register spilling", |
4029 | .insns = { | ||
4030 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
4031 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
4032 | BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0), | ||
4033 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
4034 | BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), | ||
4035 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), | ||
4036 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -152), | ||
4037 | BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0, 0), | ||
4038 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2), | ||
4039 | BPF_LDX_MEM(BPF_DW, BPF_REG_3, BPF_REG_1, 0), | ||
4040 | BPF_ST_MEM(BPF_DW, BPF_REG_3, 0, 42), | ||
4041 | BPF_EXIT_INSN(), | ||
4042 | }, | ||
4043 | .fixup_map2 = { 3 }, | ||
4044 | .errstr_unpriv = "R0 leaks addr", | ||
4045 | .result = ACCEPT, | ||
4046 | .result_unpriv = REJECT, | ||
4047 | }, | ||
4048 | { | ||
4049 | "map element value store of cleared call register", | ||
4050 | .insns = { | ||
4051 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
4052 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
4053 | BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0), | ||
4054 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
4055 | BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), | ||
4056 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1), | ||
4057 | BPF_STX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, 0), | ||
4058 | BPF_EXIT_INSN(), | ||
4059 | }, | ||
4060 | .fixup_map2 = { 3 }, | ||
4061 | .errstr_unpriv = "R1 !read_ok", | ||
4062 | .errstr = "R1 !read_ok", | ||
4063 | .result = REJECT, | ||
4064 | .result_unpriv = REJECT, | ||
4065 | }, | ||
4066 | { | ||
4067 | "map element value with unaligned store", | ||
4068 | .insns = { | ||
4069 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
4070 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
4071 | BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0), | ||
4072 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
4073 | BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), | ||
4074 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 17), | ||
4075 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 3), | ||
4076 | BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 42), | ||
4077 | BPF_ST_MEM(BPF_DW, BPF_REG_0, 2, 43), | ||
4078 | BPF_ST_MEM(BPF_DW, BPF_REG_0, -2, 44), | ||
4079 | BPF_MOV64_REG(BPF_REG_8, BPF_REG_0), | ||
4080 | BPF_ST_MEM(BPF_DW, BPF_REG_8, 0, 32), | ||
4081 | BPF_ST_MEM(BPF_DW, BPF_REG_8, 2, 33), | ||
4082 | BPF_ST_MEM(BPF_DW, BPF_REG_8, -2, 34), | ||
4083 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_8, 5), | ||
4084 | BPF_ST_MEM(BPF_DW, BPF_REG_8, 0, 22), | ||
4085 | BPF_ST_MEM(BPF_DW, BPF_REG_8, 4, 23), | ||
4086 | BPF_ST_MEM(BPF_DW, BPF_REG_8, -7, 24), | ||
4087 | BPF_MOV64_REG(BPF_REG_7, BPF_REG_8), | ||
4088 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, 3), | ||
4089 | BPF_ST_MEM(BPF_DW, BPF_REG_7, 0, 22), | ||
4090 | BPF_ST_MEM(BPF_DW, BPF_REG_7, 4, 23), | ||
4091 | BPF_ST_MEM(BPF_DW, BPF_REG_7, -4, 24), | ||
4092 | BPF_EXIT_INSN(), | ||
4093 | }, | ||
4094 | .fixup_map2 = { 3 }, | ||
4095 | .errstr_unpriv = "R0 pointer arithmetic prohibited", | ||
4096 | .result = ACCEPT, | ||
4097 | .result_unpriv = REJECT, | ||
4098 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, | ||
4099 | }, | ||
4100 | { | ||
4101 | "map element value with unaligned load", | ||
4102 | .insns = { | ||
4103 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
4104 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
4105 | BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0), | ||
4106 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
4107 | BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), | ||
4108 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 11), | ||
4109 | BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, 0), | ||
4110 | BPF_JMP_IMM(BPF_JGE, BPF_REG_1, MAX_ENTRIES, 9), | ||
4111 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 3), | ||
4112 | BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 0), | ||
4113 | BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 2), | ||
4114 | BPF_MOV64_REG(BPF_REG_8, BPF_REG_0), | ||
4115 | BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_8, 0), | ||
4116 | BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_8, 2), | ||
4117 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 5), | ||
4118 | BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 0), | ||
4119 | BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 4), | ||
4120 | BPF_EXIT_INSN(), | ||
4121 | }, | ||
4122 | .fixup_map2 = { 3 }, | ||
4123 | .errstr_unpriv = "R0 pointer arithmetic prohibited", | ||
4124 | .result = ACCEPT, | ||
4125 | .result_unpriv = REJECT, | ||
4126 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, | ||
4127 | }, | ||
4128 | { | ||
4129 | "map element value illegal alu op, 1", | ||
4130 | .insns = { | ||
4131 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
4132 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
4133 | BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0), | ||
4134 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
4135 | BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), | ||
4136 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2), | ||
4137 | BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 8), | ||
4138 | BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 22), | ||
4139 | BPF_EXIT_INSN(), | ||
4140 | }, | ||
4141 | .fixup_map2 = { 3 }, | ||
4142 | .errstr_unpriv = "R0 pointer arithmetic prohibited", | ||
4143 | .errstr = "invalid mem access 'inv'", | ||
4144 | .result = REJECT, | ||
4145 | .result_unpriv = REJECT, | ||
4146 | }, | ||
4147 | { | ||
4148 | "map element value illegal alu op, 2", | ||
4149 | .insns = { | ||
4150 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
4151 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
4152 | BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0), | ||
4153 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
4154 | BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), | ||
4155 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2), | ||
4156 | BPF_ALU32_IMM(BPF_ADD, BPF_REG_0, 0), | ||
4157 | BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 22), | ||
4158 | BPF_EXIT_INSN(), | ||
4159 | }, | ||
4160 | .fixup_map2 = { 3 }, | ||
4161 | .errstr_unpriv = "R0 pointer arithmetic prohibited", | ||
4162 | .errstr = "invalid mem access 'inv'", | ||
4163 | .result = REJECT, | ||
4164 | .result_unpriv = REJECT, | ||
4165 | }, | ||
4166 | { | ||
4167 | "map element value illegal alu op, 3", | ||
4168 | .insns = { | ||
4169 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
4170 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
4171 | BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0), | ||
4172 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
4173 | BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), | ||
4174 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2), | ||
4175 | BPF_ALU64_IMM(BPF_DIV, BPF_REG_0, 42), | ||
4176 | BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 22), | ||
4177 | BPF_EXIT_INSN(), | ||
4178 | }, | ||
4179 | .fixup_map2 = { 3 }, | ||
4180 | .errstr_unpriv = "R0 pointer arithmetic prohibited", | ||
4181 | .errstr = "invalid mem access 'inv'", | ||
4182 | .result = REJECT, | ||
4183 | .result_unpriv = REJECT, | ||
4184 | }, | ||
4185 | { | ||
4186 | "map element value illegal alu op, 4", | ||
4187 | .insns = { | ||
4188 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
4189 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
4190 | BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0), | ||
4191 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
4192 | BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), | ||
4193 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2), | ||
4194 | BPF_ENDIAN(BPF_FROM_BE, BPF_REG_0, 64), | ||
4195 | BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 22), | ||
4196 | BPF_EXIT_INSN(), | ||
4197 | }, | ||
4198 | .fixup_map2 = { 3 }, | ||
4199 | .errstr_unpriv = "R0 pointer arithmetic prohibited", | ||
4200 | .errstr = "invalid mem access 'inv'", | ||
4201 | .result = REJECT, | ||
4202 | .result_unpriv = REJECT, | ||
4203 | }, | ||
4204 | { | ||
4205 | "map element value illegal alu op, 5", | ||
4206 | .insns = { | ||
4207 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
4208 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
4209 | BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0), | ||
4210 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
4211 | BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), | ||
4212 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 7), | ||
4213 | BPF_MOV64_IMM(BPF_REG_3, 4096), | ||
4214 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
4215 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
4216 | BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_0, 0), | ||
4217 | BPF_STX_XADD(BPF_DW, BPF_REG_2, BPF_REG_3, 0), | ||
4218 | BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_2, 0), | ||
4219 | BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 22), | ||
4220 | BPF_EXIT_INSN(), | ||
4221 | }, | ||
4222 | .fixup_map2 = { 3 }, | ||
4223 | .errstr_unpriv = "R0 invalid mem access 'inv'", | ||
4224 | .errstr = "R0 invalid mem access 'inv'", | ||
4225 | .result = REJECT, | ||
4226 | .result_unpriv = REJECT, | ||
4227 | }, | ||
4228 | { | ||
4229 | "map element value is preserved across register spilling", | ||
3963 | .insns = { | 4230 | .insns = { |
3964 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | 4231 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), |
3965 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | 4232 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), |
@@ -3981,6 +4248,7 @@ static struct bpf_test tests[] = { | |||
3981 | .errstr_unpriv = "R0 pointer arithmetic prohibited", | 4248 | .errstr_unpriv = "R0 pointer arithmetic prohibited", |
3982 | .result = ACCEPT, | 4249 | .result = ACCEPT, |
3983 | .result_unpriv = REJECT, | 4250 | .result_unpriv = REJECT, |
4251 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, | ||
3984 | }, | 4252 | }, |
3985 | { | 4253 | { |
3986 | "helper access to variable memory: stack, bitwise AND + JMP, correct bounds", | 4254 | "helper access to variable memory: stack, bitwise AND + JMP, correct bounds", |
@@ -4419,6 +4687,7 @@ static struct bpf_test tests[] = { | |||
4419 | .errstr = "R0 min value is negative, either use unsigned index or do a if (index >=0) check.", | 4687 | .errstr = "R0 min value is negative, either use unsigned index or do a if (index >=0) check.", |
4420 | .result = REJECT, | 4688 | .result = REJECT, |
4421 | .result_unpriv = REJECT, | 4689 | .result_unpriv = REJECT, |
4690 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, | ||
4422 | }, | 4691 | }, |
4423 | { | 4692 | { |
4424 | "invalid range check", | 4693 | "invalid range check", |
@@ -4450,6 +4719,7 @@ static struct bpf_test tests[] = { | |||
4450 | .errstr = "R0 min value is negative, either use unsigned index or do a if (index >=0) check.", | 4719 | .errstr = "R0 min value is negative, either use unsigned index or do a if (index >=0) check.", |
4451 | .result = REJECT, | 4720 | .result = REJECT, |
4452 | .result_unpriv = REJECT, | 4721 | .result_unpriv = REJECT, |
4722 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, | ||
4453 | } | 4723 | } |
4454 | }; | 4724 | }; |
4455 | 4725 | ||
@@ -4528,11 +4798,11 @@ static void do_test_fixup(struct bpf_test *test, struct bpf_insn *prog, | |||
4528 | static void do_test_single(struct bpf_test *test, bool unpriv, | 4798 | static void do_test_single(struct bpf_test *test, bool unpriv, |
4529 | int *passes, int *errors) | 4799 | int *passes, int *errors) |
4530 | { | 4800 | { |
4801 | int fd_prog, expected_ret, reject_from_alignment; | ||
4531 | struct bpf_insn *prog = test->insns; | 4802 | struct bpf_insn *prog = test->insns; |
4532 | int prog_len = probe_filter_length(prog); | 4803 | int prog_len = probe_filter_length(prog); |
4533 | int prog_type = test->prog_type; | 4804 | int prog_type = test->prog_type; |
4534 | int fd_f1 = -1, fd_f2 = -1, fd_f3 = -1; | 4805 | int fd_f1 = -1, fd_f2 = -1, fd_f3 = -1; |
4535 | int fd_prog, expected_ret; | ||
4536 | const char *expected_err; | 4806 | const char *expected_err; |
4537 | 4807 | ||
4538 | do_test_fixup(test, prog, &fd_f1, &fd_f2, &fd_f3); | 4808 | do_test_fixup(test, prog, &fd_f1, &fd_f2, &fd_f3); |
@@ -4545,8 +4815,19 @@ static void do_test_single(struct bpf_test *test, bool unpriv, | |||
4545 | test->result_unpriv : test->result; | 4815 | test->result_unpriv : test->result; |
4546 | expected_err = unpriv && test->errstr_unpriv ? | 4816 | expected_err = unpriv && test->errstr_unpriv ? |
4547 | test->errstr_unpriv : test->errstr; | 4817 | test->errstr_unpriv : test->errstr; |
4818 | |||
4819 | reject_from_alignment = fd_prog < 0 && | ||
4820 | (test->flags & F_NEEDS_EFFICIENT_UNALIGNED_ACCESS) && | ||
4821 | strstr(bpf_vlog, "Unknown alignment."); | ||
4822 | #ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS | ||
4823 | if (reject_from_alignment) { | ||
4824 | printf("FAIL\nFailed due to alignment despite having efficient unaligned access: '%s'!\n", | ||
4825 | strerror(errno)); | ||
4826 | goto fail_log; | ||
4827 | } | ||
4828 | #endif | ||
4548 | if (expected_ret == ACCEPT) { | 4829 | if (expected_ret == ACCEPT) { |
4549 | if (fd_prog < 0) { | 4830 | if (fd_prog < 0 && !reject_from_alignment) { |
4550 | printf("FAIL\nFailed to load prog '%s'!\n", | 4831 | printf("FAIL\nFailed to load prog '%s'!\n", |
4551 | strerror(errno)); | 4832 | strerror(errno)); |
4552 | goto fail_log; | 4833 | goto fail_log; |
@@ -4556,14 +4837,15 @@ static void do_test_single(struct bpf_test *test, bool unpriv, | |||
4556 | printf("FAIL\nUnexpected success to load!\n"); | 4837 | printf("FAIL\nUnexpected success to load!\n"); |
4557 | goto fail_log; | 4838 | goto fail_log; |
4558 | } | 4839 | } |
4559 | if (!strstr(bpf_vlog, expected_err)) { | 4840 | if (!strstr(bpf_vlog, expected_err) && !reject_from_alignment) { |
4560 | printf("FAIL\nUnexpected error message!\n"); | 4841 | printf("FAIL\nUnexpected error message!\n"); |
4561 | goto fail_log; | 4842 | goto fail_log; |
4562 | } | 4843 | } |
4563 | } | 4844 | } |
4564 | 4845 | ||
4565 | (*passes)++; | 4846 | (*passes)++; |
4566 | printf("OK\n"); | 4847 | printf("OK%s\n", reject_from_alignment ? |
4848 | " (NOTE: reject due to unknown alignment)" : ""); | ||
4567 | close_fds: | 4849 | close_fds: |
4568 | close(fd_prog); | 4850 | close(fd_prog); |
4569 | close(fd_f1); | 4851 | close(fd_f1); |
@@ -4583,10 +4865,12 @@ static bool is_admin(void) | |||
4583 | cap_flag_value_t sysadmin = CAP_CLEAR; | 4865 | cap_flag_value_t sysadmin = CAP_CLEAR; |
4584 | const cap_value_t cap_val = CAP_SYS_ADMIN; | 4866 | const cap_value_t cap_val = CAP_SYS_ADMIN; |
4585 | 4867 | ||
4868 | #ifdef CAP_IS_SUPPORTED | ||
4586 | if (!CAP_IS_SUPPORTED(CAP_SETFCAP)) { | 4869 | if (!CAP_IS_SUPPORTED(CAP_SETFCAP)) { |
4587 | perror("cap_get_flag"); | 4870 | perror("cap_get_flag"); |
4588 | return false; | 4871 | return false; |
4589 | } | 4872 | } |
4873 | #endif | ||
4590 | caps = cap_get_proc(); | 4874 | caps = cap_get_proc(); |
4591 | if (!caps) { | 4875 | if (!caps) { |
4592 | perror("cap_get_proc"); | 4876 | perror("cap_get_proc"); |