summaryrefslogtreecommitdiff
path: root/kernel/bpf/verifier.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/bpf/verifier.c')
-rw-r--r--kernel/bpf/verifier.c29
1 files changed, 21 insertions, 8 deletions
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 44b97d958fb7..74ea96ea391b 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -761,22 +761,34 @@ static int check_packet_access(struct bpf_verifier_env *env, u32 regno, int off,
static int check_ctx_access(struct bpf_verifier_env *env, int insn_idx, int off, int size,
enum bpf_access_type t, enum bpf_reg_type *reg_type)
{
- int ctx_field_size = 0;
+ struct bpf_insn_access_aux info = { .reg_type = *reg_type };
/* for analyzer ctx accesses are already validated and converted */
if (env->analyzer_ops)
return 0;
if (env->prog->aux->ops->is_valid_access &&
- env->prog->aux->ops->is_valid_access(off, size, t, reg_type, &ctx_field_size)) {
- /* a non zero ctx_field_size indicates:
+ env->prog->aux->ops->is_valid_access(off, size, t, &info)) {
+ /* a non zero info.ctx_field_size indicates:
* . For this field, the prog type specific ctx conversion algorithm
* only supports whole field access.
* . This ctx access is a candiate for later verifier transformation
* to load the whole field and then apply a mask to get correct result.
+ * a non zero info.converted_op_size indicates perceived actual converted
+ * value width in convert_ctx_access.
*/
- if (ctx_field_size)
- env->insn_aux_data[insn_idx].ctx_field_size = ctx_field_size;
+ if ((info.ctx_field_size && !info.converted_op_size) ||
+ (!info.ctx_field_size && info.converted_op_size)) {
+ verbose("verifier bug in is_valid_access prog type=%u off=%d size=%d\n",
+ env->prog->type, off, size);
+ return -EACCES;
+ }
+
+ if (info.ctx_field_size) {
+ env->insn_aux_data[insn_idx].ctx_field_size = info.ctx_field_size;
+ env->insn_aux_data[insn_idx].converted_op_size = info.converted_op_size;
+ }
+ *reg_type = info.reg_type;
/* remember the offset of last byte accessed in ctx */
if (env->prog->aux->max_ctx_offset < off + size)
@@ -3388,7 +3400,7 @@ static int convert_ctx_accesses(struct bpf_verifier_env *env)
struct bpf_insn insn_buf[16], *insn;
struct bpf_prog *new_prog;
enum bpf_access_type type;
- int i, cnt, off, size, ctx_field_size, is_narrower_load, delta = 0;
+ int i, cnt, off, size, ctx_field_size, converted_op_size, is_narrower_load, delta = 0;
if (ops->gen_prologue) {
cnt = ops->gen_prologue(insn_buf, env->seen_direct_write,
@@ -3431,7 +3443,8 @@ static int convert_ctx_accesses(struct bpf_verifier_env *env)
off = insn->off;
size = bpf_size_to_bytes(BPF_SIZE(insn->code));
ctx_field_size = env->insn_aux_data[i + delta].ctx_field_size;
- is_narrower_load = (type == BPF_READ && size < ctx_field_size);
+ converted_op_size = env->insn_aux_data[i + delta].converted_op_size;
+ is_narrower_load = type == BPF_READ && size < ctx_field_size;
/* If the read access is a narrower load of the field,
* convert to a 4/8-byte load, to minimum program type specific
@@ -3453,7 +3466,7 @@ static int convert_ctx_accesses(struct bpf_verifier_env *env)
verbose("bpf verifier is misconfigured\n");
return -EINVAL;
}
- if (is_narrower_load) {
+ if (is_narrower_load && size < converted_op_size) {
if (ctx_field_size <= 4)
insn_buf[cnt++] = BPF_ALU32_IMM(BPF_AND, insn->dst_reg,
(1 << size * 8) - 1);