Consolidate all error handling and provide more user-friendly error messages from sanitize_ptr_alu() and sanitize_val_alu().
Unified · Split
| @@ -5856,6 +5856,14 @@ static struct bpf_insn_aux_data *cur_aux(struct bpf_verifier_env *env) · 5855 unmodified lines | ||
| 5856 | 5856 | return &env->insn_aux_data[env->insn_idx]; |
| 5857 | 5857 | } |
| 5858 | 5858 | |
| 5859 | +enum { | |
| 5860 | + REASON_BOUNDS = -1, | |
| 5861 | + REASON_TYPE = -2, | |
| 5862 | + REASON_PATHS = -3, | |
| 5863 | + REASON_LIMIT = -4, | |
| 5864 | + REASON_STACK = -5, | |
| 5865 | +}; | |
| 5866 | + | |
| 5859 | 5867 | static int retrieve_ptr_limit(const struct bpf_reg_state *ptr_reg, |
| 5860 | 5868 | const struct bpf_reg_state *off_reg, |
| 5861 | 5869 | u32 *alu_limit, u8 opcode) |
| @@ -5867,7 +5875,7 @@ static int retrieve_ptr_limit(const struct bpf_reg_state *ptr_reg, · 5 unmodified lines | ||
| 5867 | 5875 | |
| 5868 | 5876 | if (!tnum_is_const(off_reg->var_off) && |
| 5869 | 5877 | (off_reg->smin_value < 0) != (off_reg->smax_value < 0)) |
| 5870 | − return -EACCES; | |
| 5878 | + return REASON_BOUNDS; | |
| 5871 | 5879 | |
| 5872 | 5880 | switch (ptr_reg->type) { |
| 5873 | 5881 | case PTR_TO_STACK: |
| @@ -5894,11 +5902,11 @@ static int retrieve_ptr_limit(const struct bpf_reg_state *ptr_reg, · 20 unmodified lines | ||
| 5894 | 5902 | } |
| 5895 | 5903 | break; |
| 5896 | 5904 | default: |
| 5897 | − return -EINVAL; | |
| 5905 | + return REASON_TYPE; | |
| 5898 | 5906 | } |
| 5899 | 5907 | |
| 5900 | 5908 | if (ptr_limit >= max) |
| 5901 | − return -ERANGE; | |
| 5909 | + return REASON_LIMIT; | |
| 5902 | 5910 | *alu_limit = ptr_limit; |
| 5903 | 5911 | return 0; |
| 5904 | 5912 | } |
| @@ -5918,7 +5926,7 @@ static int update_alu_sanitation_state(struct bpf_insn_aux_data *aux, · 13 unmodified lines | ||
| 5918 | 5926 | if (aux->alu_state && |
| 5919 | 5927 | (aux->alu_state != alu_state || |
| 5920 | 5928 | aux->alu_limit != alu_limit)) |
| 5921 | − return -EACCES; | |
| 5929 | + return REASON_PATHS; | |
| 5922 | 5930 | |
| 5923 | 5931 | /* Corresponding fixup done in fixup_bpf_calls(). */ |
| 5924 | 5932 | aux->alu_state = alu_state; |
| @@ -5991,7 +5999,46 @@ do_sim: · 66 unmodified lines | ||
| 5991 | 5999 | ret = push_stack(env, env->insn_idx + 1, env->insn_idx, true); |
| 5992 | 6000 | if (!ptr_is_dst_reg && ret) |
| 5993 | 6001 | *dst_reg = tmp; |
| 5994 | − return !ret ? -EFAULT : 0; | |
| 6002 | + return !ret ? REASON_STACK : 0; | |
| 6003 | +} | |
| 6004 | + | |
| 6005 | +static int sanitize_err(struct bpf_verifier_env *env, | |
| 6006 | + const struct bpf_insn *insn, int reason, | |
| 6007 | + const struct bpf_reg_state *off_reg, | |
| 6008 | + const struct bpf_reg_state *dst_reg) | |
| 6009 | +{ | |
| 6010 | + static const char *err = "pointer arithmetic with it prohibited for !root"; | |
| 6011 | + const char *op = BPF_OP(insn->code) == BPF_ADD ? "add" : "sub"; | |
| 6012 | + u32 dst = insn->dst_reg, src = insn->src_reg; | |
| 6013 | + | |
| 6014 | + switch (reason) { | |
| 6015 | + case REASON_BOUNDS: | |
| 6016 | + verbose(env, "R%d has unknown scalar with mixed signed bounds, %s\n", | |
| 6017 | + off_reg == dst_reg ? dst : src, err); | |
| 6018 | + break; | |
| 6019 | + case REASON_TYPE: | |
| 6020 | + verbose(env, "R%d has pointer with unsupported alu operation, %s\n", | |
| 6021 | + off_reg == dst_reg ? src : dst, err); | |
| 6022 | + break; | |
| 6023 | + case REASON_PATHS: | |
| 6024 | + verbose(env, "R%d tried to %s from different maps, paths or scalars, %s\n", | |
| 6025 | + dst, op, err); | |
| 6026 | + break; | |
| 6027 | + case REASON_LIMIT: | |
| 6028 | + verbose(env, "R%d tried to %s beyond pointer bounds, %s\n", | |
| 6029 | + dst, op, err); | |
| 6030 | + break; | |
| 6031 | + case REASON_STACK: | |
| 6032 | + verbose(env, "R%d could not be pushed for speculative verification, %s\n", | |
| 6033 | + dst, err); | |
| 6034 | + break; | |
| 6035 | + default: | |
| 6036 | + verbose(env, "verifier internal error: unknown reason (%d)\n", | |
| 6037 | + reason); | |
| 6038 | + break; | |
| 6039 | + } | |
| 6040 | + | |
| 6041 | + return -EACCES; | |
| 5995 | 6042 | } |
| 5996 | 6043 | |
| 5997 | 6044 | /* check that stack access falls within stack limits and that 'reg' doesn't |
| @@ -6116,10 +6163,9 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env, · 118 unmodified lines | ||
| 6116 | 6163 | switch (opcode) { |
| 6117 | 6164 | case BPF_ADD: |
| 6118 | 6165 | ret = sanitize_ptr_alu(env, insn, ptr_reg, off_reg, dst_reg); |
| 6119 | − if (ret < 0) { | |
| 6120 | − verbose(env, "R%d tried to add from different maps, paths, or prohibited types\n", dst); | |
| 6121 | − return ret; | |
| 6122 | − } | |
| 6166 | + if (ret < 0) | |
| 6167 | + return sanitize_err(env, insn, ret, off_reg, dst_reg); | |
| 6168 | + | |
| 6123 | 6169 | /* We can take a fixed offset as long as it doesn't overflow |
| 6124 | 6170 | * the s32 'off' field |
| 6125 | 6171 | */ |
| @@ -6171,10 +6217,9 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env, · 45 unmodified lines | ||
| 6171 | 6217 | break; |
| 6172 | 6218 | case BPF_SUB: |
| 6173 | 6219 | ret = sanitize_ptr_alu(env, insn, ptr_reg, off_reg, dst_reg); |
| 6174 | − if (ret < 0) { | |
| 6175 | − verbose(env, "R%d tried to sub from different maps, paths, or prohibited types\n", dst); | |
| 6176 | − return ret; | |
| 6177 | − } | |
| 6220 | + if (ret < 0) | |
| 6221 | + return sanitize_err(env, insn, ret, off_reg, dst_reg); | |
| 6222 | + | |
| 6178 | 6223 | if (dst_reg == off_reg) { |
| 6179 | 6224 | /* scalar -= pointer. Creates an unknown scalar */ |
| 6180 | 6225 | verbose(env, "R%d tried to subtract pointer from scalar\n", |
| @@ -6863,9 +6908,8 @@ static int adjust_scalar_min_max_vals(struct bpf_verifier_env *env, · 682 unmodified lines | ||
| 6863 | 6908 | s32 s32_min_val, s32_max_val; |
| 6864 | 6909 | u32 u32_min_val, u32_max_val; |
| 6865 | 6910 | u64 insn_bitness = (BPF_CLASS(insn->code) == BPF_ALU64) ? 64 : 32; |
| 6866 | − u32 dst = insn->dst_reg; | |
| 6867 | − int ret; | |
| 6868 | 6911 | bool alu32 = (BPF_CLASS(insn->code) != BPF_ALU64); |
| 6912 | + int ret; | |
| 6869 | 6913 | |
| 6870 | 6914 | smin_val = src_reg.smin_value; |
| 6871 | 6915 | smax_val = src_reg.smax_value; |
| @@ -6924,20 +6968,16 @@ static int adjust_scalar_min_max_vals(struct bpf_verifier_env *env, · 52 unmodified lines | ||
| 6924 | 6968 | switch (opcode) { |
| 6925 | 6969 | case BPF_ADD: |
| 6926 | 6970 | ret = sanitize_val_alu(env, insn); |
| 6927 | − if (ret < 0) { | |
| 6928 | − verbose(env, "R%d tried to add from different pointers or scalars\n", dst); | |
| 6929 | − return ret; | |
| 6930 | − } | |
| 6971 | + if (ret < 0) | |
| 6972 | + return sanitize_err(env, insn, ret, NULL, NULL); | |
| 6931 | 6973 | scalar32_min_max_add(dst_reg, &src_reg); |
| 6932 | 6974 | scalar_min_max_add(dst_reg, &src_reg); |
| 6933 | 6975 | dst_reg->var_off = tnum_add(dst_reg->var_off, src_reg.var_off); |
| 6934 | 6976 | break; |
| 6935 | 6977 | case BPF_SUB: |
| 6936 | 6978 | ret = sanitize_val_alu(env, insn); |
| 6937 | − if (ret < 0) { | |
| 6938 | − verbose(env, "R%d tried to sub from different pointers or scalars\n", dst); | |
| 6939 | − return ret; | |
| 6940 | − } | |
| 6979 | + if (ret < 0) | |
| 6980 | + return sanitize_err(env, insn, ret, NULL, NULL); | |
| 6941 | 6981 | scalar32_min_max_sub(dst_reg, &src_reg); |
| 6942 | 6982 | scalar_min_max_sub(dst_reg, &src_reg); |
| 6943 | 6983 | dst_reg->var_off = tnum_sub(dst_reg->var_off, src_reg.var_off); |