summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/bpf/fixups.c33
-rw-r--r--kernel/bpf/verifier.c10
2 files changed, 40 insertions, 3 deletions
diff --git a/kernel/bpf/fixups.c b/kernel/bpf/fixups.c
index 65b441e4a351..73fb3ffc18e3 100644
--- a/kernel/bpf/fixups.c
+++ b/kernel/bpf/fixups.c
@@ -213,7 +213,8 @@ static int get_callee_stack_depth(struct bpf_verifier_env *env,
* [0, off) and [off, end) to new locations, so the patched range stays zero
*/
static void adjust_insn_aux_data(struct bpf_verifier_env *env,
- struct bpf_prog *new_prog, u32 off, u32 cnt)
+ struct bpf_prog *new_prog, u32 off, u32 cnt,
+ struct bpf_insn *original_insn)
{
struct bpf_insn_aux_data *data = env->insn_aux_data;
struct bpf_insn *insn = new_prog->insnsi;
@@ -227,8 +228,15 @@ static void adjust_insn_aux_data(struct bpf_verifier_env *env,
*/
data[off].zext_dst = bpf_insn_def32(new_prog, insn + off + cnt - 1) >= 0;
- if (cnt == 1)
+ if (cnt == 1) {
+ /*
+ * A non-memory accessing insn could have been replaced by a
+ * memory accessing insn, systematically mark it for non-stack
+ * access
+ */
+ data[off].non_stack_access = bpf_is_mem_insn(insn + off);
return;
+ }
prog_len = new_prog->len;
env->insn_aux_data_len = prog_len;
@@ -239,9 +247,26 @@ static void adjust_insn_aux_data(struct bpf_verifier_env *env,
/* Expand insni[off]'s seen count to the patched range. */
data[i].seen = old_seen;
data[i].zext_dst = bpf_insn_def32(new_prog, insn + i) >= 0;
+ if (!memcmp(insn + i, original_insn, sizeof(struct bpf_insn))) {
+ data[i].non_stack_access =
+ data[off + cnt - 1].non_stack_access;
+ data[off + cnt - 1].non_stack_access = false;
+ } else if (bpf_is_mem_insn(insn + i)) {
+ data[i].non_stack_access = true;
+ }
}
/*
+ * Last slot instruction could be a newly generated
+ * BPF_ST/BPF_LDX/BPF_STX, systematically mark it for non-stack access
+ * if it is not the original instruction, otherwise keep the
+ * original marking
+ */
+ if (bpf_is_mem_insn(insn + off + cnt - 1) &&
+ memcmp(insn + off + cnt - 1, original_insn, sizeof(struct bpf_insn)))
+ data[off + cnt - 1].non_stack_access = true;
+
+ /*
* The indirect_target flag of the original instruction was moved to the last of the
* new instructions by the above memmove and memset, but the indirect jump target is
* actually the first instruction, so move it back. This also matches with the behavior
@@ -306,6 +331,7 @@ struct bpf_prog *bpf_patch_insn_data(struct bpf_verifier_env *env, u32 off,
{
struct bpf_prog *new_prog;
struct bpf_insn_aux_data *new_data = NULL;
+ struct bpf_insn original_insn;
if (len > 1) {
new_data = vrealloc(env->insn_aux_data,
@@ -318,6 +344,7 @@ struct bpf_prog *bpf_patch_insn_data(struct bpf_verifier_env *env, u32 off,
env->insn_aux_data = new_data;
}
+ memcpy(&original_insn, env->prog->insnsi + off, sizeof(struct bpf_insn));
new_prog = bpf_patch_insn_single(env->prog, off, patch, len);
if (IS_ERR(new_prog)) {
if (PTR_ERR(new_prog) == -ERANGE)
@@ -326,7 +353,7 @@ struct bpf_prog *bpf_patch_insn_data(struct bpf_verifier_env *env, u32 off,
env->insn_aux_data[off].orig_idx);
return NULL;
}
- adjust_insn_aux_data(env, new_prog, off, len);
+ adjust_insn_aux_data(env, new_prog, off, len, &original_insn);
adjust_subprog_starts(env, off, len);
adjust_insn_arrays(env, off, len);
adjust_poke_descs(new_prog, off, len);
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 8f585ceb2cd5..5b51e7ee1a3f 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -3273,6 +3273,11 @@ static void mark_indirect_target(struct bpf_verifier_env *env, int idx)
env->insn_aux_data[idx].indirect_target = true;
}
+static void mark_non_stack_access(struct bpf_verifier_env *env, int idx)
+{
+ env->insn_aux_data[idx].non_stack_access = true;
+}
+
#define LR_FRAMENO_BITS 4
#define LR_SPI_BITS 6
#define LR_ENTRY_BITS (LR_SPI_BITS + LR_FRAMENO_BITS + 1)
@@ -6417,6 +6422,7 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, struct b
int value_regno, bool strict_alignment_once, bool is_ldsx)
{
struct bpf_reg_state *regs = cur_regs(env);
+ enum bpf_reg_type ptr_type = reg->type;
int size, err = 0;
size = bpf_size_to_bytes(bpf_size);
@@ -6655,6 +6661,10 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, struct b
clear_scalar_id(&regs[value_regno]);
}
}
+
+ if (!err && bpf_is_mem_insn(&env->prog->insnsi[insn_idx]) && ptr_type != PTR_TO_STACK)
+ mark_non_stack_access(env, insn_idx);
+
return err;
}