summaryrefslogtreecommitdiff
path: root/kernel/bpf/tnum.c
diff options
context:
space:
mode:
authorEdward Cree <ecree@solarflare.com>2017-08-07 15:26:36 +0100
committerDavid S. Miller <davem@davemloft.net>2017-08-08 17:51:34 -0700
commitb03c9f9fdc37dab81ea04d5dacdc5995d4c224c2 (patch)
tree864f5f7e43fbcba5dcc2953ee84d9c1470373d59 /kernel/bpf/tnum.c
parentf1174f77b50c94eecaa658fdc56fa69b421de4b8 (diff)
bpf/verifier: track signed and unsigned min/max values
Allows us to, sometimes, combine information from a signed check of one bound and an unsigned check of the other. We now track the full range of possible values, rather than restricting ourselves to [0, 1<<30) and considering anything beyond that as unknown. While this is probably not necessary, it makes the code more straightforward and symmetrical between signed and unsigned bounds. Signed-off-by: Edward Cree <ecree@solarflare.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'kernel/bpf/tnum.c')
-rw-r--r--kernel/bpf/tnum.c16
1 files changed, 16 insertions, 0 deletions
diff --git a/kernel/bpf/tnum.c b/kernel/bpf/tnum.c
index 92eeeb1974a2..1f4bf68c12db 100644
--- a/kernel/bpf/tnum.c
+++ b/kernel/bpf/tnum.c
@@ -17,6 +17,22 @@ struct tnum tnum_const(u64 value)
return TNUM(value, 0);
}
+struct tnum tnum_range(u64 min, u64 max)
+{
+ u64 chi = min ^ max, delta;
+ u8 bits = fls64(chi);
+
+ /* special case, needed because 1ULL << 64 is undefined */
+ if (bits > 63)
+ return tnum_unknown;
+ /* e.g. if chi = 4, bits = 3, delta = (1<<3) - 1 = 7.
+ * if chi = 0, bits = 0, delta = (1<<0) - 1 = 0, so we return
+ * constant min (since min == max).
+ */
+ delta = (1ULL << bits) - 1;
+ return TNUM(min & ~delta, delta);
+}
+
struct tnum tnum_lshift(struct tnum a, u8 shift)
{
return TNUM(a.value << shift, a.mask << shift);