diff options
| -rw-r--r-- | drivers/net/ethernet/netronome/nfp/bpf/jit.c | 27 | ||||
| -rw-r--r-- | kernel/bpf/verifier.c | 25 | ||||
| -rw-r--r-- | tools/testing/selftests/bpf/.gitignore | 1 | ||||
| -rw-r--r-- | tools/testing/selftests/bpf/test_verifier.c | 305 |
4 files changed, 308 insertions, 50 deletions
diff --git a/drivers/net/ethernet/netronome/nfp/bpf/jit.c b/drivers/net/ethernet/netronome/nfp/bpf/jit.c index 662cbc21d909..e23ca90289f7 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/jit.c +++ b/drivers/net/ethernet/netronome/nfp/bpf/jit.c | |||
| @@ -3052,26 +3052,19 @@ static int jset_imm(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) | |||
| 3052 | { | 3052 | { |
| 3053 | const struct bpf_insn *insn = &meta->insn; | 3053 | const struct bpf_insn *insn = &meta->insn; |
| 3054 | u64 imm = insn->imm; /* sign extend */ | 3054 | u64 imm = insn->imm; /* sign extend */ |
| 3055 | u8 dst_gpr = insn->dst_reg * 2; | ||
| 3055 | swreg tmp_reg; | 3056 | swreg tmp_reg; |
| 3056 | 3057 | ||
| 3057 | if (!imm) { | 3058 | tmp_reg = ur_load_imm_any(nfp_prog, imm & ~0U, imm_b(nfp_prog)); |
| 3058 | meta->skip = true; | 3059 | emit_alu(nfp_prog, imm_b(nfp_prog), |
| 3059 | return 0; | 3060 | reg_a(dst_gpr), ALU_OP_AND, tmp_reg); |
| 3060 | } | 3061 | /* Upper word of the mask can only be 0 or ~0 from sign extension, |
| 3061 | 3062 | * so either ignore it or OR the whole thing in. | |
| 3062 | if (imm & ~0U) { | 3063 | */ |
| 3063 | tmp_reg = ur_load_imm_any(nfp_prog, imm & ~0U, imm_b(nfp_prog)); | 3064 | if (imm >> 32) |
| 3064 | emit_alu(nfp_prog, reg_none(), | ||
| 3065 | reg_a(insn->dst_reg * 2), ALU_OP_AND, tmp_reg); | ||
| 3066 | emit_br(nfp_prog, BR_BNE, insn->off, 0); | ||
| 3067 | } | ||
| 3068 | |||
| 3069 | if (imm >> 32) { | ||
| 3070 | tmp_reg = ur_load_imm_any(nfp_prog, imm >> 32, imm_b(nfp_prog)); | ||
| 3071 | emit_alu(nfp_prog, reg_none(), | 3065 | emit_alu(nfp_prog, reg_none(), |
| 3072 | reg_a(insn->dst_reg * 2 + 1), ALU_OP_AND, tmp_reg); | 3066 | reg_a(dst_gpr + 1), ALU_OP_OR, imm_b(nfp_prog)); |
| 3073 | emit_br(nfp_prog, BR_BNE, insn->off, 0); | 3067 | emit_br(nfp_prog, BR_BNE, insn->off, 0); |
| 3074 | } | ||
| 3075 | 3068 | ||
| 3076 | return 0; | 3069 | return 0; |
| 3077 | } | 3070 | } |
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 5c64281d566e..d27d5a880015 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c | |||
| @@ -3859,6 +3859,12 @@ static int is_branch_taken(struct bpf_reg_state *reg, u64 val, u8 opcode) | |||
| 3859 | if (tnum_is_const(reg->var_off)) | 3859 | if (tnum_is_const(reg->var_off)) |
| 3860 | return !tnum_equals_const(reg->var_off, val); | 3860 | return !tnum_equals_const(reg->var_off, val); |
| 3861 | break; | 3861 | break; |
| 3862 | case BPF_JSET: | ||
| 3863 | if ((~reg->var_off.mask & reg->var_off.value) & val) | ||
| 3864 | return 1; | ||
| 3865 | if (!((reg->var_off.mask | reg->var_off.value) & val)) | ||
| 3866 | return 0; | ||
| 3867 | break; | ||
| 3862 | case BPF_JGT: | 3868 | case BPF_JGT: |
| 3863 | if (reg->umin_value > val) | 3869 | if (reg->umin_value > val) |
| 3864 | return 1; | 3870 | return 1; |
| @@ -3943,6 +3949,13 @@ static void reg_set_min_max(struct bpf_reg_state *true_reg, | |||
| 3943 | */ | 3949 | */ |
| 3944 | __mark_reg_known(false_reg, val); | 3950 | __mark_reg_known(false_reg, val); |
| 3945 | break; | 3951 | break; |
| 3952 | case BPF_JSET: | ||
| 3953 | false_reg->var_off = tnum_and(false_reg->var_off, | ||
| 3954 | tnum_const(~val)); | ||
| 3955 | if (is_power_of_2(val)) | ||
| 3956 | true_reg->var_off = tnum_or(true_reg->var_off, | ||
| 3957 | tnum_const(val)); | ||
| 3958 | break; | ||
| 3946 | case BPF_JGT: | 3959 | case BPF_JGT: |
| 3947 | false_reg->umax_value = min(false_reg->umax_value, val); | 3960 | false_reg->umax_value = min(false_reg->umax_value, val); |
| 3948 | true_reg->umin_value = max(true_reg->umin_value, val + 1); | 3961 | true_reg->umin_value = max(true_reg->umin_value, val + 1); |
| @@ -4015,6 +4028,13 @@ static void reg_set_min_max_inv(struct bpf_reg_state *true_reg, | |||
| 4015 | */ | 4028 | */ |
| 4016 | __mark_reg_known(false_reg, val); | 4029 | __mark_reg_known(false_reg, val); |
| 4017 | break; | 4030 | break; |
| 4031 | case BPF_JSET: | ||
| 4032 | false_reg->var_off = tnum_and(false_reg->var_off, | ||
| 4033 | tnum_const(~val)); | ||
| 4034 | if (is_power_of_2(val)) | ||
| 4035 | true_reg->var_off = tnum_or(true_reg->var_off, | ||
| 4036 | tnum_const(val)); | ||
| 4037 | break; | ||
| 4018 | case BPF_JGT: | 4038 | case BPF_JGT: |
| 4019 | true_reg->umax_value = min(true_reg->umax_value, val - 1); | 4039 | true_reg->umax_value = min(true_reg->umax_value, val - 1); |
| 4020 | false_reg->umin_value = max(false_reg->umin_value, val); | 4040 | false_reg->umin_value = max(false_reg->umin_value, val); |
| @@ -6963,10 +6983,11 @@ skip_full_check: | |||
| 6963 | free_states(env); | 6983 | free_states(env); |
| 6964 | 6984 | ||
| 6965 | if (ret == 0) | 6985 | if (ret == 0) |
| 6966 | sanitize_dead_code(env); | 6986 | ret = check_max_stack_depth(env); |
| 6967 | 6987 | ||
| 6988 | /* instruction rewrites happen after this point */ | ||
| 6968 | if (ret == 0) | 6989 | if (ret == 0) |
| 6969 | ret = check_max_stack_depth(env); | 6990 | sanitize_dead_code(env); |
| 6970 | 6991 | ||
| 6971 | if (ret == 0) | 6992 | if (ret == 0) |
| 6972 | /* program is valid, convert *(u32*)(ctx + off) accesses */ | 6993 | /* program is valid, convert *(u32*)(ctx + off) accesses */ |
diff --git a/tools/testing/selftests/bpf/.gitignore b/tools/testing/selftests/bpf/.gitignore index 1b799e30c06d..4a9785043a39 100644 --- a/tools/testing/selftests/bpf/.gitignore +++ b/tools/testing/selftests/bpf/.gitignore | |||
| @@ -27,3 +27,4 @@ test_flow_dissector | |||
| 27 | flow_dissector_load | 27 | flow_dissector_load |
| 28 | test_netcnt | 28 | test_netcnt |
| 29 | test_section_names | 29 | test_section_names |
| 30 | test_tcpnotify_user | ||
diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c index 7865b94c02c4..b246931c46ef 100644 --- a/tools/testing/selftests/bpf/test_verifier.c +++ b/tools/testing/selftests/bpf/test_verifier.c | |||
| @@ -49,6 +49,7 @@ | |||
| 49 | #define MAX_INSNS BPF_MAXINSNS | 49 | #define MAX_INSNS BPF_MAXINSNS |
| 50 | #define MAX_FIXUPS 8 | 50 | #define MAX_FIXUPS 8 |
| 51 | #define MAX_NR_MAPS 13 | 51 | #define MAX_NR_MAPS 13 |
| 52 | #define MAX_TEST_RUNS 8 | ||
| 52 | #define POINTER_VALUE 0xcafe4all | 53 | #define POINTER_VALUE 0xcafe4all |
| 53 | #define TEST_DATA_LEN 64 | 54 | #define TEST_DATA_LEN 64 |
| 54 | 55 | ||
| @@ -86,6 +87,14 @@ struct bpf_test { | |||
| 86 | uint8_t flags; | 87 | uint8_t flags; |
| 87 | __u8 data[TEST_DATA_LEN]; | 88 | __u8 data[TEST_DATA_LEN]; |
| 88 | void (*fill_helper)(struct bpf_test *self); | 89 | void (*fill_helper)(struct bpf_test *self); |
| 90 | uint8_t runs; | ||
| 91 | struct { | ||
| 92 | uint32_t retval, retval_unpriv; | ||
| 93 | union { | ||
| 94 | __u8 data[TEST_DATA_LEN]; | ||
| 95 | __u64 data64[TEST_DATA_LEN / 8]; | ||
| 96 | }; | ||
| 97 | } retvals[MAX_TEST_RUNS]; | ||
| 89 | }; | 98 | }; |
| 90 | 99 | ||
| 91 | /* Note we want this to be 64 bit aligned so that the end of our array is | 100 | /* Note we want this to be 64 bit aligned so that the end of our array is |
| @@ -14161,6 +14170,197 @@ static struct bpf_test tests[] = { | |||
| 14161 | .errstr_unpriv = "R1 leaks addr", | 14170 | .errstr_unpriv = "R1 leaks addr", |
| 14162 | .result = REJECT, | 14171 | .result = REJECT, |
| 14163 | }, | 14172 | }, |
| 14173 | { | ||
| 14174 | "jset: functional", | ||
| 14175 | .insns = { | ||
| 14176 | /* r0 = 0 */ | ||
| 14177 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
| 14178 | /* prep for direct packet access via r2 */ | ||
| 14179 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | ||
| 14180 | offsetof(struct __sk_buff, data)), | ||
| 14181 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | ||
| 14182 | offsetof(struct __sk_buff, data_end)), | ||
| 14183 | BPF_MOV64_REG(BPF_REG_4, BPF_REG_2), | ||
| 14184 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 8), | ||
| 14185 | BPF_JMP_REG(BPF_JLE, BPF_REG_4, BPF_REG_3, 1), | ||
| 14186 | BPF_EXIT_INSN(), | ||
| 14187 | |||
| 14188 | BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_2, 0), | ||
| 14189 | |||
| 14190 | /* reg, bit 63 or bit 0 set, taken */ | ||
| 14191 | BPF_LD_IMM64(BPF_REG_8, 0x8000000000000001), | ||
| 14192 | BPF_JMP_REG(BPF_JSET, BPF_REG_7, BPF_REG_8, 1), | ||
| 14193 | BPF_EXIT_INSN(), | ||
| 14194 | |||
| 14195 | /* reg, bit 62, not taken */ | ||
| 14196 | BPF_LD_IMM64(BPF_REG_8, 0x4000000000000000), | ||
| 14197 | BPF_JMP_REG(BPF_JSET, BPF_REG_7, BPF_REG_8, 1), | ||
| 14198 | BPF_JMP_IMM(BPF_JA, 0, 0, 1), | ||
| 14199 | BPF_EXIT_INSN(), | ||
| 14200 | |||
| 14201 | /* imm, any bit set, taken */ | ||
| 14202 | BPF_JMP_IMM(BPF_JSET, BPF_REG_7, -1, 1), | ||
| 14203 | BPF_EXIT_INSN(), | ||
| 14204 | |||
| 14205 | /* imm, bit 31 set, taken */ | ||
| 14206 | BPF_JMP_IMM(BPF_JSET, BPF_REG_7, 0x80000000, 1), | ||
| 14207 | BPF_EXIT_INSN(), | ||
| 14208 | |||
| 14209 | /* all good - return r0 == 2 */ | ||
| 14210 | BPF_MOV64_IMM(BPF_REG_0, 2), | ||
| 14211 | BPF_EXIT_INSN(), | ||
| 14212 | }, | ||
| 14213 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
| 14214 | .result = ACCEPT, | ||
| 14215 | .runs = 7, | ||
| 14216 | .retvals = { | ||
| 14217 | { .retval = 2, | ||
| 14218 | .data64 = { (1ULL << 63) | (1U << 31) | (1U << 0), } | ||
| 14219 | }, | ||
| 14220 | { .retval = 2, | ||
| 14221 | .data64 = { (1ULL << 63) | (1U << 31), } | ||
| 14222 | }, | ||
| 14223 | { .retval = 2, | ||
| 14224 | .data64 = { (1ULL << 31) | (1U << 0), } | ||
| 14225 | }, | ||
| 14226 | { .retval = 2, | ||
| 14227 | .data64 = { (__u32)-1, } | ||
| 14228 | }, | ||
| 14229 | { .retval = 2, | ||
| 14230 | .data64 = { ~0x4000000000000000ULL, } | ||
| 14231 | }, | ||
| 14232 | { .retval = 0, | ||
| 14233 | .data64 = { 0, } | ||
| 14234 | }, | ||
| 14235 | { .retval = 0, | ||
| 14236 | .data64 = { ~0ULL, } | ||
| 14237 | }, | ||
| 14238 | }, | ||
| 14239 | }, | ||
| 14240 | { | ||
| 14241 | "jset: sign-extend", | ||
| 14242 | .insns = { | ||
| 14243 | /* r0 = 0 */ | ||
| 14244 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
| 14245 | /* prep for direct packet access via r2 */ | ||
| 14246 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | ||
| 14247 | offsetof(struct __sk_buff, data)), | ||
| 14248 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | ||
| 14249 | offsetof(struct __sk_buff, data_end)), | ||
| 14250 | BPF_MOV64_REG(BPF_REG_4, BPF_REG_2), | ||
| 14251 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 8), | ||
| 14252 | BPF_JMP_REG(BPF_JLE, BPF_REG_4, BPF_REG_3, 1), | ||
| 14253 | BPF_EXIT_INSN(), | ||
| 14254 | |||
| 14255 | BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_2, 0), | ||
| 14256 | |||
| 14257 | BPF_JMP_IMM(BPF_JSET, BPF_REG_7, 0x80000000, 1), | ||
| 14258 | BPF_EXIT_INSN(), | ||
| 14259 | |||
| 14260 | BPF_MOV64_IMM(BPF_REG_0, 2), | ||
| 14261 | BPF_EXIT_INSN(), | ||
| 14262 | }, | ||
| 14263 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
| 14264 | .result = ACCEPT, | ||
| 14265 | .retval = 2, | ||
| 14266 | .data = { 1, 0, 0, 0, 0, 0, 0, 1, }, | ||
| 14267 | }, | ||
| 14268 | { | ||
| 14269 | "jset: known const compare", | ||
| 14270 | .insns = { | ||
| 14271 | BPF_MOV64_IMM(BPF_REG_0, 1), | ||
| 14272 | BPF_JMP_IMM(BPF_JSET, BPF_REG_0, 1, 1), | ||
| 14273 | BPF_LDX_MEM(BPF_B, BPF_REG_8, BPF_REG_9, 0), | ||
| 14274 | BPF_EXIT_INSN(), | ||
| 14275 | }, | ||
| 14276 | .prog_type = BPF_PROG_TYPE_SOCKET_FILTER, | ||
| 14277 | .retval_unpriv = 1, | ||
| 14278 | .result_unpriv = ACCEPT, | ||
| 14279 | .retval = 1, | ||
| 14280 | .result = ACCEPT, | ||
| 14281 | }, | ||
| 14282 | { | ||
| 14283 | "jset: known const compare bad", | ||
| 14284 | .insns = { | ||
| 14285 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
| 14286 | BPF_JMP_IMM(BPF_JSET, BPF_REG_0, 1, 1), | ||
| 14287 | BPF_LDX_MEM(BPF_B, BPF_REG_8, BPF_REG_9, 0), | ||
| 14288 | BPF_EXIT_INSN(), | ||
| 14289 | }, | ||
| 14290 | .prog_type = BPF_PROG_TYPE_SOCKET_FILTER, | ||
| 14291 | .errstr_unpriv = "!read_ok", | ||
| 14292 | .result_unpriv = REJECT, | ||
| 14293 | .errstr = "!read_ok", | ||
| 14294 | .result = REJECT, | ||
| 14295 | }, | ||
| 14296 | { | ||
| 14297 | "jset: unknown const compare taken", | ||
| 14298 | .insns = { | ||
| 14299 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, | ||
| 14300 | BPF_FUNC_get_prandom_u32), | ||
| 14301 | BPF_JMP_IMM(BPF_JSET, BPF_REG_0, 1, 1), | ||
| 14302 | BPF_JMP_IMM(BPF_JA, 0, 0, 1), | ||
| 14303 | BPF_LDX_MEM(BPF_B, BPF_REG_8, BPF_REG_9, 0), | ||
| 14304 | BPF_EXIT_INSN(), | ||
| 14305 | }, | ||
| 14306 | .prog_type = BPF_PROG_TYPE_SOCKET_FILTER, | ||
| 14307 | .errstr_unpriv = "!read_ok", | ||
| 14308 | .result_unpriv = REJECT, | ||
| 14309 | .errstr = "!read_ok", | ||
| 14310 | .result = REJECT, | ||
| 14311 | }, | ||
| 14312 | { | ||
| 14313 | "jset: unknown const compare not taken", | ||
| 14314 | .insns = { | ||
| 14315 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, | ||
| 14316 | BPF_FUNC_get_prandom_u32), | ||
| 14317 | BPF_JMP_IMM(BPF_JSET, BPF_REG_0, 1, 1), | ||
| 14318 | BPF_LDX_MEM(BPF_B, BPF_REG_8, BPF_REG_9, 0), | ||
| 14319 | BPF_EXIT_INSN(), | ||
| 14320 | }, | ||
| 14321 | .prog_type = BPF_PROG_TYPE_SOCKET_FILTER, | ||
| 14322 | .errstr_unpriv = "!read_ok", | ||
| 14323 | .result_unpriv = REJECT, | ||
| 14324 | .errstr = "!read_ok", | ||
| 14325 | .result = REJECT, | ||
| 14326 | }, | ||
| 14327 | { | ||
| 14328 | "jset: half-known const compare", | ||
| 14329 | .insns = { | ||
| 14330 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, | ||
| 14331 | BPF_FUNC_get_prandom_u32), | ||
| 14332 | BPF_ALU64_IMM(BPF_OR, BPF_REG_0, 2), | ||
| 14333 | BPF_JMP_IMM(BPF_JSET, BPF_REG_0, 3, 1), | ||
| 14334 | BPF_LDX_MEM(BPF_B, BPF_REG_8, BPF_REG_9, 0), | ||
| 14335 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
| 14336 | BPF_EXIT_INSN(), | ||
| 14337 | }, | ||
| 14338 | .prog_type = BPF_PROG_TYPE_SOCKET_FILTER, | ||
| 14339 | .result_unpriv = ACCEPT, | ||
| 14340 | .result = ACCEPT, | ||
| 14341 | }, | ||
| 14342 | { | ||
| 14343 | "jset: range", | ||
| 14344 | .insns = { | ||
| 14345 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, | ||
| 14346 | BPF_FUNC_get_prandom_u32), | ||
| 14347 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), | ||
| 14348 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
| 14349 | BPF_ALU64_IMM(BPF_AND, BPF_REG_1, 0xff), | ||
| 14350 | BPF_JMP_IMM(BPF_JSET, BPF_REG_1, 0xf0, 3), | ||
| 14351 | BPF_JMP_IMM(BPF_JLT, BPF_REG_1, 0x10, 1), | ||
| 14352 | BPF_LDX_MEM(BPF_B, BPF_REG_8, BPF_REG_9, 0), | ||
| 14353 | BPF_EXIT_INSN(), | ||
| 14354 | BPF_JMP_IMM(BPF_JSET, BPF_REG_1, 0x10, 1), | ||
| 14355 | BPF_EXIT_INSN(), | ||
| 14356 | BPF_JMP_IMM(BPF_JGE, BPF_REG_1, 0x10, 1), | ||
| 14357 | BPF_LDX_MEM(BPF_B, BPF_REG_8, BPF_REG_9, 0), | ||
| 14358 | BPF_EXIT_INSN(), | ||
| 14359 | }, | ||
| 14360 | .prog_type = BPF_PROG_TYPE_SOCKET_FILTER, | ||
| 14361 | .result_unpriv = ACCEPT, | ||
| 14362 | .result = ACCEPT, | ||
| 14363 | }, | ||
| 14164 | }; | 14364 | }; |
| 14165 | 14365 | ||
| 14166 | static int probe_filter_length(const struct bpf_insn *fp) | 14366 | static int probe_filter_length(const struct bpf_insn *fp) |
| @@ -14443,16 +14643,42 @@ out: | |||
| 14443 | return ret; | 14643 | return ret; |
| 14444 | } | 14644 | } |
| 14445 | 14645 | ||
| 14646 | static int do_prog_test_run(int fd_prog, bool unpriv, uint32_t expected_val, | ||
| 14647 | void *data, size_t size_data) | ||
| 14648 | { | ||
| 14649 | __u8 tmp[TEST_DATA_LEN << 2]; | ||
| 14650 | __u32 size_tmp = sizeof(tmp); | ||
| 14651 | uint32_t retval; | ||
| 14652 | int err; | ||
| 14653 | |||
| 14654 | if (unpriv) | ||
| 14655 | set_admin(true); | ||
| 14656 | err = bpf_prog_test_run(fd_prog, 1, data, size_data, | ||
| 14657 | tmp, &size_tmp, &retval, NULL); | ||
| 14658 | if (unpriv) | ||
| 14659 | set_admin(false); | ||
| 14660 | if (err && errno != 524/*ENOTSUPP*/ && errno != EPERM) { | ||
| 14661 | printf("Unexpected bpf_prog_test_run error "); | ||
| 14662 | return err; | ||
| 14663 | } | ||
| 14664 | if (!err && retval != expected_val && | ||
| 14665 | expected_val != POINTER_VALUE) { | ||
| 14666 | printf("FAIL retval %d != %d ", retval, expected_val); | ||
| 14667 | return 1; | ||
| 14668 | } | ||
| 14669 | |||
| 14670 | return 0; | ||
| 14671 | } | ||
| 14672 | |||
| 14446 | static void do_test_single(struct bpf_test *test, bool unpriv, | 14673 | static void do_test_single(struct bpf_test *test, bool unpriv, |
| 14447 | int *passes, int *errors) | 14674 | int *passes, int *errors) |
| 14448 | { | 14675 | { |
| 14449 | int fd_prog, expected_ret, alignment_prevented_execution; | 14676 | int fd_prog, expected_ret, alignment_prevented_execution; |
| 14450 | int prog_len, prog_type = test->prog_type; | 14677 | int prog_len, prog_type = test->prog_type; |
| 14451 | struct bpf_insn *prog = test->insns; | 14678 | struct bpf_insn *prog = test->insns; |
| 14679 | int run_errs, run_successes; | ||
| 14452 | int map_fds[MAX_NR_MAPS]; | 14680 | int map_fds[MAX_NR_MAPS]; |
| 14453 | const char *expected_err; | 14681 | const char *expected_err; |
| 14454 | uint32_t expected_val; | ||
| 14455 | uint32_t retval; | ||
| 14456 | __u32 pflags; | 14682 | __u32 pflags; |
| 14457 | int i, err; | 14683 | int i, err; |
| 14458 | 14684 | ||
| @@ -14476,8 +14702,6 @@ static void do_test_single(struct bpf_test *test, bool unpriv, | |||
| 14476 | test->result_unpriv : test->result; | 14702 | test->result_unpriv : test->result; |
| 14477 | expected_err = unpriv && test->errstr_unpriv ? | 14703 | expected_err = unpriv && test->errstr_unpriv ? |
| 14478 | test->errstr_unpriv : test->errstr; | 14704 | test->errstr_unpriv : test->errstr; |
| 14479 | expected_val = unpriv && test->retval_unpriv ? | ||
| 14480 | test->retval_unpriv : test->retval; | ||
| 14481 | 14705 | ||
| 14482 | alignment_prevented_execution = 0; | 14706 | alignment_prevented_execution = 0; |
| 14483 | 14707 | ||
| @@ -14489,10 +14713,8 @@ static void do_test_single(struct bpf_test *test, bool unpriv, | |||
| 14489 | } | 14713 | } |
| 14490 | #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS | 14714 | #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS |
| 14491 | if (fd_prog >= 0 && | 14715 | if (fd_prog >= 0 && |
| 14492 | (test->flags & F_NEEDS_EFFICIENT_UNALIGNED_ACCESS)) { | 14716 | (test->flags & F_NEEDS_EFFICIENT_UNALIGNED_ACCESS)) |
| 14493 | alignment_prevented_execution = 1; | 14717 | alignment_prevented_execution = 1; |
| 14494 | goto test_ok; | ||
| 14495 | } | ||
| 14496 | #endif | 14718 | #endif |
| 14497 | } else { | 14719 | } else { |
| 14498 | if (fd_prog >= 0) { | 14720 | if (fd_prog >= 0) { |
| @@ -14519,33 +14741,54 @@ static void do_test_single(struct bpf_test *test, bool unpriv, | |||
| 14519 | } | 14741 | } |
| 14520 | } | 14742 | } |
| 14521 | 14743 | ||
| 14522 | if (fd_prog >= 0) { | 14744 | run_errs = 0; |
| 14523 | __u8 tmp[TEST_DATA_LEN << 2]; | 14745 | run_successes = 0; |
| 14524 | __u32 size_tmp = sizeof(tmp); | 14746 | if (!alignment_prevented_execution && fd_prog >= 0) { |
| 14525 | 14747 | uint32_t expected_val; | |
| 14526 | if (unpriv) | 14748 | int i; |
| 14527 | set_admin(true); | 14749 | |
| 14528 | err = bpf_prog_test_run(fd_prog, 1, test->data, | 14750 | if (!test->runs) { |
| 14529 | sizeof(test->data), tmp, &size_tmp, | 14751 | expected_val = unpriv && test->retval_unpriv ? |
| 14530 | &retval, NULL); | 14752 | test->retval_unpriv : test->retval; |
| 14531 | if (unpriv) | 14753 | |
| 14532 | set_admin(false); | 14754 | err = do_prog_test_run(fd_prog, unpriv, expected_val, |
| 14533 | if (err && errno != 524/*ENOTSUPP*/ && errno != EPERM) { | 14755 | test->data, sizeof(test->data)); |
| 14534 | printf("Unexpected bpf_prog_test_run error\n"); | 14756 | if (err) |
| 14535 | goto fail_log; | 14757 | run_errs++; |
| 14758 | else | ||
| 14759 | run_successes++; | ||
| 14536 | } | 14760 | } |
| 14537 | if (!err && retval != expected_val && | 14761 | |
| 14538 | expected_val != POINTER_VALUE) { | 14762 | for (i = 0; i < test->runs; i++) { |
| 14539 | printf("FAIL retval %d != %d\n", retval, expected_val); | 14763 | if (unpriv && test->retvals[i].retval_unpriv) |
| 14540 | goto fail_log; | 14764 | expected_val = test->retvals[i].retval_unpriv; |
| 14765 | else | ||
| 14766 | expected_val = test->retvals[i].retval; | ||
| 14767 | |||
| 14768 | err = do_prog_test_run(fd_prog, unpriv, expected_val, | ||
| 14769 | test->retvals[i].data, | ||
| 14770 | sizeof(test->retvals[i].data)); | ||
| 14771 | if (err) { | ||
| 14772 | printf("(run %d/%d) ", i + 1, test->runs); | ||
| 14773 | run_errs++; | ||
| 14774 | } else { | ||
| 14775 | run_successes++; | ||
| 14776 | } | ||
| 14541 | } | 14777 | } |
| 14542 | } | 14778 | } |
| 14543 | #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS | 14779 | |
| 14544 | test_ok: | 14780 | if (!run_errs) { |
| 14545 | #endif | 14781 | (*passes)++; |
| 14546 | (*passes)++; | 14782 | if (run_successes > 1) |
| 14547 | printf("OK%s\n", alignment_prevented_execution ? | 14783 | printf("%d cases ", run_successes); |
| 14548 | " (NOTE: not executed due to unknown alignment)" : ""); | 14784 | printf("OK"); |
| 14785 | if (alignment_prevented_execution) | ||
| 14786 | printf(" (NOTE: not executed due to unknown alignment)"); | ||
| 14787 | printf("\n"); | ||
| 14788 | } else { | ||
| 14789 | printf("\n"); | ||
| 14790 | goto fail_log; | ||
| 14791 | } | ||
| 14549 | close_fds: | 14792 | close_fds: |
| 14550 | close(fd_prog); | 14793 | close(fd_prog); |
| 14551 | for (i = 0; i < MAX_NR_MAPS; i++) | 14794 | for (i = 0; i < MAX_NR_MAPS; i++) |
