In previous patch, we have split register arg type for sub-register read, but haven't touch read liveness. This patch further split read liveness into REG_LIVE_READ64 and REG_LIVE_READ32. Liveness propagation code are updated accordingly. After this split, customized actions could be defined when propagating full register read (REG_LIVE_READ64) or sub-register read (REG_LIVE_READ32). Signed-off-by: Jiong Wang <jiong.wang@xxxxxxxxxxxxx> --- include/linux/bpf_verifier.h | 9 ++++++--- kernel/bpf/verifier.c | 30 +++++++++++++++++++++--------- 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h index f03c86a..27761ab 100644 --- a/include/linux/bpf_verifier.h +++ b/include/linux/bpf_verifier.h @@ -37,11 +37,14 @@ /* Reg hasn't been read or written this branch. */ #define REG_LIVE_NONE 0x0 /* Reg was read, so we're sensitive to initial value. */ -#define REG_LIVE_READ 0x1 +#define REG_LIVE_READ32 0x1 +/* Likewise, but full 64-bit content matters. */ +#define REG_LIVE_READ64 0x2 +#define REG_LIVE_READ (REG_LIVE_READ32 | REG_LIVE_READ64) /* Reg was written first, screening off later reads. */ -#define REG_LIVE_WRITTEN 0x2 +#define REG_LIVE_WRITTEN 0x4 /* Liveness won't be updating this register anymore. */ -#define REG_LIVE_DONE 0x4 +#define REG_LIVE_DONE 0x8 struct bpf_reg_state { /* Ordering of fields matters. See states_equal() */ diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 245bb3c..b95c438 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -1126,7 +1126,7 @@ static int check_subprogs(struct bpf_verifier_env *env) */ static int mark_reg_read(struct bpf_verifier_env *env, const struct bpf_reg_state *state, - struct bpf_reg_state *parent) + struct bpf_reg_state *parent, bool dw_read) { bool writes = parent == state->parent; /* Observe write marks */ @@ -1141,7 +1141,7 @@ static int mark_reg_read(struct bpf_verifier_env *env, return -EFAULT; } /* ... then we depend on parent's value */ - parent->live |= REG_LIVE_READ; + parent->live |= dw_read ? REG_LIVE_READ64 : REG_LIVE_READ32; state = parent; parent = state->parent; writes = true; @@ -1170,7 +1170,7 @@ static int check_reg_arg(struct bpf_verifier_env *env, u32 regno, /* We don't need to worry about FP liveness because it's read-only */ if (regno != BPF_REG_FP) return mark_reg_read(env, ®s[regno], - regs[regno].parent); + regs[regno].parent, true); } else { /* check whether register used as dest operand can be written to */ if (regno == BPF_REG_FP) { @@ -1357,7 +1357,7 @@ static int check_stack_read(struct bpf_verifier_env *env, state->regs[value_regno].live |= REG_LIVE_WRITTEN; } mark_reg_read(env, ®_state->stack[spi].spilled_ptr, - reg_state->stack[spi].spilled_ptr.parent); + reg_state->stack[spi].spilled_ptr.parent, true); return 0; } else { int zeros = 0; @@ -1374,7 +1374,8 @@ static int check_stack_read(struct bpf_verifier_env *env, return -EACCES; } mark_reg_read(env, ®_state->stack[spi].spilled_ptr, - reg_state->stack[spi].spilled_ptr.parent); + reg_state->stack[spi].spilled_ptr.parent, + size == BPF_REG_SIZE); if (value_regno >= 0) { if (zeros == size) { /* any size read into register is zero extended, @@ -2220,7 +2221,8 @@ static int check_stack_boundary(struct bpf_verifier_env *env, int regno, * the whole slot to be marked as 'read' */ mark_reg_read(env, &state->stack[spi].spilled_ptr, - state->stack[spi].spilled_ptr.parent); + state->stack[spi].spilled_ptr.parent, + access_size == BPF_REG_SIZE); } return update_stack_depth(env, state, off); } @@ -6059,7 +6061,7 @@ static int propagate_liveness_reg(struct bpf_verifier_env *env, if (parent_reg->live & flag || !(reg->live & flag)) return 0; - err = mark_reg_read(env, reg, parent_reg); + err = mark_reg_read(env, reg, parent_reg, flag == REG_LIVE_READ64); if (err) return err; @@ -6092,7 +6094,12 @@ static int propagate_liveness(struct bpf_verifier_env *env, regs = vstate->frame[vstate->curframe]->regs; /* We don't need to worry about FP liveness because it's read-only */ for (i = 0; i < BPF_REG_FP; i++) { - err = propagate_liveness_reg(env, ®s[i], &parent_regs[i]); + err = propagate_liveness_reg(env, ®s[i], &parent_regs[i], + REG_LIVE_READ64); + if (err < 0) + return err; + err = propagate_liveness_reg(env, ®s[i], &parent_regs[i], + REG_LIVE_READ32); if (err < 0) return err; } @@ -6107,7 +6114,12 @@ static int propagate_liveness(struct bpf_verifier_env *env, parent_reg = &parent->stack[i].spilled_ptr; reg = &state->stack[i].spilled_ptr; - err = propagate_liveness_reg(env, reg, parent_reg); + err = propagate_liveness_reg(env, reg, parent_reg, + REG_LIVE_READ64); + if (err < 0) + return err; + err = propagate_liveness_reg(env, reg, parent_reg, + REG_LIVE_READ32); if (err < 0) return err; } -- 2.7.4