summaryrefslogtreecommitdiff
path: root/include/linux/cnum.h
diff options
context:
space:
mode:
authorEduard Zingerman <eddyz87@gmail.com>2026-04-25 15:48:23 -0700
committerAlexei Starovoitov <ast@kernel.org>2026-04-27 09:56:38 -0700
commitcd5b460ed1eca9e48f3eb07db1ee0a522c0eaa23 (patch)
tree155f0c1bb57a4b0796e019a47ceab9249762197a /include/linux/cnum.h
parent7c8d208d816d0504aa916138ae097d9cb4ed4e56 (diff)
bpf: range_within() must check cnum ranges instead of min/max pairs
states.c:range_within() must be updated to properly check if cnum-based range in an old state is a superset of a range in the cur state. Currently it makes the decision using min/max accessors: reg_umin(old) <= reg_umin(cur) <= reg_umax(old) This is wrong for cnums that cross both UT_MAX/0 and ST_MAX/ST_MIN boundaries. Consider cnum32{base=0x7FFFFFF0, size=0x80000020}, which represents values [0x7FFFFFF0, ..., U32_MAX, 0, ..., 0x10]. Its projections are u32_min/max=0/U32_MAX, s32_min/max=S32_MIN/MAX. A register with range [0x100, 0x200] (which lies entirely in the gap of the wrapping range) would pass the min/max check despite having no overlap with the actual cnum arc. This commit replaces min/max comparison with cnum{32,64}_is_subset() operation. The operation implementation is verified using cbmc model checker in [1]. [1] https://github.com/eddyz87/cnum-verif/ Fixes: bbc631085503 ("bpf: replace min/max fields with struct cnum{32,64}") Signed-off-by: Eduard Zingerman <eddyz87@gmail.com> Link: https://lore.kernel.org/r/20260425-cnum-range-within-v1-1-2fdca70cb09d@gmail.com Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Diffstat (limited to 'include/linux/cnum.h')
-rw-r--r--include/linux/cnum.h2
1 files changed, 2 insertions, 0 deletions
diff --git a/include/linux/cnum.h b/include/linux/cnum.h
index a7259b105b45..49b7d0c7645d 100644
--- a/include/linux/cnum.h
+++ b/include/linux/cnum.h
@@ -48,6 +48,7 @@ bool cnum32_is_const(struct cnum32 cnum);
bool cnum32_is_empty(struct cnum32 cnum);
struct cnum32 cnum32_add(struct cnum32 a, struct cnum32 b);
struct cnum32 cnum32_negate(struct cnum32 a);
+bool cnum32_is_subset(struct cnum32 outer, struct cnum32 inner);
/* Same as cnum32 but for 64-bit ranges */
struct cnum64 {
@@ -73,6 +74,7 @@ bool cnum64_is_const(struct cnum64 cnum);
bool cnum64_is_empty(struct cnum64 cnum);
struct cnum64 cnum64_add(struct cnum64 a, struct cnum64 b);
struct cnum64 cnum64_negate(struct cnum64 a);
+bool cnum64_is_subset(struct cnum64 outer, struct cnum64 inner);
struct cnum32 cnum32_from_cnum64(struct cnum64 cnum);
struct cnum64 cnum64_cnum32_intersect(struct cnum64 a, struct cnum32 b);