aboutsummaryrefslogtreecommitdiff
path: root/include/linux
diff options
context:
space:
mode:
authorAndrii Nakryiko <[email protected]>2023-06-13 15:14:27 -0700
committerAndrii Nakryiko <[email protected]>2023-06-13 15:15:30 -0700
commitc03531e087b550d975bc1eb32f56f9da47aaa77e (patch)
treeb54adfd56be610fc6423c01aaf05b1364fb91a23 /include/linux
parent25085b4e9251c77758964a8e8651338972353642 (diff)
parent18b89265572b5c899522b6c1f8698e87edfad369 (diff)
Merge branch 'verify scalar ids mapping in regsafe()'
Eduard Zingerman says: ==================== Update regsafe() to use check_ids() for scalar values. Otherwise the following unsafe pattern is accepted by verifier: 1: r9 = ... some pointer with range X ... 2: r6 = ... unbound scalar ID=a ... 3: r7 = ... unbound scalar ID=b ... 4: if (r6 > r7) goto +1 5: r6 = r7 6: if (r6 > X) goto ... --- checkpoint --- 7: r9 += r7 8: *(u64 *)r9 = Y This example is unsafe because not all execution paths verify r7 range. Because of the jump at (4) the verifier would arrive at (6) in two states: I. r6{.id=b}, r7{.id=b} via path 1-6; II. r6{.id=a}, r7{.id=b} via path 1-4, 6. Currently regsafe() does not call check_ids() for scalar registers, thus from POV of regsafe() states (I) and (II) are identical. The change is split in two parts: - patches #1,2: update for mark_chain_precision() to propagate precision marks through scalar IDs. - patches #3,4: update for regsafe() to use a special version of check_ids() for precise scalar values. Changelog: - V5 -> V6: - check_ids() is modified to disallow mapping different 'old_id' to the same 'cur_id', check_scalar_ids() simplified (Andrii); - idset_push() updated to return -EFAULT instead of -1 (Andrii); - comments fixed in check_ids_in_regsafe() test case (Maxim Mikityanskiy); - fixed memset warning in states_equal() reported in [4]. - V4 -> V5 (all changes are based on feedback for V4 from Andrii): - mark_precise_scalar_ids() error code is updated to EFAULT; - bpf_verifier_env::idmap_scratch field type is changed to struct bpf_idmap to encapsulate temporary ID generation counter; - regsafe() is updated to call scalar_regs_exact() only for env->explore_alu_limits case (this had no measurable impact on verification duration when tested using veristat). - V3 -> V4: - check_ids() in regsafe() is replaced by check_scalar_ids(), as discussed with Andrii in [3], Note: I did not transfer Andrii's ack for patch #3 from V3 because of the changes to the algorithm. - reg_id_scratch is renamed to idset_scratch; - mark_precise_scalar_ids() is modified to propagate error from idset_push(); - test cases adjusted according to feedback from Andrii for V3. - V2 -> V3: - u32_hashset for IDs used for range transfer is removed; - mark_chain_precision() is updated as discussed with Andrii in [2]. - V1 -> v2: - 'rold->precise' and 'rold->id' checks are dropped as unsafe (thanks to discussion with Yonghong); - patches #3,4 adding tracking of ids used for range transfer in order to mitigate performance impact. - RFC -> V1: - Function verifier.c:mark_equal_scalars_as_read() is dropped, as it was an incorrect fix for problem solved by commit [3]. - check_ids() is called only for precise scalar values. - Test case updated to use inline assembly. [V1] https://lore.kernel.org/bpf/[email protected]/ [V2] https://lore.kernel.org/bpf/[email protected]/ [V3] https://lore.kernel.org/bpf/[email protected]/ [V4] https://lore.kernel.org/bpf/[email protected]/ [V5] https://lore.kernel.org/bpf/[email protected]/ [RFC] https://lore.kernel.org/bpf/[email protected]/ [1] https://gist.github.com/eddyz87/a32ea7e62a27d3c201117c9a39ab4286 [2] https://lore.kernel.org/bpf/[email protected]/T/#mc21009dcd8574b195c1860a98014bb037f16f450 [3] https://lore.kernel.org/bpf/[email protected]/T/#m89da8eeb2fa8c9ca1202c5d0b6660e1f72e45e04 [4] https://lore.kernel.org/oe-kbuild-all/[email protected]/ ==================== Signed-off-by: Andrii Nakryiko <[email protected]>
Diffstat (limited to 'include/linux')
-rw-r--r--include/linux/bpf_verifier.h25
1 files changed, 19 insertions, 6 deletions
diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h
index 5b11a3b0fec0..f70f9ac884d2 100644
--- a/include/linux/bpf_verifier.h
+++ b/include/linux/bpf_verifier.h
@@ -313,11 +313,6 @@ struct bpf_idx_pair {
u32 idx;
};
-struct bpf_id_pair {
- u32 old;
- u32 cur;
-};
-
#define MAX_CALL_FRAMES 8
/* Maximum number of register states that can exist at once */
#define BPF_ID_MAP_SIZE ((MAX_BPF_REG + MAX_BPF_STACK / BPF_REG_SIZE) * MAX_CALL_FRAMES)
@@ -557,6 +552,21 @@ struct backtrack_state {
u64 stack_masks[MAX_CALL_FRAMES];
};
+struct bpf_id_pair {
+ u32 old;
+ u32 cur;
+};
+
+struct bpf_idmap {
+ u32 tmp_id_gen;
+ struct bpf_id_pair map[BPF_ID_MAP_SIZE];
+};
+
+struct bpf_idset {
+ u32 count;
+ u32 ids[BPF_ID_MAP_SIZE];
+};
+
/* single container for all structs
* one verifier_env per bpf_check() call
*/
@@ -588,7 +598,10 @@ struct bpf_verifier_env {
const struct bpf_line_info *prev_linfo;
struct bpf_verifier_log log;
struct bpf_subprog_info subprog_info[BPF_MAX_SUBPROGS + 1];
- struct bpf_id_pair idmap_scratch[BPF_ID_MAP_SIZE];
+ union {
+ struct bpf_idmap idmap_scratch;
+ struct bpf_idset idset_scratch;
+ };
struct {
int *insn_state;
int *insn_stack;