Skip to content

Commit a6aaece

Browse files
committed
bpf: Improve verifier error messages for users
Consolidate all error handling and provide more user-friendly error messages from sanitize_ptr_alu() and sanitize_val_alu(). Signed-off-by: Daniel Borkmann <[email protected]> Reviewed-by: John Fastabend <[email protected]> Acked-by: Alexei Starovoitov <[email protected]>
1 parent b658bbb commit a6aaece

File tree

1 file changed

+63
-23
lines changed

1 file changed

+63
-23
lines changed

kernel/bpf/verifier.c

Lines changed: 63 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5856,6 +5856,14 @@ static struct bpf_insn_aux_data *cur_aux(struct bpf_verifier_env *env)
58565856
return &env->insn_aux_data[env->insn_idx];
58575857
}
58585858

5859+
enum {
5860+
REASON_BOUNDS = -1,
5861+
REASON_TYPE = -2,
5862+
REASON_PATHS = -3,
5863+
REASON_LIMIT = -4,
5864+
REASON_STACK = -5,
5865+
};
5866+
58595867
static int retrieve_ptr_limit(const struct bpf_reg_state *ptr_reg,
58605868
const struct bpf_reg_state *off_reg,
58615869
u32 *alu_limit, u8 opcode)
@@ -5867,7 +5875,7 @@ static int retrieve_ptr_limit(const struct bpf_reg_state *ptr_reg,
58675875

58685876
if (!tnum_is_const(off_reg->var_off) &&
58695877
(off_reg->smin_value < 0) != (off_reg->smax_value < 0))
5870-
return -EACCES;
5878+
return REASON_BOUNDS;
58715879

58725880
switch (ptr_reg->type) {
58735881
case PTR_TO_STACK:
@@ -5894,11 +5902,11 @@ static int retrieve_ptr_limit(const struct bpf_reg_state *ptr_reg,
58945902
}
58955903
break;
58965904
default:
5897-
return -EINVAL;
5905+
return REASON_TYPE;
58985906
}
58995907

59005908
if (ptr_limit >= max)
5901-
return -ERANGE;
5909+
return REASON_LIMIT;
59025910
*alu_limit = ptr_limit;
59035911
return 0;
59045912
}
@@ -5918,7 +5926,7 @@ static int update_alu_sanitation_state(struct bpf_insn_aux_data *aux,
59185926
if (aux->alu_state &&
59195927
(aux->alu_state != alu_state ||
59205928
aux->alu_limit != alu_limit))
5921-
return -EACCES;
5929+
return REASON_PATHS;
59225930

59235931
/* Corresponding fixup done in fixup_bpf_calls(). */
59245932
aux->alu_state = alu_state;
@@ -5991,7 +5999,46 @@ static int sanitize_ptr_alu(struct bpf_verifier_env *env,
59915999
ret = push_stack(env, env->insn_idx + 1, env->insn_idx, true);
59926000
if (!ptr_is_dst_reg && ret)
59936001
*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;
59956042
}
59966043

59976044
/* 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,
61166163
switch (opcode) {
61176164
case BPF_ADD:
61186165
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+
61236169
/* We can take a fixed offset as long as it doesn't overflow
61246170
* the s32 'off' field
61256171
*/
@@ -6171,10 +6217,9 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
61716217
break;
61726218
case BPF_SUB:
61736219
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+
61786223
if (dst_reg == off_reg) {
61796224
/* scalar -= pointer. Creates an unknown scalar */
61806225
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,
68636908
s32 s32_min_val, s32_max_val;
68646909
u32 u32_min_val, u32_max_val;
68656910
u64 insn_bitness = (BPF_CLASS(insn->code) == BPF_ALU64) ? 64 : 32;
6866-
u32 dst = insn->dst_reg;
6867-
int ret;
68686911
bool alu32 = (BPF_CLASS(insn->code) != BPF_ALU64);
6912+
int ret;
68696913

68706914
smin_val = src_reg.smin_value;
68716915
smax_val = src_reg.smax_value;
@@ -6924,20 +6968,16 @@ static int adjust_scalar_min_max_vals(struct bpf_verifier_env *env,
69246968
switch (opcode) {
69256969
case BPF_ADD:
69266970
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);
69316973
scalar32_min_max_add(dst_reg, &src_reg);
69326974
scalar_min_max_add(dst_reg, &src_reg);
69336975
dst_reg->var_off = tnum_add(dst_reg->var_off, src_reg.var_off);
69346976
break;
69356977
case BPF_SUB:
69366978
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);
69416981
scalar32_min_max_sub(dst_reg, &src_reg);
69426982
scalar_min_max_sub(dst_reg, &src_reg);
69436983
dst_reg->var_off = tnum_sub(dst_reg->var_off, src_reg.var_off);

0 commit comments

Comments
 (0)