diff options
Diffstat (limited to 'kernel/bpf/verifier.c')
-rw-r--r-- | kernel/bpf/verifier.c | 61 |
1 files changed, 48 insertions, 13 deletions
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index f6bc62a9ee8e..56674a7c3778 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c | |||
@@ -3103,6 +3103,40 @@ static int retrieve_ptr_limit(const struct bpf_reg_state *ptr_reg, | |||
3103 | } | 3103 | } |
3104 | } | 3104 | } |
3105 | 3105 | ||
3106 | static bool can_skip_alu_sanitation(const struct bpf_verifier_env *env, | ||
3107 | const struct bpf_insn *insn) | ||
3108 | { | ||
3109 | return env->allow_ptr_leaks || BPF_SRC(insn->code) == BPF_K; | ||
3110 | } | ||
3111 | |||
3112 | static int update_alu_sanitation_state(struct bpf_insn_aux_data *aux, | ||
3113 | u32 alu_state, u32 alu_limit) | ||
3114 | { | ||
3115 | /* If we arrived here from different branches with different | ||
3116 | * state or limits to sanitize, then this won't work. | ||
3117 | */ | ||
3118 | if (aux->alu_state && | ||
3119 | (aux->alu_state != alu_state || | ||
3120 | aux->alu_limit != alu_limit)) | ||
3121 | return -EACCES; | ||
3122 | |||
3123 | /* Corresponding fixup done in fixup_bpf_calls(). */ | ||
3124 | aux->alu_state = alu_state; | ||
3125 | aux->alu_limit = alu_limit; | ||
3126 | return 0; | ||
3127 | } | ||
3128 | |||
3129 | static int sanitize_val_alu(struct bpf_verifier_env *env, | ||
3130 | struct bpf_insn *insn) | ||
3131 | { | ||
3132 | struct bpf_insn_aux_data *aux = cur_aux(env); | ||
3133 | |||
3134 | if (can_skip_alu_sanitation(env, insn)) | ||
3135 | return 0; | ||
3136 | |||
3137 | return update_alu_sanitation_state(aux, BPF_ALU_NON_POINTER, 0); | ||
3138 | } | ||
3139 | |||
3106 | static int sanitize_ptr_alu(struct bpf_verifier_env *env, | 3140 | static int sanitize_ptr_alu(struct bpf_verifier_env *env, |
3107 | struct bpf_insn *insn, | 3141 | struct bpf_insn *insn, |
3108 | const struct bpf_reg_state *ptr_reg, | 3142 | const struct bpf_reg_state *ptr_reg, |
@@ -3117,7 +3151,7 @@ static int sanitize_ptr_alu(struct bpf_verifier_env *env, | |||
3117 | struct bpf_reg_state tmp; | 3151 | struct bpf_reg_state tmp; |
3118 | bool ret; | 3152 | bool ret; |
3119 | 3153 | ||
3120 | if (env->allow_ptr_leaks || BPF_SRC(insn->code) == BPF_K) | 3154 | if (can_skip_alu_sanitation(env, insn)) |
3121 | return 0; | 3155 | return 0; |
3122 | 3156 | ||
3123 | /* We already marked aux for masking from non-speculative | 3157 | /* We already marked aux for masking from non-speculative |
@@ -3133,19 +3167,8 @@ static int sanitize_ptr_alu(struct bpf_verifier_env *env, | |||
3133 | 3167 | ||
3134 | if (retrieve_ptr_limit(ptr_reg, &alu_limit, opcode, off_is_neg)) | 3168 | if (retrieve_ptr_limit(ptr_reg, &alu_limit, opcode, off_is_neg)) |
3135 | return 0; | 3169 | return 0; |
3136 | 3170 | if (update_alu_sanitation_state(aux, alu_state, alu_limit)) | |
3137 | /* If we arrived here from different branches with different | ||
3138 | * limits to sanitize, then this won't work. | ||
3139 | */ | ||
3140 | if (aux->alu_state && | ||
3141 | (aux->alu_state != alu_state || | ||
3142 | aux->alu_limit != alu_limit)) | ||
3143 | return -EACCES; | 3171 | return -EACCES; |
3144 | |||
3145 | /* Corresponding fixup done in fixup_bpf_calls(). */ | ||
3146 | aux->alu_state = alu_state; | ||
3147 | aux->alu_limit = alu_limit; | ||
3148 | |||
3149 | do_sim: | 3172 | do_sim: |
3150 | /* Simulate and find potential out-of-bounds access under | 3173 | /* Simulate and find potential out-of-bounds access under |
3151 | * speculative execution from truncation as a result of | 3174 | * speculative execution from truncation as a result of |
@@ -3418,6 +3441,8 @@ static int adjust_scalar_min_max_vals(struct bpf_verifier_env *env, | |||
3418 | s64 smin_val, smax_val; | 3441 | s64 smin_val, smax_val; |
3419 | u64 umin_val, umax_val; | 3442 | u64 umin_val, umax_val; |
3420 | u64 insn_bitness = (BPF_CLASS(insn->code) == BPF_ALU64) ? 64 : 32; | 3443 | u64 insn_bitness = (BPF_CLASS(insn->code) == BPF_ALU64) ? 64 : 32; |
3444 | u32 dst = insn->dst_reg; | ||
3445 | int ret; | ||
3421 | 3446 | ||
3422 | if (insn_bitness == 32) { | 3447 | if (insn_bitness == 32) { |
3423 | /* Relevant for 32-bit RSH: Information can propagate towards | 3448 | /* Relevant for 32-bit RSH: Information can propagate towards |
@@ -3452,6 +3477,11 @@ static int adjust_scalar_min_max_vals(struct bpf_verifier_env *env, | |||
3452 | 3477 | ||
3453 | switch (opcode) { | 3478 | switch (opcode) { |
3454 | case BPF_ADD: | 3479 | case BPF_ADD: |
3480 | ret = sanitize_val_alu(env, insn); | ||
3481 | if (ret < 0) { | ||
3482 | verbose(env, "R%d tried to add from different pointers or scalars\n", dst); | ||
3483 | return ret; | ||
3484 | } | ||
3455 | if (signed_add_overflows(dst_reg->smin_value, smin_val) || | 3485 | if (signed_add_overflows(dst_reg->smin_value, smin_val) || |
3456 | signed_add_overflows(dst_reg->smax_value, smax_val)) { | 3486 | signed_add_overflows(dst_reg->smax_value, smax_val)) { |
3457 | dst_reg->smin_value = S64_MIN; | 3487 | dst_reg->smin_value = S64_MIN; |
@@ -3471,6 +3501,11 @@ static int adjust_scalar_min_max_vals(struct bpf_verifier_env *env, | |||
3471 | dst_reg->var_off = tnum_add(dst_reg->var_off, src_reg.var_off); | 3501 | dst_reg->var_off = tnum_add(dst_reg->var_off, src_reg.var_off); |
3472 | break; | 3502 | break; |
3473 | case BPF_SUB: | 3503 | case BPF_SUB: |
3504 | ret = sanitize_val_alu(env, insn); | ||
3505 | if (ret < 0) { | ||
3506 | verbose(env, "R%d tried to sub from different pointers or scalars\n", dst); | ||
3507 | return ret; | ||
3508 | } | ||
3474 | if (signed_sub_overflows(dst_reg->smin_value, smax_val) || | 3509 | if (signed_sub_overflows(dst_reg->smin_value, smax_val) || |
3475 | signed_sub_overflows(dst_reg->smax_value, smin_val)) { | 3510 | signed_sub_overflows(dst_reg->smax_value, smin_val)) { |
3476 | /* Overflow possible, we know nothing */ | 3511 | /* Overflow possible, we know nothing */ |